1da6c28aaSamw /* 2da6c28aaSamw * CDDL HEADER START 3da6c28aaSamw * 4da6c28aaSamw * The contents of this file are subject to the terms of the 5da6c28aaSamw * Common Development and Distribution License (the "License"). 6da6c28aaSamw * You may not use this file except in compliance with the License. 7da6c28aaSamw * 8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9da6c28aaSamw * or http://www.opensolaris.org/os/licensing. 10da6c28aaSamw * See the License for the specific language governing permissions 11da6c28aaSamw * and limitations under the License. 12da6c28aaSamw * 13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each 14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the 16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying 17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner] 18da6c28aaSamw * 19da6c28aaSamw * CDDL HEADER END 20da6c28aaSamw */ 21da6c28aaSamw /* 22c5866007SKeyur Desai * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 23437d9da7SMatt Barden * Copyright 2017 Nexenta Systems, Inc. All rights reserved. 24da6c28aaSamw */ 25da6c28aaSamw 26da6c28aaSamw #include <sys/types.h> 27da6c28aaSamw #include <errno.h> 28da6c28aaSamw #include <synch.h> 29da6c28aaSamw #include <stdio.h> 30da6c28aaSamw #include <stdlib.h> 31da6c28aaSamw #include <unistd.h> 32da6c28aaSamw #include <string.h> 33da6c28aaSamw #include <strings.h> 34da6c28aaSamw #include <syslog.h> 35da6c28aaSamw #include <fcntl.h> 36da6c28aaSamw #include <bsm/adt.h> 37da6c28aaSamw #include <bsm/adt_event.h> 38da6c28aaSamw #include <bsm/audit_uevents.h> 39c5866007SKeyur Desai #include <pwd.h> 40c5866007SKeyur Desai #include <nss_dbdefs.h> 41c5866007SKeyur Desai #include <sys/idmap.h> 42da6c28aaSamw #include "smbd.h" 43da6c28aaSamw 44da6c28aaSamw 45da6c28aaSamw /* 46da6c28aaSamw * An audit session is established at user logon and terminated at user 47da6c28aaSamw * logoff. 48da6c28aaSamw * 49da6c28aaSamw * SMB audit handles are allocated when users logon (SmbSessionSetupX) 50da6c28aaSamw * and deallocted when a user logs off (SmbLogoffX). Each time an SMB 51da6c28aaSamw * audit handle is allocated it is added to a global list. 52da6c28aaSamw */ 53da6c28aaSamw typedef struct smb_audit { 54da6c28aaSamw struct smb_audit *sa_next; 55da6c28aaSamw adt_session_data_t *sa_handle; 56da6c28aaSamw uid_t sa_uid; 57da6c28aaSamw gid_t sa_gid; 58da6c28aaSamw uint32_t sa_audit_sid; 59da6c28aaSamw uint32_t sa_refcnt; 60da6c28aaSamw char *sa_domain; 61da6c28aaSamw char *sa_username; 62da6c28aaSamw } smb_audit_t; 63da6c28aaSamw 64da6c28aaSamw static smb_audit_t *smbd_audit_list; 65da6c28aaSamw static mutex_t smbd_audit_lock; 66da6c28aaSamw 67da6c28aaSamw /* 68da6c28aaSamw * Unique identifier for audit sessions in the audit list. 69da6c28aaSamw * Used to lookup an audit session on logoff. 70da6c28aaSamw */ 71da6c28aaSamw static uint32_t smbd_audit_sid; 72da6c28aaSamw 73da6c28aaSamw static void smbd_audit_link(smb_audit_t *); 74da6c28aaSamw static smb_audit_t *smbd_audit_unlink(uint32_t); 75da6c28aaSamw 76da6c28aaSamw 77da6c28aaSamw /* 78da6c28aaSamw * Invoked at user logon due to SmbSessionSetupX. Authenticate the 79da6c28aaSamw * user, start an audit session and audit the event. 80*975041ddSGordon Ross * 81*975041ddSGordon Ross * On error, returns NULL, and status in user_info->lg_status 82da6c28aaSamw */ 83da6c28aaSamw smb_token_t * 849fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smbd_user_auth_logon(smb_logon_t *user_info) 85da6c28aaSamw { 86437d9da7SMatt Barden smb_token_t *token = NULL; 87da6c28aaSamw smb_audit_t *entry; 88437d9da7SMatt Barden adt_session_data_t *ah = NULL; 89da6c28aaSamw adt_event_data_t *event; 9012b65585SGordon Ross smb_logon_t tmp_user; 91da6c28aaSamw au_tid_addr_t termid; 926537f381Sas200622 char sidbuf[SMB_SID_STRSZ]; 937f667e74Sjose borrego char *username; 947f667e74Sjose borrego char *domain; 95da6c28aaSamw uid_t uid; 96da6c28aaSamw gid_t gid; 97da6c28aaSamw char *sid; 98da6c28aaSamw int status; 99da6c28aaSamw int retval; 100437d9da7SMatt Barden char *p; 101437d9da7SMatt Barden char *buf = NULL; 102da6c28aaSamw 10312b65585SGordon Ross if (user_info->lg_username == NULL || 10412b65585SGordon Ross user_info->lg_domain == NULL || 10512b65585SGordon Ross user_info->lg_workstation == NULL) { 106*975041ddSGordon Ross user_info->lg_status = NT_STATUS_INVALID_PARAMETER; 10712b65585SGordon Ross return (NULL); 10812b65585SGordon Ross } 10912b65585SGordon Ross 110*975041ddSGordon Ross /* 111*975041ddSGordon Ross * Avoid modifying the caller-provided struct because it 112*975041ddSGordon Ross * may or may not point to allocated strings etc. 113*975041ddSGordon Ross * Copy to tmp_user, auth, then copy the (out) lg_status 114*975041ddSGordon Ross * member back to the caller-provided struct. 115*975041ddSGordon Ross */ 11612b65585SGordon Ross tmp_user = *user_info; 11712b65585SGordon Ross if (tmp_user.lg_username[0] == '\0') { 11812b65585SGordon Ross tmp_user.lg_flags |= SMB_ATF_ANON; 11912b65585SGordon Ross tmp_user.lg_e_username = "anonymous"; 12012b65585SGordon Ross } else { 12112b65585SGordon Ross tmp_user.lg_e_username = tmp_user.lg_username; 12212b65585SGordon Ross } 123437d9da7SMatt Barden 124437d9da7SMatt Barden /* Handle user@domain format. */ 125437d9da7SMatt Barden if (tmp_user.lg_domain[0] == '\0' && 126437d9da7SMatt Barden (p = strchr(tmp_user.lg_e_username, '@')) != NULL) { 127437d9da7SMatt Barden buf = strdup(tmp_user.lg_e_username); 128437d9da7SMatt Barden if (buf == NULL) 129437d9da7SMatt Barden goto errout; 130437d9da7SMatt Barden p = buf + (p - tmp_user.lg_e_username); 131437d9da7SMatt Barden *p = '\0'; 132437d9da7SMatt Barden tmp_user.lg_e_domain = p + 1; 133437d9da7SMatt Barden tmp_user.lg_e_username = buf; 134437d9da7SMatt Barden } else { 13512b65585SGordon Ross tmp_user.lg_e_domain = tmp_user.lg_domain; 136437d9da7SMatt Barden } 13712b65585SGordon Ross 138*975041ddSGordon Ross token = smb_logon(&tmp_user); 139*975041ddSGordon Ross user_info->lg_status = tmp_user.lg_status; 140*975041ddSGordon Ross 141*975041ddSGordon Ross if (token == NULL) { 142*975041ddSGordon Ross if (user_info->lg_status == 0) /* should not happen */ 143*975041ddSGordon Ross user_info->lg_status = NT_STATUS_INTERNAL_ERROR; 144da6c28aaSamw uid = ADT_NO_ATTRIB; 145da6c28aaSamw gid = ADT_NO_ATTRIB; 1466537f381Sas200622 sid = NT_NULL_SIDSTR; 14712b65585SGordon Ross username = tmp_user.lg_e_username; 14812b65585SGordon Ross domain = tmp_user.lg_e_domain; 149da6c28aaSamw status = ADT_FAILURE; 150da6c28aaSamw retval = ADT_FAIL_VALUE_AUTH; 151da6c28aaSamw } else { 1527f667e74Sjose borrego uid = token->tkn_user.i_id; 1537f667e74Sjose borrego gid = token->tkn_primary_grp.i_id; 1547f667e74Sjose borrego smb_sid_tostr(token->tkn_user.i_sid, sidbuf); 1556537f381Sas200622 sid = sidbuf; 1567f667e74Sjose borrego username = token->tkn_account_name; 1577f667e74Sjose borrego domain = token->tkn_domain_name; 158da6c28aaSamw status = ADT_SUCCESS; 159da6c28aaSamw retval = ADT_SUCCESS; 160da6c28aaSamw } 161da6c28aaSamw 162da6c28aaSamw if (adt_start_session(&ah, NULL, 0)) { 163da6c28aaSamw syslog(LOG_AUTH | LOG_ALERT, "adt_start_session: %m"); 164*975041ddSGordon Ross user_info->lg_status = NT_STATUS_AUDIT_FAILED; 165437d9da7SMatt Barden goto errout; 166da6c28aaSamw } 167da6c28aaSamw 168da6c28aaSamw if ((event = adt_alloc_event(ah, ADT_smbd_session)) == NULL) { 169da6c28aaSamw syslog(LOG_AUTH | LOG_ALERT, 170da6c28aaSamw "adt_alloc_event(ADT_smbd_session): %m"); 171*975041ddSGordon Ross user_info->lg_status = NT_STATUS_AUDIT_FAILED; 172437d9da7SMatt Barden goto errout; 173da6c28aaSamw } 174da6c28aaSamw 175da6c28aaSamw (void) memset(&termid, 0, sizeof (au_tid_addr_t)); 1769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States termid.at_port = user_info->lg_local_port; 1777f667e74Sjose borrego 1789fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (user_info->lg_clnt_ipaddr.a_family == AF_INET) { 1799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States termid.at_addr[0] = user_info->lg_clnt_ipaddr.a_ipv4; 180da6c28aaSamw termid.at_type = AU_IPv4; 1817f667e74Sjose borrego } else { 1829fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States bcopy(&user_info->lg_clnt_ipaddr.a_ip, termid.at_addr, 183b819cea2SGordon Ross sizeof (in6_addr_t)); 1847f667e74Sjose borrego termid.at_type = AU_IPv6; 1857f667e74Sjose borrego } 186da6c28aaSamw adt_set_termid(ah, &termid); 187da6c28aaSamw 188da6c28aaSamw if (adt_set_user(ah, uid, gid, uid, gid, NULL, ADT_NEW)) { 189da6c28aaSamw syslog(LOG_AUTH | LOG_ALERT, "adt_set_user: %m"); 190da6c28aaSamw adt_free_event(event); 191*975041ddSGordon Ross user_info->lg_status = NT_STATUS_AUDIT_FAILED; 192437d9da7SMatt Barden goto errout; 193da6c28aaSamw } 194da6c28aaSamw 1957f667e74Sjose borrego event->adt_smbd_session.domain = domain; 1967f667e74Sjose borrego event->adt_smbd_session.username = username; 197da6c28aaSamw event->adt_smbd_session.sid = sid; 198da6c28aaSamw 199da6c28aaSamw if (adt_put_event(event, status, retval)) 200da6c28aaSamw syslog(LOG_AUTH | LOG_ALERT, "adt_put_event: %m"); 201da6c28aaSamw 202da6c28aaSamw adt_free_event(event); 203da6c28aaSamw 204da6c28aaSamw if (token) { 205da6c28aaSamw if ((entry = malloc(sizeof (smb_audit_t))) == NULL) { 206da6c28aaSamw syslog(LOG_ERR, "smbd_user_auth_logon: %m"); 207*975041ddSGordon Ross user_info->lg_status = 208*975041ddSGordon Ross NT_STATUS_INSUFFICIENT_RESOURCES; 209437d9da7SMatt Barden goto errout; 210da6c28aaSamw } 211da6c28aaSamw 212da6c28aaSamw entry->sa_handle = ah; 213da6c28aaSamw entry->sa_uid = uid; 214da6c28aaSamw entry->sa_gid = gid; 2157f667e74Sjose borrego entry->sa_username = strdup(username); 2167f667e74Sjose borrego entry->sa_domain = strdup(domain); 217da6c28aaSamw 218fe1c642dSBill Krier smb_autohome_add(token); 219da6c28aaSamw smbd_audit_link(entry); 220da6c28aaSamw token->tkn_audit_sid = entry->sa_audit_sid; 221*975041ddSGordon Ross 222*975041ddSGordon Ross user_info->lg_status = NT_STATUS_SUCCESS; 223da6c28aaSamw } 224da6c28aaSamw 225437d9da7SMatt Barden free(buf); 226437d9da7SMatt Barden 227da6c28aaSamw return (token); 228437d9da7SMatt Barden 229437d9da7SMatt Barden errout: 230437d9da7SMatt Barden free(buf); 231437d9da7SMatt Barden (void) adt_end_session(ah); 232437d9da7SMatt Barden smb_token_destroy(token); 233437d9da7SMatt Barden return (NULL); 234da6c28aaSamw } 235da6c28aaSamw 236da6c28aaSamw /* 237da6c28aaSamw * Logon due to a subsequent SmbSessionSetupX on an existing session. 238da6c28aaSamw * The user was authenticated during the initial session setup. 239da6c28aaSamw */ 240da6c28aaSamw void 241da6c28aaSamw smbd_user_nonauth_logon(uint32_t audit_sid) 242da6c28aaSamw { 243da6c28aaSamw smb_audit_t *entry; 244da6c28aaSamw 245da6c28aaSamw (void) mutex_lock(&smbd_audit_lock); 246da6c28aaSamw entry = smbd_audit_list; 247da6c28aaSamw 248da6c28aaSamw while (entry) { 249da6c28aaSamw if (entry->sa_audit_sid == audit_sid) { 250da6c28aaSamw ++entry->sa_refcnt; 251da6c28aaSamw break; 252da6c28aaSamw } 253da6c28aaSamw 254da6c28aaSamw entry = entry->sa_next; 255da6c28aaSamw } 256da6c28aaSamw 257da6c28aaSamw (void) mutex_unlock(&smbd_audit_lock); 258da6c28aaSamw } 259da6c28aaSamw 260da6c28aaSamw /* 261da6c28aaSamw * Invoked at user logoff due to SmbLogoffX. If this is the final 262da6c28aaSamw * logoff for this user on the session, audit the event and terminate 263da6c28aaSamw * the audit session. 264da6c28aaSamw */ 265da6c28aaSamw void 266da6c28aaSamw smbd_user_auth_logoff(uint32_t audit_sid) 267da6c28aaSamw { 268da6c28aaSamw smb_audit_t *entry; 269da6c28aaSamw adt_session_data_t *ah; 270da6c28aaSamw adt_event_data_t *event; 271c5866007SKeyur Desai struct passwd pw; 272c5866007SKeyur Desai char buf[NSS_LINELEN_PASSWD]; 273da6c28aaSamw 274da6c28aaSamw if ((entry = smbd_audit_unlink(audit_sid)) == NULL) 275da6c28aaSamw return; 276da6c28aaSamw 277c5866007SKeyur Desai if (IDMAP_ID_IS_EPHEMERAL(entry->sa_uid)) { 2783ad684d6Sjb150015 smb_autohome_remove(entry->sa_username); 279c5866007SKeyur Desai } else { 280c5866007SKeyur Desai if (getpwuid_r(entry->sa_uid, &pw, buf, sizeof (buf)) == NULL) 281c5866007SKeyur Desai return; 282c5866007SKeyur Desai 283c5866007SKeyur Desai smb_autohome_remove(pw.pw_name); 284c5866007SKeyur Desai } 285da6c28aaSamw 286da6c28aaSamw ah = entry->sa_handle; 287da6c28aaSamw 288da6c28aaSamw if ((event = adt_alloc_event(ah, ADT_smbd_logoff)) == NULL) { 289da6c28aaSamw syslog(LOG_AUTH | LOG_ALERT, 290da6c28aaSamw "adt_alloc_event(ADT_smbd_logoff): %m"); 291da6c28aaSamw } else { 292da6c28aaSamw event->adt_smbd_logoff.domain = entry->sa_domain; 293da6c28aaSamw event->adt_smbd_logoff.username = entry->sa_username; 294da6c28aaSamw 295da6c28aaSamw if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS)) 296da6c28aaSamw syslog(LOG_AUTH | LOG_ALERT, "adt_put_event: %m"); 297da6c28aaSamw 298da6c28aaSamw adt_free_event(event); 299da6c28aaSamw } 300da6c28aaSamw 301da6c28aaSamw (void) adt_end_session(ah); 302da6c28aaSamw 303da6c28aaSamw free(entry->sa_username); 304da6c28aaSamw free(entry->sa_domain); 305da6c28aaSamw free(entry); 306da6c28aaSamw } 307da6c28aaSamw 308da6c28aaSamw /* 309da6c28aaSamw * Allocate an id and link an audit handle onto the global list. 310da6c28aaSamw */ 311da6c28aaSamw static void 312da6c28aaSamw smbd_audit_link(smb_audit_t *entry) 313da6c28aaSamw { 314da6c28aaSamw (void) mutex_lock(&smbd_audit_lock); 315da6c28aaSamw 316da6c28aaSamw do { 317da6c28aaSamw ++smbd_audit_sid; 318da6c28aaSamw } while ((smbd_audit_sid == 0) || (smbd_audit_sid == (uint32_t)-1)); 319da6c28aaSamw 320da6c28aaSamw entry->sa_audit_sid = smbd_audit_sid; 321da6c28aaSamw entry->sa_refcnt = 1; 322da6c28aaSamw entry->sa_next = smbd_audit_list; 323da6c28aaSamw smbd_audit_list = entry; 324da6c28aaSamw 325da6c28aaSamw (void) mutex_unlock(&smbd_audit_lock); 326da6c28aaSamw } 327da6c28aaSamw 328da6c28aaSamw /* 329da6c28aaSamw * Unlink an audit handle. If the reference count reaches 0, the entry 330da6c28aaSamw * is removed from the list and returned. Otherwise the entry remains 331da6c28aaSamw * on the list and a null pointer is returned. 332da6c28aaSamw */ 333da6c28aaSamw static smb_audit_t * 334da6c28aaSamw smbd_audit_unlink(uint32_t audit_sid) 335da6c28aaSamw { 336da6c28aaSamw smb_audit_t *entry; 337da6c28aaSamw smb_audit_t **ppe; 338da6c28aaSamw 339da6c28aaSamw (void) mutex_lock(&smbd_audit_lock); 340da6c28aaSamw ppe = &smbd_audit_list; 341da6c28aaSamw 342da6c28aaSamw while (*ppe) { 343da6c28aaSamw entry = *ppe; 344da6c28aaSamw 345da6c28aaSamw if (entry->sa_audit_sid == audit_sid) { 346da6c28aaSamw if (entry->sa_refcnt == 0) 347da6c28aaSamw break; 348da6c28aaSamw 349da6c28aaSamw if ((--entry->sa_refcnt) != 0) 350da6c28aaSamw break; 351da6c28aaSamw 352da6c28aaSamw *ppe = entry->sa_next; 353da6c28aaSamw (void) mutex_unlock(&smbd_audit_lock); 354da6c28aaSamw return (entry); 355da6c28aaSamw } 356da6c28aaSamw 357da6c28aaSamw ppe = &(*ppe)->sa_next; 358da6c28aaSamw } 359da6c28aaSamw 360da6c28aaSamw (void) mutex_unlock(&smbd_audit_lock); 361da6c28aaSamw return (NULL); 362da6c28aaSamw } 363