summaryrefslogtreecommitdiff
path: root/Linux-PAM/modules/pam_lastlog/pam_lastlog.c
diff options
context:
space:
mode:
Diffstat (limited to 'Linux-PAM/modules/pam_lastlog/pam_lastlog.c')
-rw-r--r--Linux-PAM/modules/pam_lastlog/pam_lastlog.c510
1 files changed, 246 insertions, 264 deletions
diff --git a/Linux-PAM/modules/pam_lastlog/pam_lastlog.c b/Linux-PAM/modules/pam_lastlog/pam_lastlog.c
index c9c5e24e..a75e1ce7 100644
--- a/Linux-PAM/modules/pam_lastlog/pam_lastlog.c
+++ b/Linux-PAM/modules/pam_lastlog/pam_lastlog.c
@@ -1,8 +1,6 @@
/* pam_lastlog module */
/*
- * $Id: pam_lastlog.c,v 1.8 2004/09/24 13:13:20 kukuk Exp $
- *
* Written by Andrew Morgan <morgan@linux.kernel.org> 1996/3/11
*
* This module does the necessary work to display the last login
@@ -10,10 +8,11 @@
* present (login) service.
*/
-#include <security/_pam_aconf.h>
+#include "config.h"
#include <fcntl.h>
#include <time.h>
+#include <errno.h>
#ifdef HAVE_UTMP_H
# include <utmp.h>
#else
@@ -28,10 +27,6 @@
#include <syslog.h>
#include <unistd.h>
-#ifdef WANT_PWDB
-#include <pwdb/pwdb_public.h> /* use POSIX front end */
-#endif
-
#if defined(hpux) || defined(sunos) || defined(solaris)
# ifndef _PATH_LASTLOG
# define _PATH_LASTLOG "/usr/adm/lastlog"
@@ -56,17 +51,6 @@ struct lastlog {
#define DEFAULT_HOST "" /* "[no.where]" */
#define DEFAULT_TERM "" /* "tt???" */
-#define LASTLOG_NEVER_WELCOME "Welcome to your new account!"
-#define LASTLOG_INTRO "Last login:"
-#define LASTLOG_TIME " %s"
-#define _LASTLOG_HOST_FORMAT " from %%.%ds"
-#define _LASTLOG_LINE_FORMAT " on %%.%ds"
-#define LASTLOG_TAIL ""
-#define LASTLOG_MAXSIZE (sizeof(LASTLOG_INTRO)+0 \
- +sizeof(LASTLOG_TIME)+strlen(the_time) \
- +sizeof(_LASTLOG_HOST_FORMAT)+UT_HOSTSIZE \
- +sizeof(_LASTLOG_LINE_FORMAT)+UT_LINESIZE \
- +sizeof(LASTLOG_TAIL))
/*
* here, we make a definition for the externally accessible function
@@ -79,20 +63,8 @@ struct lastlog {
#include <security/pam_modules.h>
#include <security/_pam_macros.h>
-#include <security/_pam_modutil.h>
-
-/* some syslogging */
-
-static void _log_err(int err, const char *format, ...)
-{
- va_list args;
-
- va_start(args, format);
- openlog("PAM-lastlog", LOG_CONS|LOG_PID, LOG_AUTH);
- vsyslog(err, format, args);
- va_end(args);
- closelog();
-}
+#include <security/pam_modutil.h>
+#include <security/pam_ext.h>
/* argument parsing */
@@ -102,10 +74,12 @@ static void _log_err(int err, const char *format, ...)
#define LASTLOG_NEVER 010 /* display a welcome message for first login */
#define LASTLOG_DEBUG 020 /* send info to syslog(3) */
#define LASTLOG_QUIET 040 /* keep quiet about things */
+#define LASTLOG_WTMP 0100 /* log to wtmp as well as lastlog */
-static int _pam_parse(int flags, int argc, const char **argv)
+static int
+_pam_parse(pam_handle_t *pamh, int flags, int argc, const char **argv)
{
- int ctrl=(LASTLOG_DATE|LASTLOG_HOST|LASTLOG_LINE);
+ int ctrl=(LASTLOG_DATE|LASTLOG_HOST|LASTLOG_LINE|LASTLOG_WTMP);
/* does the appliction require quiet? */
if (flags & PAM_SILENT) {
@@ -120,17 +94,19 @@ static int _pam_parse(int flags, int argc, const char **argv)
if (!strcmp(*argv,"debug")) {
ctrl |= LASTLOG_DEBUG;
} else if (!strcmp(*argv,"nodate")) {
- ctrl |= ~LASTLOG_DATE;
+ ctrl &= ~LASTLOG_DATE;
} else if (!strcmp(*argv,"noterm")) {
- ctrl |= ~LASTLOG_LINE;
+ ctrl &= ~LASTLOG_LINE;
} else if (!strcmp(*argv,"nohost")) {
- ctrl |= ~LASTLOG_HOST;
+ ctrl &= ~LASTLOG_HOST;
} else if (!strcmp(*argv,"silent")) {
ctrl |= LASTLOG_QUIET;
} else if (!strcmp(*argv,"never")) {
ctrl |= LASTLOG_NEVER;
+ } else if (!strcmp(*argv,"nowtmp")) {
+ ctrl &= ~LASTLOG_WTMP;
} else {
- _log_err(LOG_ERR,"unknown option; %s",*argv);
+ pam_syslog(pamh, LOG_ERR, "unknown option: %s", *argv);
}
}
@@ -138,273 +114,269 @@ static int _pam_parse(int flags, int argc, const char **argv)
return ctrl;
}
-/* a front end for conversations */
-
-static int converse(pam_handle_t *pamh, int ctrl, int nargs
- , struct pam_message **message
- , struct pam_response **response)
+static const char *
+get_tty(pam_handle_t *pamh)
{
- int retval;
- struct pam_conv *conv;
+ const void *void_terminal_line = NULL;
+ const char *terminal_line;
- D(("begin to converse"));
+ if (pam_get_item(pamh, PAM_TTY, &void_terminal_line) != PAM_SUCCESS
+ || void_terminal_line == NULL) {
+ terminal_line = DEFAULT_TERM;
+ } else {
+ terminal_line = void_terminal_line;
+ }
+ if (!strncmp("/dev/", terminal_line, 5)) {
+ /* strip leading "/dev/" from tty. */
+ terminal_line += 5;
+ }
+ D(("terminal = %s", terminal_line));
+ return terminal_line;
+}
- retval = pam_get_item( pamh, PAM_CONV, (const void **) &conv ) ;
- if ( retval == PAM_SUCCESS && conv) {
+static int
+last_login_read(pam_handle_t *pamh, int announce, int last_fd, uid_t uid)
+{
+ struct flock last_lock;
+ struct lastlog last_login;
+ int retval = PAM_SUCCESS;
+ char the_time[256];
+ char *date = NULL;
+ char *host = NULL;
+ char *line = NULL;
+
+ memset(&last_lock, 0, sizeof(last_lock));
+ last_lock.l_type = F_RDLCK;
+ last_lock.l_whence = SEEK_SET;
+ last_lock.l_start = sizeof(last_login) * (off_t) uid;
+ last_lock.l_len = sizeof(last_login);
+
+ if (fcntl(last_fd, F_SETLK, &last_lock) < 0) {
+ D(("locking %s failed..(waiting a little)", _PATH_LASTLOG));
+ pam_syslog(pamh, LOG_WARNING,
+ "file %s is locked/read", _PATH_LASTLOG);
+ sleep(LASTLOG_IGNORE_LOCK_TIME);
+ }
- retval = conv->conv(nargs, ( const struct pam_message ** ) message
- , response, conv->appdata_ptr);
+ if (pam_modutil_read(last_fd, (char *) &last_login,
+ sizeof(last_login)) != sizeof(last_login)) {
+ memset(&last_login, 0, sizeof(last_login));
+ }
- D(("returned from application's conversation function"));
+ last_lock.l_type = F_UNLCK;
+ (void) fcntl(last_fd, F_SETLK, &last_lock); /* unlock */
- if (retval != PAM_SUCCESS && (ctrl & LASTLOG_DEBUG) ) {
- _log_err(LOG_DEBUG, "conversation failure [%s]"
- , pam_strerror(pamh, retval));
+ if (!last_login.ll_time) {
+ if (announce & LASTLOG_DEBUG) {
+ pam_syslog(pamh, LOG_DEBUG,
+ "first login for user with uid %lu",
+ (unsigned long int)uid);
}
-
- } else {
- _log_err(LOG_ERR, "couldn't obtain coversation function [%s]"
- , pam_strerror(pamh, retval));
- if (retval == PAM_SUCCESS)
- retval = PAM_BAD_ITEM; /* conv was NULL */
}
- D(("ready to return from module conversation"));
+ if (!(announce & LASTLOG_QUIET)) {
- return retval; /* propagate error status */
-}
+ if (last_login.ll_time) {
-static int make_remark(pam_handle_t *pamh, int ctrl, const char *remark)
-{
- int retval;
+ /* we want the date? */
+ if (announce & LASTLOG_DATE) {
+ struct tm *tm, tm_buf;
+ time_t ll_time;
- if (!(ctrl & LASTLOG_QUIET)) {
- struct pam_message msg[1], *mesg[1];
- struct pam_response *resp=NULL;
+ ll_time = last_login.ll_time;
+ tm = localtime_r (&ll_time, &tm_buf);
+ strftime (the_time, sizeof (the_time),
+ /* TRANSLATORS: "strftime options for date of last login" */
+ _(" %a %b %e %H:%M:%S %Z %Y"), tm);
- mesg[0] = &msg[0];
- msg[0].msg_style = PAM_TEXT_INFO;
- msg[0].msg = remark;
+ date = the_time;
+ }
- retval = converse(pamh, ctrl, 1, mesg, &resp);
+ /* we want & have the host? */
+ if ((announce & LASTLOG_HOST)
+ && (last_login.ll_host[0] != '\0')) {
+ /* TRANSLATORS: " from <host>" */
+ if (asprintf(&host, _(" from %.*s"), UT_HOSTSIZE,
+ last_login.ll_host) < 0) {
+ pam_syslog(pamh, LOG_ERR, "out of memory");
+ retval = PAM_BUF_ERR;
+ goto cleanup;
+ }
+ }
+
+ /* we want and have the terminal? */
+ if ((announce & LASTLOG_LINE)
+ && (last_login.ll_line[0] != '\0')) {
+ /* TRANSLATORS: " on <terminal>" */
+ if (asprintf(&line, _(" on %.*s"), UT_LINESIZE,
+ last_login.ll_line) < 0) {
+ pam_syslog(pamh, LOG_ERR, "out of memory");
+ retval = PAM_BUF_ERR;
+ goto cleanup;
+ }
+ }
- msg[0].msg = NULL;
- if (resp) {
- _pam_drop_reply(resp, 1);
+ /* TRANSLATORS: "Last login: <date> from <host> on <terminal>" */
+ retval = pam_info(pamh, _("Last login:%s%s%s"),
+ date ? date : "",
+ host ? host : "",
+ line ? line : "");
+ } else if (announce & LASTLOG_NEVER) {
+ D(("this is the first time this user has logged in"));
+ retval = pam_info(pamh, "%s", _("Welcome to your new account!"));
}
- } else {
- D(("keeping quiet"));
- retval = PAM_SUCCESS;
}
- D(("returning %s", pam_strerror(pamh, retval)));
+ /* cleanup */
+ cleanup:
+ memset(&last_login, 0, sizeof(last_login));
+ _pam_overwrite(date);
+ _pam_overwrite(host);
+ _pam_drop(host);
+ _pam_overwrite(line);
+ _pam_drop(line);
+
return retval;
}
-/*
- * Values for the announce flags..
- */
-
-static int last_login_date(pam_handle_t *pamh, int announce, uid_t uid)
+static int
+last_login_write(pam_handle_t *pamh, int announce, int last_fd,
+ uid_t uid, const char *user)
{
struct flock last_lock;
struct lastlog last_login;
- int retval = PAM_SESSION_ERR;
- int last_fd;
-
- /* obtain the last login date and all the relevant info */
- last_fd = open(_PATH_LASTLOG, O_RDWR);
- if (last_fd < 0) {
- D(("unable to open the %s file", _PATH_LASTLOG));
- if (announce & LASTLOG_DEBUG) {
- _log_err(LOG_DEBUG, "unable to open %s file", _PATH_LASTLOG);
- }
- retval = PAM_PERM_DENIED;
- } else {
- int win;
+ time_t ll_time;
+ const void *void_remote_host = NULL;
+ const char *remote_host;
+ const char *terminal_line;
+ int retval = PAM_SUCCESS;
+
+ /* rewind */
+ if (lseek(last_fd, sizeof(last_login) * (off_t) uid, SEEK_SET) < 0) {
+ pam_syslog(pamh, LOG_ERR, "failed to lseek %s: %m", _PATH_LASTLOG);
+ return PAM_SERVICE_ERR;
+ }
- /* read the lastlogin file - for this uid */
- (void) lseek(last_fd, sizeof(last_login) * (off_t) uid, SEEK_SET);
+ /* set this login date */
+ D(("set the most recent login time"));
+ (void) time(&ll_time); /* set the time */
+ last_login.ll_time = ll_time;
- memset(&last_lock, 0, sizeof(last_lock));
- last_lock.l_type = F_RDLCK;
- last_lock.l_whence = SEEK_SET;
- last_lock.l_start = sizeof(last_login) * (off_t) uid;
- last_lock.l_len = sizeof(last_login);
+ /* set the remote host */
+ if (pam_get_item(pamh, PAM_RHOST, &void_remote_host) != PAM_SUCCESS
+ || void_remote_host == NULL) {
+ remote_host = DEFAULT_HOST;
+ } else {
+ remote_host = void_remote_host;
+ }
- if ( fcntl(last_fd, F_SETLK, &last_lock) < 0 ) {
- D(("locking %s failed..(waiting a little)", _PATH_LASTLOG));
- _log_err(LOG_ALERT, "%s file is locked/read", _PATH_LASTLOG);
- sleep(LASTLOG_IGNORE_LOCK_TIME);
- }
+ /* copy to last_login */
+ last_login.ll_host[0] = '\0';
+ strncat(last_login.ll_host, remote_host, sizeof(last_login.ll_host)-1);
- win = (_pammodutil_read (last_fd, (char *) &last_login,
- sizeof(last_login)) == sizeof(last_login));
+ /* set the terminal line */
+ terminal_line = get_tty(pamh);
- last_lock.l_type = F_UNLCK;
- (void) fcntl(last_fd, F_SETLK, &last_lock); /* unlock */
+ /* copy to last_login */
+ last_login.ll_line[0] = '\0';
+ strncat(last_login.ll_line, terminal_line, sizeof(last_login.ll_line)-1);
+ terminal_line = NULL;
- if (!win) {
- D(("First login for user uid=%d", _PATH_LASTLOG, uid));
- if (announce & LASTLOG_DEBUG) {
- _log_err(LOG_DEBUG, "creating lastlog for uid %d", uid);
- }
- memset(&last_login, 0, sizeof(last_login));
- }
+ D(("locking lastlog file"));
- /* rewind */
- (void) lseek(last_fd, sizeof(last_login) * (off_t) uid, SEEK_SET);
+ /* now we try to lock this file-record exclusively; non-blocking */
+ memset(&last_lock, 0, sizeof(last_lock));
+ last_lock.l_type = F_WRLCK;
+ last_lock.l_whence = SEEK_SET;
+ last_lock.l_start = sizeof(last_login) * (off_t) uid;
+ last_lock.l_len = sizeof(last_login);
- if (!(announce & LASTLOG_QUIET)) {
- if (last_login.ll_time) {
- time_t ll_time;
- char *the_time;
- char *remark;
+ if (fcntl(last_fd, F_SETLK, &last_lock) < 0) {
+ D(("locking %s failed..(waiting a little)", _PATH_LASTLOG));
+ pam_syslog(pamh, LOG_WARNING, "file %s is locked/write", _PATH_LASTLOG);
+ sleep(LASTLOG_IGNORE_LOCK_TIME);
+ }
- ll_time = last_login.ll_time;
- the_time = ctime(&ll_time);
- the_time[-1+strlen(the_time)] = '\0'; /* delete '\n' */
+ D(("writing to the lastlog file"));
+ if (pam_modutil_write (last_fd, (char *) &last_login,
+ sizeof (last_login)) != sizeof(last_login)) {
+ pam_syslog(pamh, LOG_ERR, "failed to write %s: %m", _PATH_LASTLOG);
+ retval = PAM_SERVICE_ERR;
+ }
- remark = malloc(LASTLOG_MAXSIZE);
- if (remark == NULL) {
- D(("no memory for last login remark"));
- retval = PAM_BUF_ERR;
- } else {
- int at;
-
- /* printing prefix */
- at = sprintf(remark, "%s", LASTLOG_INTRO);
-
- /* we want the date? */
- if (announce & LASTLOG_DATE) {
- at += sprintf(remark+at, LASTLOG_TIME, the_time);
- }
-
- /* we want & have the host? */
- if ((announce & LASTLOG_HOST)
- && (last_login.ll_host[0] != '\0')) {
- char format[2*sizeof(_LASTLOG_HOST_FORMAT)];
-
- (void) sprintf(format, _LASTLOG_HOST_FORMAT
- , UT_HOSTSIZE);
- D(("format: %s", format));
- at += sprintf(remark+at, format, last_login.ll_host);
- _pam_overwrite(format);
- }
-
- /* we want and have the terminal? */
- if ((announce & LASTLOG_LINE)
- && (last_login.ll_line[0] != '\0')) {
- char format[2*sizeof(_LASTLOG_LINE_FORMAT)];
-
- (void) sprintf(format, _LASTLOG_LINE_FORMAT
- , UT_LINESIZE);
- D(("format: %s", format));
- at += sprintf(remark+at, format, last_login.ll_line);
- _pam_overwrite(format);
- }
-
- /* display requested combo */
- sprintf(remark+at, "%s", LASTLOG_TAIL);
-
- retval = make_remark(pamh, announce, remark);
-
- /* free all the stuff malloced */
- _pam_overwrite(remark);
- _pam_drop(remark);
- }
- } else if ((!last_login.ll_time) && (announce & LASTLOG_NEVER)) {
- D(("this is the first time this user has logged in"));
- retval = make_remark(pamh, announce, LASTLOG_NEVER_WELCOME);
- }
- } else {
- D(("no text was requested"));
- retval = PAM_SUCCESS;
- }
+ last_lock.l_type = F_UNLCK;
+ (void) fcntl(last_fd, F_SETLK, &last_lock); /* unlock */
+ D(("unlocked"));
- /* write latest value */
- {
- time_t ll_time;
- const char *remote_host=NULL
- , *terminal_line=DEFAULT_TERM;
+ if (announce & LASTLOG_WTMP) {
+ /* write wtmp entry for user */
+ logwtmp(last_login.ll_line, user, remote_host);
+ }
- /* set this login date */
- D(("set the most recent login time"));
+ /* cleanup */
+ memset(&last_login, 0, sizeof(last_login));
- (void) time(&ll_time); /* set the time */
- last_login.ll_time = ll_time;
+ return retval;
+}
- /* set the remote host */
- (void) pam_get_item(pamh, PAM_RHOST, (const void **)&remote_host);
- if (remote_host == NULL) {
- remote_host = DEFAULT_HOST;
- }
+static int
+last_login_date(pam_handle_t *pamh, int announce, uid_t uid, const char *user)
+{
+ int retval;
+ int last_fd;
- /* copy to last_login */
- strncpy(last_login.ll_host, remote_host,
- sizeof(last_login.ll_host));
- last_login.ll_host[sizeof(last_login.ll_host) - 1] = '\0';
- remote_host = NULL;
-
- /* set the terminal line */
- (void) pam_get_item(pamh, PAM_TTY, (const void **)&terminal_line);
- D(("terminal = %s", terminal_line));
- if (terminal_line == NULL) {
- terminal_line = DEFAULT_TERM;
- } else if ( !strncmp("/dev/", terminal_line, 5) ) {
- /* strip leading "/dev/" from tty.. */
- terminal_line += 5;
- }
- D(("terminal = %s", terminal_line));
-
- /* copy to last_login */
- strncpy(last_login.ll_line, terminal_line,
- sizeof(last_login.ll_line));
- last_login.ll_host[sizeof(last_login.ll_host) - 1] = '\0';
- terminal_line = NULL;
-
- D(("locking last_log file"));
-
- /* now we try to lock this file-record exclusively; non-blocking */
- memset(&last_lock, 0, sizeof(last_lock));
- last_lock.l_type = F_WRLCK;
- last_lock.l_whence = SEEK_SET;
- last_lock.l_start = sizeof(last_login) * (off_t) uid;
- last_lock.l_len = sizeof(last_login);
-
- if ( fcntl(last_fd, F_SETLK, &last_lock) < 0 ) {
- D(("locking %s failed..(waiting a little)", _PATH_LASTLOG));
- _log_err(LOG_ALERT, "%s file is locked/write", _PATH_LASTLOG);
- sleep(LASTLOG_IGNORE_LOCK_TIME);
- }
+ /* obtain the last login date and all the relevant info */
+ last_fd = open(_PATH_LASTLOG, O_RDWR);
+ if (last_fd < 0) {
+ if (errno == ENOENT) {
+ last_fd = open(_PATH_LASTLOG, O_RDWR|O_CREAT,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH);
+ if (last_fd < 0) {
+ pam_syslog(pamh, LOG_ERR,
+ "unable to create %s: %m", _PATH_LASTLOG);
+ D(("unable to create %s file", _PATH_LASTLOG));
+ return PAM_SERVICE_ERR;
+ }
+ pam_syslog(pamh, LOG_WARNING,
+ "file %s created", _PATH_LASTLOG);
+ D(("file %s created", _PATH_LASTLOG));
+ } else {
+ pam_syslog(pamh, LOG_ERR, "unable to open %s: %m", _PATH_LASTLOG);
+ D(("unable to open %s file", _PATH_LASTLOG));
+ return PAM_SERVICE_ERR;
+ }
+ }
- D(("writing to the last_log file"));
- _pammodutil_write (last_fd, (char *) &last_login,
- sizeof (last_login));
+ if (lseek(last_fd, sizeof(struct lastlog) * (off_t) uid, SEEK_SET) < 0) {
+ pam_syslog(pamh, LOG_ERR, "failed to lseek %s: %m", _PATH_LASTLOG);
+ D(("unable to lseek %s file", _PATH_LASTLOG));
+ return PAM_SERVICE_ERR;
+ }
- last_lock.l_type = F_UNLCK;
- (void) fcntl(last_fd, F_SETLK, &last_lock); /* unlock */
- D(("unlocked"));
+ retval = last_login_read(pamh, announce, last_fd, uid);
+ if (retval != PAM_SUCCESS)
+ {
+ close(last_fd);
+ D(("error while reading lastlog file"));
+ return retval;
+ }
- close(last_fd); /* all done */
- }
- D(("all done with last login"));
- }
+ retval = last_login_write(pamh, announce, last_fd, uid, user);
- /* reset the last login structure */
- memset(&last_login, 0, sizeof(last_login));
+ close(last_fd);
+ D(("all done with last login"));
return retval;
}
/* --- authentication management functions (only) --- */
-PAM_EXTERN
-int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc
- , const char **argv)
+PAM_EXTERN int
+pam_sm_open_session(pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
{
int retval, ctrl;
- const char *user;
+ const void *user;
const struct passwd *pwd;
uid_t uid;
@@ -413,29 +385,29 @@ int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc
* last login info and then updates the lastlog for that user.
*/
- ctrl = _pam_parse(flags, argc, argv);
+ ctrl = _pam_parse(pamh, flags, argc, argv);
/* which user? */
- retval = pam_get_item(pamh, PAM_USER, (const void **)&user);
- if (retval != PAM_SUCCESS || user == NULL || *user == '\0') {
- _log_err(LOG_NOTICE, "user unknown");
+ retval = pam_get_item(pamh, PAM_USER, &user);
+ if (retval != PAM_SUCCESS || user == NULL || *(const char *)user == '\0') {
+ pam_syslog(pamh, LOG_NOTICE, "user unknown");
return PAM_USER_UNKNOWN;
}
/* what uid? */
- pwd = _pammodutil_getpwnam (pamh, user);
+ pwd = pam_modutil_getpwnam (pamh, user);
if (pwd == NULL) {
D(("couldn't identify user %s", user));
- return PAM_CRED_INSUFFICIENT;
+ return PAM_USER_UNKNOWN;
}
uid = pwd->pw_uid;
pwd = NULL; /* tidy up */
/* process the current login attempt (indicate last) */
- retval = last_login_date(pamh, ctrl, uid);
+ retval = last_login_date(pamh, ctrl, uid, user);
/* indicate success or failure */
@@ -444,10 +416,20 @@ int pam_sm_open_session(pam_handle_t *pamh, int flags, int argc
return retval;
}
-PAM_EXTERN
-int pam_sm_close_session(pam_handle_t *pamh,int flags,int argc
- ,const char **argv)
+PAM_EXTERN int
+pam_sm_close_session (pam_handle_t *pamh, int flags,
+ int argc, const char **argv)
{
+ const char *terminal_line;
+
+ if (!(_pam_parse(pamh, flags, argc, argv) & LASTLOG_WTMP))
+ return PAM_SUCCESS;
+
+ terminal_line = get_tty(pamh);
+
+ /* Wipe out utmp logout entry */
+ logwtmp(terminal_line, "", "");
+
return PAM_SUCCESS;
}