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