pam_lastlog.c revision 92297
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.
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 92297 2002-03-14 23:27:59Z 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	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
15190955Ssobomax	fd = open(_PATH_LASTLOG, O_RDWR|O_CREAT, 0644);
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 lastlog(5).
15989728Sdes	 */
16089728Sdes	llpos = (off_t)(pwd->pw_uid * sizeof(ll));
16189728Sdes	if (lseek(fd, llpos, L_SET) != llpos)
16289728Sdes		goto file_err;
16389728Sdes	if ((flags & PAM_SILENT) == 0) {
16489728Sdes		if (read(fd, &ll, sizeof(ll)) == sizeof(ll) &&
16589728Sdes		    ll.ll_time != 0) {
16691714Sdes			pam_info(pamh, "Last login: %.*s ", 24 - 5,
16789728Sdes			    ctime(&ll.ll_time));
16889728Sdes			if (*ll.ll_host != '\0')
16991714Sdes				pam_info(pamh, "from %.*s\n",
17089728Sdes				    (int)sizeof(ll.ll_host), ll.ll_host);
17189728Sdes			else
17291714Sdes				pam_info(pamh, "on %.*s\n",
17389728Sdes				    (int)sizeof(ll.ll_line), ll.ll_line);
17489728Sdes		}
17589728Sdes		if (lseek(fd, llpos, L_SET) != llpos)
17689728Sdes			goto file_err;
17789728Sdes	}
17889728Sdes
17989728Sdes	bzero(&ll, sizeof(ll));
18089728Sdes	time(&ll.ll_time);
18189728Sdes
18289728Sdes	/* note: does not need to be NUL-terminated */
18389728Sdes	strncpy(ll.ll_line, tty, sizeof(ll.ll_line));
18489743Sdes	if (rhost != NULL)
18589728Sdes		/* note: does not need to be NUL-terminated */
18689728Sdes		strncpy(ll.ll_host, rhost, sizeof(ll.ll_host));
18789728Sdes
18889728Sdes	if (write(fd, (char *)&ll, sizeof(ll)) != sizeof(ll) || close(fd) != 0)
18989728Sdes		goto file_err;
19089728Sdes
19189728Sdes	PAM_LOG("Login recorded in %s", _PATH_LASTLOG);
19289748Sdes
19389748Sdes	/*
19489748Sdes	 * Record session in utmp(5) and wtmp(5).
19589748Sdes	 */
19689748Sdes	bzero(&utmp, sizeof(utmp));
19789748Sdes	time(&utmp.ut_time);
19889748Sdes	/* note: does not need to be NUL-terminated */
19989748Sdes	strncpy(utmp.ut_name, user, sizeof(utmp.ut_name));
20089748Sdes	if (rhost != NULL)
20189748Sdes		strncpy(utmp.ut_host, rhost, sizeof(utmp.ut_host));
20289748Sdes	(void)strncpy(utmp.ut_line, tty, sizeof(utmp.ut_line));
20389748Sdes	login(&utmp);
20489748Sdes
20589728Sdes	PAM_RETURN(PAM_IGNORE);
20689728Sdes
20789728Sdes file_err:
20889728Sdes	syslog(LOG_ERR, "%s: %m", _PATH_LASTLOG);
20989728Sdes	close(fd);
21089728Sdes	PAM_RETURN(PAM_SERVICE_ERR);
21189728Sdes}
21289728Sdes
21389728SdesPAM_EXTERN int
21490145Smarkmpam_sm_close_session(pam_handle_t *pamh __unused, int flags __unused, int argc, const char **argv)
21589728Sdes{
21689728Sdes	struct options options;
21789728Sdes
21889728Sdes	pam_std_option(&options, NULL, argc, argv);
21989728Sdes
22089728Sdes	PAM_LOG("Options processed");
22189728Sdes
22289728Sdes	PAM_RETURN(PAM_SUCCESS);
22389728Sdes}
22489728Sdes
22589728SdesPAM_MODULE_ENTRY("pam_lastlog");
226