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

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