pam_lastlog.c revision 90229
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 90229 2002-02-05 06:08:26Z 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
6590229Sdes#include <security/pam_appl.h>
6689728Sdes#include <security/pam_modules.h>
6790229Sdes#include <security/pam_mod_misc.h>
6889728Sdes
6989728Sdesextern int login_access(const char *, const char *);
7089728Sdes
7189728SdesPAM_EXTERN int
7289760Smarkmpam_sm_authenticate(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv)
7389728Sdes{
7489728Sdes	struct options options;
7589728Sdes
7689728Sdes	pam_std_option(&options, NULL, argc, argv);
7789728Sdes
7889728Sdes	PAM_LOG("Options processed");
7989728Sdes
8089728Sdes	PAM_RETURN(PAM_IGNORE);
8189728Sdes}
8289728Sdes
8389728SdesPAM_EXTERN int
8489760Smarkmpam_sm_setcred(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv)
8589728Sdes{
8689728Sdes	struct options options;
8789728Sdes
8889728Sdes	pam_std_option(&options, NULL, argc, argv);
8989728Sdes
9089728Sdes	PAM_LOG("Options processed");
9189728Sdes
9289728Sdes	PAM_RETURN(PAM_IGNORE);
9389728Sdes}
9489728Sdes
9589728SdesPAM_EXTERN int
9689760Smarkmpam_sm_acct_mgmt(pam_handle_t *pamh __unused, int flags __unused, int argc ,const char **argv)
9789728Sdes{
9889728Sdes	struct options options;
9989728Sdes
10089728Sdes	pam_std_option(&options, NULL, argc, argv);
10189728Sdes
10289728Sdes	PAM_LOG("Options processed");
10389728Sdes
10489728Sdes	PAM_RETURN(PAM_IGNORE);
10589728Sdes}
10689728Sdes
10789728SdesPAM_EXTERN int
10889760Smarkmpam_sm_chauthtok(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv)
10989728Sdes{
11089728Sdes	struct options options;
11189728Sdes
11289728Sdes	pam_std_option(&options, NULL, argc, argv);
11389728Sdes
11489728Sdes	PAM_LOG("Options processed");
11589728Sdes
11689728Sdes	PAM_RETURN(PAM_IGNORE);
11789728Sdes}
11889728Sdes
11989728SdesPAM_EXTERN int
12089728Sdespam_sm_open_session(pam_handle_t *pamh, int flags, int argc, const char **argv)
12189728Sdes{
12289728Sdes	struct options options;
12389728Sdes	struct passwd *pwd;
12489728Sdes	struct utmp utmp;
12589728Sdes	struct lastlog ll;
12689728Sdes	const char *rhost, *user, *tty;
12789728Sdes	char *buf;
12889728Sdes	off_t llpos;
12989728Sdes	int fd, pam_err;
13089728Sdes
13189728Sdes	pam_std_option(&options, NULL, argc, argv);
13289728Sdes
13389728Sdes	PAM_LOG("Options processed");
13489728Sdes
13589728Sdes	pam_err = pam_get_item(pamh, PAM_USER, (const void **)&user);
13689728Sdes	if (pam_err != PAM_SUCCESS)
13789728Sdes		PAM_RETURN(pam_err);
13889728Sdes	if (user == NULL || (pwd = getpwnam(user)) == NULL)
13989728Sdes		PAM_RETURN(PAM_SERVICE_ERR);
14089728Sdes	PAM_LOG("Got user: %s", user);
14189728Sdes
14289728Sdes	pam_err = pam_get_item(pamh, PAM_RHOST, (const void **)&rhost);
14389728Sdes	if (pam_err != PAM_SUCCESS)
14489728Sdes		PAM_RETURN(pam_err);
14589728Sdes
14689728Sdes	pam_err = pam_get_item(pamh, PAM_TTY, (const void **)&tty);
14789728Sdes	if (pam_err != PAM_SUCCESS)
14889728Sdes		PAM_RETURN(pam_err);
14989728Sdes	if (tty == NULL)
15089728Sdes		PAM_RETURN(PAM_SERVICE_ERR);
15189728Sdes
15289728Sdes	fd = open(_PATH_LASTLOG, O_RDWR, 0);
15389728Sdes	if (fd == -1) {
15489728Sdes		syslog(LOG_ERR, "cannot open %s: %m", _PATH_LASTLOG);
15589728Sdes		PAM_RETURN(PAM_SERVICE_ERR);
15689728Sdes	}
15789728Sdes
15889728Sdes	/*
15989728Sdes	 * Record session in lastlog(5).
16089728Sdes	 */
16189728Sdes	llpos = (off_t)(pwd->pw_uid * sizeof(ll));
16289728Sdes	if (lseek(fd, llpos, L_SET) != llpos)
16389728Sdes		goto file_err;
16489728Sdes	if ((flags & PAM_SILENT) == 0) {
16589728Sdes		if (read(fd, &ll, sizeof(ll)) == sizeof(ll) &&
16689728Sdes		    ll.ll_time != 0) {
16789728Sdes			asprintf(&buf, "Last login: %.*s ", 24 - 5,
16889728Sdes			    ctime(&ll.ll_time));
16989728Sdes			if (buf != NULL) {
17089728Sdes				pam_prompt(pamh, PAM_TEXT_INFO, buf, NULL);
17189728Sdes				free(buf);
17289728Sdes			}
17389728Sdes			if (*ll.ll_host != '\0')
17489728Sdes				asprintf(&buf, "from %.*s\n",
17589728Sdes				    (int)sizeof(ll.ll_host), ll.ll_host);
17689728Sdes			else
17789728Sdes				asprintf(&buf, "on %.*s\n",
17889728Sdes				    (int)sizeof(ll.ll_line), ll.ll_line);
17989728Sdes			if (buf != NULL) {
18089728Sdes				pam_prompt(pamh, PAM_TEXT_INFO, buf, NULL);
18189728Sdes				free(buf);
18289728Sdes			}
18389728Sdes		}
18489728Sdes		if (lseek(fd, llpos, L_SET) != llpos)
18589728Sdes			goto file_err;
18689728Sdes	}
18789728Sdes
18889728Sdes	bzero(&ll, sizeof(ll));
18989728Sdes	time(&ll.ll_time);
19089728Sdes
19189728Sdes	/* note: does not need to be NUL-terminated */
19289728Sdes	strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
19389743Sdes	if (rhost != NULL)
19489728Sdes		/* note: does not need to be NUL-terminated */
19589728Sdes		strncpy(ll.ll_host, rhost, sizeof(ll.ll_host));
19689728Sdes
19789728Sdes	if (write(fd, (char *)&ll, sizeof(ll)) != sizeof(ll) || close(fd) != 0)
19889728Sdes		goto file_err;
19989728Sdes
20089728Sdes	PAM_LOG("Login recorded in %s", _PATH_LASTLOG);
20189748Sdes
20289748Sdes	/*
20389748Sdes	 * Record session in utmp(5) and wtmp(5).
20489748Sdes	 */
20589748Sdes	bzero(&utmp, sizeof(utmp));
20689748Sdes	time(&utmp.ut_time);
20789748Sdes	/* note: does not need to be NUL-terminated */
20889748Sdes	strncpy(utmp.ut_name, user, sizeof(utmp.ut_name));
20989748Sdes	if (rhost != NULL)
21089748Sdes		strncpy(utmp.ut_host, rhost, sizeof(utmp.ut_host));
21189748Sdes	(void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
21289748Sdes	login(&utmp);
21389748Sdes
21489728Sdes	PAM_RETURN(PAM_IGNORE);
21589728Sdes
21689728Sdes file_err:
21789728Sdes	syslog(LOG_ERR, "%s: %m", _PATH_LASTLOG);
21889728Sdes	close(fd);
21989728Sdes	PAM_RETURN(PAM_SERVICE_ERR);
22089728Sdes}
22189728Sdes
22289728SdesPAM_EXTERN int
22390145Smarkmpam_sm_close_session(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv)
22489728Sdes{
22589728Sdes	struct options options;
22689728Sdes
22789728Sdes	pam_std_option(&options, NULL, argc, argv);
22889728Sdes
22989728Sdes	PAM_LOG("Options processed");
23089728Sdes
23189728Sdes	PAM_RETURN(PAM_SUCCESS);
23289728Sdes}
23389728Sdes
23489728SdesPAM_MODULE_ENTRY("pam_lastlog");
235