]> andersk Git - gssapi-openssh.git/blob - openssh/auth2.c
ff7d639e68a86ca956205e375131090b095415b5
[gssapi-openssh.git] / openssh / auth2.c
1 /* $OpenBSD: auth2.c,v 1.115 2007/04/14 22:01:58 stevesk Exp $ */
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  */
25
26 #include "includes.h"
27
28 #include <sys/types.h>
29
30 #include <pwd.h>
31 #include <stdarg.h>
32 #include <string.h>
33
34 #include "xmalloc.h"
35 #include "ssh2.h"
36 #include "packet.h"
37 #include "log.h"
38 #include "buffer.h"
39 #include "servconf.h"
40 #include "compat.h"
41 #include "key.h"
42 #include "hostfile.h"
43 #include "auth.h"
44 #include "dispatch.h"
45 #include "pathnames.h"
46 #include "buffer.h"
47 #include "canohost.h"
48
49 #ifdef GSSAPI
50 #include "ssh-gss.h"
51 #endif
52 #include "monitor_wrap.h"
53
54 /* import */
55 extern ServerOptions options;
56 extern u_char *session_id2;
57 extern u_int session_id2_len;
58 extern Buffer loginmsg;
59
60 /* methods */
61
62 extern Authmethod method_none;
63 extern Authmethod method_pubkey;
64 extern Authmethod method_passwd;
65 extern Authmethod method_kbdint;
66 extern Authmethod method_hostbased;
67 #ifdef GSSAPI
68 extern Authmethod method_external;
69 extern Authmethod method_gsskeyex;
70 extern Authmethod method_gssapi;
71 extern Authmethod method_gssapi_compat;
72 #endif
73
74 static int log_flag = 0;
75
76
77 Authmethod *authmethods[] = {
78         &method_none,
79         &method_pubkey,
80 #ifdef GSSAPI
81         &method_gsskeyex,
82         &method_external,
83         &method_gssapi,
84         &method_gssapi_compat,
85 #endif
86         &method_passwd,
87         &method_kbdint,
88         &method_hostbased,
89         NULL
90 };
91
92 /* protocol */
93
94 static void input_service_request(int, u_int32_t, void *);
95 static void input_userauth_request(int, u_int32_t, void *);
96
97 /* helper */
98 static Authmethod *authmethod_lookup(const char *);
99 static char *authmethods_get(void);
100 int user_key_allowed(struct passwd *, Key *);
101
102 /*
103  * loop until authctxt->success == TRUE
104  */
105
106 void
107 do_authentication2(Authctxt *authctxt)
108 {
109         dispatch_init(&dispatch_protocol_error);
110         dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
111         dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
112 }
113
114 /*ARGSUSED*/
115 static void
116 input_service_request(int type, u_int32_t seq, void *ctxt)
117 {
118         Authctxt *authctxt = ctxt;
119         u_int len;
120         int acceptit = 0;
121         char *service = packet_get_string(&len);
122         packet_check_eom();
123
124         if (authctxt == NULL)
125                 fatal("input_service_request: no authctxt");
126
127         if (strcmp(service, "ssh-userauth") == 0) {
128                 if (!authctxt->success) {
129                         acceptit = 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 (acceptit) {
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 /*ARGSUSED*/
149 static void
150 input_userauth_request(int type, u_int32_t seq, void *ctxt)
151 {
152         Authctxt *authctxt = ctxt;
153         Authmethod *m = NULL;
154         char *user, *service, *method, *style = NULL;
155         int authenticated = 0;
156
157         if (authctxt == NULL)
158                 fatal("input_userauth_request: no authctxt");
159
160         user = packet_get_string(NULL);
161         service = packet_get_string(NULL);
162         method = packet_get_string(NULL);
163
164 #ifdef GSSAPI
165         if (user[0] == '\0') {
166             debug("received empty username for %s", method);
167             if (strcmp(method, "external-keyx") == 0 ||
168                 strcmp(method, "gssapi-keyex") == 0) {
169                 char *lname = NULL;
170                 PRIVSEP(ssh_gssapi_localname(&lname));
171                 if (lname && lname[0] != '\0') {
172                     xfree(user);
173                     user = lname;
174                     debug("set username to %s from gssapi context", user);
175                 } else {
176                     debug("failed to set username from gssapi context");
177                     packet_send_debug("failed to set username from gssapi context");
178                 }
179             }
180         }
181 #endif
182
183         debug("userauth-request for user %s service %s method %s",
184               user[0] ? user : "<implicit>", service, method);
185         if (!log_flag) {
186                 logit("SSH: Server;Ltype: Authname;Remote: %s-%d;Name: %s", 
187                       get_remote_ipaddr(), get_remote_port(), user);
188                 log_flag = 1;
189         }
190         debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
191
192         if ((style = strchr(user, ':')) != NULL)
193                 *style++ = 0;
194
195         /* If first time or username changed or empty username,
196            setup/reset authentication context. */
197         if ((authctxt->attempt++ == 0) ||
198             (strcmp(user, authctxt->user) != 0) ||
199             (strcmp(user, "") == 0)) {
200                 if (authctxt->user) {
201                     xfree(authctxt->user);
202                     authctxt->user = NULL;
203                 }
204                 authctxt->valid = 0;
205         authctxt->user = xstrdup(user);
206         if (strcmp(service, "ssh-connection") != 0) {
207             packet_disconnect("Unsupported service %s", service);
208         }
209 #ifdef GSSAPI
210                 /* If we're going to set the username based on the
211                    GSSAPI context later, then wait until then to
212                    verify it. Just put in placeholders for now. */
213                 if ((strcmp(user, "") == 0) &&
214                     ((strcmp(method, "gssapi") == 0) ||
215                      (strcmp(method, "gssapi-with-mic") == 0))) {
216                         authctxt->pw = fakepw();
217                 } else {
218 #endif
219                 authctxt->pw = PRIVSEP(getpwnamallow(user));
220                 if (authctxt->pw) {
221                         authctxt->valid = 1;
222                         debug2("input_userauth_request: setting up authctxt for %s", user);
223                 } else {
224                         logit("input_userauth_request: invalid user %s", user);
225                         authctxt->pw = fakepw();
226 #ifdef SSH_AUDIT_EVENTS
227                         PRIVSEP(audit_event(SSH_INVALID_USER));
228 #endif
229                 }
230 #ifdef GSSAPI
231                 } /* endif for setting username based on GSSAPI context */
232 #endif
233 #ifdef USE_PAM
234                 if (options.use_pam)
235                         PRIVSEP(start_pam(authctxt));
236 #endif
237                 setproctitle("%s%s", authctxt->valid ? user : "unknown",
238                     use_privsep ? " [net]" : "");
239                 if (authctxt->attempt == 1) {
240             authctxt->service = xstrdup(service);
241             authctxt->style = style ? xstrdup(style) : NULL;
242             if (use_privsep)
243                 mm_inform_authserv(service, style);
244                 }
245         }
246         if (strcmp(service, authctxt->service) != 0) {
247                 packet_disconnect("Change of service not allowed: "
248                     "(%s,%s) -> (%s,%s)",
249                     authctxt->user, authctxt->service, user, service);
250         }
251         /* reset state */
252         auth2_challenge_stop(authctxt);
253
254 #ifdef GSSAPI
255         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
256         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
257 #endif
258
259         authctxt->postponed = 0;
260         authctxt->server_caused_failure = 0;
261
262         /* try to authenticate user */
263         m = authmethod_lookup(method);
264         if (m != NULL) {
265                 debug2("input_userauth_request: try method %s", method);
266                 authenticated = m->userauth(authctxt);
267         }
268         userauth_finish(authctxt, authenticated, method);
269
270         xfree(service);
271         xfree(user);
272         xfree(method);
273 }
274
275 void
276 userauth_finish(Authctxt *authctxt, int authenticated, char *method)
277 {
278         char *methods;
279
280         if (!authctxt->valid && authenticated)
281                 fatal("INTERNAL ERROR: authenticated invalid user %s",
282                     authctxt->user);
283
284         /* Special handling for root */
285         if (authenticated && authctxt->pw->pw_uid == 0 &&
286             !auth_root_allowed(method)) {
287                 authenticated = 0;
288 #ifdef SSH_AUDIT_EVENTS
289                 PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED));
290 #endif
291         }
292
293 #ifdef USE_PAM
294         if (options.use_pam && authenticated) {
295                 if (!PRIVSEP(do_pam_account())) {
296                         /* if PAM returned a message, send it to the user */
297                         if (buffer_len(&loginmsg) > 0) {
298                                 buffer_append(&loginmsg, "\0", 1);
299                                 userauth_send_banner(buffer_ptr(&loginmsg));
300                                 packet_write_wait();
301                         }
302                         fatal("Access denied for user %s by PAM account "
303                             "configuration", authctxt->user);
304                 }
305         }
306 #endif
307
308 #ifdef _UNICOS
309         if (authenticated && cray_access_denied(authctxt->user)) {
310                 authenticated = 0;
311                 fatal("Access denied for user %s.",authctxt->user);
312         }
313 #endif /* _UNICOS */
314
315         /* Log before sending the reply */
316         auth_log(authctxt, authenticated, method, " ssh2");
317
318         if (authctxt->postponed)
319                 return;
320
321         /* XXX todo: check if multiple auth methods are needed */
322         if (authenticated == 1) {
323                 /* turn off userauth */
324                 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
325                 packet_start(SSH2_MSG_USERAUTH_SUCCESS);
326                 packet_send();
327                 packet_write_wait();
328                 /* now we can break out */
329                 authctxt->success = 1;
330         } else {
331                 /* Dont count server configuration issues against the client */
332                 if (!authctxt->server_caused_failure && 
333                     authctxt->failures++ > options.max_authtries) {
334 #ifdef SSH_AUDIT_EVENTS
335                         PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES));
336 #endif
337                         packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
338                 }
339                 methods = authmethods_get();
340                 packet_start(SSH2_MSG_USERAUTH_FAILURE);
341                 packet_put_cstring(methods);
342                 packet_put_char(0);     /* XXX partial success, unused */
343                 packet_send();
344                 packet_write_wait();
345                 xfree(methods);
346         }
347 }
348
349 static char *
350 authmethods_get(void)
351 {
352         Buffer b;
353         char *list;
354         int i;
355
356         buffer_init(&b);
357         for (i = 0; authmethods[i] != NULL; i++) {
358                 if (strcmp(authmethods[i]->name, "none") == 0)
359                         continue;
360                 if (authmethods[i]->enabled != NULL &&
361                     *(authmethods[i]->enabled) != 0) {
362                         if (buffer_len(&b) > 0)
363                                 buffer_append(&b, ",", 1);
364                         buffer_append(&b, authmethods[i]->name,
365                             strlen(authmethods[i]->name));
366                 }
367         }
368         buffer_append(&b, "\0", 1);
369         list = xstrdup(buffer_ptr(&b));
370         buffer_free(&b);
371         return list;
372 }
373
374 static Authmethod *
375 authmethod_lookup(const char *name)
376 {
377         int i;
378
379         if (name != NULL)
380                 for (i = 0; authmethods[i] != NULL; i++)
381                         if (authmethods[i]->enabled != NULL &&
382                             *(authmethods[i]->enabled) != 0 &&
383                             strcmp(name, authmethods[i]->name) == 0)
384                                 return authmethods[i];
385         debug2("Unrecognized authentication method name: %s",
386             name ? name : "NULL");
387         return NULL;
388 }
This page took 0.127999 seconds and 3 git commands to generate.