Annotation of src/usr.bin/ssh/auth2.c, Revision 1.112
1.112 ! stevesk 1: /* $OpenBSD: auth2.c,v 1.111 2006/07/06 16:03:53 stevesk Exp $ */
1.1 markus 2: /*
3: * Copyright (c) 2000 Markus Friedl. All rights reserved.
4: *
5: * Redistribution and use in source and binary forms, with or without
6: * modification, are permitted provided that the following conditions
7: * are met:
8: * 1. Redistributions of source code must retain the above copyright
9: * notice, this list of conditions and the following disclaimer.
10: * 2. Redistributions in binary form must reproduce the above copyright
11: * notice, this list of conditions and the following disclaimer in the
12: * documentation and/or other materials provided with the distribution.
13: *
14: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
15: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
16: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
17: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
18: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
19: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
20: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
21: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
23: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24: */
1.14 deraadt 25:
1.1 markus 26: #include "includes.h"
1.111 stevesk 27:
28: #include <sys/types.h>
29:
30: #include <pwd.h>
1.112 ! stevesk 31: #include <string.h>
1.1 markus 32:
1.32 markus 33: #include "ssh2.h"
1.1 markus 34: #include "xmalloc.h"
35: #include "packet.h"
1.32 markus 36: #include "log.h"
1.1 markus 37: #include "servconf.h"
38: #include "compat.h"
39: #include "auth.h"
40: #include "dispatch.h"
1.29 markus 41: #include "pathnames.h"
1.88 provos 42: #include "monitor_wrap.h"
1.1 markus 43:
1.100 markus 44: #ifdef GSSAPI
45: #include "ssh-gss.h"
46: #endif
47:
1.1 markus 48: /* import */
49: extern ServerOptions options;
1.23 markus 50: extern u_char *session_id2;
1.99 markus 51: extern u_int session_id2_len;
1.1 markus 52:
1.93 markus 53: /* methods */
54:
55: extern Authmethod method_none;
56: extern Authmethod method_pubkey;
57: extern Authmethod method_passwd;
58: extern Authmethod method_kbdint;
59: extern Authmethod method_hostbased;
1.100 markus 60: #ifdef GSSAPI
61: extern Authmethod method_gssapi;
62: #endif
1.93 markus 63:
64: Authmethod *authmethods[] = {
65: &method_none,
66: &method_pubkey,
1.100 markus 67: #ifdef GSSAPI
68: &method_gssapi,
69: #endif
1.93 markus 70: &method_passwd,
71: &method_kbdint,
72: &method_hostbased,
73: NULL
1.18 markus 74: };
75:
1.1 markus 76: /* protocol */
77:
1.80 markus 78: static void input_service_request(int, u_int32_t, void *);
79: static void input_userauth_request(int, u_int32_t, void *);
1.1 markus 80:
81: /* helper */
1.66 itojun 82: static Authmethod *authmethod_lookup(const char *);
1.67 stevesk 83: static char *authmethods_get(void);
1.88 provos 84: int user_key_allowed(struct passwd *, Key *);
1.1 markus 85:
86: /*
1.18 markus 87: * loop until authctxt->success == TRUE
1.1 markus 88: */
89:
1.103 markus 90: void
91: do_authentication2(Authctxt *authctxt)
1.1 markus 92: {
1.71 markus 93: /* challenge-response is implemented via keyboard interactive */
1.57 markus 94: if (options.challenge_response_authentication)
1.34 markus 95: options.kbd_interactive_authentication = 1;
96:
1.81 markus 97: dispatch_init(&dispatch_protocol_error);
1.1 markus 98: dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
1.18 markus 99: dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
1.1 markus 100: }
101:
1.109 deraadt 102: /*ARGSUSED*/
1.66 itojun 103: static void
1.80 markus 104: input_service_request(int type, u_int32_t seq, void *ctxt)
1.1 markus 105: {
1.18 markus 106: Authctxt *authctxt = ctxt;
1.23 markus 107: u_int len;
1.94 deraadt 108: int acceptit = 0;
1.1 markus 109: char *service = packet_get_string(&len);
1.79 markus 110: packet_check_eom();
1.1 markus 111:
1.18 markus 112: if (authctxt == NULL)
113: fatal("input_service_request: no authctxt");
114:
1.1 markus 115: if (strcmp(service, "ssh-userauth") == 0) {
1.18 markus 116: if (!authctxt->success) {
1.94 deraadt 117: acceptit = 1;
1.1 markus 118: /* now we can handle user-auth requests */
119: dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
120: }
121: }
122: /* XXX all other service requests are denied */
123:
1.94 deraadt 124: if (acceptit) {
1.1 markus 125: packet_start(SSH2_MSG_SERVICE_ACCEPT);
126: packet_put_cstring(service);
127: packet_send();
128: packet_write_wait();
129: } else {
130: debug("bad service request %s", service);
131: packet_disconnect("bad service request %s", service);
132: }
133: xfree(service);
134: }
135:
1.109 deraadt 136: /*ARGSUSED*/
1.66 itojun 137: static void
1.80 markus 138: input_userauth_request(int type, u_int32_t seq, void *ctxt)
1.1 markus 139: {
1.18 markus 140: Authctxt *authctxt = ctxt;
141: Authmethod *m = NULL;
1.28 markus 142: char *user, *service, *method, *style = NULL;
1.1 markus 143: int authenticated = 0;
144:
1.18 markus 145: if (authctxt == NULL)
146: fatal("input_userauth_request: no authctxt");
1.1 markus 147:
1.18 markus 148: user = packet_get_string(NULL);
149: service = packet_get_string(NULL);
150: method = packet_get_string(NULL);
1.1 markus 151: debug("userauth-request for user %s service %s method %s", user, service, method);
1.24 markus 152: debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
1.1 markus 153:
1.28 markus 154: if ((style = strchr(user, ':')) != NULL)
155: *style++ = 0;
156:
1.36 stevesk 157: if (authctxt->attempt++ == 0) {
1.18 markus 158: /* setup auth context */
1.89 markus 159: authctxt->pw = PRIVSEP(getpwnamallow(user));
160: if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
1.18 markus 161: authctxt->valid = 1;
162: debug2("input_userauth_request: setting up authctxt for %s", user);
163: } else {
1.107 markus 164: logit("input_userauth_request: invalid user %s", user);
1.102 markus 165: authctxt->pw = fakepw();
1.18 markus 166: }
1.106 djm 167: setproctitle("%s%s", authctxt->valid ? user : "unknown",
1.88 provos 168: use_privsep ? " [net]" : "");
1.18 markus 169: authctxt->user = xstrdup(user);
170: authctxt->service = xstrdup(service);
1.62 markus 171: authctxt->style = style ? xstrdup(style) : NULL;
1.88 provos 172: if (use_privsep)
173: mm_inform_authserv(service, style);
1.62 markus 174: } else if (strcmp(user, authctxt->user) != 0 ||
175: strcmp(service, authctxt->service) != 0) {
176: packet_disconnect("Change of username or service not allowed: "
177: "(%s,%s) -> (%s,%s)",
178: authctxt->user, authctxt->service, user, service);
1.1 markus 179: }
1.28 markus 180: /* reset state */
1.75 markus 181: auth2_challenge_stop(authctxt);
1.100 markus 182:
183: #ifdef GSSAPI
184: dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
185: dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
186: #endif
187:
1.28 markus 188: authctxt->postponed = 0;
1.18 markus 189:
1.28 markus 190: /* try to authenticate user */
1.18 markus 191: m = authmethod_lookup(method);
192: if (m != NULL) {
193: debug2("input_userauth_request: try method %s", method);
194: authenticated = m->userauth(authctxt);
195: }
1.49 markus 196: userauth_finish(authctxt, authenticated, method);
197:
198: xfree(service);
199: xfree(user);
200: xfree(method);
201: }
202:
203: void
204: userauth_finish(Authctxt *authctxt, int authenticated, char *method)
205: {
1.60 markus 206: char *methods;
207:
1.28 markus 208: if (!authctxt->valid && authenticated)
209: fatal("INTERNAL ERROR: authenticated invalid user %s",
210: authctxt->user);
1.18 markus 211:
212: /* Special handling for root */
1.96 markus 213: if (authenticated && authctxt->pw->pw_uid == 0 &&
1.41 markus 214: !auth_root_allowed(method))
1.3 markus 215: authenticated = 0;
216:
1.18 markus 217: /* Log before sending the reply */
1.28 markus 218: auth_log(authctxt, authenticated, method, " ssh2");
219:
1.60 markus 220: if (authctxt->postponed)
221: return;
222:
223: /* XXX todo: check if multiple auth methods are needed */
224: if (authenticated == 1) {
225: /* turn off userauth */
1.81 markus 226: dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
1.60 markus 227: packet_start(SSH2_MSG_USERAUTH_SUCCESS);
228: packet_send();
229: packet_write_wait();
230: /* now we can break out */
231: authctxt->success = 1;
232: } else {
1.105 dtucker 233: if (authctxt->failures++ > options.max_authtries)
1.60 markus 234: packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
235: methods = authmethods_get();
236: packet_start(SSH2_MSG_USERAUTH_FAILURE);
237: packet_put_cstring(methods);
238: packet_put_char(0); /* XXX partial success, unused */
239: packet_send();
240: packet_write_wait();
241: xfree(methods);
242: }
1.1 markus 243: }
244:
1.18 markus 245: #define DELIM ","
246:
1.67 stevesk 247: static char *
1.18 markus 248: authmethods_get(void)
1.1 markus 249: {
1.82 markus 250: Buffer b;
1.18 markus 251: char *list;
1.93 markus 252: int i;
1.1 markus 253:
1.82 markus 254: buffer_init(&b);
1.93 markus 255: for (i = 0; authmethods[i] != NULL; i++) {
256: if (strcmp(authmethods[i]->name, "none") == 0)
1.18 markus 257: continue;
1.93 markus 258: if (authmethods[i]->enabled != NULL &&
259: *(authmethods[i]->enabled) != 0) {
1.82 markus 260: if (buffer_len(&b) > 0)
261: buffer_append(&b, ",", 1);
1.93 markus 262: buffer_append(&b, authmethods[i]->name,
263: strlen(authmethods[i]->name));
1.1 markus 264: }
265: }
1.82 markus 266: buffer_append(&b, "\0", 1);
267: list = xstrdup(buffer_ptr(&b));
268: buffer_free(&b);
1.18 markus 269: return list;
270: }
271:
1.66 itojun 272: static Authmethod *
1.18 markus 273: authmethod_lookup(const char *name)
274: {
1.93 markus 275: int i;
276:
1.18 markus 277: if (name != NULL)
1.93 markus 278: for (i = 0; authmethods[i] != NULL; i++)
279: if (authmethods[i]->enabled != NULL &&
280: *(authmethods[i]->enabled) != 0 &&
281: strcmp(name, authmethods[i]->name) == 0)
282: return authmethods[i];
283: debug2("Unrecognized authentication method name: %s",
284: name ? name : "NULL");
1.18 markus 285: return NULL;
1.1 markus 286: }