diff options
author | John Polstra <jdp@FreeBSD.org> | 1998-11-21 02:22:14 +0000 |
---|---|---|
committer | John Polstra <jdp@FreeBSD.org> | 1998-11-21 02:22:14 +0000 |
commit | e83348169b37fbd312e1d87265318cacceddd5b7 (patch) | |
tree | 1a4c6ba284a692921dcf72d7d78898a753fba36c /usr.bin/login | |
parent | 4700eb95cb86c1fa7f5fa110497d6af01426c73f (diff) | |
download | src-e83348169b37fbd312e1d87265318cacceddd5b7.tar.gz src-e83348169b37fbd312e1d87265318cacceddd5b7.zip |
ATTENTION: INSTALL "/etc/pam.conf" FROM "src/etc"!!!
Change login to use PAM for authentication. I kept the built-in
passwd/NIS authentication support, to handle cases where the system
is missing its "/etc/pam.conf" file. S/Key and KerberosIV
authentication methods are removed from the login program, but
still available in PAM modules.
Notes
Notes:
svn path=/head/; revision=41279
Diffstat (limited to 'usr.bin/login')
-rw-r--r-- | usr.bin/login/Makefile | 20 | ||||
-rw-r--r-- | usr.bin/login/klogin.c | 204 | ||||
-rw-r--r-- | usr.bin/login/login.c | 251 |
3 files changed, 149 insertions, 326 deletions
diff --git a/usr.bin/login/Makefile b/usr.bin/login/Makefile index 93560f1258c5..e992c31a2144 100644 --- a/usr.bin/login/Makefile +++ b/usr.bin/login/Makefile @@ -1,27 +1,15 @@ # From: @(#)Makefile 8.1 (Berkeley) 7/19/93 -# $Id: Makefile,v 1.22 1998/11/11 02:16:01 jdp Exp $ +# $Id: Makefile,v 1.23 1998/11/11 05:47:45 jdp Exp $ PROG= login MAN1= login.1 MAN5= login.access.5 SRCS= login.c login_access.c login_fbtab.c -CFLAGS+=-Wall -DSKEY -DLOGIN_ACCESS -DLOGALL +CFLAGS+=-Wall -DLOGIN_ACCESS -DLOGALL -.if defined(KLOGIN_PARANOID) -CFLAGS+=-DKLOGIN_PARANOID -.endif - -DPADD= ${LIBUTIL} ${LIBSKEY} ${LIBMD} ${LIBCRYPT} -LDADD= -lutil -lskey -lmd -lcrypt - -.if exists(${DESTDIR}${LIBDIR}/libkrb.a) && defined(MAKE_KERBEROS4) -CFLAGS+=-DKERBEROS -SRCS+= klogin.c -DPADD+= ${LIBKRB} ${LIBDES} -LDADD+= -lkrb -ldes -DISTRIBUTION= krb -.endif +DPADD= ${LIBUTIL} ${LIBCRYPT} ${LIBPAM} +LDADD= -lutil -lcrypt -lpam BINMODE=4555 INSTALLFLAGS=-fschg diff --git a/usr.bin/login/klogin.c b/usr.bin/login/klogin.c deleted file mode 100644 index 7c61b84a9cb7..000000000000 --- a/usr.bin/login/klogin.c +++ /dev/null @@ -1,204 +0,0 @@ -/*- - * Copyright (c) 1990, 1993, 1994 - * The Regents of the University of California. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - */ - -#ifndef lint -static const char sccsid[] = "@(#)klogin.c 8.3 (Berkeley) 4/2/94"; -#endif /* not lint */ - -#ifdef KERBEROS -#include <sys/param.h> -#include <sys/syslog.h> -#include <des.h> -#include <krb.h> - -#include <err.h> -#include <netdb.h> -#include <pwd.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#define INITIAL_TICKET "krbtgt" -#define VERIFY_SERVICE "rcmd" - -extern int notickets; -extern char *krbtkfile_env; - -/* - * Attempt to log the user in using Kerberos authentication - * - * return 0 on success (will be logged in) - * 1 if Kerberos failed (try local password in login) - */ -int -klogin(pw, instance, localhost, password) - struct passwd *pw; - char *instance, *localhost, *password; -{ - int kerror; - char realm[REALM_SZ], savehost[MAXHOSTNAMELEN]; - char tkt_location[MAXPATHLEN]; - char *krb_get_phost(); - extern int noticketsdontcomplain; - -#ifdef KLOGIN_PARANOID - AUTH_DAT authdata; - KTEXT_ST ticket; - struct hostent *hp; - unsigned long faddr; - - noticketsdontcomplain = 0; /* enable warning message */ -#endif - - /* - * Root logins don't use Kerberos. - * If we have a realm, try getting a ticket-granting ticket - * and using it to authenticate. Otherwise, return - * failure so that we can try the normal passwd file - * for a password. If that's ok, log the user in - * without issuing any tickets. - */ - if (strcmp(pw->pw_name, "root") == 0 || - krb_get_lrealm(realm, 0) != KSUCCESS) - return (1); - - noticketsdontcomplain = 0; /* enable warning message */ - - /* - * get TGT for local realm - * tickets are stored in a file named TKT_ROOT plus uid - * except for user.root tickets. - */ - - if (strcmp(instance, "root") != 0) - (void)sprintf(tkt_location, "%s%d", TKT_ROOT, pw->pw_uid); - else { - (void)sprintf(tkt_location, "%s_root_%d", TKT_ROOT, pw->pw_uid); - krbtkfile_env = tkt_location; - } - (void)krb_set_tkt_string(tkt_location); - - /* - * Set real as well as effective ID to 0 for the moment, - * to make the kerberos library do the right thing. - */ - if (setuid(0) < 0) { - warnx("setuid"); - return (1); - } - kerror = krb_get_pw_in_tkt(pw->pw_name, instance, - realm, INITIAL_TICKET, realm, DEFAULT_TKT_LIFE, password); - - /* - * If we got a TGT, get a local "rcmd" ticket and check it so as to - * ensure that we are not talking to a bogus Kerberos server. - * - * There are 2 cases where we still allow a login: - * 1: the VERIFY_SERVICE doesn't exist in the KDC - * 2: local host has no srvtab, as (hopefully) indicated by a - * return value of RD_AP_UNDEC from krb_rd_req(). - */ - if (kerror != INTK_OK) { - if (kerror != INTK_BADPW && kerror != KDC_PR_UNKNOWN) { - syslog(LOG_ERR, "Kerberos intkt error: %s", - krb_err_txt[kerror]); - dest_tkt(); - } - return (1); - } - - if (chown(TKT_FILE, pw->pw_uid, pw->pw_gid) < 0) - syslog(LOG_ERR, "chown tkfile (%s): %m", TKT_FILE); - - (void)strncpy(savehost, krb_get_phost(localhost), sizeof(savehost)); - savehost[sizeof(savehost)-1] = NULL; - -#ifdef KLOGIN_PARANOID - /* - * if the "VERIFY_SERVICE" doesn't exist in the KDC for this host, - * still allow login with tickets, but log the error condition. - */ - - kerror = krb_mk_req(&ticket, VERIFY_SERVICE, savehost, realm, 33); - if (kerror == KDC_PR_UNKNOWN) { - syslog(LOG_NOTICE, - "warning: TGT not verified (%s); %s.%s not registered, or srvtab is wrong?", - krb_err_txt[kerror], VERIFY_SERVICE, savehost); - notickets = 0; - return (0); - } - - if (kerror != KSUCCESS) { - warnx("unable to use TGT: (%s)", krb_err_txt[kerror]); - syslog(LOG_NOTICE, "unable to use TGT: (%s)", - krb_err_txt[kerror]); - dest_tkt(); - return (1); - } - - if (!(hp = gethostbyname(localhost))) { - syslog(LOG_ERR, "couldn't get local host address"); - dest_tkt(); - return (1); - } - - memmove((void *)&faddr, (void *)hp->h_addr, sizeof(faddr)); - - kerror = krb_rd_req(&ticket, VERIFY_SERVICE, savehost, faddr, - &authdata, ""); - - if (kerror == KSUCCESS) { - notickets = 0; - return (0); - } - - /* undecipherable: probably didn't have a srvtab on the local host */ - if (kerror == RD_AP_UNDEC) { - syslog(LOG_NOTICE, "krb_rd_req: (%s)\n", krb_err_txt[kerror]); - dest_tkt(); - return (1); - } - /* failed for some other reason */ - warnx("unable to verify %s ticket: (%s)", VERIFY_SERVICE, - krb_err_txt[kerror]); - syslog(LOG_NOTICE, "couldn't verify %s ticket: %s", VERIFY_SERVICE, - krb_err_txt[kerror]); - dest_tkt(); - return (1); -#else - notickets = 0; - return (0); -#endif -} -#endif diff --git a/usr.bin/login/login.c b/usr.bin/login/login.c index 57a385a8bb88..bb33298a640f 100644 --- a/usr.bin/login/login.c +++ b/usr.bin/login/login.c @@ -42,7 +42,7 @@ static char copyright[] = static char sccsid[] = "@(#)login.c 8.4 (Berkeley) 4/2/94"; #endif static const char rcsid[] = - "$Id: login.c,v 1.41 1998/11/11 02:16:01 jdp Exp $"; + "$Id: login.c,v 1.42 1998/11/11 05:47:45 jdp Exp $"; #endif /* not lint */ /* @@ -77,9 +77,8 @@ static const char rcsid[] = #include <unistd.h> #include <utmp.h> -#ifdef SKEY -#include <skey.h> -#endif /* SKEY */ +#include <security/pam_appl.h> +#include <security/pam_misc.h> #include "pathnames.h" @@ -96,12 +95,10 @@ char *stypeof __P((char *)); void timedout __P((int)); int login_access __P((char *, char *)); void login_fbtab __P((char *, uid_t, gid_t)); -#ifdef KERBEROS -int klogin __P((struct passwd *, char *, char *, char *)); -#endif +static int auth_pam __P((void)); +static int auth_traditional __P((void)); extern void login __P((struct utmp *)); -extern void trimdomain __P((char *, int)); static void usage __P((void)); #define TTYGRPNAME "tty" /* name of group to own ttys */ @@ -114,14 +111,6 @@ static void usage __P((void)); */ u_int timeout = 300; -#ifdef KERBEROS -int notickets = 1; -int noticketsdontcomplain = 1; -char *instance; -char *krbtkfile_env; -int authok; -#endif - struct passwd *pwd; int failures; char *term, *envinit[1], *hostname, *username, *tty; @@ -142,18 +131,11 @@ main(argc, argv) int changepass; time_t warntime; uid_t uid, euid; - char *domain, *p, *salt, *ttyn; - const char *ep; + char *domain, *p, *ttyn; char tbuf[MAXPATHLEN + 2], tname[sizeof(_PATH_TTY) + 10]; char localhost[MAXHOSTNAMELEN]; char *shell = NULL; login_cap_t *lc = NULL; -#ifdef SKEY - int permit_passwd = 0; -#endif /* SKEY */ -#ifdef KERBEROS - char *k; -#endif (void)signal(SIGALRM, timedout); (void)alarm(timeout); @@ -256,14 +238,6 @@ main(argc, argv) } rootlogin = 0; rootok = rootterm(tty); /* Default (auth may change) */ -#ifdef KERBEROS - if ((instance = strchr(username, '.')) != NULL) { - if (strncmp(instance, ".root", 5) == 0) - rootlogin = 1; - *instance++ = '\0'; - } else - instance = ""; -#endif /* KERBEROS */ if (strlen(username) > UT_NAMESIZE) username[UT_NAMESIZE] = '\0'; @@ -281,20 +255,7 @@ main(argc, argv) (void)strncpy(tbuf, username, sizeof tbuf-1); tbuf[sizeof tbuf-1] = '\0'; - if ((pwd = getpwnam(username)) != NULL) - salt = pwd->pw_passwd; - else - salt = "xx"; - - /* - * Establish the class now, before we might goto - * within the next block. pwd can be NULL since it - * falls back to the "default" class if it is. - */ - if (pwd != NULL) - (void)seteuid(rootlogin ? 0 : pwd->pw_uid); - lc = login_getpwclass(pwd); - seteuid(euid); + pwd = getpwnam(username); /* * if we have a valid account name, and it doesn't have a @@ -302,7 +263,6 @@ main(argc, argv) * is root or the caller isn't changing their uid, don't * authenticate. */ - rval = 1; if (pwd != NULL) { if (pwd->pw_uid == 0) rootlogin = 1; @@ -324,63 +284,31 @@ main(argc, argv) (void)setpriority(PRIO_PROCESS, 0, -4); -#ifdef SKEY - permit_passwd = skeyaccess(username, tty, - hostname ? full_hostname : NULL, - NULL); - p = skey_getpass("Password:", pwd, permit_passwd); - ep = skey_crypt(p, salt, pwd, permit_passwd); -#else /* !SKEY */ - p = getpass("Password:"); - ep = crypt(p, salt); -#endif/* SKEY */ - - if (pwd) { - if (!p[0] && pwd->pw_passwd[0]) - ep = ":"; -#ifdef KERBEROS -#ifdef SKEY - /* - * Do not allow user to type in kerberos password - * over the net (actually, this is ok for encrypted - * links, but we have no way of determining if the - * link is encrypted. - */ - if (!permit_passwd) { - rval = 1; /* failed */ - } else -#endif /* SKEY */ - rval = 1; - k = auth_getval("auth_list"); - if (k && strstr(k, "kerberos")) - rval = klogin(pwd, instance, localhost, p); - if (rval != 0 && rootlogin && pwd->pw_uid != 0) - rootlogin = 0; - if (rval == 0) - authok = 1; /* kerberos authenticated ok */ - else if (rval == 1) /* fallback to unix passwd */ - rval = strcmp(ep, pwd->pw_passwd); -#else /* !KERBEROS */ - rval = strcmp(ep, pwd->pw_passwd); -#endif /* KERBEROS */ - } - - /* clear entered password */ - memset(p, 0, strlen(p)); + /* + * Try to authenticate using PAM. If a PAM system error + * occurs, perhaps because of a botched configuration, + * then fall back to using traditional Unix authentication. + */ + if ((rval = auth_pam()) == -1) + rval = auth_traditional(); (void)setpriority(PRIO_PROCESS, 0, 0); + /* + * PAM authentication may have changed "pwd" to the + * entry for the template user. Check again to see if + * this is a root login after all. + */ + if (pwd != NULL && pwd->pw_uid == 0) + rootlogin = 1; + ttycheck: /* * If trying to log in as root without Kerberos, * but with insecure terminal, refuse the login attempt. */ if (pwd && !rval) { -#if defined(KERBEROS) - if (authok == 0 && rootlogin && !rootok) -#else if (rootlogin && !rootok) -#endif refused(NULL, "NOROOT", 0); else /* valid password & authenticated */ break; @@ -407,6 +335,13 @@ main(argc, argv) endpwent(); + /* + * Establish the login class. + */ + (void)seteuid(rootlogin ? 0 : pwd->pw_uid); + lc = login_getpwclass(pwd); + seteuid(euid); + /* if user not super-user, check for disabled logins */ if (!rootlogin) auth_checknologin(lc); @@ -530,11 +465,6 @@ main(argc, argv) if (hostname==NULL && isdialuptty(tty)) syslog(LOG_INFO, "DIALUP %s, %s", tty, pwd->pw_name); -#ifdef KERBEROS - if (!quietlog && notickets == 1 && !noticketsdontcomplain) - (void)printf("Warning: no Kerberos tickets issued.\n"); -#endif - #ifdef LOGALL /* * Syslog each successful login, so we don't have to watch hundreds @@ -573,7 +503,12 @@ main(argc, argv) * We don't need to be root anymore, so * set the user and session context */ - if (setusercontext(lc, pwd, pwd->pw_uid, LOGIN_SETALL) != 0) { + if (setlogin(username) != 0) { + syslog(LOG_ERR, "setlogin(%s): %m - exiting", username); + exit(1); + } + if (setusercontext(lc, pwd, pwd->pw_uid, + LOGIN_SETALL & ~LOGIN_SETLOGIN) != 0) { syslog(LOG_ERR, "setusercontext() failed - exiting"); exit(1); } @@ -585,13 +520,9 @@ main(argc, argv) else { (void)setenv("TERM", stypeof(tty), 0); /* Fallback doesn't */ } - (void)setenv("LOGNAME", pwd->pw_name, 1); - (void)setenv("USER", pwd->pw_name, 1); + (void)setenv("LOGNAME", username, 1); + (void)setenv("USER", username, 1); (void)setenv("PATH", rootlogin ? _PATH_STDPATH : _PATH_DEFPATH, 0); -#ifdef KERBEROS - if (krbtkfile_env) - (void)setenv("KRBTKFILE", krbtkfile_env, 1); -#endif if (!quietlog) { char *cw; @@ -646,6 +577,114 @@ main(argc, argv) err(1, "%s", shell); } +static int +auth_traditional() +{ + int rval; + char *p; + char *ep; + char *salt; + + rval = 1; + salt = pwd != NULL ? pwd->pw_passwd : "xx"; + + p = getpass("Password:"); + ep = crypt(p, salt); + + if (pwd) { + if (!p[0] && pwd->pw_passwd[0]) + ep = ":"; + if (strcmp(ep, pwd->pw_passwd) == 0) + rval = 0; + } + + /* clear entered password */ + memset(p, 0, strlen(p)); + return rval; +} + +/* + * Attempt to authenticate the user using PAM. Returns 0 if the user is + * authenticated, or 1 if not authenticated. If some sort of PAM system + * error occurs (e.g., the "/etc/pam.conf" file is missing) then this + * function returns -1. This can be used as an indication that we should + * fall back to a different authentication mechanism. + */ +static int +auth_pam() +{ + pam_handle_t *pamh = NULL; + const char *tmpl_user; + const void *item; + int rval; + int e; + static struct pam_conv conv = { misc_conv, NULL }; + + if ((e = pam_start("login", username, &conv, &pamh)) != PAM_SUCCESS) { + syslog(LOG_ERR, "pam_start: %s", pam_strerror(pamh, e)); + return -1; + } + if ((e = pam_set_item(pamh, PAM_TTY, tty)) != PAM_SUCCESS) { + syslog(LOG_ERR, "pam_set_item(PAM_TTY): %s", + pam_strerror(pamh, e)); + return -1; + } + if (hostname != NULL && + (e = pam_set_item(pamh, PAM_RHOST, full_hostname)) != PAM_SUCCESS) { + syslog(LOG_ERR, "pam_set_item(PAM_RHOST): %s", + pam_strerror(pamh, e)); + return -1; + } + e = pam_authenticate(pamh, 0); + switch (e) { + + case PAM_SUCCESS: + /* + * With PAM we support the concept of a "template" + * user. The user enters a login name which is + * authenticated by PAM, usually via a remote service + * such as RADIUS or TACACS+. If authentication + * succeeds, a different but related "template" name + * is used for setting the credentials, shell, and + * home directory. The name the user enters need only + * exist on the remote authentication server, but the + * template name must be present in the local password + * database. + * + * This is supported by two various mechanisms in the + * individual modules. However, from the application's + * point of view, the template user is always passed + * back as a changed value of the PAM_USER item. + */ + if ((e = pam_get_item(pamh, PAM_USER, &item)) == + PAM_SUCCESS) { + tmpl_user = (const char *) item; + if (strcmp(username, tmpl_user) != 0) + pwd = getpwnam(tmpl_user); + } else + syslog(LOG_ERR, "Couldn't get PAM_USER: %s", + pam_strerror(pamh, e)); + rval = 0; + break; + + case PAM_AUTH_ERR: + case PAM_USER_UNKNOWN: + case PAM_MAXTRIES: + rval = 1; + break; + + default: + syslog(LOG_ERR, "auth_pam: %s", pam_strerror(pamh, e)); + rval = -1; + break; + } + if ((e = pam_end(pamh, e)) != PAM_SUCCESS) { + syslog(LOG_ERR, "pam_end: %s", pam_strerror(pamh, e)); + rval = -1; + } + return rval; +} + static void usage() { |