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

Revision 20485, 10.0 KB checked in by ghudson, 20 years ago (diff)
al_acct_create no longer takes a cryptpw parameter.
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                    packet_start(SSH2_MSG_DISCONNECT);
197                    packet_put_int(SSH2_DISCONNECT_ILLEGAL_USER_NAME);
198                    packet_put_cstring(buf);
199                    packet_put_cstring("");
200                    packet_send();
201                    packet_write_wait();
202
203                    fatal("Login denied: attempted login as %s from %s: %s",
204                          user, get_canonical_hostname(1), err);
205                  }
206                if (!is_local_acct)
207                  {
208                    status = al_acct_create(user, getpid(), 0, 0, NULL);
209                    if (status != AL_SUCCESS && debug_flag)
210                      {
211                        err = al_strerror(status, &errmem);
212                        debug("al_acct_create failed for user %s: %s", user,
213                              err);
214                        al_free_errmem(errmem);
215                      }
216                    session_username = xstrdup(user);
217                    atexit(session_cleanup);
218                  }             
219               
220                authctxt->pw = PRIVSEP(getpwnamallow(user));
221                if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
222                        authctxt->valid = 1;
223                        debug2("input_userauth_request: setting up authctxt for %s", user);
224#ifdef USE_PAM
225                        PRIVSEP(start_pam(authctxt->pw->pw_name));
226#endif
227                } else {
228                        log("input_userauth_request: illegal user %s", user);
229#ifdef USE_PAM
230                        PRIVSEP(start_pam("NOUSER"));
231#endif
232                }
233                setproctitle("%s%s", authctxt->pw ? user : "unknown",
234                    use_privsep ? " [net]" : "");
235                authctxt->user = xstrdup(user);
236                authctxt->service = xstrdup(service);
237                authctxt->style = style ? xstrdup(style) : NULL;
238                if (use_privsep)
239                        mm_inform_authserv(service, style);
240        } else if (strcmp(user, authctxt->user) != 0 ||
241            strcmp(service, authctxt->service) != 0) {
242                packet_disconnect("Change of username or service not allowed: "
243                    "(%s,%s) -> (%s,%s)",
244                    authctxt->user, authctxt->service, user, service);
245        }
246        /* reset state */
247        auth2_challenge_stop(authctxt);
248
249#ifdef GSSAPI
250        dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
251        dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
252#endif
253
254        authctxt->postponed = 0;
255
256        /* try to authenticate user */
257        m = authmethod_lookup(method);
258        if (m != NULL) {
259                debug2("input_userauth_request: try method %s", method);
260                authenticated = m->userauth(authctxt);
261        }
262        userauth_finish(authctxt, authenticated, method);
263
264        xfree(service);
265        xfree(user);
266        xfree(method);
267}
268
269void
270userauth_finish(Authctxt *authctxt, int authenticated, char *method)
271{
272        char *methods;
273
274        if (!authctxt->valid && authenticated)
275                fatal("INTERNAL ERROR: authenticated invalid user %s",
276                    authctxt->user);
277
278        /* Special handling for root */
279        if (!use_privsep &&
280            authenticated && authctxt->pw->pw_uid == 0 &&
281            !auth_root_allowed(method))
282                authenticated = 0;
283
284#ifdef USE_PAM
285        if (!use_privsep && authenticated && authctxt->user &&
286            !do_pam_account(authctxt->user, NULL))
287                authenticated = 0;
288#endif /* USE_PAM */
289
290#ifdef _UNICOS
291        if (authenticated && cray_access_denied(authctxt->user)) {
292                authenticated = 0;
293                fatal("Access denied for user %s.",authctxt->user);
294        }
295#endif /* _UNICOS */
296
297        /* Log before sending the reply */
298        auth_log(authctxt, authenticated, method, " ssh2");
299
300        if (authctxt->postponed)
301                return;
302
303        /* XXX todo: check if multiple auth methods are needed */
304        if (authenticated == 1) {
305                /* turn off userauth */
306                dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
307                packet_start(SSH2_MSG_USERAUTH_SUCCESS);
308                packet_send();
309                packet_write_wait();
310                /* now we can break out */
311                authctxt->success = 1;
312        } else {
313                if (authctxt->failures++ > AUTH_FAIL_MAX) {
314                        packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
315                }
316#ifdef _UNICOS
317                if (strcmp(method, "password") == 0)
318                        cray_login_failure(authctxt->user, IA_UDBERR);
319#endif /* _UNICOS */
320                methods = authmethods_get();
321                packet_start(SSH2_MSG_USERAUTH_FAILURE);
322                packet_put_cstring(methods);
323                packet_put_char(0);     /* XXX partial success, unused */
324                packet_send();
325                packet_write_wait();
326                xfree(methods);
327        }
328}
329
330/* get current user */
331
332struct passwd*
333auth_get_user(void)
334{
335        return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL;
336}
337
338#define DELIM   ","
339
340static char *
341authmethods_get(void)
342{
343        Buffer b;
344        char *list;
345        int i;
346
347        buffer_init(&b);
348        for (i = 0; authmethods[i] != NULL; i++) {
349                if (strcmp(authmethods[i]->name, "none") == 0)
350                        continue;
351                if (authmethods[i]->enabled != NULL &&
352                    *(authmethods[i]->enabled) != 0) {
353                        if (buffer_len(&b) > 0)
354                                buffer_append(&b, ",", 1);
355                        buffer_append(&b, authmethods[i]->name,
356                            strlen(authmethods[i]->name));
357                }
358        }
359        buffer_append(&b, "\0", 1);
360        list = xstrdup(buffer_ptr(&b));
361        buffer_free(&b);
362        return list;
363}
364
365static Authmethod *
366authmethod_lookup(const char *name)
367{
368        int i;
369
370        if (name != NULL)
371                for (i = 0; authmethods[i] != NULL; i++)
372                        if (authmethods[i]->enabled != NULL &&
373                            *(authmethods[i]->enabled) != 0 &&
374                            strcmp(name, authmethods[i]->name) == 0)
375                                return authmethods[i];
376        debug2("Unrecognized authentication method name: %s",
377            name ? name : "NULL");
378        return NULL;
379}
Note: See TracBrowser for help on using the repository browser.