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