]> andersk Git - openssh.git/blob - auth2.c
c7cc0c64004cc4b0e2094d9f706bc2987b802243
[openssh.git] / auth2.c
1 /*
2  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include "includes.h"
26 RCSID("$OpenBSD: auth2.c,v 1.93 2002/05/31 11:35:15 markus Exp $");
27
28 #include "ssh2.h"
29 #include "xmalloc.h"
30 #include "packet.h"
31 #include "log.h"
32 #include "servconf.h"
33 #include "compat.h"
34 #include "auth.h"
35 #include "dispatch.h"
36 #include "pathnames.h"
37 #include "monitor_wrap.h"
38
39 /* import */
40 extern ServerOptions options;
41 extern u_char *session_id2;
42 extern int session_id2_len;
43
44 Authctxt *x_authctxt = NULL;
45
46 /* methods */
47
48 extern Authmethod method_none;
49 extern Authmethod method_pubkey;
50 extern Authmethod method_passwd;
51 extern Authmethod method_kbdint;
52 extern Authmethod method_hostbased;
53
54 Authmethod *authmethods[] = {
55         &method_none,
56         &method_pubkey,
57         &method_passwd,
58         &method_kbdint,
59         &method_hostbased,
60         NULL
61 };
62
63 /* protocol */
64
65 static void input_service_request(int, u_int32_t, void *);
66 static void input_userauth_request(int, u_int32_t, void *);
67
68 /* helper */
69 static Authmethod *authmethod_lookup(const char *);
70 static char *authmethods_get(void);
71 int user_key_allowed(struct passwd *, Key *);
72 int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
73
74 /*
75  * loop until authctxt->success == TRUE
76  */
77
78 Authctxt *
79 do_authentication2(void)
80 {
81         Authctxt *authctxt = authctxt_new();
82
83         x_authctxt = authctxt;          /*XXX*/
84
85         /* challenge-response is implemented via keyboard interactive */
86         if (options.challenge_response_authentication)
87                 options.kbd_interactive_authentication = 1;
88         if (options.pam_authentication_via_kbd_int)
89                 options.kbd_interactive_authentication = 1;
90         if (use_privsep)
91                 options.pam_authentication_via_kbd_int = 0;
92
93         dispatch_init(&dispatch_protocol_error);
94         dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
95         dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
96
97         return (authctxt);
98 }
99
100 static void
101 input_service_request(int type, u_int32_t seq, void *ctxt)
102 {
103         Authctxt *authctxt = ctxt;
104         u_int len;
105         int accept = 0;
106         char *service = packet_get_string(&len);
107         packet_check_eom();
108
109         if (authctxt == NULL)
110                 fatal("input_service_request: no authctxt");
111
112         if (strcmp(service, "ssh-userauth") == 0) {
113                 if (!authctxt->success) {
114                         accept = 1;
115                         /* now we can handle user-auth requests */
116                         dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
117                 }
118         }
119         /* XXX all other service requests are denied */
120
121         if (accept) {
122                 packet_start(SSH2_MSG_SERVICE_ACCEPT);
123                 packet_put_cstring(service);
124                 packet_send();
125                 packet_write_wait();
126         } else {
127                 debug("bad service request %s", service);
128                 packet_disconnect("bad service request %s", service);
129         }
130         xfree(service);
131 }
132
133 static void
134 input_userauth_request(int type, u_int32_t seq, void *ctxt)
135 {
136         Authctxt *authctxt = ctxt;
137         Authmethod *m = NULL;
138         char *user, *service, *method, *style = NULL;
139         int authenticated = 0;
140
141         if (authctxt == NULL)
142                 fatal("input_userauth_request: no authctxt");
143
144         user = packet_get_string(NULL);
145         service = packet_get_string(NULL);
146         method = packet_get_string(NULL);
147         debug("userauth-request for user %s service %s method %s", user, service, method);
148         debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
149
150         if ((style = strchr(user, ':')) != NULL)
151                 *style++ = 0;
152
153         if (authctxt->attempt++ == 0) {
154                 /* setup auth context */
155                 authctxt->pw = PRIVSEP(getpwnamallow(user));
156                 if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
157                         authctxt->valid = 1;
158                         debug2("input_userauth_request: setting up authctxt for %s", user);
159 #ifdef USE_PAM
160                         PRIVSEP(start_pam(authctxt->pw->pw_name));
161 #endif
162                 } else {
163                         log("input_userauth_request: illegal user %s", user);
164 #ifdef USE_PAM
165                         PRIVSEP(start_pam("NOUSER"));
166 #endif
167                 }
168                 setproctitle("%s%s", authctxt->pw ? user : "unknown",
169                     use_privsep ? " [net]" : "");
170                 authctxt->user = xstrdup(user);
171                 authctxt->service = xstrdup(service);
172                 authctxt->style = style ? xstrdup(style) : NULL;
173                 if (use_privsep)
174                         mm_inform_authserv(service, style);
175         } else if (strcmp(user, authctxt->user) != 0 ||
176             strcmp(service, authctxt->service) != 0) {
177                 packet_disconnect("Change of username or service not allowed: "
178                     "(%s,%s) -> (%s,%s)",
179                     authctxt->user, authctxt->service, user, service);
180         }
181         /* reset state */
182         auth2_challenge_stop(authctxt);
183         authctxt->postponed = 0;
184
185         /* try to authenticate user */
186         m = authmethod_lookup(method);
187         if (m != NULL) {
188                 debug2("input_userauth_request: try method %s", method);
189                 authenticated = m->userauth(authctxt);
190         }
191         userauth_finish(authctxt, authenticated, method);
192
193         xfree(service);
194         xfree(user);
195         xfree(method);
196 }
197
198 void
199 userauth_finish(Authctxt *authctxt, int authenticated, char *method)
200 {
201         char *methods;
202
203         if (!authctxt->valid && authenticated)
204                 fatal("INTERNAL ERROR: authenticated invalid user %s",
205                     authctxt->user);
206
207         /* Special handling for root */
208         if (authenticated && authctxt->pw->pw_uid == 0 &&
209             !auth_root_allowed(method))
210                 authenticated = 0;
211
212 #ifdef USE_PAM
213         if (!use_privsep && authenticated && authctxt->user && 
214             !do_pam_account(authctxt->user, NULL))
215                 authenticated = 0;
216 #endif /* USE_PAM */
217
218         /* Log before sending the reply */
219         auth_log(authctxt, authenticated, method, " ssh2");
220
221         if (authctxt->postponed)
222                 return;
223
224         /* XXX todo: check if multiple auth methods are needed */
225         if (authenticated == 1) {
226                 /* turn off userauth */
227                 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
228                 packet_start(SSH2_MSG_USERAUTH_SUCCESS);
229                 packet_send();
230                 packet_write_wait();
231                 /* now we can break out */
232                 authctxt->success = 1;
233         } else {
234                 if (authctxt->failures++ > AUTH_FAIL_MAX) {
235 #ifdef WITH_AIXAUTHENTICATE
236                         loginfailed(authctxt->user,
237                             get_canonical_hostname(options.verify_reverse_mapping),
238                             "ssh");
239 #endif /* WITH_AIXAUTHENTICATE */
240                         packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
241                 }
242                 methods = authmethods_get();
243                 packet_start(SSH2_MSG_USERAUTH_FAILURE);
244                 packet_put_cstring(methods);
245                 packet_put_char(0);     /* XXX partial success, unused */
246                 packet_send();
247                 packet_write_wait();
248                 xfree(methods);
249         }
250 }
251
252 char *
253 auth2_read_banner(void)
254 {
255         struct stat st;
256         char *banner = NULL;
257         off_t len, n;
258         int fd;
259
260         if ((fd = open(options.banner, O_RDONLY)) == -1)
261                 return (NULL);
262         if (fstat(fd, &st) == -1) {
263                 close(fd);
264                 return (NULL);
265         }
266         len = st.st_size;
267         banner = xmalloc(len + 1);
268         n = atomicio(read, fd, banner, len);
269         close(fd);
270
271         if (n != len) {
272                 free(banner);
273                 return (NULL);
274         }
275         banner[n] = '\0';
276         
277         return (banner);
278 }
279
280 static void
281 userauth_banner(void)
282 {
283         char *banner = NULL;
284
285         if (options.banner == NULL || (datafellows & SSH_BUG_BANNER))
286                 return;
287
288         if ((banner = PRIVSEP(auth2_read_banner())) == NULL)
289                 goto done;
290
291         packet_start(SSH2_MSG_USERAUTH_BANNER);
292         packet_put_cstring(banner);
293         packet_put_cstring("");         /* language, unused */
294         packet_send();
295         debug("userauth_banner: sent");
296 done:
297         if (banner)
298                 xfree(banner);
299         return;
300 }
301
302 static int
303 userauth_none(Authctxt *authctxt)
304 {
305         /* disable method "none", only allowed one time */
306         Authmethod *m = authmethod_lookup("none");
307         if (m != NULL)
308                 m->enabled = NULL;
309         packet_check_eom();
310         userauth_banner();
311
312         if (authctxt->valid == 0)
313                 return(0);
314
315 #ifdef HAVE_CYGWIN
316         if (check_nt_auth(1, authctxt->pw) == 0)
317                 return(0);
318 #endif
319         return PRIVSEP(auth_password(authctxt, ""));
320 }
321
322 static int
323 userauth_passwd(Authctxt *authctxt)
324 {
325         char *password;
326         int authenticated = 0;
327         int change;
328         u_int len;
329         change = packet_get_char();
330         if (change)
331                 log("password change not supported");
332         password = packet_get_string(&len);
333         packet_check_eom();
334         if (authctxt->valid &&
335 #ifdef HAVE_CYGWIN
336             check_nt_auth(1, authctxt->pw) &&
337 #endif
338             PRIVSEP(auth_password(authctxt, password)) == 1)
339                 authenticated = 1;
340         memset(password, 0, len);
341         xfree(password);
342         return authenticated;
343 }
344
345 static int
346 userauth_kbdint(Authctxt *authctxt)
347 {
348         int authenticated = 0;
349         char *lang, *devs;
350
351         lang = packet_get_string(NULL);
352         devs = packet_get_string(NULL);
353         packet_check_eom();
354
355         debug("keyboard-interactive devs %s", devs);
356
357         if (options.challenge_response_authentication)
358                 authenticated = auth2_challenge(authctxt, devs);
359
360 #ifdef USE_PAM
361         if (authenticated == 0 && options.pam_authentication_via_kbd_int)
362                 authenticated = auth2_pam(authctxt);
363 #endif
364         xfree(devs);
365         xfree(lang);
366 #ifdef HAVE_CYGWIN
367         if (check_nt_auth(0, authctxt->pw) == 0)
368                 return(0);
369 #endif
370         return authenticated;
371 }
372
373 static int
374 userauth_pubkey(Authctxt *authctxt)
375 {
376         Buffer b;
377         Key *key = NULL;
378         char *pkalg;
379         u_char *pkblob, *sig;
380         u_int alen, blen, slen;
381         int have_sig, pktype;
382         int authenticated = 0;
383
384         if (!authctxt->valid) {
385                 debug2("userauth_pubkey: disabled because of invalid user");
386                 return 0;
387         }
388         have_sig = packet_get_char();
389         if (datafellows & SSH_BUG_PKAUTH) {
390                 debug2("userauth_pubkey: SSH_BUG_PKAUTH");
391                 /* no explicit pkalg given */
392                 pkblob = packet_get_string(&blen);
393                 buffer_init(&b);
394                 buffer_append(&b, pkblob, blen);
395                 /* so we have to extract the pkalg from the pkblob */
396                 pkalg = buffer_get_string(&b, &alen);
397                 buffer_free(&b);
398         } else {
399                 pkalg = packet_get_string(&alen);
400                 pkblob = packet_get_string(&blen);
401         }
402         pktype = key_type_from_name(pkalg);
403         if (pktype == KEY_UNSPEC) {
404                 /* this is perfectly legal */
405                 log("userauth_pubkey: unsupported public key algorithm: %s",
406                     pkalg);
407                 goto done;
408         }
409         key = key_from_blob(pkblob, blen);
410         if (key == NULL) {
411                 error("userauth_pubkey: cannot decode key: %s", pkalg);
412                 goto done;
413         }
414         if (key->type != pktype) {
415                 error("userauth_pubkey: type mismatch for decoded key "
416                     "(received %d, expected %d)", key->type, pktype);
417                 goto done;
418         }
419         if (have_sig) {
420                 sig = packet_get_string(&slen);
421                 packet_check_eom();
422                 buffer_init(&b);
423                 if (datafellows & SSH_OLD_SESSIONID) {
424                         buffer_append(&b, session_id2, session_id2_len);
425                 } else {
426                         buffer_put_string(&b, session_id2, session_id2_len);
427                 }
428                 /* reconstruct packet */
429                 buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
430                 buffer_put_cstring(&b, authctxt->user);
431                 buffer_put_cstring(&b,
432                     datafellows & SSH_BUG_PKSERVICE ?
433                     "ssh-userauth" :
434                     authctxt->service);
435                 if (datafellows & SSH_BUG_PKAUTH) {
436                         buffer_put_char(&b, have_sig);
437                 } else {
438                         buffer_put_cstring(&b, "publickey");
439                         buffer_put_char(&b, have_sig);
440                         buffer_put_cstring(&b, pkalg);
441                 }
442                 buffer_put_string(&b, pkblob, blen);
443 #ifdef DEBUG_PK
444                 buffer_dump(&b);
445 #endif
446                 /* test for correct signature */
447                 authenticated = 0;
448                 if (PRIVSEP(user_key_allowed(authctxt->pw, key)) &&
449                     PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
450                                 buffer_len(&b))) == 1)
451                         authenticated = 1;
452                 buffer_clear(&b);
453                 xfree(sig);
454         } else {
455                 debug("test whether pkalg/pkblob are acceptable");
456                 packet_check_eom();
457
458                 /* XXX fake reply and always send PK_OK ? */
459                 /*
460                  * XXX this allows testing whether a user is allowed
461                  * to login: if you happen to have a valid pubkey this
462                  * message is sent. the message is NEVER sent at all
463                  * if a user is not allowed to login. is this an
464                  * issue? -markus
465                  */
466                 if (PRIVSEP(user_key_allowed(authctxt->pw, key))) {
467                         packet_start(SSH2_MSG_USERAUTH_PK_OK);
468                         packet_put_string(pkalg, alen);
469                         packet_put_string(pkblob, blen);
470                         packet_send();
471                         packet_write_wait();
472                         authctxt->postponed = 1;
473                 }
474         }
475         if (authenticated != 1)
476                 auth_clear_options();
477 done:
478         debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg);
479         if (key != NULL)
480                 key_free(key);
481         xfree(pkalg);
482         xfree(pkblob);
483 #ifdef HAVE_CYGWIN
484         if (check_nt_auth(0, authctxt->pw) == 0)
485                 return(0);
486 #endif
487         return authenticated;
488 }
489
490 static int
491 userauth_hostbased(Authctxt *authctxt)
492 {
493         Buffer b;
494         Key *key = NULL;
495         char *pkalg, *cuser, *chost, *service;
496         u_char *pkblob, *sig;
497         u_int alen, blen, slen;
498         int pktype;
499         int authenticated = 0;
500
501         if (!authctxt->valid) {
502                 debug2("userauth_hostbased: disabled because of invalid user");
503                 return 0;
504         }
505         pkalg = packet_get_string(&alen);
506         pkblob = packet_get_string(&blen);
507         chost = packet_get_string(NULL);
508         cuser = packet_get_string(NULL);
509         sig = packet_get_string(&slen);
510
511         debug("userauth_hostbased: cuser %s chost %s pkalg %s slen %d",
512             cuser, chost, pkalg, slen);
513 #ifdef DEBUG_PK
514         debug("signature:");
515         buffer_init(&b);
516         buffer_append(&b, sig, slen);
517         buffer_dump(&b);
518         buffer_free(&b);
519 #endif
520         pktype = key_type_from_name(pkalg);
521         if (pktype == KEY_UNSPEC) {
522                 /* this is perfectly legal */
523                 log("userauth_hostbased: unsupported "
524                     "public key algorithm: %s", pkalg);
525                 goto done;
526         }
527         key = key_from_blob(pkblob, blen);
528         if (key == NULL) {
529                 error("userauth_hostbased: cannot decode key: %s", pkalg);
530                 goto done;
531         }
532         if (key->type != pktype) {
533                 error("userauth_hostbased: type mismatch for decoded key "
534                     "(received %d, expected %d)", key->type, pktype);
535                 goto done;
536         }
537         service = datafellows & SSH_BUG_HBSERVICE ? "ssh-userauth" :
538             authctxt->service;
539         buffer_init(&b);
540         buffer_put_string(&b, session_id2, session_id2_len);
541         /* reconstruct packet */
542         buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
543         buffer_put_cstring(&b, authctxt->user);
544         buffer_put_cstring(&b, service);
545         buffer_put_cstring(&b, "hostbased");
546         buffer_put_string(&b, pkalg, alen);
547         buffer_put_string(&b, pkblob, blen);
548         buffer_put_cstring(&b, chost);
549         buffer_put_cstring(&b, cuser);
550 #ifdef DEBUG_PK
551         buffer_dump(&b);
552 #endif
553         /* test for allowed key and correct signature */
554         authenticated = 0;
555         if (PRIVSEP(hostbased_key_allowed(authctxt->pw, cuser, chost, key)) &&
556             PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b),
557                         buffer_len(&b))) == 1)
558                 authenticated = 1;
559
560         buffer_clear(&b);
561 done:
562         debug2("userauth_hostbased: authenticated %d", authenticated);
563         if (key != NULL)
564                 key_free(key);
565         xfree(pkalg);
566         xfree(pkblob);
567         xfree(cuser);
568         xfree(chost);
569         xfree(sig);
570         return authenticated;
571 }
572
573 /* get current user */
574
575 struct passwd*
576 auth_get_user(void)
577 {
578         return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL;
579 }
580
581 #define DELIM   ","
582
583 static char *
584 authmethods_get(void)
585 {
586         Buffer b;
587         char *list;
588         int i;
589
590         buffer_init(&b);
591         for (i = 0; authmethods[i] != NULL; i++) {
592                 if (strcmp(authmethods[i]->name, "none") == 0)
593                         continue;
594                 if (authmethods[i]->enabled != NULL &&
595                     *(authmethods[i]->enabled) != 0) {
596                         if (buffer_len(&b) > 0)
597                                 buffer_append(&b, ",", 1);
598                         buffer_append(&b, authmethods[i]->name,
599                             strlen(authmethods[i]->name));
600                 }
601         }
602         buffer_append(&b, "\0", 1);
603         list = xstrdup(buffer_ptr(&b));
604         buffer_free(&b);
605         return list;
606 }
607
608 static Authmethod *
609 authmethod_lookup(const char *name)
610 {
611         int i;
612
613         if (name != NULL)
614                 for (i = 0; authmethods[i] != NULL; i++)
615                         if (authmethods[i]->enabled != NULL &&
616                             *(authmethods[i]->enabled) != 0 &&
617                             strcmp(name, authmethods[i]->name) == 0)
618                                 return authmethods[i];
619         debug2("Unrecognized authentication method name: %s",
620             name ? name : "NULL");
621         return NULL;
622 }
This page took 0.074544 seconds and 3 git commands to generate.