Annotation of src/usr.bin/ssh/auth2.c, Revision 1.20
1.1 markus 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: */
1.14 deraadt 24:
1.1 markus 25: #include "includes.h"
1.20 ! markus 26: RCSID("$OpenBSD: auth2.c,v 1.19 2000/10/11 20:27:23 markus Exp $");
1.1 markus 27:
28: #include <openssl/dsa.h>
29: #include <openssl/rsa.h>
30: #include <openssl/evp.h>
31:
32: #include "xmalloc.h"
33: #include "rsa.h"
34: #include "ssh.h"
35: #include "pty.h"
36: #include "packet.h"
37: #include "buffer.h"
38: #include "servconf.h"
39: #include "compat.h"
40: #include "channels.h"
41: #include "bufaux.h"
42: #include "ssh2.h"
43: #include "auth.h"
44: #include "session.h"
45: #include "dispatch.h"
46: #include "auth.h"
47: #include "key.h"
48: #include "kex.h"
49:
50: #include "dsa.h"
51: #include "uidswap.h"
1.10 markus 52: #include "auth-options.h"
1.1 markus 53:
54: /* import */
55: extern ServerOptions options;
56: extern unsigned char *session_id2;
57: extern int session_id2_len;
58:
1.18 markus 59: static Authctxt *x_authctxt = NULL;
60: static int one = 1;
61:
62: typedef struct Authmethod Authmethod;
63: struct Authmethod {
64: char *name;
65: int (*userauth)(Authctxt *authctxt);
66: int *enabled;
67: };
68:
1.1 markus 69: /* protocol */
70:
1.15 markus 71: void input_service_request(int type, int plen, void *ctxt);
72: void input_userauth_request(int type, int plen, void *ctxt);
73: void protocol_error(int type, int plen, void *ctxt);
1.1 markus 74:
75:
76: /* helper */
1.18 markus 77: Authmethod *authmethod_lookup(const char *name);
78: struct passwd *pwcopy(struct passwd *pw);
1.1 markus 79: int user_dsa_key_allowed(struct passwd *pw, Key *key);
1.18 markus 80: char *authmethods_get(void);
1.1 markus 81:
1.18 markus 82: /* auth */
83: int userauth_none(Authctxt *authctxt);
84: int userauth_passwd(Authctxt *authctxt);
85: int userauth_pubkey(Authctxt *authctxt);
86: int userauth_kbdint(Authctxt *authctxt);
87:
88: Authmethod authmethods[] = {
89: {"none",
90: userauth_none,
91: &one},
92: {"publickey",
93: userauth_pubkey,
94: &options.dsa_authentication},
95: {"keyboard-interactive",
96: userauth_kbdint,
97: &options.kbd_interactive_authentication},
98: {"password",
99: userauth_passwd,
100: &options.password_authentication},
101: {NULL, NULL, NULL}
1.1 markus 102: };
103:
104: /*
1.18 markus 105: * loop until authctxt->success == TRUE
1.1 markus 106: */
107:
108: void
109: do_authentication2()
110: {
1.18 markus 111: Authctxt *authctxt = xmalloc(sizeof(*authctxt));
112: memset(authctxt, 'a', sizeof(*authctxt));
113: authctxt->valid = 0;
114: authctxt->attempt = 0;
115: authctxt->success = 0;
116: x_authctxt = authctxt; /*XXX*/
117:
1.5 djm 118: #ifdef KRB4
1.18 markus 119: /* turn off kerberos, not supported by SSH2 */
1.4 markus 120: options.kerberos_authentication = 0;
1.5 djm 121: #endif
1.1 markus 122: dispatch_init(&protocol_error);
123: dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
1.18 markus 124: dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
1.1 markus 125: do_authenticated2();
126: }
127:
128: void
1.15 markus 129: protocol_error(int type, int plen, void *ctxt)
1.1 markus 130: {
131: log("auth: protocol error: type %d plen %d", type, plen);
132: packet_start(SSH2_MSG_UNIMPLEMENTED);
133: packet_put_int(0);
134: packet_send();
135: packet_write_wait();
136: }
137:
138: void
1.15 markus 139: input_service_request(int type, int plen, void *ctxt)
1.1 markus 140: {
1.18 markus 141: Authctxt *authctxt = ctxt;
1.1 markus 142: unsigned int len;
143: int accept = 0;
144: char *service = packet_get_string(&len);
145: packet_done();
146:
1.18 markus 147: if (authctxt == NULL)
148: fatal("input_service_request: no authctxt");
149:
1.1 markus 150: if (strcmp(service, "ssh-userauth") == 0) {
1.18 markus 151: if (!authctxt->success) {
1.1 markus 152: accept = 1;
153: /* now we can handle user-auth requests */
154: dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
155: }
156: }
157: /* XXX all other service requests are denied */
158:
159: if (accept) {
160: packet_start(SSH2_MSG_SERVICE_ACCEPT);
161: packet_put_cstring(service);
162: packet_send();
163: packet_write_wait();
164: } else {
165: debug("bad service request %s", service);
166: packet_disconnect("bad service request %s", service);
167: }
168: xfree(service);
169: }
170:
171: void
1.15 markus 172: input_userauth_request(int type, int plen, void *ctxt)
1.1 markus 173: {
1.18 markus 174: Authctxt *authctxt = ctxt;
175: Authmethod *m = NULL;
176: char *user, *service, *method;
1.1 markus 177: int authenticated = 0;
178:
1.18 markus 179: if (authctxt == NULL)
180: fatal("input_userauth_request: no authctxt");
181: if (authctxt->attempt++ >= AUTH_FAIL_MAX)
1.1 markus 182: packet_disconnect("too many failed userauth_requests");
183:
1.18 markus 184: user = packet_get_string(NULL);
185: service = packet_get_string(NULL);
186: method = packet_get_string(NULL);
1.1 markus 187: debug("userauth-request for user %s service %s method %s", user, service, method);
1.18 markus 188: debug("attempt #%d", authctxt->attempt);
1.1 markus 189:
1.18 markus 190: if (authctxt->attempt == 1) {
191: /* setup auth context */
192: struct passwd *pw = NULL;
193: setproctitle("%s", user);
194: pw = getpwnam(user);
195: if (pw && allowed_user(pw) && strcmp(service, "ssh-connection")==0) {
196: authctxt->pw = pwcopy(pw);
197: authctxt->valid = 1;
198: debug2("input_userauth_request: setting up authctxt for %s", user);
199: } else {
200: log("input_userauth_request: illegal user %s", user);
201: }
202: authctxt->user = xstrdup(user);
203: authctxt->service = xstrdup(service);
204: } else if (authctxt->valid) {
205: if (strcmp(user, authctxt->user) != 0 ||
206: strcmp(service, authctxt->service) != 0) {
207: log("input_userauth_request: missmatch: (%s,%s)!=(%s,%s)",
208: user, service, authctxt->user, authctxt->service);
209: authctxt->valid = 0;
1.1 markus 210: }
211: }
1.18 markus 212:
213: m = authmethod_lookup(method);
214: if (m != NULL) {
215: debug2("input_userauth_request: try method %s", method);
216: authenticated = m->userauth(authctxt);
217: } else {
218: debug2("input_userauth_request: unsupported method %s", method);
219: }
220: if (!authctxt->valid && authenticated == 1) {
221: log("input_userauth_request: INTERNAL ERROR: authenticated invalid user %s service %s", user, method);
222: authenticated = 0;
223: }
224:
225: /* Special handling for root */
226: if (authenticated == 1 &&
227: authctxt->valid && authctxt->pw->pw_uid == 0 && !options.permit_root_login) {
1.3 markus 228: authenticated = 0;
1.18 markus 229: log("ROOT LOGIN REFUSED FROM %.200s", get_canonical_hostname());
1.3 markus 230: }
231:
1.18 markus 232: /* Log before sending the reply */
233: userauth_log(authctxt, authenticated, method);
234: userauth_reply(authctxt, authenticated);
235:
236: xfree(service);
237: xfree(user);
238: xfree(method);
239: }
240:
241:
242: void
243: userauth_log(Authctxt *authctxt, int authenticated, char *method)
244: {
245: void (*authlog) (const char *fmt,...) = verbose;
246: char *user = NULL, *authmsg = NULL;
247:
1.6 markus 248: /* Raise logging level */
249: if (authenticated == 1 ||
1.18 markus 250: !authctxt->valid ||
251: authctxt->attempt >= AUTH_FAIL_LOG ||
1.6 markus 252: strcmp(method, "password") == 0)
253: authlog = log;
254:
255: if (authenticated == 1) {
256: authmsg = "Accepted";
257: } else if (authenticated == 0) {
258: authmsg = "Failed";
259: } else {
260: authmsg = "Postponed";
261: }
1.18 markus 262:
263: if (authctxt->valid) {
264: user = authctxt->pw->pw_uid == 0 ? "ROOT" : authctxt->user;
265: } else {
266: user = "NOUSER";
267: }
268:
1.6 markus 269: authlog("%s %s for %.200s from %.200s port %d ssh2",
1.18 markus 270: authmsg,
271: method,
272: user,
273: get_remote_ipaddr(),
274: get_remote_port());
275: }
1.6 markus 276:
1.18 markus 277: void
278: userauth_reply(Authctxt *authctxt, int authenticated)
279: {
1.3 markus 280: /* XXX todo: check if multiple auth methods are needed */
1.1 markus 281: if (authenticated == 1) {
282: /* turn off userauth */
283: dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
284: packet_start(SSH2_MSG_USERAUTH_SUCCESS);
285: packet_send();
286: packet_write_wait();
287: /* now we can break out */
1.18 markus 288: authctxt->success = 1;
1.1 markus 289: } else if (authenticated == 0) {
1.18 markus 290: char *methods = authmethods_get();
1.1 markus 291: packet_start(SSH2_MSG_USERAUTH_FAILURE);
1.18 markus 292: packet_put_cstring(methods);
293: packet_put_char(0); /* XXX partial success, unused */
1.1 markus 294: packet_send();
295: packet_write_wait();
1.18 markus 296: xfree(methods);
297: } else {
298: /* do nothing, we did already send a reply */
1.1 markus 299: }
300: }
301:
302: int
1.18 markus 303: userauth_none(Authctxt *authctxt)
1.1 markus 304: {
1.18 markus 305: /* disable method "none", only allowed one time */
306: Authmethod *m = authmethod_lookup("none");
307: if (m != NULL)
308: m->enabled = NULL;
1.1 markus 309: packet_done();
1.18 markus 310: return authctxt->valid ? auth_password(authctxt->pw, "") : 0;
1.1 markus 311: }
1.18 markus 312:
1.1 markus 313: int
1.18 markus 314: userauth_passwd(Authctxt *authctxt)
1.1 markus 315: {
316: char *password;
317: int authenticated = 0;
318: int change;
319: unsigned int len;
320: change = packet_get_char();
321: if (change)
322: log("password change not supported");
323: password = packet_get_string(&len);
324: packet_done();
1.18 markus 325: if (authctxt->valid &&
326: auth_password(authctxt->pw, password) == 1)
1.1 markus 327: authenticated = 1;
328: memset(password, 0, len);
329: xfree(password);
330: return authenticated;
331: }
1.18 markus 332:
333: int
334: userauth_kbdint(Authctxt *authctxt)
335: {
336: int authenticated = 0;
337: char *lang = NULL;
338: char *devs = NULL;
339:
340: lang = packet_get_string(NULL);
341: devs = packet_get_string(NULL);
342: packet_done();
343:
344: debug("keyboard-interactive language %s devs %s", lang, devs);
345: #ifdef SKEY
346: /* XXX hardcoded, we should look at devs */
347: if (options.skey_authentication != 0)
348: authenticated = auth2_skey(authctxt);
349: #endif
350: xfree(lang);
351: xfree(devs);
352: return authenticated;
353: }
354:
1.1 markus 355: int
1.18 markus 356: userauth_pubkey(Authctxt *authctxt)
1.1 markus 357: {
358: Buffer b;
359: Key *key;
360: char *pkalg, *pkblob, *sig;
361: unsigned int alen, blen, slen;
362: int have_sig;
363: int authenticated = 0;
364:
1.18 markus 365: if (!authctxt->valid) {
366: debug2("userauth_pubkey: disabled because of invalid user");
1.8 markus 367: return 0;
368: }
1.1 markus 369: have_sig = packet_get_char();
370: pkalg = packet_get_string(&alen);
371: if (strcmp(pkalg, KEX_DSS) != 0) {
1.18 markus 372: log("bad pkalg %s", pkalg); /*XXX*/
1.1 markus 373: xfree(pkalg);
374: return 0;
375: }
376: pkblob = packet_get_string(&blen);
377: key = dsa_key_from_blob(pkblob, blen);
1.2 markus 378: if (key != NULL) {
379: if (have_sig) {
380: sig = packet_get_string(&slen);
381: packet_done();
382: buffer_init(&b);
1.20 ! markus 383: if (datafellows & SSH_OLD_SESSIONID) {
! 384: buffer_append(&b, session_id2, session_id2_len);
! 385: } else {
1.11 markus 386: buffer_put_string(&b, session_id2, session_id2_len);
387: }
1.9 markus 388: /* reconstruct packet */
1.2 markus 389: buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
1.18 markus 390: buffer_put_cstring(&b, authctxt->user);
1.9 markus 391: buffer_put_cstring(&b,
392: datafellows & SSH_BUG_PUBKEYAUTH ?
393: "ssh-userauth" :
1.18 markus 394: authctxt->service);
1.9 markus 395: buffer_put_cstring(&b, "publickey");
396: buffer_put_char(&b, have_sig);
397: buffer_put_cstring(&b, KEX_DSS);
398: buffer_put_string(&b, pkblob, blen);
1.1 markus 399: #ifdef DEBUG_DSS
1.2 markus 400: buffer_dump(&b);
1.1 markus 401: #endif
1.2 markus 402: /* test for correct signature */
1.18 markus 403: if (user_dsa_key_allowed(authctxt->pw, key) &&
1.2 markus 404: dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
405: authenticated = 1;
406: buffer_clear(&b);
407: xfree(sig);
408: } else {
1.18 markus 409: debug("test whether pkalg/pkblob are acceptable");
1.2 markus 410: packet_done();
1.18 markus 411:
1.2 markus 412: /* XXX fake reply and always send PK_OK ? */
1.6 markus 413: /*
414: * XXX this allows testing whether a user is allowed
415: * to login: if you happen to have a valid pubkey this
416: * message is sent. the message is NEVER sent at all
417: * if a user is not allowed to login. is this an
418: * issue? -markus
419: */
1.18 markus 420: if (user_dsa_key_allowed(authctxt->pw, key)) {
1.2 markus 421: packet_start(SSH2_MSG_USERAUTH_PK_OK);
422: packet_put_string(pkalg, alen);
423: packet_put_string(pkblob, blen);
424: packet_send();
425: packet_write_wait();
426: authenticated = -1;
427: }
1.1 markus 428: }
1.17 markus 429: if (authenticated != 1)
430: auth_clear_options();
1.2 markus 431: key_free(key);
1.1 markus 432: }
433: xfree(pkalg);
434: xfree(pkblob);
435: return authenticated;
436: }
437:
1.18 markus 438: /* get current user */
1.1 markus 439:
440: struct passwd*
441: auth_get_user(void)
442: {
1.18 markus 443: return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL;
1.1 markus 444: }
445:
1.18 markus 446: #define DELIM ","
447:
448: char *
449: authmethods_get(void)
1.1 markus 450: {
1.18 markus 451: Authmethod *method = NULL;
452: unsigned int size = 0;
453: char *list;
1.1 markus 454:
1.18 markus 455: for (method = authmethods; method->name != NULL; method++) {
456: if (strcmp(method->name, "none") == 0)
457: continue;
458: if (method->enabled != NULL && *(method->enabled) != 0) {
459: if (size != 0)
460: size += strlen(DELIM);
461: size += strlen(method->name);
1.1 markus 462: }
1.18 markus 463: }
464: size++; /* trailing '\0' */
465: list = xmalloc(size);
466: list[0] = '\0';
467:
468: for (method = authmethods; method->name != NULL; method++) {
469: if (strcmp(method->name, "none") == 0)
470: continue;
471: if (method->enabled != NULL && *(method->enabled) != 0) {
472: if (list[0] != '\0')
473: strlcat(list, DELIM, size);
474: strlcat(list, method->name, size);
1.1 markus 475: }
476: }
1.18 markus 477: return list;
478: }
479:
480: Authmethod *
481: authmethod_lookup(const char *name)
482: {
483: Authmethod *method = NULL;
484: if (name != NULL)
485: for (method = authmethods; method->name != NULL; method++)
486: if (method->enabled != NULL &&
487: *(method->enabled) != 0 &&
488: strcmp(name, method->name) == 0)
489: return method;
490: debug2("Unrecognized authentication method name: %s", name ? name : "NULL");
491: return NULL;
1.1 markus 492: }
493:
494: /* return 1 if user allows given key */
495: int
496: user_dsa_key_allowed(struct passwd *pw, Key *key)
497: {
498: char line[8192], file[1024];
499: int found_key = 0;
500: unsigned int bits = -1;
501: FILE *f;
502: unsigned long linenum = 0;
503: struct stat st;
504: Key *found;
505:
1.18 markus 506: if (pw == NULL)
507: return 0;
508:
1.1 markus 509: /* Temporarily use the user's uid. */
510: temporarily_use_uid(pw->pw_uid);
511:
512: /* The authorized keys. */
513: snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
514: SSH_USER_PERMITTED_KEYS2);
515:
516: /* Fail quietly if file does not exist */
517: if (stat(file, &st) < 0) {
518: /* Restore the privileged uid. */
519: restore_uid();
520: return 0;
521: }
522: /* Open the file containing the authorized keys. */
523: f = fopen(file, "r");
524: if (!f) {
525: /* Restore the privileged uid. */
526: restore_uid();
527: return 0;
528: }
529: if (options.strict_modes) {
530: int fail = 0;
531: char buf[1024];
532: /* Check open file in order to avoid open/stat races */
533: if (fstat(fileno(f), &st) < 0 ||
534: (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
535: (st.st_mode & 022) != 0) {
1.16 markus 536: snprintf(buf, sizeof buf,
537: "%s authentication refused for %.100s: "
538: "bad ownership or modes for '%s'.",
539: key_type(key), pw->pw_name, file);
1.1 markus 540: fail = 1;
541: } else {
542: /* Check path to SSH_USER_PERMITTED_KEYS */
543: int i;
544: static const char *check[] = {
545: "", SSH_USER_DIR, NULL
546: };
547: for (i = 0; check[i]; i++) {
548: snprintf(line, sizeof line, "%.500s/%.100s",
549: pw->pw_dir, check[i]);
550: if (stat(line, &st) < 0 ||
551: (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
552: (st.st_mode & 022) != 0) {
553: snprintf(buf, sizeof buf,
1.16 markus 554: "%s authentication refused for %.100s: "
1.1 markus 555: "bad ownership or modes for '%s'.",
1.16 markus 556: key_type(key), pw->pw_name, line);
1.1 markus 557: fail = 1;
558: break;
559: }
560: }
561: }
562: if (fail) {
563: fclose(f);
1.12 todd 564: log("%s",buf);
1.1 markus 565: restore_uid();
566: return 0;
567: }
568: }
569: found_key = 0;
1.16 markus 570: found = key_new(key->type);
1.1 markus 571:
572: while (fgets(line, sizeof(line), f)) {
1.10 markus 573: char *cp, *options = NULL;
1.1 markus 574: linenum++;
575: /* Skip leading whitespace, empty and comment lines. */
576: for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
577: ;
578: if (!*cp || *cp == '\n' || *cp == '#')
579: continue;
1.10 markus 580:
1.1 markus 581: bits = key_read(found, &cp);
1.10 markus 582: if (bits == 0) {
583: /* no key? check if there are options for this key */
584: int quoted = 0;
585: options = cp;
586: for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
587: if (*cp == '\\' && cp[1] == '"')
588: cp++; /* Skip both */
589: else if (*cp == '"')
590: quoted = !quoted;
591: }
592: /* Skip remaining whitespace. */
593: for (; *cp == ' ' || *cp == '\t'; cp++)
594: ;
595: bits = key_read(found, &cp);
596: if (bits == 0) {
597: /* still no key? advance to next line*/
598: continue;
599: }
600: }
601: if (key_equal(found, key) &&
602: auth_parse_options(pw, options, linenum) == 1) {
1.1 markus 603: found_key = 1;
604: debug("matching key found: file %s, line %ld",
605: file, linenum);
606: break;
607: }
608: }
609: restore_uid();
610: fclose(f);
611: key_free(found);
612: return found_key;
1.18 markus 613: }
614:
615: struct passwd *
616: pwcopy(struct passwd *pw)
617: {
618: struct passwd *copy = xmalloc(sizeof(*copy));
619: memset(copy, 0, sizeof(*copy));
620: copy->pw_name = xstrdup(pw->pw_name);
621: copy->pw_passwd = xstrdup(pw->pw_passwd);
622: copy->pw_uid = pw->pw_uid;
623: copy->pw_gid = pw->pw_gid;
624: copy->pw_class = xstrdup(pw->pw_class);
625: copy->pw_dir = xstrdup(pw->pw_dir);
626: copy->pw_shell = xstrdup(pw->pw_shell);
627: return copy;
1.1 markus 628: }