Annotation of src/usr.bin/ssh/auth1.c, Revision 1.66
1.66 ! djm 1: /* $OpenBSD$ */
1.1 markus 2: /*
3: * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4: * All rights reserved
1.4 deraadt 5: *
6: * As far as I am concerned, the code I have written for this software
7: * can be used freely for any purpose. Any derived versions of this
8: * software must be clearly marked as such, and if the derived work is
9: * incompatible with the protocol description in the RFC file, it must be
10: * called by a name other than "ssh" or "Secure Shell".
1.1 markus 11: */
12:
13: #include "includes.h"
14:
15: #include "xmalloc.h"
16: #include "rsa.h"
1.12 markus 17: #include "ssh1.h"
1.1 markus 18: #include "packet.h"
19: #include "buffer.h"
1.13 markus 20: #include "log.h"
1.1 markus 21: #include "servconf.h"
22: #include "compat.h"
23: #include "auth.h"
1.35 markus 24: #include "channels.h"
1.1 markus 25: #include "session.h"
1.25 dugsong 26: #include "uidswap.h"
1.38 provos 27: #include "monitor_wrap.h"
1.1 markus 28:
29: /* import */
30: extern ServerOptions options;
31:
1.60 djm 32: static int auth1_process_password(Authctxt *, char *, size_t);
33: static int auth1_process_rsa(Authctxt *, char *, size_t);
34: static int auth1_process_rhosts_rsa(Authctxt *, char *, size_t);
35: static int auth1_process_tis_challenge(Authctxt *, char *, size_t);
36: static int auth1_process_tis_response(Authctxt *, char *, size_t);
37:
38: struct AuthMethod1 {
39: int type;
40: char *name;
41: int *enabled;
42: int (*method)(Authctxt *, char *, size_t);
43: };
44:
45: const struct AuthMethod1 auth1_methods[] = {
46: {
47: SSH_CMSG_AUTH_PASSWORD, "password",
48: &options.password_authentication, auth1_process_password
49: },
50: {
51: SSH_CMSG_AUTH_RSA, "rsa",
52: &options.rsa_authentication, auth1_process_rsa
53: },
54: {
55: SSH_CMSG_AUTH_RHOSTS_RSA, "rhosts-rsa",
56: &options.rhosts_rsa_authentication, auth1_process_rhosts_rsa
57: },
58: {
59: SSH_CMSG_AUTH_TIS, "challenge-response",
60: &options.challenge_response_authentication,
61: auth1_process_tis_challenge
62: },
63: {
64: SSH_CMSG_AUTH_TIS_RESPONSE, "challenge-response",
65: &options.challenge_response_authentication,
66: auth1_process_tis_response
67: },
68: { -1, NULL, NULL, NULL}
69: };
70:
71: static const struct AuthMethod1
72: *lookup_authmethod1(int type)
73: {
74: int i;
75:
1.64 deraadt 76: for (i = 0; auth1_methods[i].name != NULL; i++)
1.60 djm 77: if (auth1_methods[i].type == type)
78: return (&(auth1_methods[i]));
79:
80: return (NULL);
81: }
82:
1.24 itojun 83: static char *
1.1 markus 84: get_authname(int type)
85: {
1.60 djm 86: const struct AuthMethod1 *a;
87: static char buf[64];
88:
89: if ((a = lookup_authmethod1(type)) != NULL)
90: return (a->name);
91: snprintf(buf, sizeof(buf), "bad-auth-msg-%d", type);
92: return (buf);
93: }
94:
1.65 deraadt 95: /*ARGSUSED*/
1.60 djm 96: static int
97: auth1_process_password(Authctxt *authctxt, char *info, size_t infolen)
98: {
99: int authenticated = 0;
100: char *password;
101: u_int dlen;
102:
103: /*
104: * Read user password. It is in plain text, but was
105: * transmitted over the encrypted channel so it is
106: * not visible to an outside observer.
107: */
108: password = packet_get_string(&dlen);
109: packet_check_eom();
110:
111: /* Try authentication with the password. */
112: authenticated = PRIVSEP(auth_password(authctxt, password));
113:
114: memset(password, 0, dlen);
115: xfree(password);
116:
117: return (authenticated);
118: }
119:
1.65 deraadt 120: /*ARGSUSED*/
1.60 djm 121: static int
122: auth1_process_rsa(Authctxt *authctxt, char *info, size_t infolen)
123: {
124: int authenticated = 0;
125: BIGNUM *n;
126:
127: /* RSA authentication requested. */
128: if ((n = BN_new()) == NULL)
129: fatal("do_authloop: BN_new failed");
130: packet_get_bignum(n);
131: packet_check_eom();
132: authenticated = auth_rsa(authctxt, n);
133: BN_clear_free(n);
134:
135: return (authenticated);
136: }
137:
1.65 deraadt 138: /*ARGSUSED*/
1.60 djm 139: static int
140: auth1_process_rhosts_rsa(Authctxt *authctxt, char *info, size_t infolen)
141: {
1.61 djm 142: int keybits, authenticated = 0;
1.60 djm 143: u_int bits;
144: char *client_user;
145: Key *client_host_key;
146: u_int ulen;
147:
148: /*
149: * Get client user name. Note that we just have to
150: * trust the client; root on the client machine can
151: * claim to be any user.
152: */
153: client_user = packet_get_string(&ulen);
154:
155: /* Get the client host key. */
156: client_host_key = key_new(KEY_RSA1);
157: bits = packet_get_int();
158: packet_get_bignum(client_host_key->rsa->e);
159: packet_get_bignum(client_host_key->rsa->n);
160:
1.61 djm 161: keybits = BN_num_bits(client_host_key->rsa->n);
162: if (keybits < 0 || bits != (u_int)keybits) {
1.60 djm 163: verbose("Warning: keysize mismatch for client_host_key: "
164: "actual %d, announced %d",
165: BN_num_bits(client_host_key->rsa->n), bits);
1.1 markus 166: }
1.60 djm 167: packet_check_eom();
168:
169: authenticated = auth_rhosts_rsa(authctxt, client_user,
170: client_host_key);
171: key_free(client_host_key);
172:
173: snprintf(info, infolen, " ruser %.100s", client_user);
174: xfree(client_user);
1.62 djm 175:
1.60 djm 176: return (authenticated);
177: }
178:
1.65 deraadt 179: /*ARGSUSED*/
1.60 djm 180: static int
181: auth1_process_tis_challenge(Authctxt *authctxt, char *info, size_t infolen)
182: {
183: char *challenge;
1.62 djm 184:
1.60 djm 185: if ((challenge = get_challenge(authctxt)) == NULL)
186: return (0);
187:
188: debug("sending challenge '%s'", challenge);
189: packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
190: packet_put_cstring(challenge);
191: xfree(challenge);
192: packet_send();
193: packet_write_wait();
194:
195: return (-1);
196: }
197:
1.65 deraadt 198: /*ARGSUSED*/
1.60 djm 199: static int
200: auth1_process_tis_response(Authctxt *authctxt, char *info, size_t infolen)
201: {
202: int authenticated = 0;
203: char *response;
204: u_int dlen;
205:
206: response = packet_get_string(&dlen);
207: packet_check_eom();
208: authenticated = verify_response(authctxt, response);
209: memset(response, 'r', dlen);
210: xfree(response);
211:
212: return (authenticated);
1.1 markus 213: }
214:
215: /*
1.11 markus 216: * read packets, try to authenticate the user and
217: * return only if authentication is successful
1.1 markus 218: */
1.24 itojun 219: static void
1.11 markus 220: do_authloop(Authctxt *authctxt)
1.1 markus 221: {
1.5 markus 222: int authenticated = 0;
1.11 markus 223: char info[1024];
1.1 markus 224: int type = 0;
1.60 djm 225: const struct AuthMethod1 *meth;
1.11 markus 226:
227: debug("Attempting authentication for %s%.100s.",
1.59 markus 228: authctxt->valid ? "" : "invalid user ", authctxt->user);
1.11 markus 229:
230: /* If the user has no password, accept authentication immediately. */
231: if (options.password_authentication &&
1.49 markus 232: #ifdef KRB5
1.11 markus 233: (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
234: #endif
1.38 provos 235: PRIVSEP(auth_password(authctxt, ""))) {
1.11 markus 236: auth_log(authctxt, 1, "without authentication", "");
237: return;
238: }
1.27 deraadt 239:
1.1 markus 240: /* Indicate that authentication is needed. */
241: packet_start(SSH_SMSG_FAILURE);
242: packet_send();
243: packet_write_wait();
244:
1.11 markus 245: for (;;) {
1.5 markus 246: /* default to fail */
247: authenticated = 0;
248:
1.11 markus 249: info[0] = '\0';
1.1 markus 250:
251: /* Get a packet from the client. */
1.34 markus 252: type = packet_read();
1.60 djm 253: if ((meth = lookup_authmethod1(type)) == NULL) {
254: logit("Unknown message during authentication: "
255: "type %d", type);
256: goto skip;
257: }
1.1 markus 258:
1.60 djm 259: if (!*(meth->enabled)) {
260: verbose("%s authentication disabled.", meth->name);
261: goto skip;
1.1 markus 262: }
1.60 djm 263:
264: authenticated = meth->method(authctxt, info, sizeof(info));
265: if (authenticated == -1)
266: continue; /* "postponed" */
267:
1.20 markus 268: #ifdef BSD_AUTH
269: if (authctxt->as) {
270: auth_close(authctxt->as);
271: authctxt->as = NULL;
272: }
273: #endif
1.11 markus 274: if (!authctxt->valid && authenticated)
275: fatal("INTERNAL ERROR: authenticated invalid user %s",
276: authctxt->user);
277:
278: /* Special handling for root */
1.47 markus 279: if (authenticated && authctxt->pw->pw_uid == 0 &&
1.60 djm 280: !auth_root_allowed(meth->name))
1.11 markus 281: authenticated = 0;
1.1 markus 282:
1.60 djm 283: skip:
1.11 markus 284: /* Log before sending the reply */
285: auth_log(authctxt, authenticated, get_authname(type), info);
1.1 markus 286:
287: if (authenticated)
288: return;
289:
1.57 dtucker 290: if (authctxt->failures++ > options.max_authtries)
1.11 markus 291: packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
1.1 markus 292:
293: packet_start(SSH_SMSG_FAILURE);
294: packet_send();
295: packet_write_wait();
296: }
297: }
298:
299: /*
300: * Performs authentication of an incoming connection. Session key has already
301: * been exchanged and encryption is enabled.
302: */
1.53 markus 303: void
304: do_authentication(Authctxt *authctxt)
1.1 markus 305: {
1.8 markus 306: u_int ulen;
1.40 markus 307: char *user, *style = NULL;
1.1 markus 308:
309: /* Get the name of the user that we wish to log in as. */
1.34 markus 310: packet_read_expect(SSH_CMSG_USER);
1.1 markus 311:
312: /* Get the user name. */
313: user = packet_get_string(&ulen);
1.32 markus 314: packet_check_eom();
1.1 markus 315:
1.11 markus 316: if ((style = strchr(user, ':')) != NULL)
1.25 dugsong 317: *style++ = '\0';
1.27 deraadt 318:
1.11 markus 319: authctxt->user = user;
320: authctxt->style = style;
321:
1.1 markus 322: /* Verify that the user is a valid user. */
1.39 markus 323: if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL)
1.11 markus 324: authctxt->valid = 1;
1.51 markus 325: else {
1.59 markus 326: debug("do_authentication: invalid user %s", user);
1.51 markus 327: authctxt->pw = fakepw();
328: }
1.17 markus 329:
1.58 djm 330: setproctitle("%s%s", authctxt->valid ? user : "unknown",
1.38 provos 331: use_privsep ? " [net]" : "");
1.1 markus 332:
333: /*
334: * If we are not running as root, the user must have the same uid as
335: * the server.
336: */
1.39 markus 337: if (!use_privsep && getuid() != 0 && authctxt->pw &&
338: authctxt->pw->pw_uid != getuid())
1.1 markus 339: packet_disconnect("Cannot change user when server not running as root.");
340:
1.11 markus 341: /*
342: * Loop until the user has been authenticated or the connection is
343: * closed, do_authloop() returns only if authentication is successful
344: */
345: do_authloop(authctxt);
1.1 markus 346:
347: /* The user has been authenticated and accepted. */
348: packet_start(SSH_SMSG_SUCCESS);
349: packet_send();
350: packet_write_wait();
351: }