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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/types.h> 27 #include <errno.h> 28 #include <synch.h> 29 #include <stdio.h> 30 #include <stdlib.h> 31 #include <unistd.h> 32 #include <string.h> 33 #include <strings.h> 34 #include <syslog.h> 35 #include <fcntl.h> 36 #include <bsm/adt.h> 37 #include <bsm/adt_event.h> 38 #include <bsm/audit_uevents.h> 39 #include "smbd.h" 40 41 42 /* 43 * An audit session is established at user logon and terminated at user 44 * logoff. 45 * 46 * SMB audit handles are allocated when users logon (SmbSessionSetupX) 47 * and deallocted when a user logs off (SmbLogoffX). Each time an SMB 48 * audit handle is allocated it is added to a global list. 49 */ 50 typedef struct smb_audit { 51 struct smb_audit *sa_next; 52 adt_session_data_t *sa_handle; 53 uid_t sa_uid; 54 gid_t sa_gid; 55 uint32_t sa_audit_sid; 56 uint32_t sa_refcnt; 57 char *sa_domain; 58 char *sa_username; 59 } smb_audit_t; 60 61 static smb_audit_t *smbd_audit_list; 62 static mutex_t smbd_audit_lock; 63 64 /* 65 * Unique identifier for audit sessions in the audit list. 66 * Used to lookup an audit session on logoff. 67 */ 68 static uint32_t smbd_audit_sid; 69 70 static void smbd_audit_link(smb_audit_t *); 71 static smb_audit_t *smbd_audit_unlink(uint32_t); 72 73 74 /* 75 * Invoked at user logon due to SmbSessionSetupX. Authenticate the 76 * user, start an audit session and audit the event. 77 */ 78 smb_token_t * 79 smbd_user_auth_logon(smb_logon_t *user_info) 80 { 81 smb_token_t *token; 82 smb_audit_t *entry; 83 adt_session_data_t *ah; 84 adt_event_data_t *event; 85 au_tid_addr_t termid; 86 char sidbuf[SMB_SID_STRSZ]; 87 char *username; 88 char *domain; 89 uid_t uid; 90 gid_t gid; 91 char *sid; 92 int status; 93 int retval; 94 95 if ((token = smb_logon(user_info)) == NULL) { 96 uid = ADT_NO_ATTRIB; 97 gid = ADT_NO_ATTRIB; 98 sid = NT_NULL_SIDSTR; 99 username = user_info->lg_e_username; 100 domain = user_info->lg_e_domain; 101 status = ADT_FAILURE; 102 retval = ADT_FAIL_VALUE_AUTH; 103 } else { 104 uid = token->tkn_user.i_id; 105 gid = token->tkn_primary_grp.i_id; 106 smb_sid_tostr(token->tkn_user.i_sid, sidbuf); 107 sid = sidbuf; 108 username = token->tkn_account_name; 109 domain = token->tkn_domain_name; 110 status = ADT_SUCCESS; 111 retval = ADT_SUCCESS; 112 } 113 114 if (adt_start_session(&ah, NULL, 0)) { 115 syslog(LOG_AUTH | LOG_ALERT, "adt_start_session: %m"); 116 smb_token_destroy(token); 117 return (NULL); 118 } 119 120 if ((event = adt_alloc_event(ah, ADT_smbd_session)) == NULL) { 121 syslog(LOG_AUTH | LOG_ALERT, 122 "adt_alloc_event(ADT_smbd_session): %m"); 123 (void) adt_end_session(ah); 124 smb_token_destroy(token); 125 return (NULL); 126 } 127 128 (void) memset(&termid, 0, sizeof (au_tid_addr_t)); 129 termid.at_port = user_info->lg_local_port; 130 131 if (user_info->lg_clnt_ipaddr.a_family == AF_INET) { 132 termid.at_addr[0] = user_info->lg_clnt_ipaddr.a_ipv4; 133 termid.at_type = AU_IPv4; 134 } else { 135 bcopy(&user_info->lg_clnt_ipaddr.a_ip, termid.at_addr, 136 IPV6_ADDR_LEN); 137 termid.at_type = AU_IPv6; 138 } 139 adt_set_termid(ah, &termid); 140 141 if (adt_set_user(ah, uid, gid, uid, gid, NULL, ADT_NEW)) { 142 syslog(LOG_AUTH | LOG_ALERT, "adt_set_user: %m"); 143 adt_free_event(event); 144 (void) adt_end_session(ah); 145 smb_token_destroy(token); 146 return (NULL); 147 } 148 149 event->adt_smbd_session.domain = domain; 150 event->adt_smbd_session.username = username; 151 event->adt_smbd_session.sid = sid; 152 153 if (adt_put_event(event, status, retval)) 154 syslog(LOG_AUTH | LOG_ALERT, "adt_put_event: %m"); 155 156 adt_free_event(event); 157 158 if (token) { 159 if ((entry = malloc(sizeof (smb_audit_t))) == NULL) { 160 syslog(LOG_ERR, "smbd_user_auth_logon: %m"); 161 (void) adt_end_session(ah); 162 smb_token_destroy(token); 163 return (NULL); 164 } 165 166 entry->sa_handle = ah; 167 entry->sa_uid = uid; 168 entry->sa_gid = gid; 169 entry->sa_username = strdup(username); 170 entry->sa_domain = strdup(domain); 171 172 smb_autohome_add(token); 173 smbd_audit_link(entry); 174 token->tkn_audit_sid = entry->sa_audit_sid; 175 } 176 177 return (token); 178 } 179 180 /* 181 * Logon due to a subsequent SmbSessionSetupX on an existing session. 182 * The user was authenticated during the initial session setup. 183 */ 184 void 185 smbd_user_nonauth_logon(uint32_t audit_sid) 186 { 187 smb_audit_t *entry; 188 189 (void) mutex_lock(&smbd_audit_lock); 190 entry = smbd_audit_list; 191 192 while (entry) { 193 if (entry->sa_audit_sid == audit_sid) { 194 ++entry->sa_refcnt; 195 break; 196 } 197 198 entry = entry->sa_next; 199 } 200 201 (void) mutex_unlock(&smbd_audit_lock); 202 } 203 204 /* 205 * Invoked at user logoff due to SmbLogoffX. If this is the final 206 * logoff for this user on the session, audit the event and terminate 207 * the audit session. 208 */ 209 void 210 smbd_user_auth_logoff(uint32_t audit_sid) 211 { 212 smb_audit_t *entry; 213 adt_session_data_t *ah; 214 adt_event_data_t *event; 215 216 if ((entry = smbd_audit_unlink(audit_sid)) == NULL) 217 return; 218 219 smb_autohome_remove(entry->sa_username); 220 221 ah = entry->sa_handle; 222 223 if ((event = adt_alloc_event(ah, ADT_smbd_logoff)) == NULL) { 224 syslog(LOG_AUTH | LOG_ALERT, 225 "adt_alloc_event(ADT_smbd_logoff): %m"); 226 } else { 227 event->adt_smbd_logoff.domain = entry->sa_domain; 228 event->adt_smbd_logoff.username = entry->sa_username; 229 230 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS)) 231 syslog(LOG_AUTH | LOG_ALERT, "adt_put_event: %m"); 232 233 adt_free_event(event); 234 } 235 236 (void) adt_end_session(ah); 237 238 free(entry->sa_username); 239 free(entry->sa_domain); 240 free(entry); 241 } 242 243 /* 244 * Allocate an id and link an audit handle onto the global list. 245 */ 246 static void 247 smbd_audit_link(smb_audit_t *entry) 248 { 249 (void) mutex_lock(&smbd_audit_lock); 250 251 do { 252 ++smbd_audit_sid; 253 } while ((smbd_audit_sid == 0) || (smbd_audit_sid == (uint32_t)-1)); 254 255 entry->sa_audit_sid = smbd_audit_sid; 256 entry->sa_refcnt = 1; 257 entry->sa_next = smbd_audit_list; 258 smbd_audit_list = entry; 259 260 (void) mutex_unlock(&smbd_audit_lock); 261 } 262 263 /* 264 * Unlink an audit handle. If the reference count reaches 0, the entry 265 * is removed from the list and returned. Otherwise the entry remains 266 * on the list and a null pointer is returned. 267 */ 268 static smb_audit_t * 269 smbd_audit_unlink(uint32_t audit_sid) 270 { 271 smb_audit_t *entry; 272 smb_audit_t **ppe; 273 274 (void) mutex_lock(&smbd_audit_lock); 275 ppe = &smbd_audit_list; 276 277 while (*ppe) { 278 entry = *ppe; 279 280 if (entry->sa_audit_sid == audit_sid) { 281 if (entry->sa_refcnt == 0) 282 break; 283 284 if ((--entry->sa_refcnt) != 0) 285 break; 286 287 *ppe = entry->sa_next; 288 (void) mutex_unlock(&smbd_audit_lock); 289 return (entry); 290 } 291 292 ppe = &(*ppe)->sa_next; 293 } 294 295 (void) mutex_unlock(&smbd_audit_lock); 296 return (NULL); 297 } 298