Annotation of src/usr.bin/ssh/auth2.c, Revision 1.4
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.4 ! markus 30: RCSID("$OpenBSD: auth2.c,v 1.3 2000/04/27 15:23:02 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);
72: int ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen);
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 */
! 96: options.skey_authentication = 0;
! 97: options.kerberos_authentication = 0;
! 98:
1.1 markus 99: dispatch_init(&protocol_error);
100: dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
101: dispatch_run(DISPATCH_BLOCK, &userauth_success);
102: do_authenticated2();
103: }
104:
105: void
106: protocol_error(int type, int plen)
107: {
108: log("auth: protocol error: type %d plen %d", type, plen);
109: packet_start(SSH2_MSG_UNIMPLEMENTED);
110: packet_put_int(0);
111: packet_send();
112: packet_write_wait();
113: }
114:
115: void
116: input_service_request(int type, int plen)
117: {
118: unsigned int len;
119: int accept = 0;
120: char *service = packet_get_string(&len);
121: packet_done();
122:
123: if (strcmp(service, "ssh-userauth") == 0) {
124: if (!userauth_success) {
125: accept = 1;
126: /* now we can handle user-auth requests */
127: dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
128: }
129: }
130: /* XXX all other service requests are denied */
131:
132: if (accept) {
133: packet_start(SSH2_MSG_SERVICE_ACCEPT);
134: packet_put_cstring(service);
135: packet_send();
136: packet_write_wait();
137: } else {
138: debug("bad service request %s", service);
139: packet_disconnect("bad service request %s", service);
140: }
141: xfree(service);
142: }
143:
144: void
145: input_userauth_request(int type, int plen)
146: {
1.3 markus 147: static void (*authlog) (const char *fmt,...) = verbose;
148: static int attempt = 0;
1.1 markus 149: unsigned int len, rlen;
150: int authenticated = 0;
1.3 markus 151: char *raw, *user, *service, *method, *authmsg = NULL;
1.1 markus 152: struct passwd *pw;
153:
1.3 markus 154: if (++attempt == AUTH_FAIL_MAX)
1.1 markus 155: packet_disconnect("too many failed userauth_requests");
156:
157: raw = packet_get_raw(&rlen);
158: if (plen != rlen)
159: fatal("plen != rlen");
160: user = packet_get_string(&len);
161: service = packet_get_string(&len);
162: method = packet_get_string(&len);
163: debug("userauth-request for user %s service %s method %s", user, service, method);
164:
165: /* XXX we only allow the ssh-connection service */
166: pw = auth_set_user(user, service);
167: if (pw && strcmp(service, "ssh-connection")==0) {
168: if (strcmp(method, "none") == 0) {
169: authenticated = ssh2_auth_none(pw);
170: } else if (strcmp(method, "password") == 0) {
171: authenticated = ssh2_auth_password(pw);
172: } else if (strcmp(method, "publickey") == 0) {
173: authenticated = ssh2_auth_pubkey(pw, raw, rlen);
174: }
175: }
1.3 markus 176: if (authenticated && pw && pw->pw_uid == 0 && !options.permit_root_login) {
177: authenticated = 0;
178: log("ROOT LOGIN REFUSED FROM %.200s",
179: get_canonical_hostname());
180: }
181:
182: /* XXX todo: check if multiple auth methods are needed */
1.1 markus 183: if (authenticated == 1) {
1.3 markus 184: authmsg = "Accepted";
1.1 markus 185: /* turn off userauth */
186: dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &protocol_error);
187: packet_start(SSH2_MSG_USERAUTH_SUCCESS);
188: packet_send();
189: packet_write_wait();
190: /* now we can break out */
191: userauth_success = 1;
192: } else if (authenticated == 0) {
1.3 markus 193: authmsg = "Failed";
1.1 markus 194: packet_start(SSH2_MSG_USERAUTH_FAILURE);
195: packet_put_cstring("publickey,password"); /* XXX dynamic */
196: packet_put_char(0); /* XXX partial success, unused */
197: packet_send();
198: packet_write_wait();
199: } else {
1.3 markus 200: authmsg = "Postponed";
1.1 markus 201: }
1.3 markus 202: /* Raise logging level */
203: if (authenticated == 1||
204: attempt == AUTH_FAIL_LOG ||
205: strcmp(method, "password") == 0)
206: authlog = log;
207:
208: authlog("%s %s for %.200s from %.200s port %d ssh2",
209: authmsg,
210: method,
211: pw && pw->pw_uid == 0 ? "ROOT" : user,
212: get_remote_ipaddr(),
213: get_remote_port());
214:
1.1 markus 215: xfree(service);
216: xfree(user);
217: xfree(method);
218: }
219:
220: int
221: ssh2_auth_none(struct passwd *pw)
222: {
223: packet_done();
224: return auth_password(pw, "");
225: }
226: int
227: ssh2_auth_password(struct passwd *pw)
228: {
229: char *password;
230: int authenticated = 0;
231: int change;
232: unsigned int len;
233: change = packet_get_char();
234: if (change)
235: log("password change not supported");
236: password = packet_get_string(&len);
237: packet_done();
1.3 markus 238: if (options.password_authentication &&
239: auth_password(pw, password) == 1)
1.1 markus 240: authenticated = 1;
241: memset(password, 0, len);
242: xfree(password);
243: return authenticated;
244: }
245: int
246: ssh2_auth_pubkey(struct passwd *pw, unsigned char *raw, unsigned int rlen)
247: {
248: Buffer b;
249: Key *key;
250: char *pkalg, *pkblob, *sig;
251: unsigned int alen, blen, slen;
252: int have_sig;
253: int authenticated = 0;
254:
1.3 markus 255: if (options.rsa_authentication == 0) {
256: debug("pubkey auth disabled");
257: return 0;
258: }
1.1 markus 259: have_sig = packet_get_char();
260: pkalg = packet_get_string(&alen);
261: if (strcmp(pkalg, KEX_DSS) != 0) {
262: xfree(pkalg);
263: log("bad pkalg %s", pkalg); /*XXX*/
264: return 0;
265: }
266: pkblob = packet_get_string(&blen);
267: key = dsa_key_from_blob(pkblob, blen);
1.2 markus 268: if (key != NULL) {
269: if (have_sig) {
270: sig = packet_get_string(&slen);
271: packet_done();
272: buffer_init(&b);
273: buffer_append(&b, session_id2, session_id2_len);
274: buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST);
275: if (slen + 4 > rlen)
276: fatal("bad rlen/slen");
277: buffer_append(&b, raw, rlen - slen - 4);
1.1 markus 278: #ifdef DEBUG_DSS
1.2 markus 279: buffer_dump(&b);
1.1 markus 280: #endif
1.2 markus 281: /* test for correct signature */
282: if (user_dsa_key_allowed(pw, key) &&
283: dsa_verify(key, sig, slen, buffer_ptr(&b), buffer_len(&b)) == 1)
284: authenticated = 1;
285: buffer_clear(&b);
286: xfree(sig);
287: } else {
288: packet_done();
289: debug("test key...");
290: /* test whether pkalg/pkblob are acceptable */
291: /* XXX fake reply and always send PK_OK ? */
292: if (user_dsa_key_allowed(pw, key)) {
293: packet_start(SSH2_MSG_USERAUTH_PK_OK);
294: packet_put_string(pkalg, alen);
295: packet_put_string(pkblob, blen);
296: packet_send();
297: packet_write_wait();
298: authenticated = -1;
299: }
1.1 markus 300: }
1.2 markus 301: key_free(key);
1.1 markus 302: }
303: xfree(pkalg);
304: xfree(pkblob);
305: return authenticated;
306: }
307:
308: /* set and get current user */
309:
310: struct passwd*
311: auth_get_user(void)
312: {
313: return (authctxt != NULL && authctxt->valid) ? &authctxt->pw : NULL;
314: }
315:
316: struct passwd*
317: auth_set_user(char *u, char *s)
318: {
319: struct passwd *pw, *copy;
320:
321: if (authctxt == NULL) {
322: authctxt = xmalloc(sizeof(*authctxt));
323: authctxt->valid = 0;
324: authctxt->user = xstrdup(u);
325: authctxt->service = xstrdup(s);
326: setproctitle("%s", u);
327: pw = getpwnam(u);
328: if (!pw || !allowed_user(pw)) {
1.3 markus 329: log("auth_set_user: illegal user %s", u);
1.1 markus 330: return NULL;
331: }
332: copy = &authctxt->pw;
333: memset(copy, 0, sizeof(*copy));
334: copy->pw_name = xstrdup(pw->pw_name);
335: copy->pw_passwd = xstrdup(pw->pw_passwd);
336: copy->pw_uid = pw->pw_uid;
337: copy->pw_gid = pw->pw_gid;
338: copy->pw_dir = xstrdup(pw->pw_dir);
339: copy->pw_shell = xstrdup(pw->pw_shell);
340: authctxt->valid = 1;
341: } else {
342: if (strcmp(u, authctxt->user) != 0 ||
343: strcmp(s, authctxt->service) != 0) {
344: log("auth_set_user: missmatch: (%s,%s)!=(%s,%s)",
345: u, s, authctxt->user, authctxt->service);
346: return NULL;
347: }
348: }
349: return auth_get_user();
350: }
351:
352: /* return 1 if user allows given key */
353: int
354: user_dsa_key_allowed(struct passwd *pw, Key *key)
355: {
356: char line[8192], file[1024];
357: int found_key = 0;
358: unsigned int bits = -1;
359: FILE *f;
360: unsigned long linenum = 0;
361: struct stat st;
362: Key *found;
363:
364: /* Temporarily use the user's uid. */
365: temporarily_use_uid(pw->pw_uid);
366:
367: /* The authorized keys. */
368: snprintf(file, sizeof file, "%.500s/%.100s", pw->pw_dir,
369: SSH_USER_PERMITTED_KEYS2);
370:
371: /* Fail quietly if file does not exist */
372: if (stat(file, &st) < 0) {
373: /* Restore the privileged uid. */
374: restore_uid();
375: return 0;
376: }
377: /* Open the file containing the authorized keys. */
378: f = fopen(file, "r");
379: if (!f) {
380: /* Restore the privileged uid. */
381: restore_uid();
382: return 0;
383: }
384: if (options.strict_modes) {
385: int fail = 0;
386: char buf[1024];
387: /* Check open file in order to avoid open/stat races */
388: if (fstat(fileno(f), &st) < 0 ||
389: (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
390: (st.st_mode & 022) != 0) {
391: snprintf(buf, sizeof buf, "DSA authentication refused for %.100s: "
392: "bad ownership or modes for '%s'.", pw->pw_name, file);
393: fail = 1;
394: } else {
395: /* Check path to SSH_USER_PERMITTED_KEYS */
396: int i;
397: static const char *check[] = {
398: "", SSH_USER_DIR, NULL
399: };
400: for (i = 0; check[i]; i++) {
401: snprintf(line, sizeof line, "%.500s/%.100s",
402: pw->pw_dir, check[i]);
403: if (stat(line, &st) < 0 ||
404: (st.st_uid != 0 && st.st_uid != pw->pw_uid) ||
405: (st.st_mode & 022) != 0) {
406: snprintf(buf, sizeof buf,
407: "DSA authentication refused for %.100s: "
408: "bad ownership or modes for '%s'.",
409: pw->pw_name, line);
410: fail = 1;
411: break;
412: }
413: }
414: }
415: if (fail) {
416: log(buf);
417: fclose(f);
418: restore_uid();
419: return 0;
420: }
421: }
422: found_key = 0;
423: found = key_new(KEY_DSA);
424:
425: while (fgets(line, sizeof(line), f)) {
426: char *cp;
427: linenum++;
428: /* Skip leading whitespace, empty and comment lines. */
429: for (cp = line; *cp == ' ' || *cp == '\t'; cp++)
430: ;
431: if (!*cp || *cp == '\n' || *cp == '#')
432: continue;
433: bits = key_read(found, &cp);
434: if (bits == 0)
435: continue;
436: if (key_equal(found, key)) {
437: found_key = 1;
438: debug("matching key found: file %s, line %ld",
439: file, linenum);
440: break;
441: }
442: }
443: restore_uid();
444: fclose(f);
445: key_free(found);
446: return found_key;
447: }