Main Page | Namespace List | Class List | Directories | File List | Class Members | File Members

auth1.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
00003  *                    All rights reserved
00004  *
00005  * As far as I am concerned, the code I have written for this software
00006  * can be used freely for any purpose.  Any derived versions of this
00007  * software must be clearly marked as such, and if the derived work is
00008  * incompatible with the protocol description in the RFC file, it must be
00009  * called by a name other than "ssh" or "Secure Shell".
00010  */
00011 
00012 #include "includes.h"
00013 RCSID("$OpenBSD: auth1.c,v 1.62 2005/07/16 01:35:24 djm Exp $");
00014 
00015 #include "xmalloc.h"
00016 #include "rsa.h"
00017 #include "ssh1.h"
00018 #include "packet.h"
00019 #include "buffer.h"
00020 #include "log.h"
00021 #include "servconf.h"
00022 #include "compat.h"
00023 #include "auth.h"
00024 #include "channels.h"
00025 #include "session.h"
00026 #include "uidswap.h"
00027 #include "monitor_wrap.h"
00028 #include "buffer.h"
00029 
00030 /* import */
00031 extern ServerOptions options;
00032 extern Buffer loginmsg;
00033 
00034 static int auth1_process_password(Authctxt *, char *, size_t);
00035 static int auth1_process_rsa(Authctxt *, char *, size_t);
00036 static int auth1_process_rhosts_rsa(Authctxt *, char *, size_t);
00037 static int auth1_process_tis_challenge(Authctxt *, char *, size_t);
00038 static int auth1_process_tis_response(Authctxt *, char *, size_t);
00039 
00040 static char *client_user = NULL;    /* Used to fill in remote user for PAM */
00041 
00042 struct AuthMethod1 {
00043         int type;
00044         char *name;
00045         int *enabled;
00046         int (*method)(Authctxt *, char *, size_t);
00047 };
00048 
00049 const struct AuthMethod1 auth1_methods[] = {
00050         {
00051                 SSH_CMSG_AUTH_PASSWORD, "password",
00052                 &options.password_authentication, auth1_process_password
00053         },
00054         {
00055                 SSH_CMSG_AUTH_RSA, "rsa",
00056                 &options.rsa_authentication, auth1_process_rsa
00057         },
00058         {
00059                 SSH_CMSG_AUTH_RHOSTS_RSA, "rhosts-rsa",
00060                 &options.rhosts_rsa_authentication, auth1_process_rhosts_rsa
00061         },
00062         {
00063                 SSH_CMSG_AUTH_TIS, "challenge-response",
00064                 &options.challenge_response_authentication,
00065                 auth1_process_tis_challenge
00066         },
00067         {
00068                 SSH_CMSG_AUTH_TIS_RESPONSE, "challenge-response",
00069                 &options.challenge_response_authentication,
00070                 auth1_process_tis_response
00071         },
00072         { -1, NULL, NULL, NULL}
00073 };
00074 
00075 static const struct AuthMethod1
00076 *lookup_authmethod1(int type)
00077 {
00078         int i;
00079 
00080         for(i = 0; auth1_methods[i].name != NULL; i++)
00081                 if (auth1_methods[i].type == type)
00082                         return (&(auth1_methods[i]));
00083 
00084         return (NULL);
00085 }
00086 
00087 static char *
00088 get_authname(int type)
00089 {
00090         const struct AuthMethod1 *a;
00091         static char buf[64];
00092 
00093         if ((a = lookup_authmethod1(type)) != NULL)
00094                 return (a->name);
00095         snprintf(buf, sizeof(buf), "bad-auth-msg-%d", type);
00096         return (buf);
00097 }
00098 
00099 static int
00100 auth1_process_password(Authctxt *authctxt, char *info, size_t infolen)
00101 {
00102         int authenticated = 0;
00103         char *password;
00104         u_int dlen;
00105 
00106         /*
00107          * Read user password.  It is in plain text, but was
00108          * transmitted over the encrypted channel so it is
00109          * not visible to an outside observer.
00110          */
00111         password = packet_get_string(&dlen);
00112         packet_check_eom();
00113 
00114         /* Try authentication with the password. */
00115         authenticated = PRIVSEP(auth_password(authctxt, password));
00116 
00117         memset(password, 0, dlen);
00118         xfree(password);
00119 
00120         return (authenticated);
00121 }
00122 
00123 static int
00124 auth1_process_rsa(Authctxt *authctxt, char *info, size_t infolen)
00125 {
00126         int authenticated = 0;
00127         BIGNUM *n;
00128 
00129         /* RSA authentication requested. */
00130         if ((n = BN_new()) == NULL)
00131                 fatal("do_authloop: BN_new failed");
00132         packet_get_bignum(n);
00133         packet_check_eom();
00134         authenticated = auth_rsa(authctxt, n);
00135         BN_clear_free(n);
00136 
00137         return (authenticated);
00138 }
00139 
00140 static int
00141 auth1_process_rhosts_rsa(Authctxt *authctxt, char *info, size_t infolen)
00142 {
00143         int keybits, authenticated = 0;
00144         u_int bits;
00145         Key *client_host_key;
00146         u_int ulen;
00147 
00148         /*
00149          * Get client user name.  Note that we just have to
00150          * trust the client; root on the client machine can
00151          * claim to be any user.
00152          */
00153         client_user = packet_get_string(&ulen);
00154 
00155         /* Get the client host key. */
00156         client_host_key = key_new(KEY_RSA1);
00157         bits = packet_get_int();
00158         packet_get_bignum(client_host_key->rsa->e);
00159         packet_get_bignum(client_host_key->rsa->n);
00160 
00161         keybits = BN_num_bits(client_host_key->rsa->n);
00162         if (keybits < 0 || bits != (u_int)keybits) {
00163                 verbose("Warning: keysize mismatch for client_host_key: "
00164                     "actual %d, announced %d",
00165                     BN_num_bits(client_host_key->rsa->n), bits);
00166         }
00167         packet_check_eom();
00168 
00169         authenticated = auth_rhosts_rsa(authctxt, client_user,
00170             client_host_key);
00171         key_free(client_host_key);
00172 
00173         snprintf(info, infolen, " ruser %.100s", client_user);
00174 
00175         return (authenticated);
00176 }
00177 
00178 static int
00179 auth1_process_tis_challenge(Authctxt *authctxt, char *info, size_t infolen)
00180 {
00181         char *challenge;
00182 
00183         if ((challenge = get_challenge(authctxt)) == NULL)
00184                 return (0);
00185 
00186         debug("sending challenge '%s'", challenge);
00187         packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
00188         packet_put_cstring(challenge);
00189         xfree(challenge);
00190         packet_send();
00191         packet_write_wait();
00192 
00193         return (-1);
00194 }
00195 
00196 static int
00197 auth1_process_tis_response(Authctxt *authctxt, char *info, size_t infolen)
00198 {
00199         int authenticated = 0;
00200         char *response;
00201         u_int dlen;
00202 
00203         response = packet_get_string(&dlen);
00204         packet_check_eom();
00205         authenticated = verify_response(authctxt, response);
00206         memset(response, 'r', dlen);
00207         xfree(response);
00208 
00209         return (authenticated);
00210 }
00211 
00212 /*
00213  * read packets, try to authenticate the user and
00214  * return only if authentication is successful
00215  */
00216 static void
00217 do_authloop(Authctxt *authctxt)
00218 {
00219         int authenticated = 0;
00220         char info[1024];
00221         int prev = 0, type = 0;
00222         const struct AuthMethod1 *meth;
00223 
00224         debug("Attempting authentication for %s%.100s.",
00225             authctxt->valid ? "" : "invalid user ", authctxt->user);
00226 
00227         /* If the user has no password, accept authentication immediately. */
00228         if (options.password_authentication &&
00229 #ifdef KRB5
00230             (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
00231 #endif
00232             PRIVSEP(auth_password(authctxt, ""))) {
00233 #ifdef USE_PAM
00234                 if (options.use_pam && (PRIVSEP(do_pam_account())))
00235 #endif
00236                 {
00237                         auth_log(authctxt, 1, "without authentication", "");
00238                         return;
00239                 }
00240         }
00241 
00242         /* Indicate that authentication is needed. */
00243         packet_start(SSH_SMSG_FAILURE);
00244         packet_send();
00245         packet_write_wait();
00246 
00247         for (;;) {
00248                 /* default to fail */
00249                 authenticated = 0;
00250 
00251                 info[0] = '\0';
00252 
00253                 /* Get a packet from the client. */
00254                 prev = type;
00255                 type = packet_read();
00256 
00257                 /*
00258                  * If we started challenge-response authentication but the
00259                  * next packet is not a response to our challenge, release
00260                  * the resources allocated by get_challenge() (which would
00261                  * normally have been released by verify_response() had we
00262                  * received such a response)
00263                  */
00264                 if (prev == SSH_CMSG_AUTH_TIS &&
00265                     type != SSH_CMSG_AUTH_TIS_RESPONSE)
00266                         abandon_challenge_response(authctxt);
00267 
00268                 if ((meth = lookup_authmethod1(type)) == NULL) {
00269                         logit("Unknown message during authentication: "
00270                             "type %d", type);
00271                         goto skip;
00272                 }
00273 
00274                 if (!*(meth->enabled)) {
00275                         verbose("%s authentication disabled.", meth->name);
00276                         goto skip;
00277                 }
00278 
00279                 authenticated = meth->method(authctxt, info, sizeof(info));
00280                 if (authenticated == -1)
00281                         continue; /* "postponed" */
00282 
00283 #ifdef BSD_AUTH
00284                 if (authctxt->as) {
00285                         auth_close(authctxt->as);
00286                         authctxt->as = NULL;
00287                 }
00288 #endif
00289                 if (!authctxt->valid && authenticated)
00290                         fatal("INTERNAL ERROR: authenticated invalid user %s",
00291                             authctxt->user);
00292 
00293 #ifdef _UNICOS
00294                 if (authenticated && cray_access_denied(authctxt->user)) {
00295                         authenticated = 0;
00296                         fatal("Access denied for user %s.",authctxt->user);
00297                 }
00298 #endif /* _UNICOS */
00299 
00300 #ifdef HAVE_CYGWIN
00301                 if (authenticated &&
00302                     !check_nt_auth(type == SSH_CMSG_AUTH_PASSWORD,
00303                     authctxt->pw)) {
00304                         packet_disconnect("Authentication rejected for uid %d.",
00305                             authctxt->pw == NULL ? -1 : authctxt->pw->pw_uid);
00306                         authenticated = 0;
00307                 }
00308 #else
00309                 /* Special handling for root */
00310                 if (authenticated && authctxt->pw->pw_uid == 0 &&
00311                     !auth_root_allowed(meth->name)) {
00312                         authenticated = 0;
00313 # ifdef SSH_AUDIT_EVENTS
00314                         PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED));
00315 # endif
00316                 }
00317 #endif
00318 
00319 #ifdef USE_PAM
00320                 if (options.use_pam && authenticated &&
00321                     !PRIVSEP(do_pam_account())) {
00322                         char *msg;
00323                         size_t len;
00324 
00325                         error("Access denied for user %s by PAM account "
00326                             "configuration", authctxt->user);
00327                         len = buffer_len(&loginmsg);
00328                         buffer_append(&loginmsg, "\0", 1);
00329                         msg = buffer_ptr(&loginmsg);
00330                         /* strip trailing newlines */
00331                         if (len > 0)
00332                                 while (len > 0 && msg[--len] == '\n')
00333                                         msg[len] = '\0';
00334                         else
00335                                 msg = "Access denied.";
00336                         packet_disconnect(msg);
00337                 }
00338 #endif
00339 
00340  skip:
00341                 /* Log before sending the reply */
00342                 auth_log(authctxt, authenticated, get_authname(type), info);
00343 
00344                 if (client_user != NULL) {
00345                         xfree(client_user);
00346                         client_user = NULL;
00347                 }
00348 
00349                 if (authenticated)
00350                         return;
00351 
00352                 if (authctxt->failures++ > options.max_authtries) {
00353 #ifdef SSH_AUDIT_EVENTS
00354                         PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES));
00355 #endif
00356                         packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
00357                 }
00358 
00359                 packet_start(SSH_SMSG_FAILURE);
00360                 packet_send();
00361                 packet_write_wait();
00362         }
00363 }
00364 
00365 /*
00366  * Performs authentication of an incoming connection.  Session key has already
00367  * been exchanged and encryption is enabled.
00368  */
00369 void
00370 do_authentication(Authctxt *authctxt)
00371 {
00372         u_int ulen;
00373         char *user, *style = NULL;
00374 
00375         /* Get the name of the user that we wish to log in as. */
00376         packet_read_expect(SSH_CMSG_USER);
00377 
00378         /* Get the user name. */
00379         user = packet_get_string(&ulen);
00380         packet_check_eom();
00381 
00382         if ((style = strchr(user, ':')) != NULL)
00383                 *style++ = '\0';
00384 
00385         authctxt->user = user;
00386         authctxt->style = style;
00387 
00388         /* Verify that the user is a valid user. */
00389         if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL)
00390                 authctxt->valid = 1;
00391         else {
00392                 debug("do_authentication: invalid user %s", user);
00393                 authctxt->pw = fakepw();
00394         }
00395 
00396         setproctitle("%s%s", authctxt->valid ? user : "unknown",
00397             use_privsep ? " [net]" : "");
00398 
00399 #ifdef USE_PAM
00400         if (options.use_pam)
00401                 PRIVSEP(start_pam(authctxt));
00402 #endif
00403 
00404         /*
00405          * If we are not running as root, the user must have the same uid as
00406          * the server.
00407          */
00408 #ifndef HAVE_CYGWIN
00409         if (!use_privsep && getuid() != 0 && authctxt->pw &&
00410             authctxt->pw->pw_uid != getuid())
00411                 packet_disconnect("Cannot change user when server not running as root.");
00412 #endif
00413 
00414         /*
00415          * Loop until the user has been authenticated or the connection is
00416          * closed, do_authloop() returns only if authentication is successful
00417          */
00418         do_authloop(authctxt);
00419 
00420         /* The user has been authenticated and accepted. */
00421         packet_start(SSH_SMSG_SUCCESS);
00422         packet_send();
00423         packet_write_wait();
00424 }

© sourcejam.com 2005-2008