source: trunk/third/openssh/auth2.c @ 22387

Revision 22387, 9.8 KB checked in by zacheiss, 19 years ago (diff)
Log failed login attempts at a lower level by using log() and packet_disconnect() instead of fatal(). Clean up misleading comment.
Line 
1/*
2 * Copyright (c) 2000 Markus Friedl.  All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 *    notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 *    notice, this list of conditions and the following disclaimer in the
11 *    documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */
24
25#include "includes.h"
26RCSID("$OpenBSD: auth2.c,v 1.95 2002/08/22 21:33:58 markus Exp $");
27
28#include "ssh2.h"
29#include "xmalloc.h"
30#include "packet.h"
31#include "log.h"
32#include "servconf.h"
33#include "compat.h"
34#include "auth.h"
35#include "dispatch.h"
36#include "pathnames.h"
37#include "monitor_wrap.h"
38
39#include <al.h>
40extern char *session_username;
41extern int is_local_acct;
42
43#ifdef GSSAPI
44#include "ssh-gss.h"
45#endif
46
47/* import */
48extern ServerOptions options;
49extern u_char *session_id2;
50extern int session_id2_len;
51extern int debug_flag;
52
53#ifdef WITH_AIXAUTHENTICATE
54extern char *aixloginmsg;
55#endif
56
57Authctxt *x_authctxt = NULL;
58
59/* methods */
60
61extern Authmethod method_none;
62extern Authmethod method_pubkey;
63extern Authmethod method_passwd;
64extern Authmethod method_kbdint;
65extern Authmethod method_hostbased;
66extern Authmethod method_external;
67extern Authmethod method_gssapi;
68
69Authmethod *authmethods[] = {
70        &method_none,
71#ifdef GSSAPI
72        &method_external,
73        &method_gssapi,
74#endif
75        &method_pubkey,
76        &method_passwd,
77        &method_kbdint,
78        &method_hostbased,
79        NULL
80};
81
82/* protocol */
83
84static void input_service_request(int, u_int32_t, void *);
85static void input_userauth_request(int, u_int32_t, void *);
86
87/* helper */
88static Authmethod *authmethod_lookup(const char *);
89static char *authmethods_get(void);
90int user_key_allowed(struct passwd *, Key *);
91int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
92
93/*
94 * loop until authctxt->success == TRUE
95 */
96
97Authctxt *
98do_authentication2(void)
99{
100        Authctxt *authctxt = authctxt_new();
101
102        x_authctxt = authctxt;          /*XXX*/
103
104        /* challenge-response is implemented via keyboard interactive */
105        if (options.challenge_response_authentication)
106                options.kbd_interactive_authentication = 1;
107        if (options.pam_authentication_via_kbd_int)
108                options.kbd_interactive_authentication = 1;
109        if (use_privsep)
110                options.pam_authentication_via_kbd_int = 0;
111
112        dispatch_init(&dispatch_protocol_error);
113        dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
114        dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
115
116        return (authctxt);
117}
118
119static void
120input_service_request(int type, u_int32_t seq, void *ctxt)
121{
122        Authctxt *authctxt = ctxt;
123        u_int len;
124        int acceptit = 0;
125        char *service = packet_get_string(&len);
126        packet_check_eom();
127
128        if (authctxt == NULL)
129                fatal("input_service_request: no authctxt");
130
131        if (strcmp(service, "ssh-userauth") == 0) {
132                if (!authctxt->success) {
133                        acceptit = 1;
134                        /* now we can handle user-auth requests */
135                        dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
136                }
137        }
138        /* XXX all other service requests are denied */
139
140        if (acceptit) {
141                packet_start(SSH2_MSG_SERVICE_ACCEPT);
142                packet_put_cstring(service);
143                packet_send();
144                packet_write_wait();
145        } else {
146                debug("bad service request %s", service);
147                packet_disconnect("bad service request %s", service);
148        }
149        xfree(service);
150}
151
152static void
153input_userauth_request(int type, u_int32_t seq, void *ctxt)
154{
155        Authctxt *authctxt = ctxt;
156        Authmethod *m = NULL;
157        char *user, *service, *method, *style = NULL;
158        int authenticated = 0, status;
159        char *filetext, *errmem;
160        const char *err;
161
162        if (authctxt == NULL)
163                fatal("input_userauth_request: no authctxt");
164
165        user = packet_get_string(NULL);
166        service = packet_get_string(NULL);
167        method = packet_get_string(NULL);
168        debug("userauth-request for user %s service %s method %s", user, service, method);
169        debug("attempt %d failures %d", authctxt->attempt, authctxt->failures);
170
171        if ((style = strchr(user, ':')) != NULL)
172                *style++ = 0;
173
174        if (authctxt->attempt++ == 0) {
175                /* setup auth context */
176                struct passwd *pw = NULL;
177
178                status = al_login_allowed(user, 1, &is_local_acct, &filetext);
179                if (status != AL_SUCCESS)
180                  {
181                    char *buf;
182
183                    err = al_strerror(status, &errmem);
184                    if (filetext && *filetext)
185                      {
186                        buf = xmalloc(40 + strlen(err) + strlen(filetext));
187                        sprintf(buf, "You are not allowed to log in here: "
188                                "%s\n%s", err, filetext);
189                      }
190                    else
191                      {
192                        buf = xmalloc(40 + strlen(err));
193                        sprintf(buf, "You are not allowed to log in here: "
194                                "%s\n", err);
195                      }
196                    log("Login denied: attempted login as %s from %s: %s",
197                        user, get_canonical_hostname(1), err);
198                    packet_disconnect(buf);
199                  }
200                if (!is_local_acct)
201                  {
202                    status = al_acct_create(user, getpid(), 0, 0, NULL);
203                    if (status != AL_SUCCESS && debug_flag)
204                      {
205                        err = al_strerror(status, &errmem);
206                        debug("al_acct_create failed for user %s: %s", user,
207                              err);
208                        al_free_errmem(errmem);
209                      }
210                    session_username = xstrdup(user);
211                    atexit(session_cleanup);
212                  }             
213               
214                authctxt->pw = PRIVSEP(getpwnamallow(user));
215                if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
216                        authctxt->valid = 1;
217                        debug2("input_userauth_request: setting up authctxt for %s", user);
218#ifdef USE_PAM
219                        PRIVSEP(start_pam(authctxt->pw->pw_name));
220#endif
221                } else {
222                        log("input_userauth_request: illegal user %s", user);
223#ifdef USE_PAM
224                        PRIVSEP(start_pam("NOUSER"));
225#endif
226                }
227                setproctitle("%s%s", authctxt->pw ? user : "unknown",
228                    use_privsep ? " [net]" : "");
229                authctxt->user = xstrdup(user);
230                authctxt->service = xstrdup(service);
231                authctxt->style = style ? xstrdup(style) : NULL;
232                if (use_privsep)
233                        mm_inform_authserv(service, style);
234        } else if (strcmp(user, authctxt->user) != 0 ||
235            strcmp(service, authctxt->service) != 0) {
236                packet_disconnect("Change of username or service not allowed: "
237                    "(%s,%s) -> (%s,%s)",
238                    authctxt->user, authctxt->service, user, service);
239        }
240        /* reset state */
241        auth2_challenge_stop(authctxt);
242
243#ifdef GSSAPI
244        dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
245        dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
246#endif
247
248        authctxt->postponed = 0;
249
250        /* try to authenticate user */
251        m = authmethod_lookup(method);
252        if (m != NULL) {
253                debug2("input_userauth_request: try method %s", method);
254                authenticated = m->userauth(authctxt);
255        }
256        userauth_finish(authctxt, authenticated, method);
257
258        xfree(service);
259        xfree(user);
260        xfree(method);
261}
262
263void
264userauth_finish(Authctxt *authctxt, int authenticated, char *method)
265{
266        char *methods;
267
268        if (!authctxt->valid && authenticated)
269                fatal("INTERNAL ERROR: authenticated invalid user %s",
270                    authctxt->user);
271
272        /* Special handling for root */
273        if (!use_privsep &&
274            authenticated && authctxt->pw->pw_uid == 0 &&
275            !auth_root_allowed(method))
276                authenticated = 0;
277
278#ifdef USE_PAM
279        if (!use_privsep && authenticated && authctxt->user &&
280            !do_pam_account(authctxt->user, NULL))
281                authenticated = 0;
282#endif /* USE_PAM */
283
284#ifdef _UNICOS
285        if (authenticated && cray_access_denied(authctxt->user)) {
286                authenticated = 0;
287                fatal("Access denied for user %s.",authctxt->user);
288        }
289#endif /* _UNICOS */
290
291        /* Log before sending the reply */
292        auth_log(authctxt, authenticated, method, " ssh2");
293
294        if (authctxt->postponed)
295                return;
296
297        /* XXX todo: check if multiple auth methods are needed */
298        if (authenticated == 1) {
299                /* turn off userauth */
300                dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
301                packet_start(SSH2_MSG_USERAUTH_SUCCESS);
302                packet_send();
303                packet_write_wait();
304                /* now we can break out */
305                authctxt->success = 1;
306        } else {
307                if (authctxt->failures++ > AUTH_FAIL_MAX) {
308                        packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
309                }
310#ifdef _UNICOS
311                if (strcmp(method, "password") == 0)
312                        cray_login_failure(authctxt->user, IA_UDBERR);
313#endif /* _UNICOS */
314                methods = authmethods_get();
315                packet_start(SSH2_MSG_USERAUTH_FAILURE);
316                packet_put_cstring(methods);
317                packet_put_char(0);     /* XXX partial success, unused */
318                packet_send();
319                packet_write_wait();
320                xfree(methods);
321        }
322}
323
324/* get current user */
325
326struct passwd*
327auth_get_user(void)
328{
329        return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL;
330}
331
332#define DELIM   ","
333
334static char *
335authmethods_get(void)
336{
337        Buffer b;
338        char *list;
339        int i;
340
341        buffer_init(&b);
342        for (i = 0; authmethods[i] != NULL; i++) {
343                if (strcmp(authmethods[i]->name, "none") == 0)
344                        continue;
345                if (authmethods[i]->enabled != NULL &&
346                    *(authmethods[i]->enabled) != 0) {
347                        if (buffer_len(&b) > 0)
348                                buffer_append(&b, ",", 1);
349                        buffer_append(&b, authmethods[i]->name,
350                            strlen(authmethods[i]->name));
351                }
352        }
353        buffer_append(&b, "\0", 1);
354        list = xstrdup(buffer_ptr(&b));
355        buffer_free(&b);
356        return list;
357}
358
359static Authmethod *
360authmethod_lookup(const char *name)
361{
362        int i;
363
364        if (name != NULL)
365                for (i = 0; authmethods[i] != NULL; i++)
366                        if (authmethods[i]->enabled != NULL &&
367                            *(authmethods[i]->enabled) != 0 &&
368                            strcmp(name, authmethods[i]->name) == 0)
369                                return authmethods[i];
370        debug2("Unrecognized authentication method name: %s",
371            name ? name : "NULL");
372        return NULL;
373}
Note: See TracBrowser for help on using the repository browser.