Annotation of src/usr.bin/ssh/auth2.c, Revision 1.126
1.126 ! djm 1: /* $OpenBSD: auth2.c,v 1.125 2012/11/04 11:09:15 djm Exp $ */
1.1 markus 2: /*
3: * Copyright (c) 2000 Markus Friedl. All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: *
14: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24: */
1.14 deraadt 25:
1.111 stevesk 26:
27: #include <sys/types.h>
1.117 djm 28: #include <sys/stat.h>
29: #include <sys/uio.h>
1.111 stevesk 30:
1.117 djm 31: #include <fcntl.h>
1.111 stevesk 32: #include <pwd.h>
1.121 dtucker 33: #include <stdarg.h>
1.112 stevesk 34: #include <string.h>
1.117 djm 35: #include <unistd.h>
1.1 markus 36:
1.117 djm 37: #include "atomicio.h"
1.113 deraadt 38: #include "xmalloc.h"
1.32 markus 39: #include "ssh2.h"
1.1 markus 40: #include "packet.h"
1.32 markus 41: #include "log.h"
1.113 deraadt 42: #include "buffer.h"
1.1 markus 43: #include "servconf.h"
44: #include "compat.h"
1.113 deraadt 45: #include "key.h"
46: #include "hostfile.h"
1.1 markus 47: #include "auth.h"
48: #include "dispatch.h"
1.29 markus 49: #include "pathnames.h"
1.100 markus 50: #ifdef GSSAPI
51: #include "ssh-gss.h"
52: #endif
1.113 deraadt 53: #include "monitor_wrap.h"
1.100 markus 54:
1.1 markus 55: /* import */
56: extern ServerOptions options;
1.23 markus 57: extern u_char *session_id2;
1.99 markus 58: extern u_int session_id2_len;
1.1 markus 59:
1.93 markus 60: /* methods */
61:
62: extern Authmethod method_none;
63: extern Authmethod method_pubkey;
64: extern Authmethod method_passwd;
65: extern Authmethod method_kbdint;
66: extern Authmethod method_hostbased;
1.100 markus 67: #ifdef GSSAPI
68: extern Authmethod method_gssapi;
69: #endif
1.120 djm 70: #ifdef JPAKE
71: extern Authmethod method_jpake;
72: #endif
1.93 markus 73:
74: Authmethod *authmethods[] = {
75: &method_none,
76: &method_pubkey,
1.100 markus 77: #ifdef GSSAPI
78: &method_gssapi,
79: #endif
1.120 djm 80: #ifdef JPAKE
81: &method_jpake,
82: #endif
1.93 markus 83: &method_passwd,
84: &method_kbdint,
85: &method_hostbased,
86: NULL
1.18 markus 87: };
88:
1.1 markus 89: /* protocol */
90:
1.80 markus 91: static void input_service_request(int, u_int32_t, void *);
92: static void input_userauth_request(int, u_int32_t, void *);
1.1 markus 93:
94: /* helper */
1.125 djm 95: static Authmethod *authmethod_lookup(Authctxt *, const char *);
96: static char *authmethods_get(Authctxt *authctxt);
97: static int method_allowed(Authctxt *, const char *);
98: static int list_starts_with(const char *, const char *);
1.1 markus 99:
1.117 djm 100: char *
101: auth2_read_banner(void)
102: {
103: struct stat st;
104: char *banner = NULL;
105: size_t len, n;
106: int fd;
107:
108: if ((fd = open(options.banner, O_RDONLY)) == -1)
109: return (NULL);
110: if (fstat(fd, &st) == -1) {
111: close(fd);
112: return (NULL);
113: }
1.124 djm 114: if (st.st_size <= 0 || st.st_size > 1*1024*1024) {
1.117 djm 115: close(fd);
116: return (NULL);
117: }
118:
119: len = (size_t)st.st_size; /* truncate */
120: banner = xmalloc(len + 1);
121: n = atomicio(read, fd, banner, len);
122: close(fd);
123:
124: if (n != len) {
125: xfree(banner);
126: return (NULL);
127: }
128: banner[n] = '\0';
129:
130: return (banner);
131: }
132:
133: static void
134: userauth_banner(void)
135: {
136: char *banner = NULL;
137:
138: if (options.banner == NULL ||
139: strcasecmp(options.banner, "none") == 0 ||
140: (datafellows & SSH_BUG_BANNER) != 0)
141: return;
142:
143: if ((banner = PRIVSEP(auth2_read_banner())) == NULL)
144: goto done;
145:
146: packet_start(SSH2_MSG_USERAUTH_BANNER);
147: packet_put_cstring(banner);
148: packet_put_cstring(""); /* language, unused */
149: packet_send();
150: debug("userauth_banner: sent");
151: done:
152: if (banner)
153: xfree(banner);
154: }
155:
1.1 markus 156: /*
1.18 markus 157: * loop until authctxt->success == TRUE
1.1 markus 158: */
1.103 markus 159: void
160: do_authentication2(Authctxt *authctxt)
1.1 markus 161: {
1.81 markus 162: dispatch_init(&dispatch_protocol_error);
1.1 markus 163: dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
1.18 markus 164: dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
1.1 markus 165: }
166:
1.109 deraadt 167: /*ARGSUSED*/
1.66 itojun 168: static void
1.80 markus 169: input_service_request(int type, u_int32_t seq, void *ctxt)
1.1 markus 170: {
1.18 markus 171: Authctxt *authctxt = ctxt;
1.23 markus 172: u_int len;
1.94 deraadt 173: int acceptit = 0;
1.122 djm 174: char *service = packet_get_cstring(&len);
1.79 markus 175: packet_check_eom();
1.1 markus 176:
1.18 markus 177: if (authctxt == NULL)
178: fatal("input_service_request: no authctxt");
179:
1.1 markus 180: if (strcmp(service, "ssh-userauth") == 0) {
1.18 markus 181: if (!authctxt->success) {
1.94 deraadt 182: acceptit = 1;
1.1 markus 183: /* now we can handle user-auth requests */
184: dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
185: }
186: }
187: /* XXX all other service requests are denied */
188:
1.94 deraadt 189: if (acceptit) {
1.1 markus 190: packet_start(SSH2_MSG_SERVICE_ACCEPT);
191: packet_put_cstring(service);
192: packet_send();
193: packet_write_wait();
194: } else {
195: debug("bad service request %s", service);
196: packet_disconnect("bad service request %s", service);
197: }
198: xfree(service);
199: }
200:
1.109 deraadt 201: /*ARGSUSED*/
1.66 itojun 202: static void
1.80 markus 203: input_userauth_request(int type, u_int32_t seq, void *ctxt)
1.1 markus 204: {
1.18 markus 205: Authctxt *authctxt = ctxt;
206: Authmethod *m = NULL;
1.28 markus 207: char *user, *service, *method, *style = NULL;
1.1 markus 208: int authenticated = 0;
209:
1.18 markus 210: if (authctxt == NULL)
211: fatal("input_userauth_request: no authctxt");
1.1 markus 212:
1.122 djm 213: user = packet_get_cstring(NULL);
214: service = packet_get_cstring(NULL);
215: method = packet_get_cstring(NULL);
1.1 markus 216: debug("userauth-request for user %s service %s method %s", user, service, method);
1.24 markus 217: debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
1.1 markus 218:
1.28 markus 219: if ((style = strchr(user, ':')) != NULL)
220: *style++ = 0;
221:
1.36 stevesk 222: if (authctxt->attempt++ == 0) {
1.18 markus 223: /* setup auth context */
1.89 markus 224: authctxt->pw = PRIVSEP(getpwnamallow(user));
225: if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
1.18 markus 226: authctxt->valid = 1;
227: debug2("input_userauth_request: setting up authctxt for %s", user);
228: } else {
1.107 markus 229: logit("input_userauth_request: invalid user %s", user);
1.102 markus 230: authctxt->pw = fakepw();
1.18 markus 231: }
1.106 djm 232: setproctitle("%s%s", authctxt->valid ? user : "unknown",
1.88 provos 233: use_privsep ? " [net]" : "");
1.18 markus 234: authctxt->user = xstrdup(user);
235: authctxt->service = xstrdup(service);
1.62 markus 236: authctxt->style = style ? xstrdup(style) : NULL;
1.88 provos 237: if (use_privsep)
238: mm_inform_authserv(service, style);
1.117 djm 239: userauth_banner();
1.125 djm 240: if (auth2_setup_methods_lists(authctxt) != 0)
241: packet_disconnect("no authentication methods enabled");
1.62 markus 242: } else if (strcmp(user, authctxt->user) != 0 ||
243: strcmp(service, authctxt->service) != 0) {
244: packet_disconnect("Change of username or service not allowed: "
245: "(%s,%s) -> (%s,%s)",
246: authctxt->user, authctxt->service, user, service);
1.1 markus 247: }
1.28 markus 248: /* reset state */
1.75 markus 249: auth2_challenge_stop(authctxt);
1.120 djm 250: #ifdef JPAKE
251: auth2_jpake_stop(authctxt);
252: #endif
1.100 markus 253:
254: #ifdef GSSAPI
1.120 djm 255: /* XXX move to auth2_gssapi_stop() */
1.100 markus 256: dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
257: dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
258: #endif
259:
1.28 markus 260: authctxt->postponed = 0;
1.123 djm 261: authctxt->server_caused_failure = 0;
1.18 markus 262:
1.28 markus 263: /* try to authenticate user */
1.125 djm 264: m = authmethod_lookup(authctxt, method);
1.117 djm 265: if (m != NULL && authctxt->failures < options.max_authtries) {
1.18 markus 266: debug2("input_userauth_request: try method %s", method);
267: authenticated = m->userauth(authctxt);
268: }
1.126 ! djm 269: userauth_finish(authctxt, authenticated, method, NULL);
1.49 markus 270:
271: xfree(service);
272: xfree(user);
273: xfree(method);
274: }
275:
276: void
1.126 ! djm 277: userauth_finish(Authctxt *authctxt, int authenticated, const char *method,
! 278: const char *submethod)
1.49 markus 279: {
1.60 markus 280: char *methods;
1.125 djm 281: int partial = 0;
1.60 markus 282:
1.28 markus 283: if (!authctxt->valid && authenticated)
284: fatal("INTERNAL ERROR: authenticated invalid user %s",
285: authctxt->user);
1.126 ! djm 286: if (authenticated && authctxt->postponed)
! 287: fatal("INTERNAL ERROR: authenticated and postponed");
1.18 markus 288:
289: /* Special handling for root */
1.96 markus 290: if (authenticated && authctxt->pw->pw_uid == 0 &&
1.41 markus 291: !auth_root_allowed(method))
1.3 markus 292: authenticated = 0;
293:
1.125 djm 294: if (authenticated && options.num_auth_methods != 0) {
295: if (!auth2_update_methods_lists(authctxt, method)) {
296: authenticated = 0;
297: partial = 1;
298: }
299: }
1.126 ! djm 300:
! 301: /* Log before sending the reply */
! 302: auth_log(authctxt, authenticated, partial, method, submethod, " ssh2");
! 303:
! 304: if (authctxt->postponed)
! 305: return;
1.125 djm 306:
1.60 markus 307: if (authenticated == 1) {
308: /* turn off userauth */
1.81 markus 309: dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
1.60 markus 310: packet_start(SSH2_MSG_USERAUTH_SUCCESS);
311: packet_send();
312: packet_write_wait();
313: /* now we can break out */
314: authctxt->success = 1;
315: } else {
1.119 djm 316: /* Allow initial try of "none" auth without failure penalty */
1.123 djm 317: if (!authctxt->server_caused_failure &&
318: (authctxt->attempt > 1 || strcmp(method, "none") != 0))
1.119 djm 319: authctxt->failures++;
320: if (authctxt->failures >= options.max_authtries)
1.60 markus 321: packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
1.125 djm 322: methods = authmethods_get(authctxt);
323: debug3("%s: failure partial=%d next methods=\"%s\"", __func__,
324: partial, methods);
1.60 markus 325: packet_start(SSH2_MSG_USERAUTH_FAILURE);
326: packet_put_cstring(methods);
1.125 djm 327: packet_put_char(partial);
1.60 markus 328: packet_send();
329: packet_write_wait();
330: xfree(methods);
331: }
1.1 markus 332: }
1.18 markus 333:
1.125 djm 334: /*
335: * Checks whether method is allowed by at least one AuthenticationMethods
336: * methods list. Returns 1 if allowed, or no methods lists configured.
337: * 0 otherwise.
338: */
339: static int
340: method_allowed(Authctxt *authctxt, const char *method)
341: {
342: u_int i;
343:
344: /*
345: * NB. authctxt->num_auth_methods might be zero as a result of
346: * auth2_setup_methods_lists(), so check the configuration.
347: */
348: if (options.num_auth_methods == 0)
349: return 1;
350: for (i = 0; i < authctxt->num_auth_methods; i++) {
351: if (list_starts_with(authctxt->auth_methods[i], method))
352: return 1;
353: }
354: return 0;
355: }
356:
1.67 stevesk 357: static char *
1.125 djm 358: authmethods_get(Authctxt *authctxt)
1.1 markus 359: {
1.82 markus 360: Buffer b;
1.18 markus 361: char *list;
1.125 djm 362: u_int i;
1.1 markus 363:
1.82 markus 364: buffer_init(&b);
1.93 markus 365: for (i = 0; authmethods[i] != NULL; i++) {
366: if (strcmp(authmethods[i]->name, "none") == 0)
1.18 markus 367: continue;
1.125 djm 368: if (authmethods[i]->enabled == NULL ||
369: *(authmethods[i]->enabled) == 0)
370: continue;
371: if (!method_allowed(authctxt, authmethods[i]->name))
372: continue;
373: if (buffer_len(&b) > 0)
374: buffer_append(&b, ",", 1);
375: buffer_append(&b, authmethods[i]->name,
376: strlen(authmethods[i]->name));
1.1 markus 377: }
1.82 markus 378: buffer_append(&b, "\0", 1);
379: list = xstrdup(buffer_ptr(&b));
380: buffer_free(&b);
1.18 markus 381: return list;
382: }
383:
1.66 itojun 384: static Authmethod *
1.125 djm 385: authmethod_lookup(Authctxt *authctxt, const char *name)
1.18 markus 386: {
1.93 markus 387: int i;
388:
1.18 markus 389: if (name != NULL)
1.93 markus 390: for (i = 0; authmethods[i] != NULL; i++)
391: if (authmethods[i]->enabled != NULL &&
392: *(authmethods[i]->enabled) != 0 &&
1.125 djm 393: strcmp(name, authmethods[i]->name) == 0 &&
394: method_allowed(authctxt, authmethods[i]->name))
1.93 markus 395: return authmethods[i];
396: debug2("Unrecognized authentication method name: %s",
397: name ? name : "NULL");
1.18 markus 398: return NULL;
1.1 markus 399: }
1.125 djm 400:
401: /*
402: * Check a comma-separated list of methods for validity. Is need_enable is
403: * non-zero, then also require that the methods are enabled.
404: * Returns 0 on success or -1 if the methods list is invalid.
405: */
406: int
407: auth2_methods_valid(const char *_methods, int need_enable)
408: {
409: char *methods, *omethods, *method;
410: u_int i, found;
411: int ret = -1;
412:
413: if (*_methods == '\0') {
414: error("empty authentication method list");
415: return -1;
416: }
417: omethods = methods = xstrdup(_methods);
418: while ((method = strsep(&methods, ",")) != NULL) {
419: for (found = i = 0; !found && authmethods[i] != NULL; i++) {
420: if (strcmp(method, authmethods[i]->name) != 0)
421: continue;
422: if (need_enable) {
423: if (authmethods[i]->enabled == NULL ||
424: *(authmethods[i]->enabled) == 0) {
425: error("Disabled method \"%s\" in "
426: "AuthenticationMethods list \"%s\"",
427: method, _methods);
428: goto out;
429: }
430: }
431: found = 1;
432: break;
433: }
434: if (!found) {
435: error("Unknown authentication method \"%s\" in list",
436: method);
437: goto out;
438: }
439: }
440: ret = 0;
441: out:
442: free(omethods);
443: return ret;
444: }
445:
446: /*
447: * Prune the AuthenticationMethods supplied in the configuration, removing
448: * any methods lists that include disabled methods. Note that this might
449: * leave authctxt->num_auth_methods == 0, even when multiple required auth
450: * has been requested. For this reason, all tests for whether multiple is
451: * enabled should consult options.num_auth_methods directly.
452: */
453: int
454: auth2_setup_methods_lists(Authctxt *authctxt)
455: {
456: u_int i;
457:
458: if (options.num_auth_methods == 0)
459: return 0;
460: debug3("%s: checking methods", __func__);
461: authctxt->auth_methods = xcalloc(options.num_auth_methods,
462: sizeof(*authctxt->auth_methods));
463: authctxt->num_auth_methods = 0;
464: for (i = 0; i < options.num_auth_methods; i++) {
465: if (auth2_methods_valid(options.auth_methods[i], 1) != 0) {
466: logit("Authentication methods list \"%s\" contains "
467: "disabled method, skipping",
468: options.auth_methods[i]);
469: continue;
470: }
471: debug("authentication methods list %d: %s",
472: authctxt->num_auth_methods, options.auth_methods[i]);
473: authctxt->auth_methods[authctxt->num_auth_methods++] =
474: xstrdup(options.auth_methods[i]);
475: }
476: if (authctxt->num_auth_methods == 0) {
477: error("No AuthenticationMethods left after eliminating "
478: "disabled methods");
479: return -1;
480: }
481: return 0;
482: }
483:
484: static int
485: list_starts_with(const char *methods, const char *method)
486: {
487: size_t l = strlen(method);
488:
489: if (strncmp(methods, method, l) != 0)
490: return 0;
491: if (methods[l] != ',' && methods[l] != '\0')
492: return 0;
493: return 1;
494: }
495:
496: /*
497: * Remove method from the start of a comma-separated list of methods.
498: * Returns 0 if the list of methods did not start with that method or 1
499: * if it did.
500: */
501: static int
502: remove_method(char **methods, const char *method)
503: {
504: char *omethods = *methods;
505: size_t l = strlen(method);
506:
507: if (!list_starts_with(omethods, method))
508: return 0;
509: *methods = xstrdup(omethods + l + (omethods[l] == ',' ? 1 : 0));
510: free(omethods);
511: return 1;
512: }
513:
514: /*
515: * Called after successful authentication. Will remove the successful method
516: * from the start of each list in which it occurs. If it was the last method
517: * in any list, then authentication is deemed successful.
518: * Returns 1 if the method completed any authentication list or 0 otherwise.
519: */
520: int
521: auth2_update_methods_lists(Authctxt *authctxt, const char *method)
522: {
523: u_int i, found = 0;
524:
525: debug3("%s: updating methods list after \"%s\"", __func__, method);
526: for (i = 0; i < authctxt->num_auth_methods; i++) {
527: if (!remove_method(&(authctxt->auth_methods[i]), method))
528: continue;
529: found = 1;
530: if (*authctxt->auth_methods[i] == '\0') {
531: debug2("authentication methods list %d complete", i);
532: return 1;
533: }
534: debug3("authentication methods list %d remaining: \"%s\"",
535: i, authctxt->auth_methods[i]);
536: }
537: /* This should not happen, but would be bad if it did */
538: if (!found)
539: fatal("%s: method not in AuthenticationMethods", __func__);
540: return 0;
541: }
542:
1.117 djm 543: