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 (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23 */ 24 25 #include <sys/types.h> 26 #include <errno.h> 27 #include <synch.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <unistd.h> 31 #include <string.h> 32 #include <strings.h> 33 #include <syslog.h> 34 #include <fcntl.h> 35 #include <bsm/adt.h> 36 #include <bsm/adt_event.h> 37 #include <bsm/audit_uevents.h> 38 #include <pwd.h> 39 #include <nss_dbdefs.h> 40 #include <sys/idmap.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(smb_logon_t *user_info) 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 char sidbuf[SMB_SID_STRSZ]; 89 char *username; 90 char *domain; 91 uid_t uid; 92 gid_t gid; 93 char *sid; 94 int status; 95 int retval; 96 97 if ((token = smb_logon(user_info)) == NULL) { 98 uid = ADT_NO_ATTRIB; 99 gid = ADT_NO_ATTRIB; 100 sid = NT_NULL_SIDSTR; 101 username = user_info->lg_e_username; 102 domain = user_info->lg_e_domain; 103 status = ADT_FAILURE; 104 retval = ADT_FAIL_VALUE_AUTH; 105 } else { 106 uid = token->tkn_user.i_id; 107 gid = token->tkn_primary_grp.i_id; 108 smb_sid_tostr(token->tkn_user.i_sid, sidbuf); 109 sid = sidbuf; 110 username = token->tkn_account_name; 111 domain = token->tkn_domain_name; 112 status = ADT_SUCCESS; 113 retval = ADT_SUCCESS; 114 } 115 116 if (adt_start_session(&ah, NULL, 0)) { 117 syslog(LOG_AUTH | LOG_ALERT, "adt_start_session: %m"); 118 smb_token_destroy(token); 119 return (NULL); 120 } 121 122 if ((event = adt_alloc_event(ah, ADT_smbd_session)) == NULL) { 123 syslog(LOG_AUTH | LOG_ALERT, 124 "adt_alloc_event(ADT_smbd_session): %m"); 125 (void) adt_end_session(ah); 126 smb_token_destroy(token); 127 return (NULL); 128 } 129 130 (void) memset(&termid, 0, sizeof (au_tid_addr_t)); 131 termid.at_port = user_info->lg_local_port; 132 133 if (user_info->lg_clnt_ipaddr.a_family == AF_INET) { 134 termid.at_addr[0] = user_info->lg_clnt_ipaddr.a_ipv4; 135 termid.at_type = AU_IPv4; 136 } else { 137 bcopy(&user_info->lg_clnt_ipaddr.a_ip, termid.at_addr, 138 sizeof (in6_addr_t)); 139 termid.at_type = AU_IPv6; 140 } 141 adt_set_termid(ah, &termid); 142 143 if (adt_set_user(ah, uid, gid, uid, gid, NULL, ADT_NEW)) { 144 syslog(LOG_AUTH | LOG_ALERT, "adt_set_user: %m"); 145 adt_free_event(event); 146 (void) adt_end_session(ah); 147 smb_token_destroy(token); 148 return (NULL); 149 } 150 151 event->adt_smbd_session.domain = domain; 152 event->adt_smbd_session.username = username; 153 event->adt_smbd_session.sid = sid; 154 155 if (adt_put_event(event, status, retval)) 156 syslog(LOG_AUTH | LOG_ALERT, "adt_put_event: %m"); 157 158 adt_free_event(event); 159 160 if (token) { 161 if ((entry = malloc(sizeof (smb_audit_t))) == NULL) { 162 syslog(LOG_ERR, "smbd_user_auth_logon: %m"); 163 (void) adt_end_session(ah); 164 smb_token_destroy(token); 165 return (NULL); 166 } 167 168 entry->sa_handle = ah; 169 entry->sa_uid = uid; 170 entry->sa_gid = gid; 171 entry->sa_username = strdup(username); 172 entry->sa_domain = strdup(domain); 173 174 smb_autohome_add(token); 175 smbd_audit_link(entry); 176 token->tkn_audit_sid = entry->sa_audit_sid; 177 } 178 179 return (token); 180 } 181 182 /* 183 * Logon due to a subsequent SmbSessionSetupX on an existing session. 184 * The user was authenticated during the initial session setup. 185 */ 186 void 187 smbd_user_nonauth_logon(uint32_t audit_sid) 188 { 189 smb_audit_t *entry; 190 191 (void) mutex_lock(&smbd_audit_lock); 192 entry = smbd_audit_list; 193 194 while (entry) { 195 if (entry->sa_audit_sid == audit_sid) { 196 ++entry->sa_refcnt; 197 break; 198 } 199 200 entry = entry->sa_next; 201 } 202 203 (void) mutex_unlock(&smbd_audit_lock); 204 } 205 206 /* 207 * Invoked at user logoff due to SmbLogoffX. If this is the final 208 * logoff for this user on the session, audit the event and terminate 209 * the audit session. 210 */ 211 void 212 smbd_user_auth_logoff(uint32_t audit_sid) 213 { 214 smb_audit_t *entry; 215 adt_session_data_t *ah; 216 adt_event_data_t *event; 217 struct passwd pw; 218 char buf[NSS_LINELEN_PASSWD]; 219 220 if ((entry = smbd_audit_unlink(audit_sid)) == NULL) 221 return; 222 223 if (IDMAP_ID_IS_EPHEMERAL(entry->sa_uid)) { 224 smb_autohome_remove(entry->sa_username); 225 } else { 226 if (getpwuid_r(entry->sa_uid, &pw, buf, sizeof (buf)) == NULL) 227 return; 228 229 smb_autohome_remove(pw.pw_name); 230 } 231 232 ah = entry->sa_handle; 233 234 if ((event = adt_alloc_event(ah, ADT_smbd_logoff)) == NULL) { 235 syslog(LOG_AUTH | LOG_ALERT, 236 "adt_alloc_event(ADT_smbd_logoff): %m"); 237 } else { 238 event->adt_smbd_logoff.domain = entry->sa_domain; 239 event->adt_smbd_logoff.username = entry->sa_username; 240 241 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS)) 242 syslog(LOG_AUTH | LOG_ALERT, "adt_put_event: %m"); 243 244 adt_free_event(event); 245 } 246 247 (void) adt_end_session(ah); 248 249 free(entry->sa_username); 250 free(entry->sa_domain); 251 free(entry); 252 } 253 254 /* 255 * Allocate an id and link an audit handle onto the global list. 256 */ 257 static void 258 smbd_audit_link(smb_audit_t *entry) 259 { 260 (void) mutex_lock(&smbd_audit_lock); 261 262 do { 263 ++smbd_audit_sid; 264 } while ((smbd_audit_sid == 0) || (smbd_audit_sid == (uint32_t)-1)); 265 266 entry->sa_audit_sid = smbd_audit_sid; 267 entry->sa_refcnt = 1; 268 entry->sa_next = smbd_audit_list; 269 smbd_audit_list = entry; 270 271 (void) mutex_unlock(&smbd_audit_lock); 272 } 273 274 /* 275 * Unlink an audit handle. If the reference count reaches 0, the entry 276 * is removed from the list and returned. Otherwise the entry remains 277 * on the list and a null pointer is returned. 278 */ 279 static smb_audit_t * 280 smbd_audit_unlink(uint32_t audit_sid) 281 { 282 smb_audit_t *entry; 283 smb_audit_t **ppe; 284 285 (void) mutex_lock(&smbd_audit_lock); 286 ppe = &smbd_audit_list; 287 288 while (*ppe) { 289 entry = *ppe; 290 291 if (entry->sa_audit_sid == audit_sid) { 292 if (entry->sa_refcnt == 0) 293 break; 294 295 if ((--entry->sa_refcnt) != 0) 296 break; 297 298 *ppe = entry->sa_next; 299 (void) mutex_unlock(&smbd_audit_lock); 300 return (entry); 301 } 302 303 ppe = &(*ppe)->sa_next; 304 } 305 306 (void) mutex_unlock(&smbd_audit_lock); 307 return (NULL); 308 } 309