=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/auth.c,v retrieving revision 1.11.2.8 retrieving revision 1.12 diff -u -r1.11.2.8 -r1.12 --- src/usr.bin/ssh/auth.c 2002/03/08 17:04:41 1.11.2.8 +++ src/usr.bin/ssh/auth.c 2001/01/13 18:56:48 1.12 @@ -1,6 +1,16 @@ /* - * Copyright (c) 2000 Markus Friedl. All rights reserved. + * Copyright (c) 1995 Tatu Ylonen , Espoo, Finland + * All rights reserved * + * As far as I am concerned, the code I have written for this software + * can be used freely for any purpose. Any derived versions of this + * software must be clearly marked as such, and if the derived work is + * incompatible with the protocol description in the RFC file, it must be + * called by a name other than "ssh" or "Secure Shell". + * + * + * Copyright (c) 2000 Markus Friedl. All rights reserved. + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -23,22 +33,25 @@ */ #include "includes.h" -RCSID("$OpenBSD: auth.c,v 1.11.2.8 2002/03/08 17:04:41 brad Exp $"); +RCSID("$OpenBSD: auth.c,v 1.12 2001/01/13 18:56:48 markus Exp $"); -#include - #include "xmalloc.h" +#include "rsa.h" +#include "ssh.h" +#include "pty.h" +#include "packet.h" +#include "buffer.h" +#include "mpaux.h" +#include "servconf.h" +#include "compat.h" +#include "channels.h" #include "match.h" #include "groupaccess.h" -#include "log.h" -#include "servconf.h" -#include "auth.h" -#include "auth-options.h" -#include "canohost.h" -#include "buffer.h" + #include "bufaux.h" -#include "uidswap.h" -#include "tildexpand.h" +#include "ssh2.h" +#include "auth.h" +#include "session.h" /* import */ extern ServerOptions options; @@ -56,7 +69,6 @@ allowed_user(struct passwd * pw) { struct stat st; - const char *hostname = NULL, *ipaddr = NULL; char *shell; int i; @@ -71,60 +83,36 @@ shell = (pw->pw_shell[0] == '\0') ? _PATH_BSHELL : pw->pw_shell; /* deny if shell does not exists or is not executable */ - if (stat(shell, &st) != 0) { - log("User %.100s not allowed because shell %.100s does not exist", - pw->pw_name, shell); + if (stat(shell, &st) != 0) return 0; - } - if (!((st.st_mode & S_IFREG) && (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)))) { - log("User %.100s not allowed because shell %.100s is not executable", - pw->pw_name, shell); + if (!((st.st_mode & S_IFREG) && (st.st_mode & (S_IXOTH|S_IXUSR|S_IXGRP)))) return 0; - } - if (options.num_deny_users > 0 || options.num_allow_users > 0) { - hostname = get_canonical_hostname(options.verify_reverse_mapping); - ipaddr = get_remote_ipaddr(); - } - /* Return false if user is listed in DenyUsers */ if (options.num_deny_users > 0) { for (i = 0; i < options.num_deny_users; i++) - if (match_user(pw->pw_name, hostname, ipaddr, - options.deny_users[i])) { - log("User %.100s not allowed because listed in DenyUsers", - pw->pw_name); + if (match_pattern(pw->pw_name, options.deny_users[i])) return 0; - } } /* Return false if AllowUsers isn't empty and user isn't listed there */ if (options.num_allow_users > 0) { for (i = 0; i < options.num_allow_users; i++) - if (match_user(pw->pw_name, hostname, ipaddr, - options.allow_users[i])) + if (match_pattern(pw->pw_name, options.allow_users[i])) break; /* i < options.num_allow_users iff we break for loop */ - if (i >= options.num_allow_users) { - log("User %.100s not allowed because not listed in AllowUsers", - pw->pw_name); + if (i >= options.num_allow_users) return 0; - } } if (options.num_deny_groups > 0 || options.num_allow_groups > 0) { /* Get the user's group access list (primary and supplementary) */ - if (ga_init(pw->pw_name, pw->pw_gid) == 0) { - log("User %.100s not allowed because not in any group", - pw->pw_name); + if (ga_init(pw->pw_name, pw->pw_gid) == 0) return 0; - } /* Return false if one of user's groups is listed in DenyGroups */ if (options.num_deny_groups > 0) if (ga_match(options.deny_groups, options.num_deny_groups)) { ga_free(); - log("User %.100s not allowed because a group is listed in DenyGroups", - pw->pw_name); return 0; } /* @@ -135,254 +123,10 @@ if (!ga_match(options.allow_groups, options.num_allow_groups)) { ga_free(); - log("User %.100s not allowed because none of user's groups are listed in AllowGroups", - pw->pw_name); return 0; } ga_free(); } /* We found no reason not to let this user try to log on... */ return 1; -} - -Authctxt * -authctxt_new(void) -{ - Authctxt *authctxt = xmalloc(sizeof(*authctxt)); - memset(authctxt, 0, sizeof(*authctxt)); - return authctxt; -} - -void -auth_log(Authctxt *authctxt, int authenticated, char *method, char *info) -{ - void (*authlog) (const char *fmt,...) = verbose; - char *authmsg; - - /* Raise logging level */ - if (authenticated == 1 || - !authctxt->valid || - authctxt->failures >= AUTH_FAIL_LOG || - strcmp(method, "password") == 0) - authlog = log; - - if (authctxt->postponed) - authmsg = "Postponed"; - else - authmsg = authenticated ? "Accepted" : "Failed"; - - authlog("%s %s for %s%.100s from %.200s port %d%s", - authmsg, - method, - authctxt->valid ? "" : "illegal user ", - authctxt->user, - get_remote_ipaddr(), - get_remote_port(), - info); -} - -/* - * Check whether root logins are disallowed. - */ -int -auth_root_allowed(char *method) -{ - switch (options.permit_root_login) { - case PERMIT_YES: - return 1; - break; - case PERMIT_NO_PASSWD: - if (strcmp(method, "password") != 0) - return 1; - break; - case PERMIT_FORCED_ONLY: - if (forced_command) { - log("Root login accepted for forced command."); - return 1; - } - break; - } - log("ROOT LOGIN REFUSED FROM %.200s", get_remote_ipaddr()); - return 0; -} - - -/* - * Given a template and a passwd structure, build a filename - * by substituting % tokenised options. Currently, %% becomes '%', - * %h becomes the home directory and %u the username. - * - * This returns a buffer allocated by xmalloc. - */ -char * -expand_filename(const char *filename, struct passwd *pw) -{ - Buffer buffer; - char *file; - const char *cp; - - /* - * Build the filename string in the buffer by making the appropriate - * substitutions to the given file name. - */ - buffer_init(&buffer); - for (cp = filename; *cp; cp++) { - if (cp[0] == '%' && cp[1] == '%') { - buffer_append(&buffer, "%", 1); - cp++; - continue; - } - if (cp[0] == '%' && cp[1] == 'h') { - buffer_append(&buffer, pw->pw_dir, strlen(pw->pw_dir)); - cp++; - continue; - } - if (cp[0] == '%' && cp[1] == 'u') { - buffer_append(&buffer, pw->pw_name, - strlen(pw->pw_name)); - cp++; - continue; - } - buffer_append(&buffer, cp, 1); - } - buffer_append(&buffer, "\0", 1); - - /* - * Ensure that filename starts anchored. If not, be backward - * compatible and prepend the '%h/' - */ - file = xmalloc(MAXPATHLEN); - cp = buffer_ptr(&buffer); - if (*cp != '/') - snprintf(file, MAXPATHLEN, "%s/%s", pw->pw_dir, cp); - else - strlcpy(file, cp, MAXPATHLEN); - - buffer_free(&buffer); - return file; -} - -char * -authorized_keys_file(struct passwd *pw) -{ - return expand_filename(options.authorized_keys_file, pw); -} - -char * -authorized_keys_file2(struct passwd *pw) -{ - return expand_filename(options.authorized_keys_file2, pw); -} - -/* return ok if key exists in sysfile or userfile */ -HostStatus -check_key_in_hostfiles(struct passwd *pw, Key *key, const char *host, - const char *sysfile, const char *userfile) -{ - Key *found; - char *user_hostfile; - struct stat st; - HostStatus host_status; - - /* Check if we know the host and its host key. */ - found = key_new(key->type); - host_status = check_host_in_hostfile(sysfile, host, key, found, NULL); - - if (host_status != HOST_OK && userfile != NULL) { - user_hostfile = tilde_expand_filename(userfile, pw->pw_uid); - if (options.strict_modes && - (stat(user_hostfile, &st) == 0) && - ((st.st_uid != 0 && st.st_uid != pw->pw_uid) || - (st.st_mode & 022) != 0)) { - log("Authentication refused for %.100s: " - "bad owner or modes for %.200s", - pw->pw_name, user_hostfile); - } else { - temporarily_use_uid(pw); - host_status = check_host_in_hostfile(user_hostfile, - host, key, found, NULL); - restore_uid(); - } - xfree(user_hostfile); - } - key_free(found); - - debug2("check_key_in_hostfiles: key %s for %s", host_status == HOST_OK ? - "ok" : "not found", host); - return host_status; -} - - -/* - * Check a given file for security. This is defined as all components - * of the path to the file must either be owned by either the owner of - * of the file or root and no directories must be group or world writable. - * - * XXX Should any specific check be done for sym links ? - * - * Takes an open file descriptor, the file name, a uid and and - * error buffer plus max size as arguments. - * - * Returns 0 on success and -1 on failure - */ -int -secure_filename(FILE *f, const char *file, struct passwd *pw, - char *err, size_t errlen) -{ - uid_t uid = pw->pw_uid; - char buf[MAXPATHLEN], homedir[MAXPATHLEN]; - char *cp; - struct stat st; - - if (realpath(file, buf) == NULL) { - snprintf(err, errlen, "realpath %s failed: %s", file, - strerror(errno)); - return -1; - } - if (realpath(pw->pw_dir, homedir) == NULL) { - snprintf(err, errlen, "realpath %s failed: %s", pw->pw_dir, - strerror(errno)); - return -1; - } - - /* check the open file to avoid races */ - if (fstat(fileno(f), &st) < 0 || - (st.st_uid != 0 && st.st_uid != uid) || - (st.st_mode & 022) != 0) { - snprintf(err, errlen, "bad ownership or modes for file %s", - buf); - return -1; - } - - /* for each component of the canonical path, walking upwards */ - for (;;) { - if ((cp = dirname(buf)) == NULL) { - snprintf(err, errlen, "dirname() failed"); - return -1; - } - strlcpy(buf, cp, sizeof(buf)); - - debug3("secure_filename: checking '%s'", buf); - if (stat(buf, &st) < 0 || - (st.st_uid != 0 && st.st_uid != uid) || - (st.st_mode & 022) != 0) { - snprintf(err, errlen, - "bad ownership or modes for directory %s", buf); - return -1; - } - - /* If are passed the homedir then we can stop */ - if (strcmp(homedir, buf) == 0) { - debug3("secure_filename: terminating check at '%s'", - buf); - break; - } - /* - * dirname should always complete with a "/" path, - * but we can be paranoid and check for "." too - */ - if ((strcmp("/", buf) == 0) || (strcmp(".", buf) == 0)) - break; - } - return 0; }