1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate #include <strings.h>
30*0Sstevel@tonic-gate #include <sys/types.h>
31*0Sstevel@tonic-gate #include <sys/wait.h>
32*0Sstevel@tonic-gate #include <sys/stat.h>
33*0Sstevel@tonic-gate #include <fcntl.h>
34*0Sstevel@tonic-gate #include <stdlib.h>
35*0Sstevel@tonic-gate #include <security/pam_appl.h>
36*0Sstevel@tonic-gate #include <security/pam_modules.h>
37*0Sstevel@tonic-gate #include <security/pam_impl.h>
38*0Sstevel@tonic-gate #include <syslog.h>
39*0Sstevel@tonic-gate #include <pwd.h>
40*0Sstevel@tonic-gate #include <shadow.h>
41*0Sstevel@tonic-gate #include <lastlog.h>
42*0Sstevel@tonic-gate #include <ctype.h>
43*0Sstevel@tonic-gate #include <unistd.h>
44*0Sstevel@tonic-gate #include <stdlib.h>
45*0Sstevel@tonic-gate #include <stdio.h>
46*0Sstevel@tonic-gate #include <libintl.h>
47*0Sstevel@tonic-gate #include <signal.h>
48*0Sstevel@tonic-gate #include <thread.h>
49*0Sstevel@tonic-gate #include <synch.h>
50*0Sstevel@tonic-gate #include <errno.h>
51*0Sstevel@tonic-gate #include <time.h>
52*0Sstevel@tonic-gate #include <string.h>
53*0Sstevel@tonic-gate #include <crypt.h>
54*0Sstevel@tonic-gate #include <assert.h>
55*0Sstevel@tonic-gate #include <nss_dbdefs.h>
56*0Sstevel@tonic-gate 
57*0Sstevel@tonic-gate #define	LASTLOG		"/var/adm/lastlog"
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate /*
60*0Sstevel@tonic-gate  * pam_sm_close_session	- Terminate a PAM authenticated session
61*0Sstevel@tonic-gate  */
62*0Sstevel@tonic-gate /*ARGSUSED*/
63*0Sstevel@tonic-gate int
pam_sm_close_session(pam_handle_t * pamh,int flags,int argc,const char ** argv)64*0Sstevel@tonic-gate pam_sm_close_session(pam_handle_t *pamh, int flags, int argc,
65*0Sstevel@tonic-gate 	const char **argv)
66*0Sstevel@tonic-gate {
67*0Sstevel@tonic-gate 	int	i;
68*0Sstevel@tonic-gate 	int	debug = 0;
69*0Sstevel@tonic-gate 
70*0Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
71*0Sstevel@tonic-gate 		if (strcasecmp(argv[i], "debug") == 0)
72*0Sstevel@tonic-gate 			debug = 1;
73*0Sstevel@tonic-gate 		else
74*0Sstevel@tonic-gate 			syslog(LOG_ERR, "illegal option %s", argv[i]);
75*0Sstevel@tonic-gate 	}
76*0Sstevel@tonic-gate 
77*0Sstevel@tonic-gate 	if (debug)
78*0Sstevel@tonic-gate 		syslog(LOG_DEBUG,
79*0Sstevel@tonic-gate 		    "pam_unix_session: inside pam_sm_close_session()");
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate 	return (PAM_SUCCESS);
82*0Sstevel@tonic-gate }
83*0Sstevel@tonic-gate 
84*0Sstevel@tonic-gate /*ARGSUSED*/
85*0Sstevel@tonic-gate int
pam_sm_open_session(pam_handle_t * pamh,int flags,int argc,const char ** argv)86*0Sstevel@tonic-gate pam_sm_open_session(pam_handle_t *pamh, int flags, int argc,
87*0Sstevel@tonic-gate 	const char **argv)
88*0Sstevel@tonic-gate {
89*0Sstevel@tonic-gate 	int	error;
90*0Sstevel@tonic-gate 	char    *ttyn, *rhost, *user;
91*0Sstevel@tonic-gate 	int	fdl;
92*0Sstevel@tonic-gate 	struct lastlog  newll;
93*0Sstevel@tonic-gate 	struct passwd pwd;
94*0Sstevel@tonic-gate 	char    buffer[NSS_BUFLEN_PASSWD];
95*0Sstevel@tonic-gate 	int	i;
96*0Sstevel@tonic-gate 	int	debug = 0;
97*0Sstevel@tonic-gate 	offset_t	offset;
98*0Sstevel@tonic-gate 	time_t  cur_time;
99*0Sstevel@tonic-gate 
100*0Sstevel@tonic-gate 	for (i = 0; i < argc; i++) {
101*0Sstevel@tonic-gate 		if (strcasecmp(argv[i], "debug") == 0)
102*0Sstevel@tonic-gate 			debug = 1;
103*0Sstevel@tonic-gate 		else
104*0Sstevel@tonic-gate 			syslog(LOG_ERR, "illegal option %s", argv[i]);
105*0Sstevel@tonic-gate 	}
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate 	if (debug)
108*0Sstevel@tonic-gate 		syslog(LOG_DEBUG,
109*0Sstevel@tonic-gate 		    "pam_unix_session: inside pam_sm_open_session()");
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 	if ((error = pam_get_item(pamh, PAM_TTY, (void **)&ttyn))
112*0Sstevel@tonic-gate 	    != PAM_SUCCESS ||
113*0Sstevel@tonic-gate 	    (error = pam_get_item(pamh, PAM_USER, (void **)&user))
114*0Sstevel@tonic-gate 	    != PAM_SUCCESS ||
115*0Sstevel@tonic-gate 	    (error = pam_get_item(pamh, PAM_RHOST, (void **)&rhost))
116*0Sstevel@tonic-gate 	    != PAM_SUCCESS) {
117*0Sstevel@tonic-gate 		return (error);
118*0Sstevel@tonic-gate 	}
119*0Sstevel@tonic-gate 
120*0Sstevel@tonic-gate 	if (user == NULL || *user == '\0')
121*0Sstevel@tonic-gate 		return (PAM_USER_UNKNOWN);
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate 	/* report error if ttyn not set */
124*0Sstevel@tonic-gate 	if (ttyn == NULL)
125*0Sstevel@tonic-gate 		return (PAM_SESSION_ERR);
126*0Sstevel@tonic-gate 
127*0Sstevel@tonic-gate 	if (getpwnam_r(user, &pwd, buffer, sizeof (buffer)) == NULL) {
128*0Sstevel@tonic-gate 		return (PAM_USER_UNKNOWN);
129*0Sstevel@tonic-gate 	}
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate 	if ((fdl = open(LASTLOG, O_RDWR|O_CREAT|O_DSYNC, 0444)) >= 0) {
132*0Sstevel@tonic-gate 		/*
133*0Sstevel@tonic-gate 		 * The value of lastlog is read by the UNIX
134*0Sstevel@tonic-gate 		 * account management module
135*0Sstevel@tonic-gate 		 */
136*0Sstevel@tonic-gate 		offset = (offset_t)pwd.pw_uid *
137*0Sstevel@tonic-gate 		    (offset_t)sizeof (struct lastlog);
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate 		if (llseek(fdl, offset, SEEK_SET) != offset) {
140*0Sstevel@tonic-gate 			syslog(LOG_ERR,
141*0Sstevel@tonic-gate 			    "pam_unix_session: Can't update lastlog: uid %d "
142*0Sstevel@tonic-gate 			    "too large", pwd.pw_uid);
143*0Sstevel@tonic-gate 			(void) close(fdl);
144*0Sstevel@tonic-gate 			return (PAM_SUCCESS);
145*0Sstevel@tonic-gate 		}
146*0Sstevel@tonic-gate 		/*
147*0Sstevel@tonic-gate 		 * use time32_t in case of _LP64
148*0Sstevel@tonic-gate 		 * since it's written in lastlog.h
149*0Sstevel@tonic-gate 		 */
150*0Sstevel@tonic-gate 		(void) time(&cur_time);
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 		bzero((char *)&newll, sizeof (struct lastlog));
153*0Sstevel@tonic-gate #ifdef _LP64
154*0Sstevel@tonic-gate 		newll.ll_time = (time32_t)cur_time;
155*0Sstevel@tonic-gate #else
156*0Sstevel@tonic-gate 		newll.ll_time = cur_time;
157*0Sstevel@tonic-gate #endif
158*0Sstevel@tonic-gate 		if ((strncmp(ttyn, "/dev/", 5) == 0)) {
159*0Sstevel@tonic-gate 			(void) strlcpy(newll.ll_line,
160*0Sstevel@tonic-gate 			    (ttyn + sizeof ("/dev/")-1),
161*0Sstevel@tonic-gate 			    sizeof (newll.ll_line));
162*0Sstevel@tonic-gate 		} else {
163*0Sstevel@tonic-gate 			(void) strlcpy(newll.ll_line, ttyn,
164*0Sstevel@tonic-gate 			    sizeof (newll.ll_line));
165*0Sstevel@tonic-gate 		}
166*0Sstevel@tonic-gate 		if (rhost != NULL) {
167*0Sstevel@tonic-gate 			(void) strlcpy(newll.ll_host, rhost,
168*0Sstevel@tonic-gate 			    sizeof (newll.ll_host));
169*0Sstevel@tonic-gate 		}
170*0Sstevel@tonic-gate 		if (debug) {
171*0Sstevel@tonic-gate 			char	buf[26];
172*0Sstevel@tonic-gate 
173*0Sstevel@tonic-gate 			(void) ctime_r((const time_t *)&cur_time, buf,
174*0Sstevel@tonic-gate 			    sizeof (buf));
175*0Sstevel@tonic-gate 			buf[24] = '\000';
176*0Sstevel@tonic-gate 			syslog(LOG_DEBUG, "pam_unix_session: "
177*0Sstevel@tonic-gate 			    "user = %s, time = %s, tty = %s, host = %s.",
178*0Sstevel@tonic-gate 			    user, buf, newll.ll_line, newll.ll_host);
179*0Sstevel@tonic-gate 		}
180*0Sstevel@tonic-gate 		if (write(fdl, (char *)&newll, sizeof (newll))
181*0Sstevel@tonic-gate 		    != sizeof (newll))
182*0Sstevel@tonic-gate 			syslog(LOG_ERR, "pam_unix_session: Can't write "
183*0Sstevel@tonic-gate 			    "lastlog: uid %d: %m", pwd.pw_uid);
184*0Sstevel@tonic-gate 		if (close(fdl) != 0)
185*0Sstevel@tonic-gate 			syslog(LOG_ERR, "pam_unix_session: Can't close "
186*0Sstevel@tonic-gate 			    "lastlog: uid %d: %m", pwd.pw_uid);
187*0Sstevel@tonic-gate 	}
188*0Sstevel@tonic-gate 	return (PAM_SUCCESS);
189*0Sstevel@tonic-gate }
190