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 2004 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 <assert.h> 30 #include <pwd.h> 31 #include <signal.h> 32 #include <stdlib.h> 33 #include <string.h> 34 #include <syslog.h> 35 #include <unistd.h> 36 #include <sys/wait.h> 37 38 #include <bsm/adt.h> 39 #include <bsm/adt_event.h> 40 #include "login_audit.h" 41 42 43 44 /* 45 * Key assumption: login is single threaded. 46 */ 47 static void audit_logout(adt_session_data_t *); 48 49 /* 50 * if audit is not enabled, the adt_*() functions simply return without 51 * doing anything. In the success case, the credential has already been 52 * setup with audit data by PAM. 53 */ 54 55 /* 56 * There is no information passed to login.c from rlogin or telnet 57 * about the terminal id. They both set the tid before they 58 * exec login; the value is picked up by adt_start_session() and is 59 * carefully *not* overwritten by adt_load_hostname(). 60 */ 61 62 void 63 audit_success(uint_t event_id, struct passwd *pwd, char *optional_text) 64 { 65 adt_session_data_t *ah; 66 adt_event_data_t *event; 67 int rc; 68 69 assert(pwd != NULL); 70 71 if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA)) { 72 syslog(LOG_AUTH | LOG_ALERT, "audit: %m"); 73 return; 74 } 75 if (adt_set_user(ah, pwd->pw_uid, pwd->pw_gid, 76 pwd->pw_uid, pwd->pw_gid, NULL, ADT_USER)) { 77 syslog(LOG_AUTH | LOG_ALERT, "audit: %m"); 78 (void) adt_end_session(ah); 79 return; 80 } 81 event = adt_alloc_event(ah, event_id); 82 83 if (event == NULL) 84 return; 85 86 switch (event_id) { 87 case ADT_zlogin: 88 event->adt_zlogin.message = optional_text; 89 break; 90 default: 91 break; 92 } 93 rc = adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS); 94 95 (void) adt_free_event(event); 96 if (rc) { 97 (void) adt_end_session(ah); 98 syslog(LOG_AUTH | LOG_ALERT, "audit: %m"); 99 return; 100 } 101 /* 102 * The code above executes whether or not audit is enabled. 103 * However audit_logout must only execute if audit is 104 * enabled so we don't fork unnecessarily. 105 */ 106 if (adt_audit_enabled()) { 107 switch (event_id) { 108 case ADT_login: 109 case ADT_rlogin: 110 case ADT_telnet: 111 case ADT_zlogin: 112 audit_logout(ah); /* fork to catch logout */ 113 break; 114 } 115 } 116 (void) adt_end_session(ah); 117 } 118 119 /* 120 * errors are ignored since there is no action to take on error 121 */ 122 static void 123 audit_logout(adt_session_data_t *ah) 124 { 125 adt_event_data_t *logout; 126 int status; /* wait status */ 127 pid_t pid; 128 129 if ((pid = fork()) == 0) { 130 return; 131 } else if (pid == -1) { 132 syslog(LOG_AUTH | LOG_ALERT, "login: could not fork: %m"); 133 exit(1); 134 } else { 135 /* 136 * When this routine is called, the current working 137 * directory is the user's home directory. Change it 138 * to root for the waiting process so that the user's 139 * home directory can be unmounted if necessary. 140 */ 141 if (chdir("/") != 0) { 142 syslog(LOG_AUTH | LOG_ALERT, 143 "login: could not chdir: %m"); 144 /* since we let the child finish we just bail */ 145 exit(0); 146 } 147 while (pid != waitpid(pid, &status, 0)) 148 continue; 149 150 logout = adt_alloc_event(ah, ADT_logout); 151 if (logout == NULL) 152 exit(0); 153 154 (void) adt_put_event(logout, ADT_SUCCESS, ADT_SUCCESS); 155 156 adt_free_event(logout); 157 exit(0); 158 } 159 } 160 161 /* 162 * errors are ignored since there is no action to take on error. 163 * 164 * If the user id is invalid, pwd is NULL. 165 */ 166 void 167 audit_failure(uint_t event_id, int failure_code, struct passwd *pwd, 168 const char *hostname, const char *ttyname, char *optional_text) 169 { 170 adt_session_data_t *ah; 171 adt_event_data_t *event; 172 uid_t uid; 173 gid_t gid; 174 adt_termid_t *p_tid; 175 176 if (adt_start_session(&ah, NULL, ADT_USE_PROC_DATA)) 177 return; 178 179 uid = ADT_NO_ATTRIB; 180 gid = ADT_NO_ATTRIB; 181 if (pwd != NULL) { 182 uid = pwd->pw_uid; 183 gid = pwd->pw_gid; 184 } 185 /* 186 * If this is a remote login, in.rlogind or in.telnetd has 187 * already set the terminal id, in which case 188 * adt_load_hostname() will use the preset terminal id and 189 * ignore hostname. (If no remote host and ttyname is NULL, 190 * let adt_load_ttyname() figure out what to do.) 191 */ 192 if (*hostname == '\0') 193 (void) adt_load_ttyname(ttyname, &p_tid); 194 else 195 (void) adt_load_hostname(hostname, &p_tid); 196 197 if (adt_set_user(ah, uid, gid, uid, gid, p_tid, ADT_NEW)) { 198 (void) adt_end_session(ah); 199 if (p_tid != NULL) 200 free(p_tid); 201 return; 202 } 203 if (p_tid != NULL) 204 free(p_tid); 205 206 event = adt_alloc_event(ah, event_id); 207 if (event == NULL) { 208 return; 209 } 210 switch (event_id) { 211 case ADT_zlogin: 212 event->adt_zlogin.message = optional_text; 213 break; 214 } 215 (void) adt_put_event(event, ADT_FAILURE, failure_code); 216 217 adt_free_event(event); 218 (void) adt_end_session(ah); 219 } 220