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