pam_lastlog.c revision 89728
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.
689728Sdes * Copyright (c) 2001 Networks Associates Technologies, Inc.
789728Sdes * All rights reserved.
889728Sdes *
989728Sdes * Portions of this software were developed for the FreeBSD Project by
1089728Sdes * ThinkSec AS and NAI Labs, the Security Research Division of Network
1189728Sdes * Associates, Inc.  under DARPA/SPAWAR contract N66001-01-C-8035
1289728Sdes * ("CBOSS"), as part of the DARPA CHATS research program.
1389728Sdes *
1489728Sdes * Redistribution and use in source and binary forms, with or without
1589728Sdes * modification, are permitted provided that the following conditions
1689728Sdes * are met:
1789728Sdes * 1. Redistributions of source code must retain the above copyright
1889728Sdes *    notice, this list of conditions and the following disclaimer.
1989728Sdes * 2. Redistributions in binary form must reproduce the above copyright
2089728Sdes *    notice, this list of conditions and the following disclaimer in the
2189728Sdes *    documentation and/or other materials provided with the distribution.
2289728Sdes * 3. The name of the author may not be used to endorse or promote
2389728Sdes *    products derived from this software without specific prior written
2489728Sdes *    permission.
2589728Sdes * 4. Neither the name of the University nor the names of its contributors
2689728Sdes *    may be used to endorse or promote products derived from this software
2789728Sdes *    without specific prior written permission.
2889728Sdes *
2989728Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
3089728Sdes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
3189728Sdes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
3289728Sdes * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
3389728Sdes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
3489728Sdes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3589728Sdes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
3689728Sdes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
3789728Sdes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3889728Sdes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3989728Sdes * SUCH DAMAGE.
4089728Sdes */
4189728Sdes
4289728Sdes#include <sys/cdefs.h>
4389728Sdes__FBSDID("$FreeBSD: head/lib/libpam/modules/pam_lastlog/pam_lastlog.c 89728 2002-01-24 09:45:17Z des $");
4489728Sdes
4589728Sdes#define _BSD_SOURCE
4689728Sdes
4789728Sdes#include <sys/param.h>
4889728Sdes
4989728Sdes#include <fcntl.h>
5089728Sdes#include <libutil.h>
5189728Sdes#include <pwd.h>
5289728Sdes#include <stdio.h>
5389728Sdes#include <stdlib.h>
5489728Sdes#include <string.h>
5589728Sdes#include <syslog.h>
5689728Sdes#include <time.h>
5789728Sdes#include <unistd.h>
5889728Sdes#include <utmp.h>
5989728Sdes
6089728Sdes#define PAM_SM_AUTH
6189728Sdes#define PAM_SM_ACCOUNT
6289728Sdes#define PAM_SM_SESSION
6389728Sdes#define PAM_SM_PASSWORD
6489728Sdes
6589728Sdes#include <security/pam_modules.h>
6689728Sdes#include <pam_mod_misc.h>
6789728Sdes
6889728Sdesextern int login_access(const char *, const char *);
6989728Sdes
7089728SdesPAM_EXTERN int
7189728Sdespam_sm_authenticate(pam_handle_t *pamh, int flags, int argc, const char **argv)
7289728Sdes{
7389728Sdes	struct options options;
7489728Sdes
7589728Sdes	pam_std_option(&options, NULL, argc, argv);
7689728Sdes
7789728Sdes	PAM_LOG("Options processed");
7889728Sdes
7989728Sdes	PAM_RETURN(PAM_IGNORE);
8089728Sdes}
8189728Sdes
8289728SdesPAM_EXTERN int
8389728Sdespam_sm_setcred(pam_handle_t *pamh, int flags, int argc, const char **argv)
8489728Sdes{
8589728Sdes	struct options options;
8689728Sdes
8789728Sdes	pam_std_option(&options, NULL, argc, argv);
8889728Sdes
8989728Sdes	PAM_LOG("Options processed");
9089728Sdes
9189728Sdes	PAM_RETURN(PAM_IGNORE);
9289728Sdes}
9389728Sdes
9489728SdesPAM_EXTERN int
9589728Sdespam_sm_acct_mgmt(pam_handle_t *pamh, int flags, int argc ,const char **argv)
9689728Sdes{
9789728Sdes	struct options options;
9889728Sdes
9989728Sdes	pam_std_option(&options, NULL, argc, argv);
10089728Sdes
10189728Sdes	PAM_LOG("Options processed");
10289728Sdes
10389728Sdes	PAM_RETURN(PAM_IGNORE);
10489728Sdes}
10589728Sdes
10689728SdesPAM_EXTERN int
10789728Sdespam_sm_chauthtok(pam_handle_t *pamh, int flags, int argc, const char **argv)
10889728Sdes{
10989728Sdes	struct options options;
11089728Sdes
11189728Sdes	pam_std_option(&options, NULL, argc, argv);
11289728Sdes
11389728Sdes	PAM_LOG("Options processed");
11489728Sdes
11589728Sdes	PAM_RETURN(PAM_IGNORE);
11689728Sdes}
11789728Sdes
11889728SdesPAM_EXTERN int
11989728Sdespam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
12089728Sdes{
12189728Sdes	struct options options;
12289728Sdes	struct passwd *pwd;
12389728Sdes	struct utmp utmp;
12489728Sdes	struct lastlog ll;
12589728Sdes	const char *rhost, *user, *tty;
12689728Sdes	char *buf;
12789728Sdes	off_t llpos;
12889728Sdes	int fd, pam_err;
12989728Sdes
13089728Sdes	pam_std_option(&options, NULL, argc, argv);
13189728Sdes
13289728Sdes	PAM_LOG("Options processed");
13389728Sdes
13489728Sdes	pam_err = pam_get_item(pamh, PAM_USER, (const void **)&user);
13589728Sdes	if (pam_err != PAM_SUCCESS)
13689728Sdes		PAM_RETURN(pam_err);
13789728Sdes	if (user == NULL || (pwd = getpwnam(user)) == NULL)
13889728Sdes		PAM_RETURN(PAM_SERVICE_ERR);
13989728Sdes	PAM_LOG("Got user: %s", user);
14089728Sdes
14189728Sdes	pam_err = pam_get_item(pamh, PAM_RHOST, (const void **)&rhost);
14289728Sdes	if (pam_err != PAM_SUCCESS)
14389728Sdes		PAM_RETURN(pam_err);
14489728Sdes
14589728Sdes	pam_err = pam_get_item(pamh, PAM_TTY, (const void **)&tty);
14689728Sdes	if (pam_err != PAM_SUCCESS)
14789728Sdes		PAM_RETURN(pam_err);
14889728Sdes	if (tty == NULL)
14989728Sdes		PAM_RETURN(PAM_SERVICE_ERR);
15089728Sdes
15189728Sdes	fd = open(_PATH_LASTLOG, O_RDWR, 0);
15289728Sdes	if (fd == -1) {
15389728Sdes		syslog(LOG_ERR, "cannot open %s: %m", _PATH_LASTLOG);
15489728Sdes		PAM_RETURN(PAM_SERVICE_ERR);
15589728Sdes	}
15689728Sdes
15789728Sdes	/*
15889728Sdes	 * Record session in utmp(5) and wtmp(5).
15989728Sdes	 */
16089728Sdes	bzero(&utmp, sizeof(utmp));
16189728Sdes	time(&utmp.ut_time);
16289728Sdes	/* note: does not need to be NUL-terminated */
16389728Sdes	strncpy(utmp.ut_name, user, sizeof(utmp.ut_name));
16489728Sdes	if (rhost)
16589728Sdes		strncpy(utmp.ut_host, rhost, sizeof(utmp.ut_host));
16689728Sdes	(void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
16789728Sdes	login(&utmp);
16889728Sdes
16989728Sdes	/*
17089728Sdes	 * Record session in lastlog(5).
17189728Sdes	 */
17289728Sdes	llpos = (off_t)(pwd->pw_uid * sizeof(ll));
17389728Sdes	if (lseek(fd, llpos, L_SET) != llpos)
17489728Sdes		goto file_err;
17589728Sdes	if ((flags & PAM_SILENT) == 0) {
17689728Sdes		if (read(fd, &ll, sizeof(ll)) == sizeof(ll) &&
17789728Sdes		    ll.ll_time != 0) {
17889728Sdes			asprintf(&buf, "Last login: %.*s ", 24 - 5,
17989728Sdes			    ctime(&ll.ll_time));
18089728Sdes			if (buf != NULL) {
18189728Sdes				pam_prompt(pamh, PAM_TEXT_INFO, buf, NULL);
18289728Sdes				free(buf);
18389728Sdes			}
18489728Sdes			if (*ll.ll_host != '\0')
18589728Sdes				asprintf(&buf, "from %.*s\n",
18689728Sdes				    (int)sizeof(ll.ll_host), ll.ll_host);
18789728Sdes			else
18889728Sdes				asprintf(&buf, "on %.*s\n",
18989728Sdes				    (int)sizeof(ll.ll_line), ll.ll_line);
19089728Sdes			if (buf != NULL) {
19189728Sdes				pam_prompt(pamh, PAM_TEXT_INFO, buf, NULL);
19289728Sdes				free(buf);
19389728Sdes			}
19489728Sdes		}
19589728Sdes		if (lseek(fd, llpos, L_SET) != llpos)
19689728Sdes			goto file_err;
19789728Sdes	}
19889728Sdes
19989728Sdes	bzero(&ll, sizeof(ll));
20089728Sdes	time(&ll.ll_time);
20189728Sdes
20289728Sdes	/* note: does not need to be NUL-terminated */
20389728Sdes	strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
20489728Sdes	if (rhost)
20589728Sdes		/* note: does not need to be NUL-terminated */
20689728Sdes		strncpy(ll.ll_host, rhost, sizeof(ll.ll_host));
20789728Sdes
20889728Sdes	if (write(fd, (char *)&ll, sizeof(ll)) != sizeof(ll) || close(fd) != 0)
20989728Sdes		goto file_err;
21089728Sdes
21189728Sdes	PAM_LOG("Login recorded in %s", _PATH_LASTLOG);
21289728Sdes	PAM_RETURN(PAM_IGNORE);
21389728Sdes
21489728Sdes file_err:
21589728Sdes	syslog(LOG_ERR, "%s: %m", _PATH_LASTLOG);
21689728Sdes	close(fd);
21789728Sdes	PAM_RETURN(PAM_SERVICE_ERR);
21889728Sdes}
21989728Sdes
22089728SdesPAM_EXTERN int
22189728Sdespam_sm_close_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
22289728Sdes{
22389728Sdes	struct options options;
22489728Sdes	const char *tty;
22589728Sdes	int pam_err;
22689728Sdes
22789728Sdes	pam_std_option(&options, NULL, argc, argv);
22889728Sdes
22989728Sdes	PAM_LOG("Options processed");
23089728Sdes
23189728Sdes	pam_err = pam_get_item(pamh, PAM_TTY, (const void **)&tty);
23289728Sdes	if (pam_err != PAM_SUCCESS)
23389728Sdes		PAM_RETURN(pam_err);
23489728Sdes	if (tty != NULL)
23589728Sdes		logout(tty);
23689728Sdes
23789728Sdes	PAM_RETURN(PAM_SUCCESS);
23889728Sdes}
23989728Sdes
24089728SdesPAM_MODULE_ENTRY("pam_lastlog");
241