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