pam_lastlog.c revision 171543
189728Sdes/*-
289728Sdes * Copyright (c) 1980, 1987, 1988, 1991, 1993, 1994
389728Sdes *	The Regents of the University of California.  All rights reserved.
489728Sdes * Copyright (c) 2001 Mark R V Murray
589728Sdes * All rights reserved.
692297Sdes * Copyright (c) 2001 Networks Associates Technology, Inc.
789728Sdes * All rights reserved.
8125046Sdes * Copyright (c) 2004 Joe R. Doupnik
9125046Sdes * All rights reserved.
1089728Sdes *
1189728Sdes * Portions of this software were developed for the FreeBSD Project by
1289728Sdes * ThinkSec AS and NAI Labs, the Security Research Division of Network
1389728Sdes * Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
1489728Sdes * ("CBOSS"), as part of the DARPA CHATS research program.
1589728Sdes *
1689728Sdes * Redistribution and use in source and binary forms, with or without
1789728Sdes * modification, are permitted provided that the following conditions
1889728Sdes * are met:
1989728Sdes * 1. Redistributions of source code must retain the above copyright
2089728Sdes *    notice, this list of conditions and the following disclaimer.
2189728Sdes * 2. Redistributions in binary form must reproduce the above copyright
2289728Sdes *    notice, this list of conditions and the following disclaimer in the
2389728Sdes *    documentation and/or other materials provided with the distribution.
2489728Sdes * 3. The name of the author may not be used to endorse or promote
2589728Sdes *    products derived from this software without specific prior written
2689728Sdes *    permission.
2789728Sdes * 4. Neither the name of the University nor the names of its contributors
2889728Sdes *    may be used to endorse or promote products derived from this software
2989728Sdes *    without specific prior written permission.
3089728Sdes *
3189728Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
3289728Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3389728Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3489728Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
3589728Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3689728Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3789728Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3889728Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3989728Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
4089728Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
4189728Sdes * SUCH DAMAGE.
4289728Sdes */
4389728Sdes
4489728Sdes#include <sys/cdefs.h>
4589728Sdes__FBSDID("$FreeBSD: head/lib/libpam/modules/pam_lastlog/pam_lastlog.c 171543 2007-07-22 15:14:40Z des $");
4689728Sdes
4789728Sdes#define _BSD_SOURCE
4889728Sdes
4989728Sdes#include <sys/param.h>
5089728Sdes
5189728Sdes#include <fcntl.h>
5289728Sdes#include <libutil.h>
5395135Sdes#include <paths.h>
5489728Sdes#include <pwd.h>
5589728Sdes#include <stdio.h>
5689728Sdes#include <stdlib.h>
5789728Sdes#include <string.h>
5889728Sdes#include <syslog.h>
5989728Sdes#include <time.h>
6089728Sdes#include <unistd.h>
6189728Sdes#include <utmp.h>
6289728Sdes
6389728Sdes#define PAM_SM_SESSION
6489728Sdes
6590229Sdes#include <security/pam_appl.h>
6689728Sdes#include <security/pam_modules.h>
6790229Sdes#include <security/pam_mod_misc.h>
6889728Sdes
6989728SdesPAM_EXTERN int
7094564Sdespam_sm_open_session(pam_handle_t *pamh, int flags,
7194564Sdes    int argc __unused, const char *argv[] __unused)
7289728Sdes{
7389728Sdes	struct passwd *pwd;
7489728Sdes	struct utmp utmp;
7589728Sdes	struct lastlog ll;
76106966Speter	time_t t;
77123448Sdes	const char *user;
78123448Sdes	const void *rhost, *tty;
7989728Sdes	off_t llpos;
8089728Sdes	int fd, pam_err;
8189728Sdes
8294564Sdes	pam_err = pam_get_user(pamh, &user, NULL);
8389728Sdes	if (pam_err != PAM_SUCCESS)
8494564Sdes		return (pam_err);
8589728Sdes	if (user == NULL || (pwd = getpwnam(user)) == NULL)
8694564Sdes		return (PAM_SERVICE_ERR);
8789728Sdes	PAM_LOG("Got user: %s", user);
8889728Sdes
89123448Sdes	pam_err = pam_get_item(pamh, PAM_RHOST, &rhost);
90161209Sdes	if (pam_err != PAM_SUCCESS) {
91161209Sdes		PAM_LOG("No PAM_RHOST");
9297148Sdes		goto err;
93161209Sdes	}
94123448Sdes	pam_err = pam_get_item(pamh, PAM_TTY, &tty);
95161209Sdes	if (pam_err != PAM_SUCCESS) {
96161209Sdes		PAM_LOG("No PAM_TTY");
9797148Sdes		goto err;
98161209Sdes	}
9997625Sdes	if (tty == NULL) {
100161209Sdes		PAM_LOG("No PAM_TTY");
10197625Sdes		pam_err = PAM_SERVICE_ERR;
10297625Sdes		goto err;
10397625Sdes	}
10495136Sdes	if (strncmp(tty, _PATH_DEV, strlen(_PATH_DEV)) == 0)
105123448Sdes		tty = (const char *)tty + strlen(_PATH_DEV);
106123448Sdes	if (*(const char *)tty == '\0')
10795135Sdes		return (PAM_SERVICE_ERR);
10894564Sdes
10990955Ssobomax	fd = open(_PATH_LASTLOG, O_RDWR|O_CREAT, 0644);
110161209Sdes	if (fd == -1) {
111161209Sdes		PAM_LOG("Failed to open %s", _PATH_LASTLOG);
11296192Sdes		goto file_err;
113161209Sdes	}
11489728Sdes
11589728Sdes	/*
11689728Sdes	 * Record session in lastlog(5).
11789728Sdes	 */
11889728Sdes	llpos = (off_t)(pwd->pw_uid * sizeof(ll));
11989728Sdes	if (lseek(fd, llpos, L_SET) != llpos)
12089728Sdes		goto file_err;
12189728Sdes	if ((flags & PAM_SILENT) == 0) {
12295135Sdes		if (read(fd, &ll, sizeof ll) == sizeof ll && ll.ll_time != 0) {
123106966Speter			t = ll.ll_time;
12489728Sdes			if (*ll.ll_host != '\0')
12595135Sdes				pam_info(pamh, "Last login: %.*s from %.*s",
126106966Speter				    24 - 5, ctime(&t),
12789728Sdes				    (int)sizeof(ll.ll_host), ll.ll_host);
12889728Sdes			else
12995135Sdes				pam_info(pamh, "Last login: %.*s on %.*s",
130106966Speter				    24 - 5, ctime(&t),
13189728Sdes				    (int)sizeof(ll.ll_line), ll.ll_line);
13289728Sdes		}
13389728Sdes		if (lseek(fd, llpos, L_SET) != llpos)
13489728Sdes			goto file_err;
13589728Sdes	}
13694564Sdes
13789728Sdes	bzero(&ll, sizeof(ll));
138106966Speter	ll.ll_time = time(NULL);
13994564Sdes
14089728Sdes	/* note: does not need to be NUL-terminated */
14189728Sdes	strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
142123448Sdes	if (rhost != NULL && *(const char *)rhost != '\0')
14389728Sdes		/* note: does not need to be NUL-terminated */
14489728Sdes		strncpy(ll.ll_host, rhost, sizeof(ll.ll_host));
14594564Sdes
14689728Sdes	if (write(fd, (char *)&ll, sizeof(ll)) != sizeof(ll) || close(fd) != 0)
14789728Sdes		goto file_err;
14889728Sdes
14989728Sdes	PAM_LOG("Login recorded in %s", _PATH_LASTLOG);
15094564Sdes
15189748Sdes	/*
15289748Sdes	 * Record session in utmp(5) and wtmp(5).
15389748Sdes	 */
15489748Sdes	bzero(&utmp, sizeof(utmp));
155106966Speter	utmp.ut_time = time(NULL);
15689748Sdes	/* note: does not need to be NUL-terminated */
15789748Sdes	strncpy(utmp.ut_name, user, sizeof(utmp.ut_name));
158123448Sdes	if (rhost != NULL && *(const char *)rhost != '\0')
15989748Sdes		strncpy(utmp.ut_host, rhost, sizeof(utmp.ut_host));
16089748Sdes	(void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
16189748Sdes	login(&utmp);
16294564Sdes
16396192Sdes	return (PAM_SUCCESS);
16494564Sdes
16597148Sdesfile_err:
16689728Sdes	syslog(LOG_ERR, "%s: %m", _PATH_LASTLOG);
16796192Sdes	if (fd != -1)
16896192Sdes		close(fd);
16997148Sdes	pam_err = PAM_SYSTEM_ERR;
17097148Sdeserr:
17196192Sdes	if (openpam_get_option(pamh, "no_fail"))
17296192Sdes		return (PAM_SUCCESS);
17397148Sdes	return (pam_err);
17489728Sdes}
17589728Sdes
17689728SdesPAM_EXTERN int
17794564Sdespam_sm_close_session(pam_handle_t *pamh __unused, int flags __unused,
17894564Sdes    int argc __unused, const char *argv[] __unused)
17989728Sdes{
180171543Sdes	const void *tty;
18189728Sdes
182171543Sdes	pam_get_item(pamh, PAM_TTY, (const void **)&tty);
183125046Sdes	if (strncmp(tty, _PATH_DEV, strlen(_PATH_DEV)) == 0)
184125046Sdes		tty = (const char *)tty + strlen(_PATH_DEV);
185125046Sdes	if (*(const char *)tty == '\0')
186125046Sdes		return (PAM_SERVICE_ERR);
187171543Sdes	if (logout(tty) != 1)
188171543Sdes		syslog(LOG_ERR, "%s(): no utmp record for %s",
189125046Sdes		    __func__, (const char *)tty);
190171543Sdes	logwtmp(tty, "", "");
191171543Sdes	return (PAM_SUCCESS);
19289728Sdes}
19389728Sdes
19489728SdesPAM_MODULE_ENTRY("pam_lastlog");
195