Annotation of src/usr.bin/ssh/auth2.c, Revision 1.17
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.17 ! markus 26: RCSID("$OpenBSD: auth2.c,v 1.16 2000/09/27 21:41:34 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 "cipher.h"
39: #include "servconf.h"
40: #include "compat.h"
41: #include "channels.h"
42: #include "bufaux.h"
43: #include "ssh2.h"
44: #include "auth.h"
45: #include "session.h"
46: #include "dispatch.h"
47: #include "auth.h"
48: #include "key.h"
49: #include "kex.h"
50:
51: #include "dsa.h"
52: #include "uidswap.h"
1.10 markus 53: #include "auth-options.h"
1.1 markus 54:
55: /* import */
56: extern ServerOptions options;
57: extern unsigned char *session_id2;
58: extern int session_id2_len;
59:
60: /* protocol */
61:
1.15 markus 62: void input_service_request(int type, int plen, void *ctxt);
63: void input_userauth_request(int type, int plen, void *ctxt);
64: void protocol_error(int type, int plen, void *ctxt);
1.1 markus 65:
66: /* auth */
67: int ssh2_auth_none(struct passwd *pw);
68: int ssh2_auth_password(struct passwd *pw);
1.9 markus 69: int ssh2_auth_pubkey(struct passwd *pw, char *service);
1.1 markus 70:
71: /* helper */
72: struct passwd* auth_set_user(char *u, char *s);
73: int user_dsa_key_allowed(struct passwd *pw, Key *key);
74:
75: typedef struct Authctxt Authctxt;
76: struct Authctxt {
77: char *user;
78: char *service;
79: struct passwd pw;
80: int valid;
81: };
82: static Authctxt *authctxt = NULL;
83: static int userauth_success = 0;
84:
85: /*
86: * loop until userauth_success == TRUE
87: */
88:
89: void
90: do_authentication2()
91: {
1.4 markus 92: /* turn off skey/kerberos, not supported by SSH2 */
1.5 djm 93: #ifdef SKEY
1.4 markus 94: options.skey_authentication = 0;
1.5 djm 95: #endif
96: #ifdef KRB4
1.4 markus 97: options.kerberos_authentication = 0;
1.5 djm 98: #endif
1.4 markus 99:
1.1 markus 100: dispatch_init(&protocol_error);
101: dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
1.15 markus 102: dispatch_run(DISPATCH_BLOCK, &userauth_success, NULL);
1.1 markus 103: do_authenticated2();
104: }
105:
106: void
1.15 markus 107: protocol_error(int type, int plen, void *ctxt)
1.1 markus 108: {
109: log("auth: protocol error: type %d plen %d", type, plen);
110: packet_start(SSH2_MSG_UNIMPLEMENTED);
111: packet_put_int(0);
112: packet_send();
113: packet_write_wait();
114: }
115:
116: void
1.15 markus 117: input_service_request(int type, int plen, void *ctxt)
1.1 markus 118: {
119: unsigned int len;
120: int accept = 0;
121: char *service = packet_get_string(&len);
122: packet_done();
123:
124: if (strcmp(service, "ssh-userauth") == 0) {
125: if (!userauth_success) {
126: accept = 1;
127: /* now we can handle user-auth requests */
128: dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
129: }
130: }
131: /* XXX all other service requests are denied */
132:
133: if (accept) {
134: packet_start(SSH2_MSG_SERVICE_ACCEPT);
135: packet_put_cstring(service);
136: packet_send();
137: packet_write_wait();
138: } else {
139: debug("bad service request %s", service);
140: packet_disconnect("bad service request %s", service);
141: }
142: xfree(service);
143: }
144:
145: void
1.15 markus 146: input_userauth_request(int type, int plen, void *ctxt)
1.1 markus 147: {
1.3 markus 148: static void (*authlog) (const char *fmt,...) = verbose;
149: static int attempt = 0;
1.9 markus 150: unsigned int len;
1.1 markus 151: int authenticated = 0;
1.9 markus 152: char *user, *service, *method, *authmsg = NULL;
1.1 markus 153: struct passwd *pw;
154:
1.3 markus 155: if (++attempt == AUTH_FAIL_MAX)
1.1 markus 156: packet_disconnect("too many failed userauth_requests");
157:
158: user = packet_get_string(&len);
159: service = packet_get_string(&len);
160: method = packet_get_string(&len);
161: debug("userauth-request for user %s service %s method %s", user, service, method);
162:
163: /* XXX we only allow the ssh-connection service */
164: pw = auth_set_user(user, service);
165: if (pw && strcmp(service, "ssh-connection")==0) {
166: if (strcmp(method, "none") == 0) {
167: authenticated = ssh2_auth_none(pw);
168: } else if (strcmp(method, "password") == 0) {
169: authenticated = ssh2_auth_password(pw);
170: } else if (strcmp(method, "publickey") == 0) {
1.9 markus 171: authenticated = ssh2_auth_pubkey(pw, service);
1.1 markus 172: }
173: }
1.3 markus 174: if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
175: authenticated = 0;
176: log("ROOT LOGIN REFUSED FROM %.200s",
177: get_canonical_hostname());
178: }
179:
1.6 markus 180: /* Raise logging level */
181: if (authenticated == 1 ||
182: attempt == AUTH_FAIL_LOG ||
183: strcmp(method, "password") == 0)
184: authlog = log;
185:
186: /* Log before sending the reply */
187: if (authenticated == 1) {
188: authmsg = "Accepted";
189: } else if (authenticated == 0) {
190: authmsg = "Failed";
191: } else {
192: authmsg = "Postponed";
193: }
194: authlog("%s %s for %.200s from %.200s port %d ssh2",
195: authmsg,
196: method,
197: pw && pw->pw_uid == 0 ? "ROOT" : user,
198: get_remote_ipaddr(),
199: get_remote_port());
200:
1.3 markus 201: /* XXX todo: check if multiple auth methods are needed */
1.1 markus 202: if (authenticated == 1) {
203: /* turn off userauth */
204: dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
205: packet_start(SSH2_MSG_USERAUTH_SUCCESS);
206: packet_send();
207: packet_write_wait();
208: /* now we can break out */
209: userauth_success = 1;
210: } else if (authenticated == 0) {
211: packet_start(SSH2_MSG_USERAUTH_FAILURE);
212: packet_put_cstring("publickey,password"); /* XXX dynamic */
213: packet_put_char(0); /* XXX partial success, unused */
214: packet_send();
215: packet_write_wait();
216: }
1.3 markus 217:
1.1 markus 218: xfree(service);
219: xfree(user);
220: xfree(method);
221: }
222:
223: int
224: ssh2_auth_none(struct passwd *pw)
225: {
226: packet_done();
227: return auth_password(pw, "");
228: }
229: int
230: ssh2_auth_password(struct passwd *pw)
231: {
232: char *password;
233: int authenticated = 0;
234: int change;
235: unsigned int len;
236: change = packet_get_char();
237: if (change)
238: log("password change not supported");
239: password = packet_get_string(&len);
240: packet_done();
1.3 markus 241: if (options.password_authentication &&
242: auth_password(pw, password) == 1)
1.1 markus 243: authenticated = 1;
244: memset(password, 0, len);
245: xfree(password);
246: return authenticated;
247: }
248: int
1.9 markus 249: ssh2_auth_pubkey(struct passwd *pw, char *service)
1.1 markus 250: {
251: Buffer b;
252: Key *key;
253: char *pkalg, *pkblob, *sig;
254: unsigned int alen, blen, slen;
255: int have_sig;
256: int authenticated = 0;
257:
1.7 markus 258: if (options.dsa_authentication == 0) {
1.3 markus 259: debug("pubkey auth disabled");
1.8 markus 260: return 0;
261: }
1.1 markus 262: have_sig = packet_get_char();
263: pkalg = packet_get_string(&alen);
264: if (strcmp(pkalg, KEX_DSS) != 0) {
265: xfree(pkalg);
266: log("bad pkalg %s", pkalg); /*XXX*/
267: return 0;
268: }
269: pkblob = packet_get_string(&blen);
270: key = dsa_key_from_blob(pkblob, blen);
1.2 markus 271: if (key != NULL) {
272: if (have_sig) {
273: sig = packet_get_string(&slen);
274: packet_done();
275: buffer_init(&b);
1.11 markus 276: if (datafellows & SSH_COMPAT_SESSIONID_ENCODING) {
277: buffer_put_string(&b, session_id2, session_id2_len);
278: } else {
279: buffer_append(&b, session_id2, session_id2_len);
280: }
1.9 markus 281: /* reconstruct packet */
1.2 markus 282: buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
1.9 markus 283: buffer_put_cstring(&b, pw->pw_name);
284: buffer_put_cstring(&b,
285: datafellows & SSH_BUG_PUBKEYAUTH ?
286: "ssh-userauth" :
287: service);
288: buffer_put_cstring(&b, "publickey");
289: buffer_put_char(&b, have_sig);
290: buffer_put_cstring(&b, KEX_DSS);
291: buffer_put_string(&b, pkblob, blen);
1.1 markus 292: #ifdef DEBUG_DSS
1.2 markus 293: buffer_dump(&b);
1.1 markus 294: #endif
1.2 markus 295: /* test for correct signature */
296: if (user_dsa_key_allowed(pw, key) &&
297: dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
298: authenticated = 1;
299: buffer_clear(&b);
300: xfree(sig);
301: } else {
302: packet_done();
303: debug("test key...");
304: /* test whether pkalg/pkblob are acceptable */
305: /* XXX fake reply and always send PK_OK ? */
1.6 markus 306: /*
307: * XXX this allows testing whether a user is allowed
308: * to login: if you happen to have a valid pubkey this
309: * message is sent. the message is NEVER sent at all
310: * if a user is not allowed to login. is this an
311: * issue? -markus
312: */
1.2 markus 313: if (user_dsa_key_allowed(pw, key)) {
314: packet_start(SSH2_MSG_USERAUTH_PK_OK);
315: packet_put_string(pkalg, alen);
316: packet_put_string(pkblob, blen);
317: packet_send();
318: packet_write_wait();
319: authenticated = -1;
320: }
1.1 markus 321: }
1.17 ! markus 322: if (authenticated != 1)
! 323: auth_clear_options();
1.2 markus 324: key_free(key);
1.1 markus 325: }
326: xfree(pkalg);
327: xfree(pkblob);
328: return authenticated;
329: }
330:
331: /* set and get current user */
332:
333: struct passwd*
334: auth_get_user(void)
335: {
336: return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
337: }
338:
339: struct passwd*
340: auth_set_user(char *u, char *s)
341: {
342: struct passwd *pw, *copy;
343:
344: if (authctxt == NULL) {
345: authctxt = xmalloc(sizeof(*authctxt));
346: authctxt->valid = 0;
347: authctxt->user = xstrdup(u);
348: authctxt->service = xstrdup(s);
349: setproctitle("%s", u);
350: pw = getpwnam(u);
351: if (!pw || !allowed_user(pw)) {
1.3 markus 352: log("auth_set_user: illegal user %s", u);
1.1 markus 353: return NULL;
354: }
355: copy = &authctxt->pw;
356: memset(copy, 0, sizeof(*copy));
357: copy->pw_name = xstrdup(pw->pw_name);
358: copy->pw_passwd = xstrdup(pw->pw_passwd);
359: copy->pw_uid = pw->pw_uid;
360: copy->pw_gid = pw->pw_gid;
1.13 millert 361: copy->pw_class = xstrdup(pw->pw_class);
1.1 markus 362: copy->pw_dir = xstrdup(pw->pw_dir);
363: copy->pw_shell = xstrdup(pw->pw_shell);
364: authctxt->valid = 1;
365: } else {
366: if (strcmp(u, authctxt->user) != 0 ||
367: strcmp(s, authctxt->service) != 0) {
368: log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
369: u, s, authctxt->user, authctxt->service);
370: return NULL;
371: }
372: }
373: return auth_get_user();
374: }
375:
376: /* return 1 if user allows given key */
377: int
378: user_dsa_key_allowed(struct passwd *pw, Key *key)
379: {
380: char line[8192], file[1024];
381: int found_key = 0;
382: unsigned int bits = -1;
383: FILE *f;
384: unsigned long linenum = 0;
385: struct stat st;
386: Key *found;
387:
388: /* Temporarily use the user's uid. */
389: temporarily_use_uid(pw->pw_uid);
390:
391: /* The authorized keys. */
392: snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
393: SSH_USER_PERMITTED_KEYS2);
394:
395: /* Fail quietly if file does not exist */
396: if (stat(file, &st) < 0) {
397: /* Restore the privileged uid. */
398: restore_uid();
399: return 0;
400: }
401: /* Open the file containing the authorized keys. */
402: f = fopen(file, "r");
403: if (!f) {
404: /* Restore the privileged uid. */
405: restore_uid();
406: return 0;
407: }
408: if (options.strict_modes) {
409: int fail = 0;
410: char buf[1024];
411: /* Check open file in order to avoid open/stat races */
412: if (fstat(fileno(f), &st) < 0 ||
413: (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
414: (st.st_mode & 022) != 0) {
1.16 markus 415: snprintf(buf, sizeof buf,
416: "%s authentication refused for %.100s: "
417: "bad ownership or modes for '%s'.",
418: key_type(key), pw->pw_name, file);
1.1 markus 419: fail = 1;
420: } else {
421: /* Check path to SSH_USER_PERMITTED_KEYS */
422: int i;
423: static const char *check[] = {
424: "", SSH_USER_DIR, NULL
425: };
426: for (i = 0; check[i]; i++) {
427: snprintf(line, sizeof line, "%.500s/%.100s",
428: pw->pw_dir, check[i]);
429: if (stat(line, &st) < 0 ||
430: (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
431: (st.st_mode & 022) != 0) {
432: snprintf(buf, sizeof buf,
1.16 markus 433: "%s authentication refused for %.100s: "
1.1 markus 434: "bad ownership or modes for '%s'.",
1.16 markus 435: key_type(key), pw->pw_name, line);
1.1 markus 436: fail = 1;
437: break;
438: }
439: }
440: }
441: if (fail) {
442: fclose(f);
1.12 todd 443: log("%s",buf);
1.1 markus 444: restore_uid();
445: return 0;
446: }
447: }
448: found_key = 0;
1.16 markus 449: found = key_new(key->type);
1.1 markus 450:
451: while (fgets(line, sizeof(line), f)) {
1.10 markus 452: char *cp, *options = NULL;
1.1 markus 453: linenum++;
454: /* Skip leading whitespace, empty and comment lines. */
455: for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
456: ;
457: if (!*cp || *cp == '\n' || *cp == '#')
458: continue;
1.10 markus 459:
1.1 markus 460: bits = key_read(found, &cp);
1.10 markus 461: if (bits == 0) {
462: /* no key? check if there are options for this key */
463: int quoted = 0;
464: options = cp;
465: for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
466: if (*cp == '\\' && cp[1] == '"')
467: cp++; /* Skip both */
468: else if (*cp == '"')
469: quoted = !quoted;
470: }
471: /* Skip remaining whitespace. */
472: for (; *cp == ' ' || *cp == '\t'; cp++)
473: ;
474: bits = key_read(found, &cp);
475: if (bits == 0) {
476: /* still no key? advance to next line*/
477: continue;
478: }
479: }
480: if (key_equal(found, key) &&
481: auth_parse_options(pw, options, linenum) == 1) {
1.1 markus 482: found_key = 1;
483: debug("matching key found: file %s, line %ld",
484: file, linenum);
485: break;
486: }
487: }
488: restore_uid();
489: fclose(f);
490: key_free(found);
491: return found_key;
492: }