Annotation of src/usr.bin/ssh/auth2.c, Revision 1.8.2.1
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: * 3. All advertising materials mentioning features or use of this software
13: * must display the following acknowledgement:
14: * This product includes software developed by Markus Friedl.
15: * 4. The name of the author may not be used to endorse or promote products
16: * derived from this software without specific prior written permission.
17: *
18: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28: */
29: #include "includes.h"
1.8.2.1 ! jason 30: RCSID("$OpenBSD: auth2.c,v 1.13 2000/08/20 18:42:40 millert Exp $");
1.1 markus 31:
32: #include <openssl/dsa.h>
33: #include <openssl/rsa.h>
34: #include <openssl/evp.h>
35:
36: #include "xmalloc.h"
37: #include "rsa.h"
38: #include "ssh.h"
39: #include "pty.h"
40: #include "packet.h"
41: #include "buffer.h"
42: #include "cipher.h"
43: #include "servconf.h"
44: #include "compat.h"
45: #include "channels.h"
46: #include "bufaux.h"
47: #include "ssh2.h"
48: #include "auth.h"
49: #include "session.h"
50: #include "dispatch.h"
51: #include "auth.h"
52: #include "key.h"
53: #include "kex.h"
54:
55: #include "dsa.h"
56: #include "uidswap.h"
1.8.2.1 ! jason 57: #include "auth-options.h"
1.1 markus 58:
59: /* import */
60: extern ServerOptions options;
61: extern unsigned char *session_id2;
62: extern int session_id2_len;
63:
64: /* protocol */
65:
66: void input_service_request(int type, int plen);
67: void input_userauth_request(int type, int plen);
68: void protocol_error(int type, int plen);
69:
70: /* auth */
71: int ssh2_auth_none(struct passwd *pw);
72: int ssh2_auth_password(struct passwd *pw);
1.8.2.1 ! jason 73: int ssh2_auth_pubkey(struct passwd *pw, char *service);
1.1 markus 74:
75: /* helper */
76: struct passwd* auth_set_user(char *u, char *s);
77: int user_dsa_key_allowed(struct passwd *pw, Key *key);
78:
79: typedef struct Authctxt Authctxt;
80: struct Authctxt {
81: char *user;
82: char *service;
83: struct passwd pw;
84: int valid;
85: };
86: static Authctxt *authctxt = NULL;
87: static int userauth_success = 0;
88:
89: /*
90: * loop until userauth_success == TRUE
91: */
92:
93: void
94: do_authentication2()
95: {
1.4 markus 96: /* turn off skey/kerberos, not supported by SSH2 */
1.5 djm 97: #ifdef SKEY
1.4 markus 98: options.skey_authentication = 0;
1.5 djm 99: #endif
100: #ifdef KRB4
1.4 markus 101: options.kerberos_authentication = 0;
1.5 djm 102: #endif
1.4 markus 103:
1.1 markus 104: dispatch_init(&protocol_error);
105: dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
106: dispatch_run(DISPATCH_BLOCK, &userauth_success);
107: do_authenticated2();
108: }
109:
110: void
111: protocol_error(int type, int plen)
112: {
113: log("auth: protocol error: type %d plen %d", type, plen);
114: packet_start(SSH2_MSG_UNIMPLEMENTED);
115: packet_put_int(0);
116: packet_send();
117: packet_write_wait();
118: }
119:
120: void
121: input_service_request(int type, int plen)
122: {
123: unsigned int len;
124: int accept = 0;
125: char *service = packet_get_string(&len);
126: packet_done();
127:
128: if (strcmp(service, "ssh-userauth") == 0) {
129: if (!userauth_success) {
130: accept = 1;
131: /* now we can handle user-auth requests */
132: dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
133: }
134: }
135: /* XXX all other service requests are denied */
136:
137: if (accept) {
138: packet_start(SSH2_MSG_SERVICE_ACCEPT);
139: packet_put_cstring(service);
140: packet_send();
141: packet_write_wait();
142: } else {
143: debug("bad service request %s", service);
144: packet_disconnect("bad service request %s", service);
145: }
146: xfree(service);
147: }
148:
149: void
150: input_userauth_request(int type, int plen)
151: {
1.3 markus 152: static void (*authlog) (const char *fmt,...) = verbose;
153: static int attempt = 0;
1.8.2.1 ! jason 154: unsigned int len;
1.1 markus 155: int authenticated = 0;
1.8.2.1 ! jason 156: char *user, *service, *method, *authmsg = NULL;
1.1 markus 157: struct passwd *pw;
158:
1.3 markus 159: if (++attempt == AUTH_FAIL_MAX)
1.1 markus 160: packet_disconnect("too many failed userauth_requests");
161:
162: user = packet_get_string(&len);
163: service = packet_get_string(&len);
164: method = packet_get_string(&len);
165: debug("userauth-request for user %s service %s method %s", user, service, method);
166:
167: /* XXX we only allow the ssh-connection service */
168: pw = auth_set_user(user, service);
169: if (pw && strcmp(service, "ssh-connection")==0) {
170: if (strcmp(method, "none") == 0) {
171: authenticated = ssh2_auth_none(pw);
172: } else if (strcmp(method, "password") == 0) {
173: authenticated = ssh2_auth_password(pw);
174: } else if (strcmp(method, "publickey") == 0) {
1.8.2.1 ! jason 175: authenticated = ssh2_auth_pubkey(pw, service);
1.1 markus 176: }
177: }
1.3 markus 178: if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
179: authenticated = 0;
180: log("ROOT LOGIN REFUSED FROM %.200s",
181: get_canonical_hostname());
182: }
183:
1.6 markus 184: /* Raise logging level */
185: if (authenticated == 1 ||
186: attempt == AUTH_FAIL_LOG ||
187: strcmp(method, "password") == 0)
188: authlog = log;
189:
190: /* Log before sending the reply */
191: if (authenticated == 1) {
192: authmsg = "Accepted";
193: } else if (authenticated == 0) {
194: authmsg = "Failed";
195: } else {
196: authmsg = "Postponed";
197: }
198: authlog("%s %s for %.200s from %.200s port %d ssh2",
199: authmsg,
200: method,
201: pw && pw->pw_uid == 0 ? "ROOT" : user,
202: get_remote_ipaddr(),
203: get_remote_port());
204:
1.3 markus 205: /* XXX todo: check if multiple auth methods are needed */
1.1 markus 206: if (authenticated == 1) {
207: /* turn off userauth */
208: dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
209: packet_start(SSH2_MSG_USERAUTH_SUCCESS);
210: packet_send();
211: packet_write_wait();
212: /* now we can break out */
213: userauth_success = 1;
214: } else if (authenticated == 0) {
215: packet_start(SSH2_MSG_USERAUTH_FAILURE);
216: packet_put_cstring("publickey,password"); /* XXX dynamic */
217: packet_put_char(0); /* XXX partial success, unused */
218: packet_send();
219: packet_write_wait();
220: }
1.3 markus 221:
1.1 markus 222: xfree(service);
223: xfree(user);
224: xfree(method);
225: }
226:
227: int
228: ssh2_auth_none(struct passwd *pw)
229: {
230: packet_done();
231: return auth_password(pw, "");
232: }
233: int
234: ssh2_auth_password(struct passwd *pw)
235: {
236: char *password;
237: int authenticated = 0;
238: int change;
239: unsigned int len;
240: change = packet_get_char();
241: if (change)
242: log("password change not supported");
243: password = packet_get_string(&len);
244: packet_done();
1.3 markus 245: if (options.password_authentication &&
246: auth_password(pw, password) == 1)
1.1 markus 247: authenticated = 1;
248: memset(password, 0, len);
249: xfree(password);
250: return authenticated;
251: }
252: int
1.8.2.1 ! jason 253: ssh2_auth_pubkey(struct passwd *pw, char *service)
1.1 markus 254: {
255: Buffer b;
256: Key *key;
257: char *pkalg, *pkblob, *sig;
258: unsigned int alen, blen, slen;
259: int have_sig;
260: int authenticated = 0;
261:
1.7 markus 262: if (options.dsa_authentication == 0) {
1.3 markus 263: debug("pubkey auth disabled");
1.8 markus 264: return 0;
265: }
1.1 markus 266: have_sig = packet_get_char();
267: pkalg = packet_get_string(&alen);
268: if (strcmp(pkalg, KEX_DSS) != 0) {
269: xfree(pkalg);
270: log("bad pkalg %s", pkalg); /*XXX*/
271: return 0;
272: }
273: pkblob = packet_get_string(&blen);
274: key = dsa_key_from_blob(pkblob, blen);
1.2 markus 275: if (key != NULL) {
276: if (have_sig) {
277: sig = packet_get_string(&slen);
278: packet_done();
279: buffer_init(&b);
1.8.2.1 ! jason 280: if (datafellows & SSH_COMPAT_SESSIONID_ENCODING) {
! 281: buffer_put_string(&b, session_id2, session_id2_len);
! 282: } else {
! 283: buffer_append(&b, session_id2, session_id2_len);
! 284: }
! 285: /* reconstruct packet */
1.2 markus 286: buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
1.8.2.1 ! jason 287: buffer_put_cstring(&b, pw->pw_name);
! 288: buffer_put_cstring(&b,
! 289: datafellows & SSH_BUG_PUBKEYAUTH ?
! 290: "ssh-userauth" :
! 291: service);
! 292: buffer_put_cstring(&b, "publickey");
! 293: buffer_put_char(&b, have_sig);
! 294: buffer_put_cstring(&b, KEX_DSS);
! 295: buffer_put_string(&b, pkblob, blen);
1.1 markus 296: #ifdef DEBUG_DSS
1.2 markus 297: buffer_dump(&b);
1.1 markus 298: #endif
1.2 markus 299: /* test for correct signature */
300: if (user_dsa_key_allowed(pw, key) &&
301: dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
302: authenticated = 1;
303: buffer_clear(&b);
304: xfree(sig);
305: } else {
306: packet_done();
307: debug("test key...");
308: /* test whether pkalg/pkblob are acceptable */
309: /* XXX fake reply and always send PK_OK ? */
1.6 markus 310: /*
311: * XXX this allows testing whether a user is allowed
312: * to login: if you happen to have a valid pubkey this
313: * message is sent. the message is NEVER sent at all
314: * if a user is not allowed to login. is this an
315: * issue? -markus
316: */
1.2 markus 317: if (user_dsa_key_allowed(pw, key)) {
318: packet_start(SSH2_MSG_USERAUTH_PK_OK);
319: packet_put_string(pkalg, alen);
320: packet_put_string(pkblob, blen);
321: packet_send();
322: packet_write_wait();
323: authenticated = -1;
324: }
1.1 markus 325: }
1.2 markus 326: key_free(key);
1.1 markus 327: }
328: xfree(pkalg);
329: xfree(pkblob);
330: return authenticated;
331: }
332:
333: /* set and get current user */
334:
335: struct passwd*
336: auth_get_user(void)
337: {
338: return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
339: }
340:
341: struct passwd*
342: auth_set_user(char *u, char *s)
343: {
344: struct passwd *pw, *copy;
345:
346: if (authctxt == NULL) {
347: authctxt = xmalloc(sizeof(*authctxt));
348: authctxt->valid = 0;
349: authctxt->user = xstrdup(u);
350: authctxt->service = xstrdup(s);
351: setproctitle("%s", u);
352: pw = getpwnam(u);
353: if (!pw || !allowed_user(pw)) {
1.3 markus 354: log("auth_set_user: illegal user %s", u);
1.1 markus 355: return NULL;
356: }
357: copy = &authctxt->pw;
358: memset(copy, 0, sizeof(*copy));
359: copy->pw_name = xstrdup(pw->pw_name);
360: copy->pw_passwd = xstrdup(pw->pw_passwd);
361: copy->pw_uid = pw->pw_uid;
362: copy->pw_gid = pw->pw_gid;
1.8.2.1 ! jason 363: copy->pw_class = xstrdup(pw->pw_class);
1.1 markus 364: copy->pw_dir = xstrdup(pw->pw_dir);
365: copy->pw_shell = xstrdup(pw->pw_shell);
366: authctxt->valid = 1;
367: } else {
368: if (strcmp(u, authctxt->user) != 0 ||
369: strcmp(s, authctxt->service) != 0) {
370: log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
371: u, s, authctxt->user, authctxt->service);
372: return NULL;
373: }
374: }
375: return auth_get_user();
376: }
377:
378: /* return 1 if user allows given key */
379: int
380: user_dsa_key_allowed(struct passwd *pw, Key *key)
381: {
382: char line[8192], file[1024];
383: int found_key = 0;
384: unsigned int bits = -1;
385: FILE *f;
386: unsigned long linenum = 0;
387: struct stat st;
388: Key *found;
389:
390: /* Temporarily use the user's uid. */
391: temporarily_use_uid(pw->pw_uid);
392:
393: /* The authorized keys. */
394: snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
395: SSH_USER_PERMITTED_KEYS2);
396:
397: /* Fail quietly if file does not exist */
398: if (stat(file, &st) < 0) {
399: /* Restore the privileged uid. */
400: restore_uid();
401: return 0;
402: }
403: /* Open the file containing the authorized keys. */
404: f = fopen(file, "r");
405: if (!f) {
406: /* Restore the privileged uid. */
407: restore_uid();
408: return 0;
409: }
410: if (options.strict_modes) {
411: int fail = 0;
412: char buf[1024];
413: /* Check open file in order to avoid open/stat races */
414: if (fstat(fileno(f), &st) < 0 ||
415: (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
416: (st.st_mode & 022) != 0) {
417: snprintf(buf, sizeof buf, "DSA authentication refused for %.100s: "
418: "bad ownership or modes for '%s'.", pw->pw_name, file);
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,
433: "DSA authentication refused for %.100s: "
434: "bad ownership or modes for '%s'.",
435: pw->pw_name, line);
436: fail = 1;
437: break;
438: }
439: }
440: }
441: if (fail) {
442: fclose(f);
1.8.2.1 ! jason 443: log("%s",buf);
1.1 markus 444: restore_uid();
445: return 0;
446: }
447: }
448: found_key = 0;
449: found = key_new(KEY_DSA);
450:
451: while (fgets(line, sizeof(line), f)) {
1.8.2.1 ! jason 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.8.2.1 ! jason 459:
1.1 markus 460: bits = key_read(found, &cp);
1.8.2.1 ! jason 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: }