Annotation of src/usr.bin/ssh/auth2.c, Revision 1.10
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.10 ! markus 30: RCSID("$OpenBSD: auth2.c,v 1.9 2000/06/18 01:09:10 markus 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.10 ! markus 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.9 markus 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.9 markus 154: unsigned int len;
1.1 markus 155: int authenticated = 0;
1.9 markus 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.9 markus 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.9 markus 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);
280: buffer_append(&b, session_id2, session_id2_len);
1.9 markus 281:
282: /* reconstruct packet */
1.2 markus 283: buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
1.9 markus 284: buffer_put_cstring(&b, pw->pw_name);
285: buffer_put_cstring(&b,
286: datafellows & SSH_BUG_PUBKEYAUTH ?
287: "ssh-userauth" :
288: service);
289: buffer_put_cstring(&b, "publickey");
290: buffer_put_char(&b, have_sig);
291: buffer_put_cstring(&b, KEX_DSS);
292: buffer_put_string(&b, pkblob, blen);
1.1 markus 293: #ifdef DEBUG_DSS
1.2 markus 294: buffer_dump(&b);
1.1 markus 295: #endif
1.2 markus 296: /* test for correct signature */
297: if (user_dsa_key_allowed(pw, key) &&
298: dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
299: authenticated = 1;
300: buffer_clear(&b);
301: xfree(sig);
302: } else {
303: packet_done();
304: debug("test key...");
305: /* test whether pkalg/pkblob are acceptable */
306: /* XXX fake reply and always send PK_OK ? */
1.6 markus 307: /*
308: * XXX this allows testing whether a user is allowed
309: * to login: if you happen to have a valid pubkey this
310: * message is sent. the message is NEVER sent at all
311: * if a user is not allowed to login. is this an
312: * issue? -markus
313: */
1.2 markus 314: if (user_dsa_key_allowed(pw, key)) {
315: packet_start(SSH2_MSG_USERAUTH_PK_OK);
316: packet_put_string(pkalg, alen);
317: packet_put_string(pkblob, blen);
318: packet_send();
319: packet_write_wait();
320: authenticated = -1;
321: }
1.1 markus 322: }
1.2 markus 323: key_free(key);
1.1 markus 324: }
325: xfree(pkalg);
326: xfree(pkblob);
327: return authenticated;
328: }
329:
330: /* set and get current user */
331:
332: struct passwd*
333: auth_get_user(void)
334: {
335: return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
336: }
337:
338: struct passwd*
339: auth_set_user(char *u, char *s)
340: {
341: struct passwd *pw, *copy;
342:
343: if (authctxt == NULL) {
344: authctxt = xmalloc(sizeof(*authctxt));
345: authctxt->valid = 0;
346: authctxt->user = xstrdup(u);
347: authctxt->service = xstrdup(s);
348: setproctitle("%s", u);
349: pw = getpwnam(u);
350: if (!pw || !allowed_user(pw)) {
1.3 markus 351: log("auth_set_user: illegal user %s", u);
1.1 markus 352: return NULL;
353: }
354: copy = &authctxt->pw;
355: memset(copy, 0, sizeof(*copy));
356: copy->pw_name = xstrdup(pw->pw_name);
357: copy->pw_passwd = xstrdup(pw->pw_passwd);
358: copy->pw_uid = pw->pw_uid;
359: copy->pw_gid = pw->pw_gid;
360: copy->pw_dir = xstrdup(pw->pw_dir);
361: copy->pw_shell = xstrdup(pw->pw_shell);
362: authctxt->valid = 1;
363: } else {
364: if (strcmp(u, authctxt->user) != 0 ||
365: strcmp(s, authctxt->service) != 0) {
366: log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
367: u, s, authctxt->user, authctxt->service);
368: return NULL;
369: }
370: }
371: return auth_get_user();
372: }
373:
374: /* return 1 if user allows given key */
375: int
376: user_dsa_key_allowed(struct passwd *pw, Key *key)
377: {
378: char line[8192], file[1024];
379: int found_key = 0;
380: unsigned int bits = -1;
381: FILE *f;
382: unsigned long linenum = 0;
383: struct stat st;
384: Key *found;
385:
386: /* Temporarily use the user's uid. */
387: temporarily_use_uid(pw->pw_uid);
388:
389: /* The authorized keys. */
390: snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
391: SSH_USER_PERMITTED_KEYS2);
392:
393: /* Fail quietly if file does not exist */
394: if (stat(file, &st) < 0) {
395: /* Restore the privileged uid. */
396: restore_uid();
397: return 0;
398: }
399: /* Open the file containing the authorized keys. */
400: f = fopen(file, "r");
401: if (!f) {
402: /* Restore the privileged uid. */
403: restore_uid();
404: return 0;
405: }
406: if (options.strict_modes) {
407: int fail = 0;
408: char buf[1024];
409: /* Check open file in order to avoid open/stat races */
410: if (fstat(fileno(f), &st) < 0 ||
411: (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
412: (st.st_mode & 022) != 0) {
413: snprintf(buf, sizeof buf, "DSA authentication refused for %.100s: "
414: "bad ownership or modes for '%s'.", pw->pw_name, file);
415: fail = 1;
416: } else {
417: /* Check path to SSH_USER_PERMITTED_KEYS */
418: int i;
419: static const char *check[] = {
420: "", SSH_USER_DIR, NULL
421: };
422: for (i = 0; check[i]; i++) {
423: snprintf(line, sizeof line, "%.500s/%.100s",
424: pw->pw_dir, check[i]);
425: if (stat(line, &st) < 0 ||
426: (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
427: (st.st_mode & 022) != 0) {
428: snprintf(buf, sizeof buf,
429: "DSA authentication refused for %.100s: "
430: "bad ownership or modes for '%s'.",
431: pw->pw_name, line);
432: fail = 1;
433: break;
434: }
435: }
436: }
437: if (fail) {
438: log(buf);
439: fclose(f);
440: restore_uid();
441: return 0;
442: }
443: }
444: found_key = 0;
445: found = key_new(KEY_DSA);
446:
447: while (fgets(line, sizeof(line), f)) {
1.10 ! markus 448: char *cp, *options = NULL;
1.1 markus 449: linenum++;
450: /* Skip leading whitespace, empty and comment lines. */
451: for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
452: ;
453: if (!*cp || *cp == '\n' || *cp == '#')
454: continue;
1.10 ! markus 455:
1.1 markus 456: bits = key_read(found, &cp);
1.10 ! markus 457: if (bits == 0) {
! 458: /* no key? check if there are options for this key */
! 459: int quoted = 0;
! 460: options = cp;
! 461: for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) {
! 462: if (*cp == '\\' && cp[1] == '"')
! 463: cp++; /* Skip both */
! 464: else if (*cp == '"')
! 465: quoted = !quoted;
! 466: }
! 467: /* Skip remaining whitespace. */
! 468: for (; *cp == ' ' || *cp == '\t'; cp++)
! 469: ;
! 470: bits = key_read(found, &cp);
! 471: if (bits == 0) {
! 472: /* still no key? advance to next line*/
! 473: continue;
! 474: }
! 475: }
! 476: if (key_equal(found, key) &&
! 477: auth_parse_options(pw, options, linenum) == 1) {
1.1 markus 478: found_key = 1;
479: debug("matching key found: file %s, line %ld",
480: file, linenum);
481: break;
482: }
483: }
484: restore_uid();
485: fclose(f);
486: key_free(found);
487: return found_key;
488: }