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 * Copyright 2016 Toomas Soome <tsoome@me.com> 26 */ 27 28 #include <strings.h> 29 #include <sys/types.h> 30 #include <sys/wait.h> 31 #include <sys/stat.h> 32 #include <fcntl.h> 33 #include <stdlib.h> 34 #include <security/pam_appl.h> 35 #include <security/pam_modules.h> 36 #include <security/pam_impl.h> 37 #include <syslog.h> 38 #include <pwd.h> 39 #include <shadow.h> 40 #include <lastlog.h> 41 #include <ctype.h> 42 #include <unistd.h> 43 #include <stdlib.h> 44 #include <stdio.h> 45 #include <libintl.h> 46 #include <signal.h> 47 #include <thread.h> 48 #include <synch.h> 49 #include <errno.h> 50 #include <time.h> 51 #include <string.h> 52 #include <crypt.h> 53 #include <assert.h> 54 #include <nss_dbdefs.h> 55 56 #define LASTLOG "/var/adm/lastlog" 57 58 /* 59 * pam_sm_close_session - Terminate a PAM authenticated session 60 */ 61 /*ARGSUSED*/ 62 int 63 pam_sm_close_session(pam_handle_t *pamh, int flags, int argc, 64 const char **argv) 65 { 66 int i; 67 int debug = 0; 68 69 for (i = 0; i < argc; i++) { 70 if (strcasecmp(argv[i], "debug") == 0) 71 debug = 1; 72 else if (strcasecmp(argv[i], "nowarn") != 0) 73 syslog(LOG_ERR, "illegal option %s", argv[i]); 74 } 75 76 if (debug) 77 syslog(LOG_DEBUG, 78 "pam_unix_session: inside pam_sm_close_session()"); 79 80 return (PAM_SUCCESS); 81 } 82 83 /*ARGSUSED*/ 84 int 85 pam_sm_open_session(pam_handle_t *pamh, int flags, int argc, 86 const char **argv) 87 { 88 int error; 89 char *ttyn, *rhost, *user; 90 int fdl; 91 struct lastlog newll; 92 struct passwd pwd; 93 char buffer[NSS_BUFLEN_PASSWD]; 94 int i; 95 int debug = 0; 96 offset_t offset; 97 time_t cur_time; 98 99 for (i = 0; i < argc; i++) { 100 if (strcasecmp(argv[i], "debug") == 0) 101 debug = 1; 102 else if (strcasecmp(argv[i], "nowarn") == 0) 103 flags = flags | PAM_SILENT; 104 else 105 syslog(LOG_ERR, "illegal option %s", argv[i]); 106 } 107 108 if (debug) 109 syslog(LOG_DEBUG, 110 "pam_unix_session: inside pam_sm_open_session()"); 111 112 if ((error = pam_get_item(pamh, PAM_TTY, (void **)&ttyn)) 113 != PAM_SUCCESS || 114 (error = pam_get_item(pamh, PAM_USER, (void **)&user)) 115 != PAM_SUCCESS || 116 (error = pam_get_item(pamh, PAM_RHOST, (void **)&rhost)) 117 != PAM_SUCCESS) { 118 return (error); 119 } 120 121 if (user == NULL || *user == '\0') 122 return (PAM_USER_UNKNOWN); 123 124 /* report error if ttyn not set */ 125 if (ttyn == NULL) 126 return (PAM_SESSION_ERR); 127 128 if (getpwnam_r(user, &pwd, buffer, sizeof (buffer)) == NULL) { 129 return (PAM_USER_UNKNOWN); 130 } 131 132 if ((fdl = open(LASTLOG, O_RDWR|O_CREAT|O_DSYNC, 0444)) >= 0) { 133 /* 134 * The value of lastlog is read by the UNIX 135 * account management module 136 */ 137 offset = (offset_t)pwd.pw_uid * 138 (offset_t)sizeof (struct lastlog); 139 140 if (llseek(fdl, offset, SEEK_SET) != offset) { 141 syslog(LOG_ERR, 142 "pam_unix_session: Can't update lastlog: uid %d " 143 "too large", pwd.pw_uid); 144 (void) close(fdl); 145 return (PAM_SUCCESS); 146 } 147 /* 148 * use time32_t in case of _LP64 149 * since it's written in lastlog.h 150 */ 151 (void) time(&cur_time); 152 153 bzero((char *)&newll, sizeof (struct lastlog)); 154 #ifdef _LP64 155 newll.ll_time = (time32_t)cur_time; 156 #else 157 newll.ll_time = cur_time; 158 #endif 159 if ((strncmp(ttyn, "/dev/", 5) == 0)) { 160 (void) strlcpy(newll.ll_line, 161 (ttyn + sizeof ("/dev/")-1), 162 sizeof (newll.ll_line)); 163 } else { 164 (void) strlcpy(newll.ll_line, ttyn, 165 sizeof (newll.ll_line)); 166 } 167 if (rhost != NULL) { 168 (void) strlcpy(newll.ll_host, rhost, 169 sizeof (newll.ll_host)); 170 } 171 if (debug) { 172 char buf[26]; 173 174 (void) ctime_r((const time_t *)&cur_time, buf, 175 sizeof (buf)); 176 buf[24] = '\000'; 177 syslog(LOG_DEBUG, "pam_unix_session: " 178 "user = %s, time = %s, tty = %s, host = %s.", 179 user, buf, newll.ll_line, newll.ll_host); 180 } 181 if (write(fdl, (char *)&newll, sizeof (newll)) 182 != sizeof (newll)) 183 syslog(LOG_ERR, "pam_unix_session: Can't write " 184 "lastlog: uid %d: %m", pwd.pw_uid); 185 if (close(fdl) != 0) 186 syslog(LOG_ERR, "pam_unix_session: Can't close " 187 "lastlog: uid %d: %m", pwd.pw_uid); 188 } 189 return (PAM_SUCCESS); 190 } 191