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