Annotation of src/usr.bin/ssh/auth2.c, Revision 1.111
1.111 ! stevesk 1: /* $OpenBSD: auth2.c,v 1.110 2006/03/25 13:17:01 djm 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.1 markus 31:
1.32 markus 32: #include "ssh2.h"
1.1 markus 33: #include "xmalloc.h"
34: #include "packet.h"
1.32 markus 35: #include "log.h"
1.1 markus 36: #include "servconf.h"
37: #include "compat.h"
38: #include "auth.h"
39: #include "dispatch.h"
1.29 markus 40: #include "pathnames.h"
1.88 provos 41: #include "monitor_wrap.h"
1.1 markus 42:
1.100 markus 43: #ifdef GSSAPI
44: #include "ssh-gss.h"
45: #endif
46:
1.1 markus 47: /* import */
48: extern ServerOptions options;
1.23 markus 49: extern u_char *session_id2;
1.99 markus 50: extern u_int session_id2_len;
1.1 markus 51:
1.93 markus 52: /* methods */
53:
54: extern Authmethod method_none;
55: extern Authmethod method_pubkey;
56: extern Authmethod method_passwd;
57: extern Authmethod method_kbdint;
58: extern Authmethod method_hostbased;
1.100 markus 59: #ifdef GSSAPI
60: extern Authmethod method_gssapi;
61: #endif
1.93 markus 62:
63: Authmethod *authmethods[] = {
64: &method_none,
65: &method_pubkey,
1.100 markus 66: #ifdef GSSAPI
67: &method_gssapi,
68: #endif
1.93 markus 69: &method_passwd,
70: &method_kbdint,
71: &method_hostbased,
72: NULL
1.18 markus 73: };
74:
1.1 markus 75: /* protocol */
76:
1.80 markus 77: static void input_service_request(int, u_int32_t, void *);
78: static void input_userauth_request(int, u_int32_t, void *);
1.1 markus 79:
80: /* helper */
1.66 itojun 81: static Authmethod *authmethod_lookup(const char *);
1.67 stevesk 82: static char *authmethods_get(void);
1.88 provos 83: int user_key_allowed(struct passwd *, Key *);
1.1 markus 84:
85: /*
1.18 markus 86: * loop until authctxt->success == TRUE
1.1 markus 87: */
88:
1.103 markus 89: void
90: do_authentication2(Authctxt *authctxt)
1.1 markus 91: {
1.71 markus 92: /* challenge-response is implemented via keyboard interactive */
1.57 markus 93: if (options.challenge_response_authentication)
1.34 markus 94: options.kbd_interactive_authentication = 1;
95:
1.81 markus 96: dispatch_init(&dispatch_protocol_error);
1.1 markus 97: dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
1.18 markus 98: dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
1.1 markus 99: }
100:
1.109 deraadt 101: /*ARGSUSED*/
1.66 itojun 102: static void
1.80 markus 103: input_service_request(int type, u_int32_t seq, void *ctxt)
1.1 markus 104: {
1.18 markus 105: Authctxt *authctxt = ctxt;
1.23 markus 106: u_int len;
1.94 deraadt 107: int acceptit = 0;
1.1 markus 108: char *service = packet_get_string(&len);
1.79 markus 109: packet_check_eom();
1.1 markus 110:
1.18 markus 111: if (authctxt == NULL)
112: fatal("input_service_request: no authctxt");
113:
1.1 markus 114: if (strcmp(service, "ssh-userauth") == 0) {
1.18 markus 115: if (!authctxt->success) {
1.94 deraadt 116: acceptit = 1;
1.1 markus 117: /* now we can handle user-auth requests */
118: dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
119: }
120: }
121: /* XXX all other service requests are denied */
122:
1.94 deraadt 123: if (acceptit) {
1.1 markus 124: packet_start(SSH2_MSG_SERVICE_ACCEPT);
125: packet_put_cstring(service);
126: packet_send();
127: packet_write_wait();
128: } else {
129: debug("bad service request %s", service);
130: packet_disconnect("bad service request %s", service);
131: }
132: xfree(service);
133: }
134:
1.109 deraadt 135: /*ARGSUSED*/
1.66 itojun 136: static void
1.80 markus 137: input_userauth_request(int type, u_int32_t seq, void *ctxt)
1.1 markus 138: {
1.18 markus 139: Authctxt *authctxt = ctxt;
140: Authmethod *m = NULL;
1.28 markus 141: char *user, *service, *method, *style = NULL;
1.1 markus 142: int authenticated = 0;
143:
1.18 markus 144: if (authctxt == NULL)
145: fatal("input_userauth_request: no authctxt");
1.1 markus 146:
1.18 markus 147: user = packet_get_string(NULL);
148: service = packet_get_string(NULL);
149: method = packet_get_string(NULL);
1.1 markus 150: debug("userauth-request for user %s service %s method %s", user, service, method);
1.24 markus 151: debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
1.1 markus 152:
1.28 markus 153: if ((style = strchr(user, ':')) != NULL)
154: *style++ = 0;
155:
1.36 stevesk 156: if (authctxt->attempt++ == 0) {
1.18 markus 157: /* setup auth context */
1.89 markus 158: authctxt->pw = PRIVSEP(getpwnamallow(user));
159: if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
1.18 markus 160: authctxt->valid = 1;
161: debug2("input_userauth_request: setting up authctxt for %s", user);
162: } else {
1.107 markus 163: logit("input_userauth_request: invalid user %s", user);
1.102 markus 164: authctxt->pw = fakepw();
1.18 markus 165: }
1.106 djm 166: setproctitle("%s%s", authctxt->valid ? user : "unknown",
1.88 provos 167: use_privsep ? " [net]" : "");
1.18 markus 168: authctxt->user = xstrdup(user);
169: authctxt->service = xstrdup(service);
1.62 markus 170: authctxt->style = style ? xstrdup(style) : NULL;
1.88 provos 171: if (use_privsep)
172: mm_inform_authserv(service, style);
1.62 markus 173: } else if (strcmp(user, authctxt->user) != 0 ||
174: strcmp(service, authctxt->service) != 0) {
175: packet_disconnect("Change of username or service not allowed: "
176: "(%s,%s) -> (%s,%s)",
177: authctxt->user, authctxt->service, user, service);
1.1 markus 178: }
1.28 markus 179: /* reset state */
1.75 markus 180: auth2_challenge_stop(authctxt);
1.100 markus 181:
182: #ifdef GSSAPI
183: dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
184: dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
185: #endif
186:
1.28 markus 187: authctxt->postponed = 0;
1.18 markus 188:
1.28 markus 189: /* try to authenticate user */
1.18 markus 190: m = authmethod_lookup(method);
191: if (m != NULL) {
192: debug2("input_userauth_request: try method %s", method);
193: authenticated = m->userauth(authctxt);
194: }
1.49 markus 195: userauth_finish(authctxt, authenticated, method);
196:
197: xfree(service);
198: xfree(user);
199: xfree(method);
200: }
201:
202: void
203: userauth_finish(Authctxt *authctxt, int authenticated, char *method)
204: {
1.60 markus 205: char *methods;
206:
1.28 markus 207: if (!authctxt->valid && authenticated)
208: fatal("INTERNAL ERROR: authenticated invalid user %s",
209: authctxt->user);
1.18 markus 210:
211: /* Special handling for root */
1.96 markus 212: if (authenticated && authctxt->pw->pw_uid == 0 &&
1.41 markus 213: !auth_root_allowed(method))
1.3 markus 214: authenticated = 0;
215:
1.18 markus 216: /* Log before sending the reply */
1.28 markus 217: auth_log(authctxt, authenticated, method, " ssh2");
218:
1.60 markus 219: if (authctxt->postponed)
220: return;
221:
222: /* XXX todo: check if multiple auth methods are needed */
223: if (authenticated == 1) {
224: /* turn off userauth */
1.81 markus 225: dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
1.60 markus 226: packet_start(SSH2_MSG_USERAUTH_SUCCESS);
227: packet_send();
228: packet_write_wait();
229: /* now we can break out */
230: authctxt->success = 1;
231: } else {
1.105 dtucker 232: if (authctxt->failures++ > options.max_authtries)
1.60 markus 233: packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
234: methods = authmethods_get();
235: packet_start(SSH2_MSG_USERAUTH_FAILURE);
236: packet_put_cstring(methods);
237: packet_put_char(0); /* XXX partial success, unused */
238: packet_send();
239: packet_write_wait();
240: xfree(methods);
241: }
1.1 markus 242: }
243:
1.18 markus 244: #define DELIM ","
245:
1.67 stevesk 246: static char *
1.18 markus 247: authmethods_get(void)
1.1 markus 248: {
1.82 markus 249: Buffer b;
1.18 markus 250: char *list;
1.93 markus 251: int i;
1.1 markus 252:
1.82 markus 253: buffer_init(&b);
1.93 markus 254: for (i = 0; authmethods[i] != NULL; i++) {
255: if (strcmp(authmethods[i]->name, "none") == 0)
1.18 markus 256: continue;
1.93 markus 257: if (authmethods[i]->enabled != NULL &&
258: *(authmethods[i]->enabled) != 0) {
1.82 markus 259: if (buffer_len(&b) > 0)
260: buffer_append(&b, ",", 1);
1.93 markus 261: buffer_append(&b, authmethods[i]->name,
262: strlen(authmethods[i]->name));
1.1 markus 263: }
264: }
1.82 markus 265: buffer_append(&b, "\0", 1);
266: list = xstrdup(buffer_ptr(&b));
267: buffer_free(&b);
1.18 markus 268: return list;
269: }
270:
1.66 itojun 271: static Authmethod *
1.18 markus 272: authmethod_lookup(const char *name)
273: {
1.93 markus 274: int i;
275:
1.18 markus 276: if (name != NULL)
1.93 markus 277: for (i = 0; authmethods[i] != NULL; i++)
278: if (authmethods[i]->enabled != NULL &&
279: *(authmethods[i]->enabled) != 0 &&
280: strcmp(name, authmethods[i]->name) == 0)
281: return authmethods[i];
282: debug2("Unrecognized authentication method name: %s",
283: name ? name : "NULL");
1.18 markus 284: return NULL;
1.1 markus 285: }