* Copyright (c) 1989 - 1994, Julianne Frances Haugh
* Copyright (c) 1996 - 2001, Marek Michałkiewicz
* Copyright (c) 2001 - 2006, Tomasz Kłoczko
- * Copyright (c) 2007 - 2008, Nicolas François
+ * Copyright (c) 2007 - 2010, Nicolas François
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
#include <errno.h>
#include <grp.h>
+#ifndef USE_PAM
#include <lastlog.h>
-#ifdef UT_ADDR
-#include <netdb.h>
-#endif
+#endif /* !USE_PAM */
#include <pwd.h>
#include <signal.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
+#include <assert.h>
#include "defines.h"
#include "faillog.h"
#include "failure.h"
#include "getdef.h"
#include "prototypes.h"
#include "pwauth.h"
+/*@-exitarg@*/
#include "exitcodes.h"
+
#ifdef USE_PAM
#include "pam_defs.h"
#endif /* USE_PAM */
+#ifndef USE_PAM
/*
* Needed for MkLinux DR1/2/2.1 - J.
*/
#ifndef LASTLOG_FILE
#define LASTLOG_FILE "/var/log/lastlog"
#endif
+#endif /* !USE_PAM */
/*
* Global variables
*/
-const char *hostname = "";
+const char *Prog;
-static struct passwd pwent;
+static const char *hostname = "";
+static /*@null@*/ /*@only@*/char *username = NULL;
+static int reason = PW_LOGIN;
-#if HAVE_UTMPX_H
-extern struct utmpx utxent;
-struct utmpx failent;
-#else
-struct utmp failent;
-#endif
-extern struct utmp utent;
-
-struct lastlog lastlog;
+#ifndef USE_PAM
+static struct lastlog ll;
+#endif /* !USE_PAM */
static bool pflg = false;
static bool fflg = false;
#ifdef RLOGIN
static bool rflg = false;
-#else
+#else /* RLOGIN */
#define rflg false
-#endif
+#endif /* !RLOGIN */
static bool hflg = false;
static bool preauth_flag = false;
-/*
- * Global variables.
- */
-char *Prog;
-
static bool amroot;
-static int timeout;
+static unsigned int timeout;
/*
* External identifiers.
/* local function prototypes */
static void usage (void);
static void setup_tty (void);
-static void check_flags (int, char *const *);
+static void process_flags (int argc, char *const *argv);
+static /*@observer@*/const char *get_failent_user (/*@returned@*/const char *user);
+#ifndef USE_PAM
+static void update_utmp (const char *user,
+ const char *tty,
+ const char *host,
+ /*@null@*/const struct utmp *utent);
+#endif /* ! USE_PAM */
#ifndef USE_PAM
static struct faillog faillog;
static void bad_time_notify (void);
-static void check_nologin (void);
+static void check_nologin (bool login_to_root);
+#else
+static void get_pam_user (char **ptr_pam_user);
#endif
static void init_env (void);
fprintf (stderr, _(" %s [-p] [-h host] [-f name]\n"), Prog);
#ifdef RLOGIN
fprintf (stderr, _(" %s [-p] -r host\n"), Prog);
-#endif
+#endif /* RLOGIN */
exit (1);
}
{
TERMIO termio;
- GTTY (0, &termio); /* get terminal characteristics */
+ if (GTTY (0, &termio) == 0) { /* get terminal characteristics */
+ int erasechar;
+ int killchar;
- /*
- * Add your favorite terminal modes here ...
- */
- termio.c_lflag |= ISIG | ICANON | ECHO | ECHOE;
- termio.c_iflag |= ICRNL;
+ /*
+ * Add your favorite terminal modes here ...
+ */
+ termio.c_lflag |= ISIG | ICANON | ECHO | ECHOE;
+ termio.c_iflag |= ICRNL;
- /* leave these values unchanged if not specified in login.defs */
- termio.c_cc[VERASE] = getdef_num ("ERASECHAR", termio.c_cc[VERASE]);
- termio.c_cc[VKILL] = getdef_num ("KILLCHAR", termio.c_cc[VKILL]);
+#if defined(ECHOKE) && defined(ECHOCTL)
+ termio.c_lflag |= ECHOKE | ECHOCTL;
+#endif
+#if defined(ECHOPRT) && defined(NOFLSH) && defined(TOSTOP)
+ termio.c_lflag &= ~(ECHOPRT | NOFLSH | TOSTOP);
+#endif
+#ifdef ONLCR
+ termio.c_oflag |= ONLCR;
+#endif
- /*
- * ttymon invocation prefers this, but these settings won't come into
- * effect after the first username login
- */
- STTY (0, &termio);
+ /* leave these values unchanged if not specified in login.defs */
+ erasechar = getdef_num ("ERASECHAR", (int) termio.c_cc[VERASE]);
+ killchar = getdef_num ("KILLCHAR", (int) termio.c_cc[VKILL]);
+ termio.c_cc[VERASE] = (cc_t) erasechar;
+ termio.c_cc[VKILL] = (cc_t) killchar;
+ /* Make sure the values were valid.
+ * getdef_num cannot validate this.
+ */
+ if (erasechar != (int) termio.c_cc[VERASE]) {
+ fprintf (stderr,
+ _("configuration error - cannot parse %s value: '%d'"),
+ "ERASECHAR", erasechar);
+ exit (1);
+ }
+ if (killchar != (int) termio.c_cc[VKILL]) {
+ fprintf (stderr,
+ _("configuration error - cannot parse %s value: '%d'"),
+ "KILLCHAR", killchar);
+ exit (1);
+ }
+
+ /*
+ * ttymon invocation prefers this, but these settings
+ * won't come into effect after the first username login
+ */
+ (void) STTY (0, &termio);
+ }
}
(void) fflush (stdout);
}
-static void check_nologin (void)
+static void check_nologin (bool login_to_root)
{
char *fname;
fname = getdef_str ("NOLOGINS_FILE");
if ((NULL != fname) && (access (fname, F_OK) == 0)) {
FILE *nlfp;
- int c;
/*
* Cat the file if it can be opened, otherwise just
*/
nlfp = fopen (fname, "r");
if (NULL != nlfp) {
+ int c;
while ((c = getc (nlfp)) != EOF) {
if (c == '\n') {
(void) putchar ('\r');
* gets to login.
*/
- if (pwent.pw_uid != 0) {
+ if (!login_to_root) {
closelog ();
exit (0);
}
- puts (_("\n[Disconnect bypassed -- root login allowed.]"));
+ (void) puts (_("\n[Disconnect bypassed -- root login allowed.]"));
}
}
#endif /* !USE_PAM */
-static void check_flags (int argc, char *const *argv)
+static void process_flags (int argc, char *const *argv)
{
int arg;
+ int flag;
/*
* Check the flags for proper form. Every argument starting with
break; /* stop checking on a "--" */
}
}
+
+ /*
+ * Process options.
+ */
+ while ((flag = getopt (argc, argv, "d:fh:pr:")) != EOF) {
+ switch (flag) {
+ case 'd':
+ /* "-d device" ignored for compatibility */
+ break;
+ case 'f':
+ fflg = true;
+ break;
+ case 'h':
+ hflg = true;
+ hostname = optarg;
+ reason = PW_TELNET;
+ break;
+#ifdef RLOGIN
+ case 'r':
+ rflg = true;
+ hostname = optarg;
+ reason = PW_RLOGIN;
+ break;
+#endif /* RLOGIN */
+ case 'p':
+ pflg = true;
+ break;
+ default:
+ usage ();
+ }
+ }
+
+#ifdef RLOGIN
+ /*
+ * Neither -h nor -f should be combined with -r.
+ */
+
+ if (rflg && (hflg || fflg)) {
+ usage ();
+ }
+#endif /* RLOGIN */
+
+ /*
+ * Allow authentication bypass only if real UID is zero.
+ */
+
+ if ((rflg || fflg || hflg) && !amroot) {
+ fprintf (stderr, _("%s: Permission denied.\n"), Prog);
+ exit (1);
+ }
+
+ /*
+ * Get the user name.
+ */
+ if (optind < argc) {
+ assert (NULL == username);
+ username = xstrdup (argv[optind]);
+ strzero (argv[optind]);
+ ++optind;
+ }
+
+#ifdef RLOGIN
+ if (rflg && (NULL != username)) {
+ usage ();
+ }
+#endif /* RLOGIN */
+ if (fflg && (NULL == username)) {
+ usage ();
+ }
+
}
static RETSIGTYPE alarm_handler (unused int sig)
{
- fprintf (stderr, _("\nLogin timed out after %d seconds.\n"), timeout);
+ fprintf (stderr, _("\nLogin timed out after %u seconds.\n"), timeout);
exit (0);
}
+#ifdef USE_PAM
+/*
+ * get_pam_user - Get the username according to PAM
+ *
+ * ptr_pam_user shall point to a malloc'ed string (or NULL).
+ */
+static void get_pam_user (char **ptr_pam_user)
+{
+ int retcode;
+ void *ptr_user;
+
+ assert (NULL != ptr_pam_user);
+
+ retcode = pam_get_item (pamh, PAM_USER, (const void **)&ptr_user);
+ PAM_FAIL_CHECK;
+
+ if (NULL != *ptr_pam_user) {
+ free (*ptr_pam_user);
+ }
+ if (NULL != ptr_user) {
+ *ptr_pam_user = xstrdup ((const char *)ptr_user);
+ } else {
+ *ptr_pam_user = NULL;
+ }
+}
+#endif
+
+/*
+ * get_failent_user - Return a string that can be used to log failure
+ * from an user.
+ *
+ * This will be either the user argument, or "UNKNOWN".
+ *
+ * It is quite common to mistyped the password for username, and passwords
+ * should not be logged.
+ */
+static /*@observer@*/const char *get_failent_user (/*@returned@*/const char *user)
+{
+ const char *failent_user = "UNKNOWN";
+ bool log_unkfail_enab = getdef_bool("LOG_UNKFAIL_ENAB");
+
+ if ((NULL != user) && ('\0' != user[0])) {
+ if ( log_unkfail_enab
+ || (getpwnam (user) != NULL)) {
+ failent_user = user;
+ }
+ }
+
+ return failent_user;
+}
+
+#ifndef USE_PAM
+/*
+ * update_utmp - Update or create an utmp entry in utmp, wtmp, utmpw, and
+ * wtmpx
+ *
+ * utent should be the utmp entry returned by get_current_utmp (or
+ * NULL).
+ */
+static void update_utmp (const char *user,
+ const char *tty,
+ const char *host,
+ /*@null@*/const struct utmp *utent)
+{
+ struct utmp *ut = prepare_utmp (user, tty, host, utent);
+#ifdef USE_UTMPX
+ struct utmpx *utx = prepare_utmpx (user, tty, host, utent);
+#endif /* USE_UTMPX */
+
+ (void) setutmp (ut); /* make entry in the utmp & wtmp files */
+ free (ut);
+
+#ifdef USE_UTMPX
+ (void) setutmpx (utx); /* make entry in the utmpx & wtmpx files */
+ free (utx);
+#endif /* USE_UTMPX */
+}
+#endif /* ! USE_PAM */
/*
* login - create a new login session for a user
*/
int main (int argc, char **argv)
{
- char username[32];
+ const char *tmptty;
char tty[BUFSIZ];
#ifdef RLOGIN
char term[128] = "";
-#endif
+#endif /* RLOGIN */
#if defined(HAVE_STRFTIME) && !defined(USE_PAM)
char ptime[80];
#endif
- int reason = PW_LOGIN;
- int delay;
- int retries;
- bool failed;
- int flag;
+ unsigned int delay;
+ unsigned int retries;
bool subroot = false;
#ifndef USE_PAM
bool is_console;
#endif
int err;
const char *cp;
- char *tmp;
+ const char *tmp;
char fromhost[512];
- struct passwd *pwd;
+ struct passwd *pwd = NULL;
char **envp = environ;
- static char temp_pw[2];
- static char temp_shell[] = "/bin/sh";
+ const char *failent_user;
+ /*@null@*/struct utmp *utent;
#ifdef USE_PAM
int retcode;
pid_t child;
- char *pam_user;
- char **ptr_pam_user = &pam_user;
+ char *pam_user = NULL;
#else
struct spwd *spwd = NULL;
#endif
initenv ();
- username[0] = '\0';
amroot = (getuid () == 0);
Prog = Basename (argv[0]);
- check_flags (argc, argv);
-
- while ((flag = getopt (argc, argv, "d:f::h:pr:")) != EOF) {
- switch (flag) {
- case 'd':
- /* "-d device" ignored for compatibility */
- break;
- case 'f':
- /*
- * username must be a separate token
- * (-f root, *not* -froot). --marekm
- *
- * if -f has an arg, use that, else use the
- * normal user name passed after all options
- * --benc
- */
- if (optarg != NULL && optarg != argv[optind - 1]) {
- usage ();
- }
- fflg = true;
- if (optarg) {
- STRFCPY (username, optarg);
- }
- break;
- case 'h':
- hflg = true;
- hostname = optarg;
- reason = PW_TELNET;
- break;
-#ifdef RLOGIN
- case 'r':
- rflg = true;
- hostname = optarg;
- reason = PW_RLOGIN;
- break;
-#endif
- case 'p':
- pflg = true;
- break;
- default:
- usage ();
- }
- }
-
-#ifdef RLOGIN
- /*
- * Neither -h nor -f should be combined with -r.
- */
-
- if (rflg && (hflg || fflg)) {
- usage ();
- }
-#endif
-
- /*
- * Allow authentication bypass only if real UID is zero.
- */
-
- if ((rflg || fflg || hflg) && !amroot) {
- fprintf (stderr, _("%s: Permission denied.\n"), Prog);
+ if (geteuid() != 0) {
+ fprintf (stderr, _("%s: Cannot possibly work without effective root\n"), Prog);
exit (1);
}
+ process_flags (argc, argv);
+
if ((isatty (0) == 0) || (isatty (1) == 0) || (isatty (2) == 0)) {
exit (1); /* must be a terminal */
}
+ utent = get_current_utmp ();
/*
* Be picky if run by normal users (possible if installed setuid
* root), but not if run by root. This way it still allows logins
* but users must "exec login" which will use the existing utmp
* entry (will not overwrite remote hostname). --marekm
*/
- checkutmp (!amroot);
- STRFCPY (tty, utent.ut_line);
+ if (!amroot && (NULL == utent)) {
+ (void) puts (_("No utmp entry. You must exec \"login\" from the lowest level \"sh\""));
+ exit (1);
+ }
+ /* NOTE: utent might be NULL afterwards */
+
+ tmptty = ttyname (0);
+ if (NULL == tmptty) {
+ tmptty = "UNKNOWN";
+ }
+ STRFCPY (tty, tmptty);
+
#ifndef USE_PAM
is_console = console (tty);
#endif
if (rflg || hflg) {
-#ifdef UT_ADDR
- struct hostent *he;
-
/*
- * Fill in the ut_addr field (remote login IP address). XXX
- * - login from util-linux does it, but this is not the
- * right place to do it. The program that starts login
- * (telnetd, rlogind) knows the IP address, so it should
- * create the utmp entry and fill in ut_addr.
- * gethostbyname() is not 100% reliable (the remote host may
- * be unknown, etc.). --marekm
+ * Add remote hostname to the environment. I think
+ * (not sure) I saw it once on Irix. --marekm
*/
- he = gethostbyname (hostname);
- if (NULL != he) {
- utent.ut_addr = *((int32_t *) (he->h_addr_list[0]));
-#endif
-#ifdef UT_HOST
- strncpy (utent.ut_host, hostname,
- sizeof (utent.ut_host));
-#endif
-#if HAVE_UTMPX_H
- strncpy (utxent.ut_host, hostname,
- sizeof (utxent.ut_host));
-#endif
- /*
- * Add remote hostname to the environment. I think
- * (not sure) I saw it once on Irix. --marekm
- */
- addenv ("REMOTEHOST", hostname);
- }
-#ifdef __linux__
- /*
- * workaround for init/getty leaving junk in ut_host at least in
- * some version of RedHat. --marekm
- */
- else if (amroot) {
- memzero (utent.ut_host, sizeof utent.ut_host);
- }
-#endif
- if (fflg) {
- preauth_flag = true;
- }
- if (hflg) {
- reason = PW_RLOGIN;
- }
+ addenv ("REMOTEHOST", hostname);
+ }
+ if (fflg) {
+ preauth_flag = true;
+ }
+ if (hflg) {
+ reason = PW_RLOGIN;
+ }
#ifdef RLOGIN
- if ( rflg
- && do_rlogin (hostname, username, sizeof username,
- term, sizeof term)) {
+ if (rflg) {
+ assert (NULL == username);
+ username = xmalloc (USER_NAME_MAX_LENGTH + 1);
+ username[USER_NAME_MAX_LENGTH] = '\0';
+ if (do_rlogin (hostname, username, USER_NAME_MAX_LENGTH, term, sizeof term)) {
preauth_flag = true;
+ } else {
+ free (username);
+ username = NULL;
}
-#endif
+ }
+#endif /* RLOGIN */
- OPENLOG ("login");
+ OPENLOG ("login");
- setup_tty ();
+ setup_tty ();
#ifndef USE_PAM
- umask (getdef_num ("UMASK", GETDEF_DEFAULT_UMASK));
-
- {
- /*
- * Use the ULIMIT in the login.defs file, and if
- * there isn't one, use the default value. The
- * user may have one for themselves, but otherwise,
- * just take what you get.
- */
- long limit = getdef_long ("ULIMIT", -1L);
+ (void) umask (getdef_num ("UMASK", GETDEF_DEFAULT_UMASK));
- if (limit != -1) {
- set_filesize_limit (limit);
- }
+ {
+ /*
+ * Use the ULIMIT in the login.defs file, and if
+ * there isn't one, use the default value. The
+ * user may have one for themselves, but otherwise,
+ * just take what you get.
+ */
+ long limit = getdef_long ("ULIMIT", -1L);
+
+ if (limit != -1) {
+ set_filesize_limit (limit);
}
+ }
#endif
- /*
- * The entire environment will be preserved if the -p flag
- * is used.
- */
- if (pflg) {
- while (NULL != *envp) { /* add inherited environment, */
- addenv (*envp, NULL); /* some variables change later */
- envp++;
- }
+ /*
+ * The entire environment will be preserved if the -p flag
+ * is used.
+ */
+ if (pflg) {
+ while (NULL != *envp) { /* add inherited environment, */
+ addenv (*envp, NULL); /* some variables change later */
+ envp++;
}
+ }
#ifdef RLOGIN
- if (term[0] != '\0') {
- addenv ("TERM", term);
- } else
-#endif
- {
- /* preserve TERM from getty */
- if (!pflg) {
- tmp = getenv ("TERM");
- if (NULL != tmp) {
- addenv ("TERM", tmp);
- }
+ if (term[0] != '\0') {
+ addenv ("TERM", term);
+ } else
+#endif /* RLOGIN */
+ {
+ /* preserve TERM from getty */
+ if (!pflg) {
+ tmp = getenv ("TERM");
+ if (NULL != tmp) {
+ addenv ("TERM", tmp);
}
}
+ }
- init_env ();
-
- if (optind < argc) { /* get the user name */
- if (rflg || (fflg && ('\0' != username[0]))) {
- usage ();
- }
+ init_env ();
- STRFCPY (username, argv[optind]);
- strzero (argv[optind]);
- ++optind;
- }
- if (optind < argc) { /* now set command line variables */
- set_env (argc - optind, &argv[optind]);
- }
+ if (optind < argc) { /* now set command line variables */
+ set_env (argc - optind, &argv[optind]);
+ }
- if (rflg || hflg) {
- cp = hostname;
- } else {
- /* FIXME: What is the priority:
- * UT_HOST or HAVE_UTMPX_H? */
-#ifdef UT_HOST
- if ('\0' != utent.ut_host[0]) {
- cp = utent.ut_host;
- } else
-#endif
-#if HAVE_UTMPX_H
- if ('\0' != utxent.ut_host[0]) {
- cp = utxent.ut_host;
- } else
-#endif
- {
- cp = "";
- }
- }
+ if (rflg || hflg) {
+ cp = hostname;
+#ifdef HAVE_STRUCT_UTMP_UT_HOST
+ } else if ((NULL != utent) && ('\0' != utent->ut_host[0])) {
+ cp = utent->ut_host;
+#endif /* HAVE_STRUCT_UTMP_UT_HOST */
+ } else {
+ cp = "";
+ }
- if ('\0' != *cp) {
- snprintf (fromhost, sizeof fromhost,
- " on '%.100s' from '%.200s'", tty, cp);
- } else {
- snprintf (fromhost, sizeof fromhost,
- " on '%.100s'", tty);
- }
+ if ('\0' != *cp) {
+ snprintf (fromhost, sizeof fromhost,
+ " on '%.100s' from '%.200s'", tty, cp);
+ } else {
+ snprintf (fromhost, sizeof fromhost,
+ " on '%.100s'", tty);
+ }
- top:
- /* only allow ALARM sec. for login */
- (void) signal (SIGALRM, alarm_handler);
- timeout = getdef_num ("LOGIN_TIMEOUT", ALARM);
- if (timeout > 0) {
- alarm (timeout);
- }
+ top:
+ /* only allow ALARM sec. for login */
+ (void) signal (SIGALRM, alarm_handler);
+ timeout = getdef_unum ("LOGIN_TIMEOUT", ALARM);
+ if (timeout > 0) {
+ (void) alarm (timeout);
+ }
- environ = newenvp; /* make new environment active */
- delay = getdef_num ("FAIL_DELAY", 1);
- retries = getdef_num ("LOGIN_RETRIES", RETRIES);
+ environ = newenvp; /* make new environment active */
+ delay = getdef_unum ("FAIL_DELAY", 1);
+ retries = getdef_unum ("LOGIN_RETRIES", RETRIES);
#ifdef USE_PAM
- retcode = pam_start ("login", username, &conv, &pamh);
- if (retcode != PAM_SUCCESS) {
- fprintf (stderr,
- _("login: PAM Failure, aborting: %s\n"),
- pam_strerror (pamh, retcode));
- SYSLOG ((LOG_ERR, "Couldn't initialize PAM: %s",
- pam_strerror (pamh, retcode)));
- exit (99);
- }
+ retcode = pam_start ("login", username, &conv, &pamh);
+ if (retcode != PAM_SUCCESS) {
+ fprintf (stderr,
+ _("login: PAM Failure, aborting: %s\n"),
+ pam_strerror (pamh, retcode));
+ SYSLOG ((LOG_ERR, "Couldn't initialize PAM: %s",
+ pam_strerror (pamh, retcode)));
+ exit (99);
+ }
- /*
- * hostname & tty are either set to NULL or their correct values,
- * depending on how much we know. We also set PAM's fail delay to
- * ours.
- */
- retcode = pam_set_item (pamh, PAM_RHOST, hostname);
- PAM_FAIL_CHECK;
- retcode = pam_set_item (pamh, PAM_TTY, tty);
- PAM_FAIL_CHECK;
+ /*
+ * hostname & tty are either set to NULL or their correct values,
+ * depending on how much we know. We also set PAM's fail delay to
+ * ours.
+ *
+ * PAM_RHOST and PAM_TTY are used for authentication, only use
+ * information coming from login or from the caller (e.g. no utmp)
+ */
+ retcode = pam_set_item (pamh, PAM_RHOST, hostname);
+ PAM_FAIL_CHECK;
+ retcode = pam_set_item (pamh, PAM_TTY, tty);
+ PAM_FAIL_CHECK;
#ifdef HAS_PAM_FAIL_DELAY
- retcode = pam_fail_delay (pamh, 1000000 * delay);
- PAM_FAIL_CHECK;
+ retcode = pam_fail_delay (pamh, 1000000 * delay);
+ PAM_FAIL_CHECK;
#endif
- /* if fflg, then the user has already been authenticated */
- if (!fflg || (getuid () != 0)) {
- int failcount = 0;
- char hostn[256];
- char loginprompt[256]; /* That's one hell of a prompt :) */
-
- /* Make the login prompt look like we want it */
- if (gethostname (hostn, sizeof (hostn)) == 0) {
- snprintf (loginprompt,
- sizeof (loginprompt),
- _("%s login: "), hostn);
- } else {
- snprintf (loginprompt,
- sizeof (loginprompt), _("login: "));
- }
+ /* if fflg, then the user has already been authenticated */
+ if (!fflg) {
+ unsigned int failcount = 0;
+ char hostn[256];
+ char loginprompt[256]; /* That's one hell of a prompt :) */
+
+ /* Make the login prompt look like we want it */
+ if (gethostname (hostn, sizeof (hostn)) == 0) {
+ snprintf (loginprompt,
+ sizeof (loginprompt),
+ _("%s login: "), hostn);
+ } else {
+ strncpy (loginprompt, _("login: "),
+ sizeof (loginprompt));
+ }
- retcode =
- pam_set_item (pamh, PAM_USER_PROMPT, loginprompt);
- PAM_FAIL_CHECK;
+ retcode = pam_set_item (pamh, PAM_USER_PROMPT, loginprompt);
+ PAM_FAIL_CHECK;
- /* if we didn't get a user on the command line,
- set it to NULL */
- pam_get_item (pamh, PAM_USER,
- (const void **)ptr_pam_user);
- if (pam_user[0] == '\0') {
- pam_set_item (pamh, PAM_USER, NULL);
- }
+ /* if we didn't get a user on the command line,
+ set it to NULL */
+ get_pam_user (&pam_user);
+ if ((NULL != pam_user) && ('\0' == pam_user[0])) {
+ retcode = pam_set_item (pamh, PAM_USER, NULL);
+ PAM_FAIL_CHECK;
+ }
- /*
- * There may be better ways to deal with some of
- * these conditions, but at least this way I don't
- * think we'll be giving away information. Perhaps
- * someday we can trust that all PAM modules will
- * pay attention to failure count and get rid of
- * MAX_LOGIN_TRIES?
- */
- failcount = 0;
- while (true) {
- const char *failent_user;
- failed = false;
+ /*
+ * There may be better ways to deal with some of
+ * these conditions, but at least this way I don't
+ * think we'll be giving away information. Perhaps
+ * someday we can trust that all PAM modules will
+ * pay attention to failure count and get rid of
+ * MAX_LOGIN_TRIES?
+ */
+ failcount = 0;
+ while (true) {
+ bool failed = false;
- failcount++;
+ failcount++;
#ifdef HAS_PAM_FAIL_DELAY
- if (delay > 0) {
- retcode = pam_fail_delay(pamh, 1000000*delay);
- }
+ if (delay > 0) {
+ retcode = pam_fail_delay(pamh, 1000000*delay);
+ PAM_FAIL_CHECK;
+ }
#endif
- retcode = pam_authenticate (pamh, 0);
-
- pam_get_item (pamh, PAM_USER,
- (const void **) ptr_pam_user);
-
- if ((NULL != pam_user) && ('\0' != pam_user[0])) {
- pwd = xgetpwnam(pam_user);
- if (NULL != pwd) {
- pwent = *pwd;
- failent_user = pwent.pw_name;
- } else {
- if ( getdef_bool("LOG_UNKFAIL_ENAB")
- && (NULL != pam_user)) {
- failent_user = pam_user;
- } else {
- failent_user = "UNKNOWN";
- }
- }
- } else {
- pwd = NULL;
- failent_user = "UNKNOWN";
- }
-
- if (retcode == PAM_MAXTRIES || failcount >= retries) {
- SYSLOG ((LOG_NOTICE,
- "TOO MANY LOGIN TRIES (%d)%s FOR '%s'",
- failcount, fromhost, failent_user));
- fprintf(stderr,
- _("Maximum number of tries exceeded (%d)\n"),
- failcount);
- PAM_END;
- exit(0);
- } else if (retcode == PAM_ABORT) {
- /* Serious problems, quit now */
- fputs (_("login: abort requested by PAM\n"),stderr);
- SYSLOG ((LOG_ERR,"PAM_ABORT returned from pam_authenticate()"));
- PAM_END;
- exit(99);
- } else if (retcode != PAM_SUCCESS) {
- SYSLOG ((LOG_NOTICE,"FAILED LOGIN (%d)%s FOR '%s', %s",
- failcount, fromhost, failent_user,
- pam_strerror (pamh, retcode)));
- failed = true;
- }
-
- if (!failed) {
- break;
- }
-
-#ifdef WITH_AUDIT
- audit_fd = audit_open ();
- audit_log_acct_message (audit_fd,
- AUDIT_USER_LOGIN,
- NULL, /* Prog. name */
- "login",
- failent_user,
- AUDIT_NO_ID,
- hostname,
- NULL, /* addr */
- tty,
- 0); /* result */
- close (audit_fd);
-#endif /* WITH_AUDIT */
-
- fprintf (stderr, "\nLogin incorrect\n");
-
- /* Let's give it another go around */
- pam_set_item (pamh, PAM_USER, NULL);
+ retcode = pam_authenticate (pamh, 0);
+
+ get_pam_user (&pam_user);
+ failent_user = get_failent_user (pam_user);
+
+ if (retcode == PAM_MAXTRIES) {
+ SYSLOG ((LOG_NOTICE,
+ "TOO MANY LOGIN TRIES (%u)%s FOR '%s'",
+ failcount, fromhost, failent_user));
+ fprintf(stderr,
+ _("Maximum number of tries exceeded (%u)\n"),
+ failcount);
+ PAM_END;
+ exit(0);
+ } else if (retcode == PAM_ABORT) {
+ /* Serious problems, quit now */
+ (void) fputs (_("login: abort requested by PAM\n"), stderr);
+ SYSLOG ((LOG_ERR,"PAM_ABORT returned from pam_authenticate()"));
+ PAM_END;
+ exit(99);
+ } else if (retcode != PAM_SUCCESS) {
+ SYSLOG ((LOG_NOTICE,"FAILED LOGIN (%u)%s FOR '%s', %s",
+ failcount, fromhost, failent_user,
+ pam_strerror (pamh, retcode)));
+ failed = true;
}
- /* We don't get here unless they were authenticated above */
- alarm (0);
- retcode = pam_acct_mgmt (pamh, 0);
-
- if (retcode == PAM_NEW_AUTHTOK_REQD) {
- retcode =
- pam_chauthtok (pamh,
- PAM_CHANGE_EXPIRED_AUTHTOK);
+ if (!failed) {
+ break;
}
- PAM_FAIL_CHECK;
- }
+#ifdef WITH_AUDIT
+ audit_fd = audit_open ();
+ audit_log_acct_message (audit_fd,
+ AUDIT_USER_LOGIN,
+ NULL, /* Prog. name */
+ "login",
+ failent_user,
+ AUDIT_NO_ID,
+ hostname,
+ NULL, /* addr */
+ tty,
+ 0); /* result */
+ close (audit_fd);
+#endif /* WITH_AUDIT */
- /* Grab the user information out of the password file for future usage
- First get the username that we are actually using, though.
- */
- retcode =
- pam_get_item (pamh, PAM_USER, (const void **)ptr_pam_user);
- pwd = xgetpwnam (pam_user);
- if (NULL == pwd) {
- SYSLOG ((LOG_ERR, "xgetpwnam(%s) failed",
- getdef_bool ("LOG_UNKFAIL_ENAB") ?
- pam_user : "UNKNOWN"));
- exit (1);
- }
+ (void) puts ("");
+ (void) puts (_("Login incorrect"));
+
+ if (failcount >= retries) {
+ SYSLOG ((LOG_NOTICE,
+ "TOO MANY LOGIN TRIES (%u)%s FOR '%s'",
+ failcount, fromhost, failent_user));
+ fprintf(stderr,
+ _("Maximum number of tries exceeded (%u)\n"),
+ failcount);
+ PAM_END;
+ exit(0);
+ }
- if (fflg) {
- retcode = pam_acct_mgmt (pamh, 0);
+ /*
+ * Let's give it another go around.
+ * Even if a username was given on the command
+ * line, prompt again for the username.
+ */
+ retcode = pam_set_item (pamh, PAM_USER, NULL);
PAM_FAIL_CHECK;
}
- if (setup_groups (pwd) != 0) {
- exit (1);
- }
+ /* We don't get here unless they were authenticated above */
+ (void) alarm (0);
+ }
- pwent = *pwd;
+ /* Check the account validity */
+ retcode = pam_acct_mgmt (pamh, 0);
+ if (retcode == PAM_NEW_AUTHTOK_REQD) {
+ retcode = pam_chauthtok (pamh, PAM_CHANGE_EXPIRED_AUTHTOK);
+ }
+ PAM_FAIL_CHECK;
+
+ /* Open the PAM session */
+ get_pam_user (&pam_user);
+ retcode = pam_open_session (pamh, hushed (pam_user) ? PAM_SILENT : 0);
+ PAM_FAIL_CHECK;
+
+ /* Grab the user information out of the password file for future usage
+ * First get the username that we are actually using, though.
+ *
+ * From now on, we will discard changes of the user (PAM_USER) by
+ * PAM APIs.
+ */
+ get_pam_user (&pam_user);
+ if (NULL != username) {
+ free (username);
+ }
+ username = pam_user;
+ failent_user = get_failent_user (username);
- retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED);
- PAM_FAIL_CHECK;
+ pwd = xgetpwnam (username);
+ if (NULL == pwd) {
+ SYSLOG ((LOG_ERR, "cannot find user %s", failent_user));
+ exit (1);
+ }
- retcode = pam_open_session (pamh,
- hushed (&pwent) ? PAM_SILENT : 0);
- PAM_FAIL_CHECK;
+ /* This set up the process credential (group) and initialize the
+ * supplementary group access list.
+ * This has to be done before pam_setcred
+ */
+ if (setup_groups (pwd) != 0) {
+ exit (1);
+ }
- pwd = xgetpwnam (pam_user);
- if (NULL == pwd) {
- pwent.pw_name = pam_user;
- strcpy (temp_pw, "!");
- pwent.pw_passwd = temp_pw;
- pwent.pw_shell = temp_shell;
+ retcode = pam_setcred (pamh, PAM_ESTABLISH_CRED);
+ PAM_FAIL_CHECK;
+ /* NOTE: If pam_setcred changes PAM_USER, this will not be taken
+ * into account.
+ */
- preauth_flag = false;
- failed = true;
- } else {
- pwent = *pwd;
+#else /* ! USE_PAM */
+ while (true) { /* repeatedly get login/password pairs */
+ bool failed;
+ /* user_passwd is always a pointer to this constant string
+ * or a passwd or shadow password that will be memzero by
+ * pw_free / spw_free.
+ * Do not free() user_passwd. */
+ const char *user_passwd = "!";
+
+ /* Do some cleanup to avoid keeping entries we do not need
+ * anymore. */
+ if (NULL != pwd) {
+ pw_free (pwd);
+ pwd = NULL;
+ }
+ if (NULL != spwd) {
+ spw_free (spwd);
+ spwd = NULL;
}
-#else /* ! USE_PAM */
- while (true) { /* repeatedly get login/password pairs */
- failed = false; /* haven't failed authentication yet */
- if ('\0' == username[0]) { /* need to get a login id */
- if (subroot) {
- closelog ();
- exit (1);
- }
- preauth_flag = false;
- login_prompt (_("\n%s login: "), username,
- sizeof username);
+ failed = false; /* haven't failed authentication yet */
+ if (NULL == username) { /* need to get a login id */
+ if (subroot) {
+ closelog ();
+ exit (1);
+ }
+ preauth_flag = false;
+ username = xmalloc (USER_NAME_MAX_LENGTH + 1);
+ username[USER_NAME_MAX_LENGTH] = '\0';
+ login_prompt (_("\n%s login: "), username, USER_NAME_MAX_LENGTH);
+
+ if ('\0' == username[0]) {
+ /* Prompt for a new login */
+ free (username);
+ username = NULL;
continue;
}
+ }
+ /* Get the username to be used to log failures */
+ failent_user = get_failent_user (username);
pwd = xgetpwnam (username);
if (NULL == pwd) {
- pwent.pw_name = username;
- strcpy (temp_pw, "!");
- pwent.pw_passwd = temp_pw;
- pwent.pw_shell = temp_shell;
-
preauth_flag = false;
failed = true;
} else {
- pwent = *pwd;
+ user_passwd = pwd->pw_passwd;
+ /*
+ * If the encrypted password begins with a "!",
+ * the account is locked and the user cannot
+ * login, even if they have been
+ * "pre-authenticated."
+ */
+ if ( ('!' == user_passwd[0])
+ || ('*' == user_passwd[0])) {
+ failed = true;
+ }
}
- spwd = NULL;
- if ( (NULL != pwd)
- && (strcmp (pwd->pw_passwd, SHADOW_PASSWD_STRING) == 0)) {
- /* !USE_PAM, no need for xgetspnam */
- spwd = getspnam (username);
+ if (strcmp (user_passwd, SHADOW_PASSWD_STRING) == 0) {
+ spwd = xgetspnam (username);
if (NULL != spwd) {
- pwent.pw_passwd = spwd->sp_pwdp;
+ user_passwd = spwd->sp_pwdp;
} else {
+ /* The user exists in passwd, but not in
+ * shadow. SHADOW_PASSWD_STRING indicates
+ * that the password shall be in shadow.
+ */
SYSLOG ((LOG_WARN,
- "no shadow password for '%s'%s",
- username, fromhost));
+ "no shadow password for '%s'%s",
+ username, fromhost));
}
}
- /*
- * If the encrypted password begins with a "!", the account
- * is locked and the user cannot login, even if they have
- * been "pre-authenticated."
- */
- if ( ('!' == pwent.pw_passwd[0])
- || ('*' == pwent.pw_passwd[0])) {
- failed = true;
- }
-
/*
* The -r and -f flags provide a name which has already
* been authenticated by some server.
goto auth_ok;
}
- if (pw_auth (pwent.pw_passwd, username,
- reason, (char *) 0) == 0) {
+ if (pw_auth (user_passwd, username, reason, (char *) 0) == 0) {
goto auth_ok;
}
- /*
- * Don't log unknown usernames - I mistyped the password for
- * username at least once. Should probably use LOG_AUTHPRIV
- * for those who really want to log them. --marekm
- */
SYSLOG ((LOG_WARN, "invalid password for '%s' %s",
- ( (NULL != pwd)
- || getdef_bool ("LOG_UNKFAIL_ENAB")) ?
- username : "UNKNOWN", fromhost));
+ failent_user, fromhost));
failed = true;
auth_ok:
* authenticated and so on.
*/
if ( !failed
- && (NULL != pwent.pw_name)
- && (0 == pwent.pw_uid)
+ && (NULL != pwd)
+ && (0 == pwd->pw_uid)
&& !is_console) {
SYSLOG ((LOG_CRIT, "ILLEGAL ROOT LOGIN %s", fromhost));
failed = true;
}
if ( !failed
- && !login_access (username, *hostname ? hostname : tty)) {
+ && !login_access (username, ('\0' != *hostname) ? hostname : tty)) {
SYSLOG ((LOG_WARN, "LOGIN '%s' REFUSED %s",
- username, fromhost));
+ username, fromhost));
failed = true;
}
if ( (NULL != pwd)
&& getdef_bool ("FAILLOG_ENAB")
- && !failcheck (pwent.pw_uid, &faillog, failed)) {
+ && !failcheck (pwd->pw_uid, &faillog, failed)) {
SYSLOG ((LOG_CRIT,
- "exceeded failure limit for '%s' %s",
- username, fromhost));
+ "exceeded failure limit for '%s' %s",
+ username, fromhost));
failed = true;
}
if (!failed) {
/* don't log non-existent users */
if ((NULL != pwd) && getdef_bool ("FAILLOG_ENAB")) {
- failure (pwent.pw_uid, tty, &faillog);
+ failure (pwd->pw_uid, tty, &faillog);
}
if (getdef_str ("FTMP_FILE") != NULL) {
- const char *failent_user;
-
-#if HAVE_UTMPX_H
- failent = utxent;
- if (sizeof (failent.ut_tv) == sizeof (struct timeval)) {
- gettimeofday ((struct timeval *) &failent.ut_tv,
- NULL);
- } else {
- struct timeval tv;
-
- gettimeofday (&tv, NULL);
- failent.ut_tv.tv_sec = tv.tv_sec;
- failent.ut_tv.tv_usec = tv.tv_usec;
- }
-#else
- failent = utent;
- failent.ut_time = time (NULL);
-#endif
- if (NULL != pwd) {
- failent_user = pwent.pw_name;
- } else {
- if (getdef_bool ("LOG_UNKFAIL_ENAB")) {
- failent_user = username;
- } else {
- failent_user = "UNKNOWN";
- }
- }
- strncpy (failent.ut_user, failent_user,
- sizeof (failent.ut_user));
- failent.ut_type = USER_PROCESS;
- failtmp (&failent);
+#ifdef USE_UTMPX
+ struct utmpx *failent =
+ prepare_utmpx (failent_user,
+ tty,
+ /* FIXME: or fromhost? */hostname,
+ utent);
+#else /* !USE_UTMPX */
+ struct utmp *failent =
+ prepare_utmp (failent_user,
+ tty,
+ hostname,
+ utent);
+#endif /* !USE_UTMPX */
+ failtmp (failent_user, failent);
+ free (failent);
}
- memzero (username, sizeof username);
retries--;
if (retries <= 0) {
SYSLOG ((LOG_CRIT, "REPEATED login failures%s",
- fromhost));
+ fromhost));
}
+
/*
* If this was a passwordless account and we get here, login
* was denied (securetty, faillog, etc.). There was no
* guys won't see that the passwordless account exists at
* all). --marekm
*/
- if (pwent.pw_passwd[0] == '\0') {
+ if (user_passwd[0] == '\0') {
pw_auth ("!", username, reason, (char *) 0);
}
+ /*
+ * Authentication of this user failed.
+ * The username must be confirmed in the next try.
+ */
+ free (username);
+ username = NULL;
+
/*
* Wait a while (a la SVR4 /usr/bin/login) before attempting
* to login the user again. If the earlier alarm occurs
* before the sleep() below completes, login will exit.
*/
if (delay > 0) {
- sleep (delay);
+ (void) sleep (delay);
}
- puts (_("Login incorrect"));
+ (void) puts (_("Login incorrect"));
/* allow only one attempt with -r or -f */
if (rflg || fflg || (retries <= 0)) {
}
} /* while (true) */
#endif /* ! USE_PAM */
+ assert (NULL != username);
+ assert (NULL != pwd);
- alarm (0); /* turn off alarm clock */
+ (void) alarm (0); /* turn off alarm clock */
#ifndef USE_PAM /* PAM does this */
/*
* by Ivan Nejgebauer <ian@unsux.ns.ac.yu>. --marekm
*/
if ( getdef_bool ("PORTTIME_CHECKS_ENAB")
- && !isttytime (pwent.pw_name, tty, time ((time_t *) 0))) {
+ && !isttytime (username, tty, time ((time_t *) 0))) {
SYSLOG ((LOG_WARN, "invalid login time for '%s'%s",
- username, fromhost));
+ username, fromhost));
closelog ();
bad_time_notify ();
exit (1);
}
- check_nologin ();
+ check_nologin (pwd->pw_uid == 0);
#endif
if (getenv ("IFS")) { /* don't export user IFS ... */
addenv ("IFS= \t\n", NULL); /* ... instead, set a safe IFS */
}
-#ifdef USE_PAM
- setutmp (pam_user, tty, hostname); /* make entry in utmp & wtmp files */
-#else
- setutmp (username, tty, hostname); /* make entry in utmp & wtmp files */
-#endif
- if (pwent.pw_shell[0] == '*') { /* subsystem root */
- pwent.pw_shell++; /* skip the '*' */
- subsystem (&pwent); /* figure out what to execute */
+ if (pwd->pw_shell[0] == '*') { /* subsystem root */
+ pwd->pw_shell++; /* skip the '*' */
+ subsystem (pwd); /* figure out what to execute */
subroot = true; /* say I was here again */
endpwent (); /* close all of the file which were */
endgrent (); /* open in the original rooted file */
AUDIT_USER_LOGIN,
NULL, /* Prog. name */
"login",
- pwd->pw_name,
+ username,
AUDIT_NO_ID,
hostname,
NULL, /* addr */
#ifndef USE_PAM /* pam_lastlog handles this */
if (getdef_bool ("LASTLOG_ENAB")) { /* give last login and log this one */
- dolastlog (&lastlog, &pwent, utent.ut_line, hostname);
+ dolastlog (&ll, pwd, tty, hostname);
}
#endif
#ifndef USE_PAM /* PAM handles this as well */
/*
* Have to do this while we still have root privileges, otherwise we
- * don't have access to /etc/shadow. expire() closes password files,
- * and changes to the user in the child before executing the passwd
- * program. --marekm
+ * don't have access to /etc/shadow.
*/
- if (spwd) { /* check for age of password */
- if (expire (&pwent, spwd)) {
- /* !USE_PAM, no need for xgetpwnam */
- pwd = getpwnam (username);
- /* !USE_PAM, no need for xgetspnam */
- spwd = getspnam (username);
- if (pwd) {
- pwent = *pwd;
+ if (NULL != spwd) { /* check for age of password */
+ if (expire (pwd, spwd)) {
+ /* The user updated her password, get the new
+ * entries.
+ * Use the x variants because we need to keep the
+ * entry for a long time, and there might be other
+ * getxxyy in between.
+ */
+ pw_free (pwd);
+ pwd = xgetpwnam (username);
+ if (NULL == pwd) {
+ SYSLOG ((LOG_ERR,
+ "cannot find user %s after update of expired password",
+ username));
+ exit (1);
}
+ spw_free (spwd);
+ spwd = xgetspnam (username);
}
}
- setup_limits (&pwent); /* nice, ulimit etc. */
+ setup_limits (pwd); /* nice, ulimit etc. */
#endif /* ! USE_PAM */
- chown_tty (tty, &pwent);
+ chown_tty (pwd);
#ifdef USE_PAM
/*
if (child < 0) {
/* error in fork() */
fprintf (stderr, _("%s: failure forking: %s"),
- Prog, strerror (errno));
+ Prog, strerror (errno));
PAM_END;
exit (0);
} else if (child != 0) {
}
/* child */
#endif
+
/* If we were init, we need to start a new session */
if (getppid() == 1) {
setsid();
if (ioctl(0, TIOCSCTTY, 1) != 0) {
- fprintf (stderr,_("TIOCSCTTY failed on %s"),tty);
+ fprintf (stderr, _("TIOCSCTTY failed on %s"), tty);
}
}
- /* We call set_groups() above because this clobbers pam_groups.so */
#ifndef USE_PAM
- if (setup_uid_gid (&pwent, is_console))
+ /*
+ * The utmp entry needs to be updated to indicate the new status
+ * of the session, the new PID and SID.
+ */
+ update_utmp (username, tty, hostname, utent);
+#endif /* ! USE_PAM */
+
+ /* The pwd and spwd entries for the user have been copied.
+ *
+ * Close all the files so that unauthorized access won't occur.
+ */
+ endpwent (); /* stop access to password file */
+ endgrent (); /* stop access to group file */
+ endspent (); /* stop access to shadow passwd file */
+#ifdef SHADOWGRP
+ endsgent (); /* stop access to shadow group file */
+#endif
+
+ /* Drop root privileges */
+#ifndef USE_PAM
+ if (setup_uid_gid (pwd, is_console))
#else
- if (change_uid (&pwent))
+ /* The group privileges were already dropped.
+ * See setup_groups() above.
+ */
+ if (change_uid (pwd))
#endif
{
exit (1);
}
- setup_env (&pwent); /* set env vars, cd to the home dir */
+ setup_env (pwd); /* set env vars, cd to the home dir */
#ifdef USE_PAM
{
(void) bindtextdomain (PACKAGE, LOCALEDIR);
(void) textdomain (PACKAGE);
- if (!hushed (&pwent)) {
+ if (!hushed (username)) {
addenv ("HUSHLOGIN=FALSE", NULL);
/*
* pam_unix, pam_mail and pam_lastlog should take care of
/* Reset the lockout times if logged in */
if ( (0 != faillog.fail_max)
&& (faillog.fail_cnt >= faillog.fail_max)) {
- puts (_
- ("Warning: login re-enabled after temporary lockout."));
+ (void) puts (_("Warning: login re-enabled after temporary lockout."));
SYSLOG ((LOG_WARN,
- "login '%s' re-enabled after temporary lockout (%d failures)",
- username, (int) faillog.fail_cnt));
+ "login '%s' re-enabled after temporary lockout (%d failures)",
+ username, (int) faillog.fail_cnt));
}
}
if ( getdef_bool ("LASTLOG_ENAB")
- && (lastlog.ll_time != 0)) {
- time_t ll_time = lastlog.ll_time;
+ && (ll.ll_time != 0)) {
+ time_t ll_time = ll.ll_time;
#ifdef HAVE_STRFTIME
- strftime (ptime, sizeof (ptime),
- "%a %b %e %H:%M:%S %z %Y",
- localtime (&ll_time));
+ (void) strftime (ptime, sizeof (ptime),
+ "%a %b %e %H:%M:%S %z %Y",
+ localtime (&ll_time));
printf (_("Last login: %s on %s"),
- ptime, lastlog.ll_line);
+ ptime, ll.ll_line);
#else
printf (_("Last login: %.19s on %s"),
- ctime (&ll_time), lastlog.ll_line);
+ ctime (&ll_time), ll.ll_line);
#endif
#ifdef HAVE_LL_HOST /* __linux__ || SUN4 */
- if ('\0' != lastlog.ll_host[0]) {
+ if ('\0' != ll.ll_host[0]) {
printf (_(" from %.*s"),
- (int) sizeof lastlog.
- ll_host, lastlog.ll_host);
+ (int) sizeof ll.ll_host, ll.ll_host);
}
#endif
printf (".\n");
}
- agecheck (&pwent, spwd);
+ agecheck (spwd);
mailcheck (); /* report on the status of mail */
#endif /* !USE_PAM */
addenv ("HUSHLOGIN=TRUE", NULL);
}
- if ( (NULL != getdef_str ("TTYTYPE_FILE"))
- && (NULL == getenv ("TERM"))) {
- ttytype (tty);
- }
+ ttytype (tty);
(void) signal (SIGQUIT, SIG_DFL); /* default quit signal */
(void) signal (SIGTERM, SIG_DFL); /* default terminate signal */
(void) signal (SIGHUP, SIG_DFL); /* added this. --marekm */
(void) signal (SIGINT, SIG_DFL); /* default interrupt signal */
- endpwent (); /* stop access to password file */
- endgrent (); /* stop access to group file */
- endspent (); /* stop access to shadow passwd file */
-#ifdef SHADOWGRP
- endsgent (); /* stop access to shadow group file */
-#endif
- if (0 == pwent.pw_uid) {
+ if (0 == pwd->pw_uid) {
SYSLOG ((LOG_NOTICE, "ROOT LOGIN %s", fromhost));
} else if (getdef_bool ("LOG_OK_LOGINS")) {
-#ifdef USE_PAM
- SYSLOG ((LOG_INFO, "'%s' logged in %s", pam_user, fromhost));
-#else
SYSLOG ((LOG_INFO, "'%s' logged in %s", username, fromhost));
-#endif
}
closelog ();
tmp = getdef_str ("FAKE_SHELL");
if (NULL != tmp) {
- err = shell (tmp, pwent.pw_shell, newenvp); /* fake shell */
+ err = shell (tmp, pwd->pw_shell, newenvp); /* fake shell */
} else {
/* exec the shell finally */
- err = shell (pwent.pw_shell, (char *) 0, newenvp);
+ err = shell (pwd->pw_shell, (char *) 0, newenvp);
}
- exit (err == ENOENT ? E_CMD_NOTFOUND : E_CMD_NOEXEC);
- /* NOT REACHED */
- return 0;
+
+ return ((err == ENOENT) ? E_CMD_NOTFOUND : E_CMD_NOEXEC);
}