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 * Copyright 2022 Tintri by DDN, Inc. All rights reserved. 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 <pwd.h> 40 #include <nss_dbdefs.h> 41 #include <sys/idmap.h> 42 #include "smbd.h" 43 44 45 /* 46 * An audit session is established at user logon and terminated at user 47 * logoff. 48 * 49 * SMB audit handles are allocated when users logon (SmbSessionSetupX) 50 * and deallocted when a user logs off (SmbLogoffX). Each time an SMB 51 * audit handle is allocated it is added to a global list. 52 */ 53 typedef struct smb_audit { 54 struct smb_audit *sa_next; 55 adt_session_data_t *sa_handle; 56 uid_t sa_uid; 57 gid_t sa_gid; 58 uint32_t sa_audit_sid; 59 uint32_t sa_refcnt; 60 char *sa_domain; 61 char *sa_username; 62 } smb_audit_t; 63 64 static smb_audit_t *smbd_audit_list; 65 static mutex_t smbd_audit_lock; 66 67 /* 68 * Unique identifier for audit sessions in the audit list. 69 * Used to lookup an audit session on logoff. 70 */ 71 static uint32_t smbd_audit_sid; 72 73 static void smbd_audit_link(smb_audit_t *); 74 static smb_audit_t *smbd_audit_unlink(uint32_t); 75 76 77 /* 78 * Invoked at user logon due to SmbSessionSetupX. Authenticate the 79 * user. 80 * 81 * On error, returns NULL, and status in user_info->lg_status. 82 * 83 * Equivalent to smbd_krb5ssp_work(). 84 */ 85 smb_token_t * 86 smbd_user_auth_logon(smb_logon_t *user_info) 87 { 88 smb_token_t *token = NULL; 89 smb_logon_t tmp_user; 90 char *p; 91 char *buf = NULL; 92 93 if (user_info->lg_username == NULL || 94 user_info->lg_domain == NULL || 95 user_info->lg_workstation == NULL) { 96 user_info->lg_status = NT_STATUS_INVALID_PARAMETER; 97 return (NULL); 98 } 99 100 /* 101 * Avoid modifying the caller-provided struct because it 102 * may or may not point to allocated strings etc. 103 * Copy to tmp_user, auth, then copy the (out) lg_status 104 * member back to the caller-provided struct. 105 */ 106 tmp_user = *user_info; 107 if (tmp_user.lg_username[0] == '\0') { 108 tmp_user.lg_flags |= SMB_ATF_ANON; 109 tmp_user.lg_e_username = "anonymous"; 110 } else { 111 tmp_user.lg_e_username = tmp_user.lg_username; 112 } 113 114 /* Handle user@domain format. */ 115 if (tmp_user.lg_domain[0] == '\0' && 116 (p = strchr(tmp_user.lg_e_username, '@')) != NULL) { 117 buf = strdup(tmp_user.lg_e_username); 118 if (buf == NULL) { 119 user_info->lg_status = NT_STATUS_NO_MEMORY; 120 return (NULL); 121 } 122 p = buf + (p - tmp_user.lg_e_username); 123 *p = '\0'; 124 tmp_user.lg_e_domain = p + 1; 125 tmp_user.lg_e_username = buf; 126 } else { 127 tmp_user.lg_e_domain = tmp_user.lg_domain; 128 } 129 130 token = smb_logon(&tmp_user); 131 132 if (token == NULL && tmp_user.lg_status == 0) /* should not happen */ 133 user_info->lg_status = NT_STATUS_INTERNAL_ERROR; 134 else 135 user_info->lg_status = tmp_user.lg_status; 136 137 user_info->lg_status = smbd_logon_final(token, 138 &user_info->lg_clnt_ipaddr, tmp_user.lg_e_username, 139 tmp_user.lg_e_domain, user_info->lg_status); 140 141 free(buf); 142 143 if (user_info->lg_status != 0) { 144 smb_token_destroy(token); 145 token = NULL; 146 } 147 return (token); 148 } 149 150 /* Start an audit session and audit the event. */ 151 static boolean_t 152 smbd_logon_audit(smb_token_t *token, smb_inaddr_t *ipaddr, char *username, 153 char *domain) 154 { 155 smb_audit_t *entry; 156 adt_session_data_t *ah = NULL; 157 adt_event_data_t *event; 158 au_tid_addr_t termid; 159 char sidbuf[SMB_SID_STRSZ]; 160 uid_t uid; 161 gid_t gid; 162 char *sid; 163 int status; 164 int retval; 165 166 assert(username != NULL); 167 assert(domain != NULL); 168 169 if (token == NULL) { 170 uid = ADT_NO_ATTRIB; 171 gid = ADT_NO_ATTRIB; 172 sid = NT_NULL_SIDSTR; 173 /* use the 'default' username and domain we were given */ 174 status = ADT_FAILURE; 175 retval = ADT_FAIL_VALUE_AUTH; 176 } else { 177 uid = token->tkn_user.i_id; 178 gid = token->tkn_primary_grp.i_id; 179 smb_sid_tostr(token->tkn_user.i_sid, sidbuf); 180 sid = sidbuf; 181 username = token->tkn_account_name; 182 domain = token->tkn_domain_name; 183 status = ADT_SUCCESS; 184 retval = ADT_SUCCESS; 185 } 186 187 if (adt_start_session(&ah, NULL, 0)) { 188 syslog(LOG_AUTH | LOG_ALERT, "adt_start_session: %m"); 189 goto errout; 190 } 191 192 if ((event = adt_alloc_event(ah, ADT_smbd_session)) == NULL) { 193 syslog(LOG_AUTH | LOG_ALERT, 194 "adt_alloc_event(ADT_smbd_session): %m"); 195 goto errout; 196 } 197 198 (void) memset(&termid, 0, sizeof (au_tid_addr_t)); 199 termid.at_port = IPPORT_SMB; 200 201 if (ipaddr->a_family == AF_INET) { 202 termid.at_addr[0] = ipaddr->a_ipv4; 203 termid.at_type = AU_IPv4; 204 } else { 205 bcopy(&ipaddr->a_ip, termid.at_addr, 206 sizeof (in6_addr_t)); 207 termid.at_type = AU_IPv6; 208 } 209 adt_set_termid(ah, &termid); 210 211 if (adt_set_user(ah, uid, gid, uid, gid, NULL, ADT_NEW)) { 212 syslog(LOG_AUTH | LOG_ALERT, "adt_set_user: %m"); 213 adt_free_event(event); 214 goto errout; 215 } 216 217 event->adt_smbd_session.domain = domain; 218 event->adt_smbd_session.username = username; 219 event->adt_smbd_session.sid = sid; 220 221 if (adt_put_event(event, status, retval)) 222 syslog(LOG_AUTH | LOG_ALERT, "adt_put_event: %m"); 223 224 adt_free_event(event); 225 226 if (token) { 227 if ((entry = malloc(sizeof (smb_audit_t))) == NULL) { 228 syslog(LOG_ERR, "smbd_user_auth_logon: %m"); 229 goto errout; 230 } 231 232 entry->sa_handle = ah; 233 entry->sa_uid = uid; 234 entry->sa_gid = gid; 235 entry->sa_username = strdup(username); 236 entry->sa_domain = strdup(domain); 237 238 smbd_audit_link(entry); 239 token->tkn_audit_sid = entry->sa_audit_sid; 240 } 241 242 return (B_TRUE); 243 errout: 244 (void) adt_end_session(ah); 245 return (B_FALSE); 246 } 247 248 /* 249 * Handles all of the work needed to be done after SMB authentication, 250 * regardless of the auth flavor (Kerberos or NTLM). 251 * 252 * This should return the original status to the caller, unless something 253 * here causes us to turn what would be a success into a failure 254 * (or we decide we should override the original error for some reason). 255 */ 256 uint32_t 257 smbd_logon_final(smb_token_t *token, smb_inaddr_t *ipaddr, char *username, 258 char *domain, uint32_t status) 259 { 260 assert(token != NULL || status != 0); 261 262 if (!smbd_logon_audit(token, ipaddr, username, domain) && status == 0) 263 return (NT_STATUS_AUDIT_FAILED); 264 265 if (status == 0) 266 smb_autohome_add(token); 267 268 return (status); 269 } 270 271 /* 272 * Logon due to a subsequent SmbSessionSetupX on an existing session. 273 * The user was authenticated during the initial session setup. 274 */ 275 void 276 smbd_user_nonauth_logon(uint32_t audit_sid) 277 { 278 smb_audit_t *entry; 279 280 (void) mutex_lock(&smbd_audit_lock); 281 entry = smbd_audit_list; 282 283 while (entry) { 284 if (entry->sa_audit_sid == audit_sid) { 285 ++entry->sa_refcnt; 286 break; 287 } 288 289 entry = entry->sa_next; 290 } 291 292 (void) mutex_unlock(&smbd_audit_lock); 293 } 294 295 /* 296 * Invoked at user logoff due to SMB Logoff. If this is the final 297 * logoff for this user on the session, audit the event and terminate 298 * the audit session. 299 * 300 * This is called to logoff both NTLMSSP and KRB5SSP authentications. 301 */ 302 void 303 smbd_user_auth_logoff(uint32_t audit_sid) 304 { 305 smb_audit_t *entry; 306 adt_session_data_t *ah; 307 adt_event_data_t *event; 308 struct passwd pw; 309 char buf[NSS_LINELEN_PASSWD]; 310 311 if ((entry = smbd_audit_unlink(audit_sid)) == NULL) 312 return; 313 314 if (IDMAP_ID_IS_EPHEMERAL(entry->sa_uid)) { 315 smb_autohome_remove(entry->sa_username); 316 } else { 317 if (getpwuid_r(entry->sa_uid, &pw, buf, sizeof (buf)) == NULL) 318 return; 319 320 smb_autohome_remove(pw.pw_name); 321 } 322 323 ah = entry->sa_handle; 324 325 if ((event = adt_alloc_event(ah, ADT_smbd_logoff)) == NULL) { 326 syslog(LOG_AUTH | LOG_ALERT, 327 "adt_alloc_event(ADT_smbd_logoff): %m"); 328 } else { 329 event->adt_smbd_logoff.domain = entry->sa_domain; 330 event->adt_smbd_logoff.username = entry->sa_username; 331 332 if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS)) 333 syslog(LOG_AUTH | LOG_ALERT, "adt_put_event: %m"); 334 335 adt_free_event(event); 336 } 337 338 (void) adt_end_session(ah); 339 340 free(entry->sa_username); 341 free(entry->sa_domain); 342 free(entry); 343 } 344 345 /* 346 * Allocate an id and link an audit handle onto the global list. 347 */ 348 static void 349 smbd_audit_link(smb_audit_t *entry) 350 { 351 (void) mutex_lock(&smbd_audit_lock); 352 353 do { 354 ++smbd_audit_sid; 355 } while ((smbd_audit_sid == 0) || (smbd_audit_sid == (uint32_t)-1)); 356 357 entry->sa_audit_sid = smbd_audit_sid; 358 entry->sa_refcnt = 1; 359 entry->sa_next = smbd_audit_list; 360 smbd_audit_list = entry; 361 362 (void) mutex_unlock(&smbd_audit_lock); 363 } 364 365 /* 366 * Unlink an audit handle. If the reference count reaches 0, the entry 367 * is removed from the list and returned. Otherwise the entry remains 368 * on the list and a null pointer is returned. 369 */ 370 static smb_audit_t * 371 smbd_audit_unlink(uint32_t audit_sid) 372 { 373 smb_audit_t *entry; 374 smb_audit_t **ppe; 375 376 (void) mutex_lock(&smbd_audit_lock); 377 ppe = &smbd_audit_list; 378 379 while (*ppe) { 380 entry = *ppe; 381 382 if (entry->sa_audit_sid == audit_sid) { 383 if (entry->sa_refcnt == 0) 384 break; 385 386 if ((--entry->sa_refcnt) != 0) 387 break; 388 389 *ppe = entry->sa_next; 390 (void) mutex_unlock(&smbd_audit_lock); 391 return (entry); 392 } 393 394 ppe = &(*ppe)->sa_next; 395 } 396 397 (void) mutex_unlock(&smbd_audit_lock); 398 return (NULL); 399 } 400