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

auth2.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  * 1. Redistributions of source code must retain the above copyright
00008  *    notice, this list of conditions and the following disclaimer.
00009  * 2. Redistributions in binary form must reproduce the above copyright
00010  *    notice, this list of conditions and the following disclaimer in the
00011  *    documentation and/or other materials provided with the distribution.
00012  *
00013  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
00014  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00015  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
00016  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
00017  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
00018  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
00019  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
00020  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00021  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
00022  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00023  */
00024 
00025 #include "includes.h"
00026 RCSID("$OpenBSD: auth2.c,v 1.107 2004/07/28 09:40:29 markus Exp $");
00027 
00028 #include "ssh2.h"
00029 #include "xmalloc.h"
00030 #include "packet.h"
00031 #include "log.h"
00032 #include "servconf.h"
00033 #include "compat.h"
00034 #include "auth.h"
00035 #include "dispatch.h"
00036 #include "pathnames.h"
00037 #include "monitor_wrap.h"
00038 #include "buffer.h"
00039 
00040 #ifdef GSSAPI
00041 #include "ssh-gss.h"
00042 #endif
00043 
00044 /* import */
00045 extern ServerOptions options;
00046 extern u_char *session_id2;
00047 extern u_int session_id2_len;
00048 extern Buffer loginmsg;
00049 
00050 /* methods */
00051 
00052 extern Authmethod method_none;
00053 extern Authmethod method_pubkey;
00054 extern Authmethod method_passwd;
00055 extern Authmethod method_kbdint;
00056 extern Authmethod method_hostbased;
00057 #ifdef GSSAPI
00058 extern Authmethod method_gssapi;
00059 #endif
00060 
00061 Authmethod *authmethods[] = {
00062         &method_none,
00063         &method_pubkey,
00064 #ifdef GSSAPI
00065         &method_gssapi,
00066 #endif
00067         &method_passwd,
00068         &method_kbdint,
00069         &method_hostbased,
00070         NULL
00071 };
00072 
00073 /* protocol */
00074 
00075 static void input_service_request(int, u_int32_t, void *);
00076 static void input_userauth_request(int, u_int32_t, void *);
00077 
00078 /* helper */
00079 static Authmethod *authmethod_lookup(const char *);
00080 static char *authmethods_get(void);
00081 int user_key_allowed(struct passwd *, Key *);
00082 
00083 /*
00084  * loop until authctxt->success == TRUE
00085  */
00086 
00087 void
00088 do_authentication2(Authctxt *authctxt)
00089 {
00090         /* challenge-response is implemented via keyboard interactive */
00091         if (options.challenge_response_authentication)
00092                 options.kbd_interactive_authentication = 1;
00093 
00094         dispatch_init(&dispatch_protocol_error);
00095         dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
00096         dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
00097 }
00098 
00099 static void
00100 input_service_request(int type, u_int32_t seq, void *ctxt)
00101 {
00102         Authctxt *authctxt = ctxt;
00103         u_int len;
00104         int acceptit = 0;
00105         char *service = packet_get_string(&len);
00106         packet_check_eom();
00107 
00108         if (authctxt == NULL)
00109                 fatal("input_service_request: no authctxt");
00110 
00111         if (strcmp(service, "ssh-userauth") == 0) {
00112                 if (!authctxt->success) {
00113                         acceptit = 1;
00114                         /* now we can handle user-auth requests */
00115                         dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
00116                 }
00117         }
00118         /* XXX all other service requests are denied */
00119 
00120         if (acceptit) {
00121                 packet_start(SSH2_MSG_SERVICE_ACCEPT);
00122                 packet_put_cstring(service);
00123                 packet_send();
00124                 packet_write_wait();
00125         } else {
00126                 debug("bad service request %s", service);
00127                 packet_disconnect("bad service request %s", service);
00128         }
00129         xfree(service);
00130 }
00131 
00132 static void
00133 input_userauth_request(int type, u_int32_t seq, void *ctxt)
00134 {
00135         Authctxt *authctxt = ctxt;
00136         Authmethod *m = NULL;
00137         char *user, *service, *method, *style = NULL;
00138         int authenticated = 0;
00139 
00140         if (authctxt == NULL)
00141                 fatal("input_userauth_request: no authctxt");
00142 
00143         user = packet_get_string(NULL);
00144         service = packet_get_string(NULL);
00145         method = packet_get_string(NULL);
00146         debug("userauth-request for user %s service %s method %s", user, service, method);
00147         debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
00148 
00149         if ((style = strchr(user, ':')) != NULL)
00150                 *style++ = 0;
00151 
00152         if (authctxt->attempt++ == 0) {
00153                 /* setup auth context */
00154                 authctxt->pw = PRIVSEP(getpwnamallow(user));
00155                 authctxt->user = xstrdup(user);
00156                 if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
00157                         authctxt->valid = 1;
00158                         debug2("input_userauth_request: setting up authctxt for %s", user);
00159                 } else {
00160                         logit("input_userauth_request: invalid user %s", user);
00161                         authctxt->pw = fakepw();
00162 #ifdef SSH_AUDIT_EVENTS
00163                         PRIVSEP(audit_event(SSH_INVALID_USER));
00164 #endif
00165                 }
00166 #ifdef USE_PAM
00167                 if (options.use_pam)
00168                         PRIVSEP(start_pam(authctxt));
00169 #endif
00170                 setproctitle("%s%s", authctxt->valid ? user : "unknown",
00171                     use_privsep ? " [net]" : "");
00172                 authctxt->service = xstrdup(service);
00173                 authctxt->style = style ? xstrdup(style) : NULL;
00174                 if (use_privsep)
00175                         mm_inform_authserv(service, style);
00176         } else if (strcmp(user, authctxt->user) != 0 ||
00177             strcmp(service, authctxt->service) != 0) {
00178                 packet_disconnect("Change of username or service not allowed: "
00179                     "(%s,%s) -> (%s,%s)",
00180                     authctxt->user, authctxt->service, user, service);
00181         }
00182         /* reset state */
00183         auth2_challenge_stop(authctxt);
00184 
00185 #ifdef GSSAPI
00186         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
00187         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
00188 #endif
00189 
00190         authctxt->postponed = 0;
00191 
00192         /* try to authenticate user */
00193         m = authmethod_lookup(method);
00194         if (m != NULL) {
00195                 debug2("input_userauth_request: try method %s", method);
00196                 authenticated = m->userauth(authctxt);
00197         }
00198         userauth_finish(authctxt, authenticated, method);
00199 
00200         xfree(service);
00201         xfree(user);
00202         xfree(method);
00203 }
00204 
00205 void
00206 userauth_finish(Authctxt *authctxt, int authenticated, char *method)
00207 {
00208         char *methods;
00209 
00210         if (!authctxt->valid && authenticated)
00211                 fatal("INTERNAL ERROR: authenticated invalid user %s",
00212                     authctxt->user);
00213 
00214         /* Special handling for root */
00215         if (authenticated && authctxt->pw->pw_uid == 0 &&
00216             !auth_root_allowed(method)) {
00217                 authenticated = 0;
00218 #ifdef SSH_AUDIT_EVENTS
00219                 PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED));
00220 #endif
00221         }
00222 
00223 #ifdef USE_PAM
00224         if (options.use_pam && authenticated) {
00225                 if (!PRIVSEP(do_pam_account())) {
00226                         /* if PAM returned a message, send it to the user */
00227                         if (buffer_len(&loginmsg) > 0) {
00228                                 buffer_append(&loginmsg, "\0", 1);
00229                                 userauth_send_banner(buffer_ptr(&loginmsg));
00230                                 packet_write_wait();
00231                         }
00232                         fatal("Access denied for user %s by PAM account "
00233                             "configuration", authctxt->user);
00234                 }
00235         }
00236 #endif
00237 
00238 #ifdef _UNICOS
00239         if (authenticated && cray_access_denied(authctxt->user)) {
00240                 authenticated = 0;
00241                 fatal("Access denied for user %s.",authctxt->user);
00242         }
00243 #endif /* _UNICOS */
00244 
00245         /* Log before sending the reply */
00246         auth_log(authctxt, authenticated, method, " ssh2");
00247 
00248         if (authctxt->postponed)
00249                 return;
00250 
00251         /* XXX todo: check if multiple auth methods are needed */
00252         if (authenticated == 1) {
00253                 /* turn off userauth */
00254                 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
00255                 packet_start(SSH2_MSG_USERAUTH_SUCCESS);
00256                 packet_send();
00257                 packet_write_wait();
00258                 /* now we can break out */
00259                 authctxt->success = 1;
00260         } else {
00261                 if (authctxt->failures++ > options.max_authtries) {
00262 #ifdef SSH_AUDIT_EVENTS
00263                         PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES));
00264 #endif
00265                         packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
00266                 }
00267                 methods = authmethods_get();
00268                 packet_start(SSH2_MSG_USERAUTH_FAILURE);
00269                 packet_put_cstring(methods);
00270                 packet_put_char(0);     /* XXX partial success, unused */
00271                 packet_send();
00272                 packet_write_wait();
00273                 xfree(methods);
00274         }
00275 }
00276 
00277 #define DELIM   ","
00278 
00279 static char *
00280 authmethods_get(void)
00281 {
00282         Buffer b;
00283         char *list;
00284         int i;
00285 
00286         buffer_init(&b);
00287         for (i = 0; authmethods[i] != NULL; i++) {
00288                 if (strcmp(authmethods[i]->name, "none") == 0)
00289                         continue;
00290                 if (authmethods[i]->enabled != NULL &&
00291                     *(authmethods[i]->enabled) != 0) {
00292                         if (buffer_len(&b) > 0)
00293                                 buffer_append(&b, ",", 1);
00294                         buffer_append(&b, authmethods[i]->name,
00295                             strlen(authmethods[i]->name));
00296                 }
00297         }
00298         buffer_append(&b, "\0", 1);
00299         list = xstrdup(buffer_ptr(&b));
00300         buffer_free(&b);
00301         return list;
00302 }
00303 
00304 static Authmethod *
00305 authmethod_lookup(const char *name)
00306 {
00307         int i;
00308 
00309         if (name != NULL)
00310                 for (i = 0; authmethods[i] != NULL; i++)
00311                         if (authmethods[i]->enabled != NULL &&
00312                             *(authmethods[i]->enabled) != 0 &&
00313                             strcmp(name, authmethods[i]->name) == 0)
00314                                 return authmethods[i];
00315         debug2("Unrecognized authentication method name: %s",
00316             name ? name : "NULL");
00317         return NULL;
00318 }

© sourcejam.com 2005-2008