]> andersk Git - gssapi-openssh.git/blob - openssh/auth1.c
merged OpenSSH 3.7p1 to trunk
[gssapi-openssh.git] / openssh / auth1.c
1 /*
2  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
3  *                    All rights reserved
4  *
5  * As far as I am concerned, the code I have written for this software
6  * can be used freely for any purpose.  Any derived versions of this
7  * software must be clearly marked as such, and if the derived work is
8  * incompatible with the protocol description in the RFC file, it must be
9  * called by a name other than "ssh" or "Secure Shell".
10  */
11
12 #include "includes.h"
13 RCSID("$OpenBSD: auth1.c,v 1.52 2003/08/28 12:54:34 markus Exp $");
14
15 #include "xmalloc.h"
16 #include "rsa.h"
17 #include "ssh1.h"
18 #include "dispatch.h"
19 #include "packet.h"
20 #include "buffer.h"
21 #include "mpaux.h"
22 #include "log.h"
23 #include "servconf.h"
24 #include "compat.h"
25 #include "auth.h"
26 #include "channels.h"
27 #include "session.h"
28 #include "uidswap.h"
29 #include "monitor_wrap.h"
30
31 /* import */
32 extern ServerOptions options;
33
34 #ifdef GSSAPI
35 #ifdef GSI
36 #include "globus_gss_assist.h"
37 #endif
38
39 extern Authmethod method_gssapi;
40
41 int     userauth_gssapi(Authctxt *authctxt);
42
43 void
44 auth1_gss_protocol_error(int type, u_int32_t plen, void *ctxt)
45 {
46   Authctxt *authctxt = ctxt;
47   /* Other side told us to abort, dont need to tell him */ 
48   /* maybe we can use some other method. */
49   if (type == SSH_MSG_AUTH_GSSAPI_ABORT) {
50       logit("auth1: GSSAPI aborting");
51       dispatch_set(SSH_MSG_AUTH_GSSAPI_TOKEN, NULL);
52       authctxt->success = 1; /* get out of loop*/
53       return;
54   }
55
56   logit("auth1: protocol error: type %d plen %d", type, plen);
57   packet_disconnect("Protocol error during GSSAPI authentication: "
58           "Unknown packet type %d", type);
59 }
60
61 #ifdef GSI
62 int
63 gsi_gridmap(char *subject_name, char **mapped_name)
64 {
65 #ifdef GLOBUS_GSI_GSS_ASSIST_MODULE
66     if (globus_module_activate(GLOBUS_GSI_GSS_ASSIST_MODULE) != 0) {
67         return 0;
68     }
69 #endif
70     return(globus_gss_assist_gridmap(subject_name, mapped_name) == 0);
71 }
72 #endif
73
74 /*
75  * SSH1 GSSAPI clients may send us a user name of the form:
76  *
77  *   (1) username:x:SSL Subject Name
78  *     or
79  *   (2) username:i:SSL Subject Name
80  *     or
81  *   (3) username
82  *
83  *  if case 1, then uname is an explicit name (ssh -l uname). Keep this
84  *  name always, rewrite the user parameter to be just uname. We'll pull
85  *  the GSSAPI idenity out and deal with (or skip it) later.
86  *  
87  *  if case 2, then uname is implicit (user didn't use the -l option), so
88  *  use the default gridmap mapping and replace uname with whatever
89  *  the gridmap maps to. If the gridmap mapping fails, drop down
90  *  to just uname
91  *  
92  *  if case 3, then leave it be.
93  *
94  *  This function may return the original pointer to the orginal string,
95  *  the original pointer to a modified string, or a completely new pointer.
96  */
97 static char *
98 ssh1_gssapi_parse_userstring(char *userstring)
99 {
100   char name_type = '\0';        /* explicit 'x' or implicit 'i' */
101   char *ssl_subject_name = NULL;
102   char *delim = NULL;
103
104   debug("Looking at username '%s' for gssapi-ssleay type name", userstring);
105   if((delim = strchr(userstring, ':')) != NULL) {
106       /* Parse and split into components */
107       ssl_subject_name = strchr(delim + 1, ':');
108
109       if (ssl_subject_name) {
110         /* Successful parse, split into components */
111         *delim = '\0';
112         name_type = *(delim + 1);
113         *ssl_subject_name = '\0';
114         ssl_subject_name++;
115
116         debug("Name parsed. type = '%c'. ssl subject name is \"%s\"",
117               name_type, ssl_subject_name);
118
119       } else {
120
121         debug("Don't understand name format. Letting it pass.");
122       } 
123   }     
124
125 #ifdef GSI
126   if(ssl_subject_name) {
127     char *gridmapped_name = NULL;
128     switch (name_type) {
129     case 'x':
130       debug("explicit name given, using %s as username", userstring);
131       break;
132
133     case 'i':
134       /* gridmap check */
135       debug("implicit name given. gridmapping '%s'", ssl_subject_name);
136
137       PRIVSEP(gsi_gridmap(ssl_subject_name, &gridmapped_name));
138       if (gridmapped_name && gridmapped_name[0] != '\0') {
139         userstring = gridmapped_name;
140         debug("I gridmapped and got %s", userstring);
141
142       } else {
143         debug("I gridmapped and got null, reverting to %s", userstring);
144       }
145       break;
146
147     default:
148       debug("Unknown name type '%c'. Ignoring.", name_type);
149       break;
150     }
151   } else {
152     debug("didn't find any :'s so I assume it's just a user name");
153   }
154 #endif /* GSI */
155
156   return userstring;
157 }
158 #endif
159
160 /*
161  * convert ssh auth msg type into description
162  */
163 static char *
164 get_authname(int type)
165 {
166         static char buf[1024];
167         switch (type) {
168         case SSH_CMSG_AUTH_PASSWORD:
169                 return "password";
170         case SSH_CMSG_AUTH_RSA:
171                 return "rsa";
172         case SSH_CMSG_AUTH_RHOSTS_RSA:
173                 return "rhosts-rsa";
174         case SSH_CMSG_AUTH_RHOSTS:
175                 return "rhosts";
176         case SSH_CMSG_AUTH_TIS:
177         case SSH_CMSG_AUTH_TIS_RESPONSE:
178                 return "challenge-response";
179 #if defined(GSSAPI)
180         case SSH_CMSG_AUTH_GSSAPI:
181                 return "gssapi";
182 #endif
183         }
184         snprintf(buf, sizeof buf, "bad-auth-msg-%d", type);
185         return buf;
186 }
187
188 /*
189  * read packets, try to authenticate the user and
190  * return only if authentication is successful
191  */
192 static void
193 do_authloop(Authctxt *authctxt)
194 {
195         int authenticated = 0;
196         u_int bits;
197         Key *client_host_key;
198         BIGNUM *n;
199         char *client_user, *password;
200         char info[1024];
201         u_int dlen;
202         u_int ulen;
203         int prev, type = 0;
204         struct passwd *pw = authctxt->pw;
205
206         debug("Attempting authentication for %s%.100s.",
207             authctxt->valid ? "" : "illegal user ", authctxt->user);
208
209         /* If the user has no password, accept authentication immediately. */
210         if (options.password_authentication &&
211 #ifdef KRB5
212             (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
213 #endif
214             PRIVSEP(auth_password(authctxt, ""))) {
215                 auth_log(authctxt, 1, "without authentication", "");
216                 return;
217         }
218
219         /* Indicate that authentication is needed. */
220         packet_start(SSH_SMSG_FAILURE);
221         packet_send();
222         packet_write_wait();
223
224         client_user = NULL;
225
226         for (;;) {
227                 /* default to fail */
228                 authenticated = 0;
229
230                 info[0] = '\0';
231
232                 /* Get a packet from the client. */
233                 prev = type;
234                 type = packet_read();
235
236                 /*
237                  * If we started challenge-response authentication but the
238                  * next packet is not a response to our challenge, release
239                  * the resources allocated by get_challenge() (which would
240                  * normally have been released by verify_response() had we
241                  * received such a response)
242                  */
243                 if (prev == SSH_CMSG_AUTH_TIS &&
244                     type != SSH_CMSG_AUTH_TIS_RESPONSE)
245                         abandon_challenge_response(authctxt);
246
247                 /* Process the packet. */
248                 switch (type) {
249 #ifdef GSSAPI
250                 case SSH_CMSG_AUTH_GSSAPI:
251                         if (!options.gss_authentication) {
252                                 verbose("GSSAPI authentication disabled.");
253                                 break;
254                         }
255                         /*
256                         * GSSAPI was first added to ssh1 in ssh-1.2.27, and
257                         * was added to the SecurtCRT product. In order
258                         * to continue operating with these, we will add
259                         * the equivelent GSSAPI support to SSH1. 
260                         * Will use the gssapi routines from the ssh2 as
261                         * they are almost identical. But they use dispatch
262                         * so we need to setup the dispatch tables here 
263                         * auth1.c for use only by the gssapi code. 
264                         * Since we already have the packet, we will call
265                         * userauth_gssapi then start the dispatch loop.
266                         */
267                         if (!authctxt->valid) {
268                         packet_disconnect("Authentication rejected for invalid user");
269                         }
270                         dispatch_init(&auth1_gss_protocol_error);
271                         method_gssapi.userauth(authctxt);
272                         if (!authctxt->postponed) { /* failed before starting dispatch */
273                                 authctxt->success = 0;
274                                 authctxt->postponed = 0;
275                                 break;
276                         }
277                         dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
278                         if (authctxt->postponed) { /* failed, try other methods */
279                                 authctxt->success = 0;
280                                 authctxt->postponed = 0;
281                                 break;
282                         }
283                         authenticated = 1;
284                         break;
285 #endif /* GSSAPI */
286
287                 case SSH_CMSG_AUTH_RHOSTS_RSA:
288                         if (!options.rhosts_rsa_authentication) {
289                                 verbose("Rhosts with RSA authentication disabled.");
290                                 break;
291                         }
292                         /*
293                          * Get client user name.  Note that we just have to
294                          * trust the client; root on the client machine can
295                          * claim to be any user.
296                          */
297                         client_user = packet_get_string(&ulen);
298
299                         /* Get the client host key. */
300                         client_host_key = key_new(KEY_RSA1);
301                         bits = packet_get_int();
302                         packet_get_bignum(client_host_key->rsa->e);
303                         packet_get_bignum(client_host_key->rsa->n);
304
305                         if (bits != BN_num_bits(client_host_key->rsa->n))
306                                 verbose("Warning: keysize mismatch for client_host_key: "
307                                     "actual %d, announced %d",
308                                     BN_num_bits(client_host_key->rsa->n), bits);
309                         packet_check_eom();
310
311                         authenticated = auth_rhosts_rsa(pw, client_user,
312                             client_host_key);
313                         key_free(client_host_key);
314
315                         snprintf(info, sizeof info, " ruser %.100s", client_user);
316                         break;
317
318                 case SSH_CMSG_AUTH_RSA:
319                         if (!options.rsa_authentication) {
320                                 verbose("RSA authentication disabled.");
321                                 break;
322                         }
323                         /* RSA authentication requested. */
324                         if ((n = BN_new()) == NULL)
325                                 fatal("do_authloop: BN_new failed");
326                         packet_get_bignum(n);
327                         packet_check_eom();
328                         authenticated = auth_rsa(pw, n);
329                         BN_clear_free(n);
330                         break;
331
332                 case SSH_CMSG_AUTH_PASSWORD:
333                         if (!options.password_authentication) {
334                                 verbose("Password authentication disabled.");
335                                 break;
336                         }
337                         /*
338                          * Read user password.  It is in plain text, but was
339                          * transmitted over the encrypted channel so it is
340                          * not visible to an outside observer.
341                          */
342                         password = packet_get_string(&dlen);
343                         packet_check_eom();
344
345                         /* Try authentication with the password. */
346                         authenticated = PRIVSEP(auth_password(authctxt, password));
347
348                         memset(password, 0, strlen(password));
349                         xfree(password);
350                         break;
351
352                 case SSH_CMSG_AUTH_TIS:
353                         debug("rcvd SSH_CMSG_AUTH_TIS");
354                         if (options.challenge_response_authentication == 1) {
355                                 char *challenge = get_challenge(authctxt);
356                                 if (challenge != NULL) {
357                                         debug("sending challenge '%s'", challenge);
358                                         packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
359                                         packet_put_cstring(challenge);
360                                         xfree(challenge);
361                                         packet_send();
362                                         packet_write_wait();
363                                         continue;
364                                 }
365                         }
366                         break;
367                 case SSH_CMSG_AUTH_TIS_RESPONSE:
368                         debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
369                         if (options.challenge_response_authentication == 1) {
370                                 char *response = packet_get_string(&dlen);
371                                 packet_check_eom();
372                                 authenticated = verify_response(authctxt, response);
373                                 memset(response, 'r', dlen);
374                                 xfree(response);
375                         }
376                         break;
377
378                 default:
379                         /*
380                          * Any unknown messages will be ignored (and failure
381                          * returned) during authentication.
382                          */
383                         logit("Unknown message during authentication: type %d", type);
384                         break;
385                 }
386 #ifdef BSD_AUTH
387                 if (authctxt->as) {
388                         auth_close(authctxt->as);
389                         authctxt->as = NULL;
390                 }
391 #endif
392                 if (!authctxt->valid && authenticated)
393                         fatal("INTERNAL ERROR: authenticated invalid user %s",
394                             authctxt->user);
395
396 #ifdef _UNICOS
397                 if (authenticated && cray_access_denied(authctxt->user)) {
398                         authenticated = 0;
399                         fatal("Access denied for user %s.",authctxt->user);
400                 }
401 #endif /* _UNICOS */
402
403 #ifdef HAVE_CYGWIN
404                 if (authenticated &&
405                     !check_nt_auth(type == SSH_CMSG_AUTH_PASSWORD, pw)) {
406                         packet_disconnect("Authentication rejected for uid %d.",
407                         pw == NULL ? -1 : pw->pw_uid);
408                         authenticated = 0;
409                 }
410 #else
411                 /* Special handling for root */
412                 if (authenticated && authctxt->pw->pw_uid == 0 &&
413                     !auth_root_allowed(get_authname(type)))
414                         authenticated = 0;
415 #endif
416
417 #ifdef USE_PAM
418                 if (options.use_pam && authenticated && 
419                     !PRIVSEP(do_pam_account()))
420                         authenticated = 0;
421 #endif
422
423                 /* Log before sending the reply */
424                 auth_log(authctxt, authenticated, get_authname(type), info);
425
426                 if (client_user != NULL) {
427                         xfree(client_user);
428                         client_user = NULL;
429                 }
430
431                 if (authenticated)
432                         return;
433
434                 if (authctxt->failures++ > AUTH_FAIL_MAX)
435                         packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
436
437                 packet_start(SSH_SMSG_FAILURE);
438                 packet_send();
439                 packet_write_wait();
440         }
441 }
442
443 /*
444  * Performs authentication of an incoming connection.  Session key has already
445  * been exchanged and encryption is enabled.
446  */
447 Authctxt *
448 do_authentication(void)
449 {
450         Authctxt *authctxt;
451         u_int ulen;
452         char *user, *style = NULL;
453
454         /* Get the name of the user that we wish to log in as. */
455         packet_read_expect(SSH_CMSG_USER);
456
457         /* Get the user name. */
458         user = packet_get_string(&ulen);
459         packet_check_eom();
460
461 #ifdef GSSAPI
462         /* Parse GSSAPI identity from userstring */
463         user = ssh1_gssapi_parse_userstring(user);
464 #endif /* GSSAPI */
465
466         if ((style = strchr(user, ':')) != NULL)
467                 *style++ = '\0';
468
469         authctxt = authctxt_new();
470         authctxt->user = user;
471         authctxt->style = style;
472
473         /* Verify that the user is a valid user. */
474         if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL)
475                 authctxt->valid = 1;
476         else {
477                 debug("do_authentication: illegal user %s", user);
478                 authctxt->pw = fakepw();
479         }
480
481         setproctitle("%s%s", authctxt->pw ? user : "unknown",
482             use_privsep ? " [net]" : "");
483
484 #ifdef USE_PAM
485         if (options.use_pam)
486                 PRIVSEP(start_pam(user));
487 #endif
488
489         /*
490          * If we are not running as root, the user must have the same uid as
491          * the server. (Unless you are running Windows)
492          */
493 #ifndef HAVE_CYGWIN
494         if (!use_privsep && getuid() != 0 && authctxt->pw &&
495             authctxt->pw->pw_uid != getuid())
496                 packet_disconnect("Cannot change user when server not running as root.");
497 #endif
498
499         /*
500          * Loop until the user has been authenticated or the connection is
501          * closed, do_authloop() returns only if authentication is successful
502          */
503         do_authloop(authctxt);
504
505         /* The user has been authenticated and accepted. */
506         packet_start(SSH_SMSG_SUCCESS);
507         packet_send();
508         packet_write_wait();
509
510         return (authctxt);
511 }
This page took 0.090728 seconds and 5 git commands to generate.