Import OpenSSH-5.1p1.
[dragonfly.git] / crypto / openssh-5 / auth2.c
1 /* $OpenBSD: auth2.c,v 1.119 2008/07/04 23:30:16 djm 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 #include <sys/stat.h>
30 #include <sys/uio.h>
31
32 #include <fcntl.h>
33 #include <pwd.h>
34 #include <stdarg.h>
35 #include <string.h>
36 #include <unistd.h>
37
38 #include "xmalloc.h"
39 #include "atomicio.h"
40 #include "ssh2.h"
41 #include "packet.h"
42 #include "log.h"
43 #include "buffer.h"
44 #include "servconf.h"
45 #include "compat.h"
46 #include "key.h"
47 #include "hostfile.h"
48 #include "auth.h"
49 #include "dispatch.h"
50 #include "pathnames.h"
51 #include "buffer.h"
52
53 #ifdef GSSAPI
54 #include "ssh-gss.h"
55 #endif
56 #include "monitor_wrap.h"
57
58 /* import */
59 extern ServerOptions options;
60 extern u_char *session_id2;
61 extern u_int session_id2_len;
62 extern Buffer loginmsg;
63
64 /* methods */
65
66 extern Authmethod method_none;
67 extern Authmethod method_pubkey;
68 extern Authmethod method_passwd;
69 extern Authmethod method_kbdint;
70 extern Authmethod method_hostbased;
71 #ifdef GSSAPI
72 extern Authmethod method_gssapi;
73 #endif
74
75 Authmethod *authmethods[] = {
76         &method_none,
77         &method_pubkey,
78 #ifdef GSSAPI
79         &method_gssapi,
80 #endif
81         &method_passwd,
82         &method_kbdint,
83         &method_hostbased,
84         NULL
85 };
86
87 /* protocol */
88
89 static void input_service_request(int, u_int32_t, void *);
90 static void input_userauth_request(int, u_int32_t, void *);
91
92 /* helper */
93 static Authmethod *authmethod_lookup(const char *);
94 static char *authmethods_get(void);
95
96 char *
97 auth2_read_banner(void)
98 {
99         struct stat st;
100         char *banner = NULL;
101         size_t len, n;
102         int fd;
103
104         if ((fd = open(options.banner, O_RDONLY)) == -1)
105                 return (NULL);
106         if (fstat(fd, &st) == -1) {
107                 close(fd);
108                 return (NULL);
109         }
110         if (st.st_size > 1*1024*1024) {
111                 close(fd);
112                 return (NULL);
113         }
114
115         len = (size_t)st.st_size;               /* truncate */
116         banner = xmalloc(len + 1);
117         n = atomicio(read, fd, banner, len);
118         close(fd);
119
120         if (n != len) {
121                 xfree(banner);
122                 return (NULL);
123         }
124         banner[n] = '\0';
125
126         return (banner);
127 }
128
129 void
130 userauth_send_banner(const char *msg)
131 {
132         if (datafellows & SSH_BUG_BANNER)
133                 return;
134
135         packet_start(SSH2_MSG_USERAUTH_BANNER);
136         packet_put_cstring(msg);
137         packet_put_cstring("");         /* language, unused */
138         packet_send();
139         debug("%s: sent", __func__);
140 }
141
142 static void
143 userauth_banner(void)
144 {
145         char *banner = NULL;
146
147         if (options.banner == NULL ||
148             strcasecmp(options.banner, "none") == 0 ||
149             (datafellows & SSH_BUG_BANNER) != 0)
150                 return;
151
152         if ((banner = PRIVSEP(auth2_read_banner())) == NULL)
153                 goto done;
154         userauth_send_banner(banner);
155
156 done:
157         if (banner)
158                 xfree(banner);
159 }
160
161 /*
162  * loop until authctxt->success == TRUE
163  */
164 void
165 do_authentication2(Authctxt *authctxt)
166 {
167         dispatch_init(&dispatch_protocol_error);
168         dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
169         dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
170 }
171
172 /*ARGSUSED*/
173 static void
174 input_service_request(int type, u_int32_t seq, void *ctxt)
175 {
176         Authctxt *authctxt = ctxt;
177         u_int len;
178         int acceptit = 0;
179         char *service = packet_get_string(&len);
180         packet_check_eom();
181
182         if (authctxt == NULL)
183                 fatal("input_service_request: no authctxt");
184
185         if (strcmp(service, "ssh-userauth") == 0) {
186                 if (!authctxt->success) {
187                         acceptit = 1;
188                         /* now we can handle user-auth requests */
189                         dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
190                 }
191         }
192         /* XXX all other service requests are denied */
193
194         if (acceptit) {
195                 packet_start(SSH2_MSG_SERVICE_ACCEPT);
196                 packet_put_cstring(service);
197                 packet_send();
198                 packet_write_wait();
199         } else {
200                 debug("bad service request %s", service);
201                 packet_disconnect("bad service request %s", service);
202         }
203         xfree(service);
204 }
205
206 /*ARGSUSED*/
207 static void
208 input_userauth_request(int type, u_int32_t seq, void *ctxt)
209 {
210         Authctxt *authctxt = ctxt;
211         Authmethod *m = NULL;
212         char *user, *service, *method, *style = NULL;
213         int authenticated = 0;
214
215         if (authctxt == NULL)
216                 fatal("input_userauth_request: no authctxt");
217
218         user = packet_get_string(NULL);
219         service = packet_get_string(NULL);
220         method = packet_get_string(NULL);
221         debug("userauth-request for user %s service %s method %s", user, service, method);
222         debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
223
224         if ((style = strchr(user, ':')) != NULL)
225                 *style++ = 0;
226
227         if (authctxt->attempt++ == 0) {
228                 /* setup auth context */
229                 authctxt->pw = PRIVSEP(getpwnamallow(user));
230                 authctxt->user = xstrdup(user);
231                 if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
232                         authctxt->valid = 1;
233                         debug2("input_userauth_request: setting up authctxt for %s", user);
234                 } else {
235                         logit("input_userauth_request: invalid user %s", user);
236                         authctxt->pw = fakepw();
237 #ifdef SSH_AUDIT_EVENTS
238                         PRIVSEP(audit_event(SSH_INVALID_USER));
239 #endif
240                 }
241 #ifdef USE_PAM
242                 if (options.use_pam)
243                         PRIVSEP(start_pam(authctxt));
244 #endif
245                 setproctitle("%s%s", authctxt->valid ? user : "unknown",
246                     use_privsep ? " [net]" : "");
247                 authctxt->service = xstrdup(service);
248                 authctxt->style = style ? xstrdup(style) : NULL;
249                 if (use_privsep)
250                         mm_inform_authserv(service, style);
251                 userauth_banner();
252         } else if (strcmp(user, authctxt->user) != 0 ||
253             strcmp(service, authctxt->service) != 0) {
254                 packet_disconnect("Change of username or service not allowed: "
255                     "(%s,%s) -> (%s,%s)",
256                     authctxt->user, authctxt->service, user, service);
257         }
258         /* reset state */
259         auth2_challenge_stop(authctxt);
260
261 #ifdef GSSAPI
262         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
263         dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
264 #endif
265
266         authctxt->postponed = 0;
267
268         /* try to authenticate user */
269         m = authmethod_lookup(method);
270         if (m != NULL && authctxt->failures < options.max_authtries) {
271                 debug2("input_userauth_request: try method %s", method);
272                 authenticated = m->userauth(authctxt);
273         }
274         userauth_finish(authctxt, authenticated, method);
275
276         xfree(service);
277         xfree(user);
278         xfree(method);
279 }
280
281 void
282 userauth_finish(Authctxt *authctxt, int authenticated, char *method)
283 {
284         char *methods;
285
286         if (!authctxt->valid && authenticated)
287                 fatal("INTERNAL ERROR: authenticated invalid user %s",
288                     authctxt->user);
289
290         /* Special handling for root */
291         if (authenticated && authctxt->pw->pw_uid == 0 &&
292             !auth_root_allowed(method)) {
293                 authenticated = 0;
294 #ifdef SSH_AUDIT_EVENTS
295                 PRIVSEP(audit_event(SSH_LOGIN_ROOT_DENIED));
296 #endif
297         }
298
299 #ifdef USE_PAM
300         if (options.use_pam && authenticated) {
301                 if (!PRIVSEP(do_pam_account())) {
302                         /* if PAM returned a message, send it to the user */
303                         if (buffer_len(&loginmsg) > 0) {
304                                 buffer_append(&loginmsg, "\0", 1);
305                                 userauth_send_banner(buffer_ptr(&loginmsg));
306                                 packet_write_wait();
307                         }
308                         fatal("Access denied for user %s by PAM account "
309                             "configuration", authctxt->user);
310                 }
311         }
312 #endif
313
314 #ifdef _UNICOS
315         if (authenticated && cray_access_denied(authctxt->user)) {
316                 authenticated = 0;
317                 fatal("Access denied for user %s.",authctxt->user);
318         }
319 #endif /* _UNICOS */
320
321         /* Log before sending the reply */
322         auth_log(authctxt, authenticated, method, " ssh2");
323
324         if (authctxt->postponed)
325                 return;
326
327         /* XXX todo: check if multiple auth methods are needed */
328         if (authenticated == 1) {
329                 /* turn off userauth */
330                 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
331                 packet_start(SSH2_MSG_USERAUTH_SUCCESS);
332                 packet_send();
333                 packet_write_wait();
334                 /* now we can break out */
335                 authctxt->success = 1;
336         } else {
337
338                 /* Allow initial try of "none" auth without failure penalty */
339                 if (authctxt->attempt > 1 || strcmp(method, "none") != 0)
340                         authctxt->failures++;
341                 if (authctxt->failures >= options.max_authtries) {
342 #ifdef SSH_AUDIT_EVENTS
343                         PRIVSEP(audit_event(SSH_LOGIN_EXCEED_MAXTRIES));
344 #endif
345                         packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
346                 }
347                 methods = authmethods_get();
348                 packet_start(SSH2_MSG_USERAUTH_FAILURE);
349                 packet_put_cstring(methods);
350                 packet_put_char(0);     /* XXX partial success, unused */
351                 packet_send();
352                 packet_write_wait();
353                 xfree(methods);
354         }
355 }
356
357 static char *
358 authmethods_get(void)
359 {
360         Buffer b;
361         char *list;
362         int i;
363
364         buffer_init(&b);
365         for (i = 0; authmethods[i] != NULL; i++) {
366                 if (strcmp(authmethods[i]->name, "none") == 0)
367                         continue;
368                 if (authmethods[i]->enabled != NULL &&
369                     *(authmethods[i]->enabled) != 0) {
370                         if (buffer_len(&b) > 0)
371                                 buffer_append(&b, ",", 1);
372                         buffer_append(&b, authmethods[i]->name,
373                             strlen(authmethods[i]->name));
374                 }
375         }
376         buffer_append(&b, "\0", 1);
377         list = xstrdup(buffer_ptr(&b));
378         buffer_free(&b);
379         return list;
380 }
381
382 static Authmethod *
383 authmethod_lookup(const char *name)
384 {
385         int i;
386
387         if (name != NULL)
388                 for (i = 0; authmethods[i] != NULL; i++)
389                         if (authmethods[i]->enabled != NULL &&
390                             *(authmethods[i]->enabled) != 0 &&
391                             strcmp(name, authmethods[i]->name) == 0)
392                                 return authmethods[i];
393         debug2("Unrecognized authentication method name: %s",
394             name ? name : "NULL");
395         return NULL;
396 }
397