summaryrefslogtreecommitdiffstats
path: root/usr.bin/login
diff options
context:
space:
mode:
authorjdp <jdp@FreeBSD.org>1998-11-21 02:22:14 +0000
committerjdp <jdp@FreeBSD.org>1998-11-21 02:22:14 +0000
commit37a1ff186f2f3ad663b3028d8111eab96a4d49e7 (patch)
tree9af4742f09f8bc013792371cf3d03782a97d0d90 /usr.bin/login
parent7e9c3df2e65c74915f8c8916e13fd46a4375e52d (diff)
downloadFreeBSD-src-37a1ff186f2f3ad663b3028d8111eab96a4d49e7.zip
FreeBSD-src-37a1ff186f2f3ad663b3028d8111eab96a4d49e7.tar.gz
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.
Diffstat (limited to 'usr.bin/login')
-rw-r--r--usr.bin/login/Makefile20
-rw-r--r--usr.bin/login/klogin.c204
-rw-r--r--usr.bin/login/login.c251
3 files changed, 149 insertions, 326 deletions
diff --git a/usr.bin/login/Makefile b/usr.bin/login/Makefile
index 93560f1..e992c31 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 7c61b84..0000000
--- 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 57a385a..bb33298 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()
{
OpenPOWER on IntegriCloud