* Copyright (c) 1989 - 1994, Julianne Frances Haugh
* Copyright (c) 1996 - 2001, Marek Michałkiewicz
* Copyright (c) 2001 - 2006, Tomasz Kłoczko
- * Copyright (c) 2007 - 2009, 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 "getdef.h"
#include "prototypes.h"
#include "pwauth.h"
+/*@-exitarg@*/
#include "exitcodes.h"
+
#ifdef USE_PAM
#include "pam_defs.h"
/*
* Global variables
*/
-char *Prog;
+const char *Prog;
static const char *hostname = "";
-static char *username = NULL;
+static /*@null@*/ /*@only@*/char *username = NULL;
static int reason = PW_LOGIN;
#ifndef USE_PAM
/* local function prototypes */
static void usage (void);
static void setup_tty (void);
-static void process_flags (int, char *const *);
-static const char *get_failent_user (const char *user);
-static void update_utmp (const char *username,
+static void process_flags (int argc, char *const *argv);
+static /*@observer@*/const char *get_failent_user (/*@returned@*/const char *user);
+static void update_utmp (const char *user,
const char *tty,
- const char *hostname,
- const struct utmp *utent);
+ const char *host,
+ /*@null@*/const struct utmp *utent);
#ifndef USE_PAM
static struct faillog faillog;
static void setup_tty (void)
{
TERMIO termio;
- int erasechar;
- int killchar;
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;
#if defined(ECHOKE) && defined(ECHOCTL)
- termio.c_lflag |= ECHOKE | ECHOCTL;
+ termio.c_lflag |= ECHOKE | ECHOCTL;
#endif
#if defined(ECHOPRT) && defined(NOFLSH) && defined(TOSTOP)
- termio.c_lflag &= ~(ECHOPRT | NOFLSH | TOSTOP);
+ termio.c_lflag &= ~(ECHOPRT | NOFLSH | TOSTOP);
#endif
#ifdef ONLCR
- termio.c_oflag |= ONLCR;
+ termio.c_oflag |= ONLCR;
#endif
- /* 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 != termio.c_cc[VERASE]) {
- fprintf (stderr,
- _("configuration error - cannot parse %s value: '%d'"),
- "ERASECHAR", erasechar);
- exit (1);
- }
- if (killchar != termio.c_cc[VKILL]) {
- fprintf (stderr,
- _("configuration error - cannot parse %s value: '%d'"),
- "KILLCHAR", killchar);
- exit (1);
- }
+ /* 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);
+ /*
+ * ttymon invocation prefers this, but these settings
+ * won't come into effect after the first username login
+ */
+ (void) STTY (0, &termio);
}
}
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');
* Get the user name.
*/
if (optind < argc) {
+ assert (NULL == username);
username = xstrdup (argv[optind]);
strzero (argv[optind]);
++optind;
* It is quite common to mistyped the password for username, and passwords
* should not be logged.
*/
-static const char *get_failent_user (const char *user)
+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");
* utent should be the utmp entry returned by get_current_utmp (or
* NULL).
*/
-static void update_utmp (const char *username,
+static void update_utmp (const char *user,
const char *tty,
- const char *hostname,
+ const char *host,
/*@null@*/const struct utmp *utent)
{
- struct utmp *ut = prepare_utmp (username, tty, hostname, utent);
-#ifdef HAVE_UTMPX_H
- struct utmpx *utx = prepare_utmpx (username, tty, hostname, utent);
-#endif /* HAVE_UTMPX_H */
+ 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 HAVE_UTMPX_H
+#ifdef USE_UTMPX
(void) setutmpx (utx); /* make entry in the utmpx & wtmpx files */
free (utx);
-#endif /* HAVE_UTMPX_H */
+#endif /* USE_UTMPX */
}
/*
#endif
unsigned int delay;
unsigned int retries;
- bool failed;
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 = NULL;
char **envp = environ;
const char *failent_user;
- struct utmp *utent;
+ /*@null@*/struct utmp *utent;
#ifdef USE_PAM
int retcode;
}
#ifdef RLOGIN
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)) {
#endif
/* if fflg, then the user has already been authenticated */
if (!fflg) {
- int failcount = 0;
+ unsigned int failcount = 0;
char hostn[256];
char loginprompt[256]; /* That's one hell of a prompt :) */
sizeof (loginprompt),
_("%s login: "), hostn);
} else {
- snprintf (loginprompt,
- sizeof (loginprompt), _("login: "));
+ strncpy (loginprompt, _("login: "),
+ sizeof (loginprompt));
}
retcode = pam_set_item (pamh, PAM_USER_PROMPT, loginprompt);
*/
failcount = 0;
while (true) {
- failed = false;
+ bool failed = false;
failcount++;
#ifdef HAS_PAM_FAIL_DELAY
if (retcode == PAM_MAXTRIES) {
SYSLOG ((LOG_NOTICE,
- "TOO MANY LOGIN TRIES (%d)%s FOR '%s'",
+ "TOO MANY LOGIN TRIES (%u)%s FOR '%s'",
failcount, fromhost, failent_user));
fprintf(stderr,
- _("Maximum number of tries exceeded (%d)\n"),
+ _("Maximum number of tries exceeded (%u)\n"),
failcount);
PAM_END;
exit(0);
PAM_END;
exit(99);
} else if (retcode != PAM_SUCCESS) {
- SYSLOG ((LOG_NOTICE,"FAILED LOGIN (%d)%s FOR '%s', %s",
+ SYSLOG ((LOG_NOTICE,"FAILED LOGIN (%u)%s FOR '%s', %s",
failcount, fromhost, failent_user,
pam_strerror (pamh, retcode)));
failed = true;
close (audit_fd);
#endif /* WITH_AUDIT */
- fprintf (stderr, "\nLogin incorrect\n");
+ (void) puts ("");
+ (void) puts (_("Login incorrect"));
if (failcount >= retries) {
SYSLOG ((LOG_NOTICE,
- "TOO MANY LOGIN TRIES (%d)%s FOR '%s'",
+ "TOO MANY LOGIN TRIES (%u)%s FOR '%s'",
failcount, fromhost, failent_user));
fprintf(stderr,
- _("Maximum number of tries exceeded (%d)\n"),
+ _("Maximum number of tries exceeded (%u)\n"),
failcount);
PAM_END;
exit(0);
#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.
* anymore. */
if (NULL != pwd) {
pw_free (pwd);
+ pwd = NULL;
}
if (NULL != spwd) {
spw_free (spwd);
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));
failed = true;
failure (pwd->pw_uid, tty, &faillog);
}
if (getdef_str ("FTMP_FILE") != NULL) {
-#ifdef HAVE_UTMPX_H
+#ifdef USE_UTMPX
struct utmpx *failent =
prepare_utmpx (failent_user,
tty,
/* FIXME: or fromhost? */hostname,
utent);
-#else
+#else /* !USE_UTMPX */
struct utmp *failent =
prepare_utmp (failent_user,
tty,
hostname,
utent);
-#endif
+#endif /* !USE_UTMPX */
failtmp (failent_user, failent);
free (failent);
}
}
} /* while (true) */
#endif /* ! USE_PAM */
+ assert (NULL != username);
+ assert (NULL != pwd);
(void) alarm (0); /* turn off alarm clock */
addenv ("IFS= \t\n", NULL); /* ... instead, set a safe IFS */
}
- update_utmp (username, tty, hostname, utent);
-
if (pwd->pw_shell[0] == '*') { /* subsystem root */
pwd->pw_shell++; /* skip the '*' */
subsystem (pwd); /* figure out what to execute */
}
/* child */
#endif
+
/* If we were init, we need to start a new session */
if (getppid() == 1) {
setsid();
}
}
+ /*
+ * 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);
/* The pwd and spwd entries for the user have been copied.
*
/* exec the shell finally */
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);
}