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