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

Revision 22387, 12.7 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) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
3 *                    All rights reserved
4 *
5 * As far as I am concerned, the code I have written for this software
6 * can be used freely for any purpose.  Any derived versions of this
7 * software must be clearly marked as such, and if the derived work is
8 * incompatible with the protocol description in the RFC file, it must be
9 * called by a name other than "ssh" or "Secure Shell".
10 */
11
12#include "includes.h"
13RCSID("$OpenBSD: auth1.c,v 1.44 2002/09/26 11:38:43 markus Exp $");
14
15#include "xmalloc.h"
16#include "rsa.h"
17#include "ssh1.h"
18#include "packet.h"
19#include "buffer.h"
20#include "mpaux.h"
21#include "log.h"
22#include "servconf.h"
23#include "compat.h"
24#include "auth.h"
25#include "channels.h"
26#include "session.h"
27#include "uidswap.h"
28#include "monitor_wrap.h"
29#include "canohost.h"
30
31#include <al.h>
32extern char *session_username;
33extern int is_local_acct;
34
35/* import */
36extern ServerOptions options;
37extern int debug_flag;
38
39#ifdef WITH_AIXAUTHENTICATE
40extern char *aixloginmsg;
41#endif /* WITH_AIXAUTHENTICATE */
42
43/*
44 * convert ssh auth msg type into description
45 */
46static char *
47get_authname(int type)
48{
49        static char buf[1024];
50        switch (type) {
51        case SSH_CMSG_AUTH_PASSWORD:
52                return "password";
53        case SSH_CMSG_AUTH_RSA:
54                return "rsa";
55        case SSH_CMSG_AUTH_RHOSTS_RSA:
56                return "rhosts-rsa";
57        case SSH_CMSG_AUTH_RHOSTS:
58                return "rhosts";
59        case SSH_CMSG_AUTH_TIS:
60        case SSH_CMSG_AUTH_TIS_RESPONSE:
61                return "challenge-response";
62#if defined(KRB4) || defined(KRB5)
63        case SSH_CMSG_AUTH_KERBEROS:
64                return "kerberos";
65#endif
66        }
67        snprintf(buf, sizeof buf, "bad-auth-msg-%d", type);
68        return buf;
69}
70
71/*
72 * read packets, try to authenticate the user and
73 * return only if authentication is successful
74 */
75static void
76do_authloop(Authctxt *authctxt)
77{
78        int authenticated = 0, nonauthentication = 0;
79        u_int bits;
80        Key *client_host_key;
81        BIGNUM *n;
82        char *client_user, *password;
83        char info[1024];
84        u_int dlen;
85        u_int ulen;
86        int type = 0;
87        struct passwd *pw = authctxt->pw;
88
89        debug("Attempting authentication for %s%.100s.",
90            authctxt->valid ? "" : "illegal user ", authctxt->user);
91
92        /* If the user has no password, accept authentication immediately. */
93        if (options.password_authentication &&
94#if defined(KRB4) || defined(KRB5)
95            (!options.kerberos_authentication || options.kerberos_or_local_passwd) &&
96#endif
97            PRIVSEP(auth_password(authctxt, ""))) {
98                auth_log(authctxt, 1, "without authentication", "");
99                return;
100        }
101
102        /* Indicate that authentication is needed. */
103        packet_start(SSH_SMSG_FAILURE);
104        packet_send();
105        packet_write_wait();
106
107        client_user = NULL;
108
109        for (;;) {
110                /* default to fail */
111                authenticated = 0;
112                nonauthentication = 0;
113
114                info[0] = '\0';
115
116                /* Get a packet from the client. */
117                type = packet_read();
118
119                /* Process the packet. */
120                switch (type) {
121
122#if defined(KRB4) || defined(KRB5)
123                case SSH_CMSG_AUTH_KERBEROS:
124                        if (!options.kerberos_authentication) {
125                                verbose("Kerberos authentication disabled.");
126                        } else {
127                                char *kdata = packet_get_string(&dlen);
128                                packet_check_eom();
129
130                                if (kdata[0] == 4) { /* KRB_PROT_VERSION */
131#ifdef KRB4
132                                        KTEXT_ST tkt, reply;
133                                        tkt.length = dlen;
134                                        if (tkt.length < MAX_KTXT_LEN)
135                                                memcpy(tkt.dat, kdata, tkt.length);
136
137                                        if (PRIVSEP(auth_krb4(authctxt, &tkt,
138                                            &client_user, &reply))) {
139                                                authenticated = 1;
140                                                snprintf(info, sizeof(info),
141                                                    " tktuser %.100s",
142                                                    client_user);
143
144                                                packet_start(
145                                                    SSH_SMSG_AUTH_KERBEROS_RESPONSE);
146                                                packet_put_string((char *)
147                                                    reply.dat, reply.length);
148                                                packet_send();
149                                                packet_write_wait();
150                                        }
151#endif /* KRB4 */
152                                } else {
153#ifdef KRB5
154                                        krb5_data tkt, reply;
155                                        tkt.length = dlen;
156                                        tkt.data = kdata;
157
158                                        if (PRIVSEP(auth_krb5(authctxt, &tkt,
159                                            &client_user, &reply))) {
160                                                authenticated = 1;
161                                                snprintf(info, sizeof(info),
162                                                    " tktuser %.100s",
163                                                    client_user);
164 
165                                                /* Send response to client */
166                                                packet_start(
167                                                    SSH_SMSG_AUTH_KERBEROS_RESPONSE);
168                                                packet_put_string((char *)
169                                                    reply.data, reply.length);
170                                                packet_send();
171                                                packet_write_wait();
172
173                                                if (reply.length)
174                                                        xfree(reply.data);
175                                        }
176#endif /* KRB5 */
177                                }
178                                xfree(kdata);
179                        }
180                        break;
181#endif /* KRB4 || KRB5 */
182
183#if defined(AFS) || defined(KRB5)
184                case SSH_CMSG_HAVE_KERBEROS_TGT: {
185                        /*
186                         * This is for backwards compatability with SSH.COM's
187                         * implementation, which passes the TGT before
188                         * authenticating.
189                         *
190                         * Perhaps this should be disallowed from other
191                         * client versions?
192                         */
193                        int s;
194
195                        s = do_auth1_kerberos_tgt_pass(authctxt, type);
196                        packet_start(s ? SSH_SMSG_SUCCESS : SSH_SMSG_FAILURE);
197                        packet_send();
198                        packet_write_wait();
199                        nonauthentication = 1;
200                }
201                        break;
202
203#ifdef AFS
204                case SSH_CMSG_HAVE_AFS_TOKEN:
205                        packet_send_debug("AFS token passing disabled before authentication.");
206                        break;
207#endif /* AFS */
208#endif /* AFS || KRB5 */
209
210                case SSH_CMSG_AUTH_RHOSTS:
211                        if (!options.rhosts_authentication) {
212                                verbose("Rhosts authentication disabled.");
213                                break;
214                        }
215                        /*
216                         * Get client user name.  Note that we just have to
217                         * trust the client; this is one reason why rhosts
218                         * authentication is insecure. (Another is
219                         * IP-spoofing on a local network.)
220                         */
221                        client_user = packet_get_string(&ulen);
222                        packet_check_eom();
223
224                        /* Try to authenticate using /etc/hosts.equiv and .rhosts. */
225                        authenticated = auth_rhosts(pw, client_user);
226
227                        snprintf(info, sizeof info, " ruser %.100s", client_user);
228                        break;
229
230                case SSH_CMSG_AUTH_RHOSTS_RSA:
231                        if (!options.rhosts_rsa_authentication) {
232                                verbose("Rhosts with RSA authentication disabled.");
233                                break;
234                        }
235                        /*
236                         * Get client user name.  Note that we just have to
237                         * trust the client; root on the client machine can
238                         * claim to be any user.
239                         */
240                        client_user = packet_get_string(&ulen);
241
242                        /* Get the client host key. */
243                        client_host_key = key_new(KEY_RSA1);
244                        bits = packet_get_int();
245                        packet_get_bignum(client_host_key->rsa->e);
246                        packet_get_bignum(client_host_key->rsa->n);
247
248                        if (bits != BN_num_bits(client_host_key->rsa->n))
249                                verbose("Warning: keysize mismatch for client_host_key: "
250                                    "actual %d, announced %d",
251                                    BN_num_bits(client_host_key->rsa->n), bits);
252                        packet_check_eom();
253
254                        authenticated = auth_rhosts_rsa(pw, client_user,
255                            client_host_key);
256                        key_free(client_host_key);
257
258                        snprintf(info, sizeof info, " ruser %.100s", client_user);
259                        break;
260
261                case SSH_CMSG_AUTH_RSA:
262                        if (!options.rsa_authentication) {
263                                verbose("RSA authentication disabled.");
264                                break;
265                        }
266                        /* RSA authentication requested. */
267                        if ((n = BN_new()) == NULL)
268                                fatal("do_authloop: BN_new failed");
269                        packet_get_bignum(n);
270                        packet_check_eom();
271                        authenticated = auth_rsa(pw, n);
272                        BN_clear_free(n);
273                        break;
274
275                case SSH_CMSG_AUTH_PASSWORD:
276                        if (!options.password_authentication) {
277                                verbose("Password authentication disabled.");
278                                break;
279                        }
280                        /*
281                         * Read user password.  It is in plain text, but was
282                         * transmitted over the encrypted channel so it is
283                         * not visible to an outside observer.
284                         */
285                        password = packet_get_string(&dlen);
286                        packet_check_eom();
287
288                        /* Try authentication with the password. */
289                        authenticated = PRIVSEP(auth_password(authctxt, password));
290
291                        memset(password, 0, strlen(password));
292                        xfree(password);
293                        break;
294
295                case SSH_CMSG_AUTH_TIS:
296                        debug("rcvd SSH_CMSG_AUTH_TIS");
297                        if (options.challenge_response_authentication == 1) {
298                                char *challenge = get_challenge(authctxt);
299                                if (challenge != NULL) {
300                                        debug("sending challenge '%s'", challenge);
301                                        packet_start(SSH_SMSG_AUTH_TIS_CHALLENGE);
302                                        packet_put_cstring(challenge);
303                                        xfree(challenge);
304                                        packet_send();
305                                        packet_write_wait();
306                                        continue;
307                                }
308                        }
309                        break;
310                case SSH_CMSG_AUTH_TIS_RESPONSE:
311                        debug("rcvd SSH_CMSG_AUTH_TIS_RESPONSE");
312                        if (options.challenge_response_authentication == 1) {
313                                char *response = packet_get_string(&dlen);
314                                debug("got response '%s'", response);
315                                packet_check_eom();
316                                authenticated = verify_response(authctxt, response);
317                                memset(response, 'r', dlen);
318                                xfree(response);
319                        }
320                        break;
321
322                default:
323                        /*
324                         * Any unknown messages will be ignored (and failure
325                         * returned) during authentication.
326                         */
327                        log("Unknown message during authentication: type %d", type);
328                        break;
329                }
330#ifdef BSD_AUTH
331                if (authctxt->as) {
332                        auth_close(authctxt->as);
333                        authctxt->as = NULL;
334                }
335#endif
336                if (!authctxt->valid && authenticated)
337                        fatal("INTERNAL ERROR: authenticated invalid user %s",
338                            authctxt->user);
339
340#ifdef _UNICOS
341                if (type == SSH_CMSG_AUTH_PASSWORD && !authenticated)
342                        cray_login_failure(authctxt->user, IA_UDBERR);
343                if (authenticated && cray_access_denied(authctxt->user)) {
344                        authenticated = 0;
345                        fatal("Access denied for user %s.",authctxt->user);
346                }
347#endif /* _UNICOS */
348
349#ifdef HAVE_CYGWIN
350                if (authenticated &&
351                    !check_nt_auth(type == SSH_CMSG_AUTH_PASSWORD, pw)) {
352                        packet_disconnect("Authentication rejected for uid %d.",
353                        pw == NULL ? -1 : pw->pw_uid);
354                        authenticated = 0;
355                }
356#else
357                /* Special handling for root */
358                if (!use_privsep &&
359                    authenticated && authctxt->pw->pw_uid == 0 &&
360                    !auth_root_allowed(get_authname(type)))
361                        authenticated = 0;
362#endif
363#ifdef USE_PAM
364                if (!use_privsep && authenticated &&
365                    !do_pam_account(pw->pw_name, client_user))
366                        authenticated = 0;
367#endif
368
369                /*
370                 * If we received a non-authentication message, right now
371                 * only possible for Kerberos 5 TGT passing
372                 * support for SSH.COM compatibility, assume that the
373                 * FAILURE/SUCCESS return has already been handled, skip
374                 * the logging, and restart the loop.
375                 */
376                if (nonauthentication)
377                        continue;
378
379                /* Log before sending the reply */
380                auth_log(authctxt, authenticated, get_authname(type), info);
381
382                if (client_user != NULL) {
383                        xfree(client_user);
384                        client_user = NULL;
385                }
386
387                if (authenticated)
388                        return;
389
390                if (authctxt->failures++ > AUTH_FAIL_MAX) {
391                        packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
392                }
393
394                packet_start(SSH_SMSG_FAILURE);
395                packet_send();
396                packet_write_wait();
397        }
398}
399
400/*
401 * Performs authentication of an incoming connection.  Session key has already
402 * been exchanged and encryption is enabled.
403 */
404Authctxt *
405do_authentication(void)
406{
407        Authctxt *authctxt;
408        int status;
409        u_int ulen;
410        char *user, *style = NULL;
411        char *filetext, *errmem;
412        const char *err;
413
414        /* Get the name of the user that we wish to log in as. */
415        packet_read_expect(SSH_CMSG_USER);
416
417        /* Get the user name. */
418        user = packet_get_string(&ulen);
419        packet_check_eom();
420
421        if ((style = strchr(user, ':')) != NULL)
422                *style++ = '\0';
423
424#ifdef KRB5
425        /* XXX - SSH.com Kerberos v5 braindeath. */
426        if ((datafellows & SSH_BUG_K5USER) &&
427            options.kerberos_authentication) {
428                char *p;
429                if ((p = strchr(user, '@')) != NULL)
430                        *p = '\0';
431        }
432#endif
433
434        authctxt = authctxt_new();
435        authctxt->user = user;
436        authctxt->style = style;
437
438        status = al_login_allowed(user, 1, &is_local_acct, &filetext);
439        if (status != AL_SUCCESS)
440          {
441            char *buf;
442
443            err = al_strerror(status, &errmem);
444            if (filetext && *filetext)
445              {
446                buf = xmalloc(40 + strlen(err) + strlen(filetext));
447                sprintf(buf, "You are not allowed to log in here: %s\n%s",
448                        err, filetext);
449              }
450            else
451              {
452                buf = xmalloc(40 + strlen(err));
453                sprintf(buf, "You are not allowed to log in here: %s\n", err);
454              }
455
456            log("Login denied: attempted login as %s from %s: %s",
457                user, get_canonical_hostname(1), err);
458            packet_disconnect(buf);
459          }
460        if (!is_local_acct)
461          {
462            status = al_acct_create(user, getpid(), 0, 0, NULL);
463            if (status != AL_SUCCESS && debug_flag)
464              {
465                err = al_strerror(status, &errmem);
466                debug("al_acct_create failed for user %s: %s", user,
467                      err);
468                al_free_errmem(errmem);
469              }
470            session_username = xstrdup(user);
471            atexit(session_cleanup);
472          }
473
474        /* Verify that the user is a valid user. */
475        if ((authctxt->pw = PRIVSEP(getpwnamallow(user))) != NULL)
476                authctxt->valid = 1;
477        else
478                debug("do_authentication: illegal user %s", user);
479
480        setproctitle("%s%s", authctxt->pw ? user : "unknown",
481            use_privsep ? " [net]" : "");
482
483#ifdef USE_PAM
484        PRIVSEP(start_pam(authctxt->pw == NULL ? "NOUSER" : user));
485#endif
486
487        /*
488         * If we are not running as root, the user must have the same uid as
489         * the server. (Unless you are running Windows)
490         */
491#ifndef HAVE_CYGWIN
492        if (!use_privsep && getuid() != 0 && authctxt->pw &&
493            authctxt->pw->pw_uid != getuid())
494                packet_disconnect("Cannot change user when server not running as root.");
495#endif
496
497        /*
498         * Loop until the user has been authenticated or the connection is
499         * closed, do_authloop() returns only if authentication is successful
500         */
501        do_authloop(authctxt);
502
503        /* The user has been authenticated and accepted. */
504        packet_start(SSH_SMSG_SUCCESS);
505        packet_send();
506        packet_write_wait();
507
508        return (authctxt);
509}
Note: See TracBrowser for help on using the repository browser.