xref: /onnv-gate/usr/src/cmd/smbsrv/smbd/smbd_logon.c (revision 12065:0e89d02a32ea)
15331Samw /*
25331Samw  * CDDL HEADER START
35331Samw  *
45331Samw  * The contents of this file are subject to the terms of the
55331Samw  * Common Development and Distribution License (the "License").
65331Samw  * You may not use this file except in compliance with the License.
75331Samw  *
85331Samw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw  * or http://www.opensolaris.org/os/licensing.
105331Samw  * See the License for the specific language governing permissions
115331Samw  * and limitations under the License.
125331Samw  *
135331Samw  * When distributing Covered Code, include this CDDL HEADER in each
145331Samw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw  * If applicable, add the following below this CDDL HEADER, with the
165331Samw  * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw  * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw  *
195331Samw  * CDDL HEADER END
205331Samw  */
215331Samw /*
22*12065SKeyur.Desai@Sun.COM  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
235331Samw  */
245331Samw 
255331Samw #include <sys/types.h>
265331Samw #include <errno.h>
275331Samw #include <synch.h>
285331Samw #include <stdio.h>
295331Samw #include <stdlib.h>
305331Samw #include <unistd.h>
315331Samw #include <string.h>
325331Samw #include <strings.h>
335331Samw #include <syslog.h>
345331Samw #include <fcntl.h>
355331Samw #include <bsm/adt.h>
365331Samw #include <bsm/adt_event.h>
375331Samw #include <bsm/audit_uevents.h>
38*12065SKeyur.Desai@Sun.COM #include <pwd.h>
39*12065SKeyur.Desai@Sun.COM #include <nss_dbdefs.h>
40*12065SKeyur.Desai@Sun.COM #include <sys/idmap.h>
415331Samw #include "smbd.h"
425331Samw 
435331Samw 
445331Samw /*
455331Samw  * An audit session is established at user logon and terminated at user
465331Samw  * logoff.
475331Samw  *
485331Samw  * SMB audit handles are allocated when users logon (SmbSessionSetupX)
495331Samw  * and deallocted when a user logs off (SmbLogoffX).  Each time an SMB
505331Samw  * audit handle is allocated it is added to a global list.
515331Samw  */
525331Samw typedef struct smb_audit {
535331Samw 	struct smb_audit *sa_next;
545331Samw 	adt_session_data_t *sa_handle;
555331Samw 	uid_t sa_uid;
565331Samw 	gid_t sa_gid;
575331Samw 	uint32_t sa_audit_sid;
585331Samw 	uint32_t sa_refcnt;
595331Samw 	char *sa_domain;
605331Samw 	char *sa_username;
615331Samw } smb_audit_t;
625331Samw 
635331Samw static smb_audit_t *smbd_audit_list;
645331Samw static mutex_t smbd_audit_lock;
655331Samw 
665331Samw /*
675331Samw  * Unique identifier for audit sessions in the audit list.
685331Samw  * Used to lookup an audit session on logoff.
695331Samw  */
705331Samw static uint32_t smbd_audit_sid;
715331Samw 
725331Samw static void smbd_audit_link(smb_audit_t *);
735331Samw static smb_audit_t *smbd_audit_unlink(uint32_t);
745331Samw 
755331Samw 
765331Samw /*
775331Samw  * Invoked at user logon due to SmbSessionSetupX.  Authenticate the
785331Samw  * user, start an audit session and audit the event.
795331Samw  */
805331Samw smb_token_t *
smbd_user_auth_logon(smb_logon_t * user_info)8111963SAfshin.Ardakani@Sun.COM smbd_user_auth_logon(smb_logon_t *user_info)
825331Samw {
835331Samw 	smb_token_t *token;
845331Samw 	smb_audit_t *entry;
855331Samw 	adt_session_data_t *ah;
865331Samw 	adt_event_data_t *event;
875331Samw 	au_tid_addr_t termid;
886432Sas200622 	char sidbuf[SMB_SID_STRSZ];
898670SJose.Borrego@Sun.COM 	char *username;
908670SJose.Borrego@Sun.COM 	char *domain;
915331Samw 	uid_t uid;
925331Samw 	gid_t gid;
935331Samw 	char *sid;
945331Samw 	int status;
955331Samw 	int retval;
965331Samw 
9711963SAfshin.Ardakani@Sun.COM 	if ((token = smb_logon(user_info)) == NULL) {
985331Samw 		uid = ADT_NO_ATTRIB;
995331Samw 		gid = ADT_NO_ATTRIB;
1006432Sas200622 		sid = NT_NULL_SIDSTR;
10111963SAfshin.Ardakani@Sun.COM 		username = user_info->lg_e_username;
10211963SAfshin.Ardakani@Sun.COM 		domain = user_info->lg_e_domain;
1035331Samw 		status = ADT_FAILURE;
1045331Samw 		retval = ADT_FAIL_VALUE_AUTH;
1055331Samw 	} else {
1068670SJose.Borrego@Sun.COM 		uid = token->tkn_user.i_id;
1078670SJose.Borrego@Sun.COM 		gid = token->tkn_primary_grp.i_id;
1088670SJose.Borrego@Sun.COM 		smb_sid_tostr(token->tkn_user.i_sid, sidbuf);
1096432Sas200622 		sid = sidbuf;
1108670SJose.Borrego@Sun.COM 		username = token->tkn_account_name;
1118670SJose.Borrego@Sun.COM 		domain = token->tkn_domain_name;
1125331Samw 		status = ADT_SUCCESS;
1135331Samw 		retval = ADT_SUCCESS;
1145331Samw 	}
1155331Samw 
1165331Samw 	if (adt_start_session(&ah, NULL, 0)) {
1175331Samw 		syslog(LOG_AUTH | LOG_ALERT, "adt_start_session: %m");
1185331Samw 		smb_token_destroy(token);
1195331Samw 		return (NULL);
1205331Samw 	}
1215331Samw 
1225331Samw 	if ((event = adt_alloc_event(ah, ADT_smbd_session)) == NULL) {
1235331Samw 		syslog(LOG_AUTH | LOG_ALERT,
1245331Samw 		    "adt_alloc_event(ADT_smbd_session): %m");
1255331Samw 		(void) adt_end_session(ah);
1265331Samw 		smb_token_destroy(token);
1275331Samw 		return (NULL);
1285331Samw 	}
1295331Samw 
1305331Samw 	(void) memset(&termid, 0, sizeof (au_tid_addr_t));
13111963SAfshin.Ardakani@Sun.COM 	termid.at_port = user_info->lg_local_port;
1328670SJose.Borrego@Sun.COM 
13311963SAfshin.Ardakani@Sun.COM 	if (user_info->lg_clnt_ipaddr.a_family == AF_INET) {
13411963SAfshin.Ardakani@Sun.COM 		termid.at_addr[0] = user_info->lg_clnt_ipaddr.a_ipv4;
1358670SJose.Borrego@Sun.COM 		termid.at_type = AU_IPv4;
1368670SJose.Borrego@Sun.COM 	} else {
13711963SAfshin.Ardakani@Sun.COM 		bcopy(&user_info->lg_clnt_ipaddr.a_ip, termid.at_addr,
13811963SAfshin.Ardakani@Sun.COM 		    IPV6_ADDR_LEN);
1398670SJose.Borrego@Sun.COM 		termid.at_type = AU_IPv6;
1408670SJose.Borrego@Sun.COM 	}
1415331Samw 	adt_set_termid(ah, &termid);
1425331Samw 
1435331Samw 	if (adt_set_user(ah, uid, gid, uid, gid, NULL, ADT_NEW)) {
1445331Samw 		syslog(LOG_AUTH | LOG_ALERT, "adt_set_user: %m");
1455331Samw 		adt_free_event(event);
1465331Samw 		(void) adt_end_session(ah);
1475331Samw 		smb_token_destroy(token);
1485331Samw 		return (NULL);
1495331Samw 	}
1505331Samw 
1518670SJose.Borrego@Sun.COM 	event->adt_smbd_session.domain = domain;
1528670SJose.Borrego@Sun.COM 	event->adt_smbd_session.username = username;
1535331Samw 	event->adt_smbd_session.sid = sid;
1545331Samw 
1555331Samw 	if (adt_put_event(event, status, retval))
1565331Samw 		syslog(LOG_AUTH | LOG_ALERT, "adt_put_event: %m");
1575331Samw 
1585331Samw 	adt_free_event(event);
1595331Samw 
1605331Samw 	if (token) {
1615331Samw 		if ((entry = malloc(sizeof (smb_audit_t))) == NULL) {
1625331Samw 			syslog(LOG_ERR, "smbd_user_auth_logon: %m");
1635331Samw 			(void) adt_end_session(ah);
1645331Samw 			smb_token_destroy(token);
1655331Samw 			return (NULL);
1665331Samw 		}
1675331Samw 
1685331Samw 		entry->sa_handle = ah;
1695331Samw 		entry->sa_uid = uid;
1705331Samw 		entry->sa_gid = gid;
1718670SJose.Borrego@Sun.COM 		entry->sa_username = strdup(username);
1728670SJose.Borrego@Sun.COM 		entry->sa_domain = strdup(domain);
1735331Samw 
17411337SWilliam.Krier@Sun.COM 		smb_autohome_add(token);
1755331Samw 		smbd_audit_link(entry);
1765331Samw 		token->tkn_audit_sid = entry->sa_audit_sid;
1775331Samw 	}
1785331Samw 
1795331Samw 	return (token);
1805331Samw }
1815331Samw 
1825331Samw /*
1835331Samw  * Logon due to a subsequent SmbSessionSetupX on an existing session.
1845331Samw  * The user was authenticated during the initial session setup.
1855331Samw  */
1865331Samw void
smbd_user_nonauth_logon(uint32_t audit_sid)1875331Samw smbd_user_nonauth_logon(uint32_t audit_sid)
1885331Samw {
1895331Samw 	smb_audit_t *entry;
1905331Samw 
1915331Samw 	(void) mutex_lock(&smbd_audit_lock);
1925331Samw 	entry = smbd_audit_list;
1935331Samw 
1945331Samw 	while (entry) {
1955331Samw 		if (entry->sa_audit_sid == audit_sid) {
1965331Samw 			++entry->sa_refcnt;
1975331Samw 			break;
1985331Samw 		}
1995331Samw 
2005331Samw 		entry = entry->sa_next;
2015331Samw 	}
2025331Samw 
2035331Samw 	(void) mutex_unlock(&smbd_audit_lock);
2045331Samw }
2055331Samw 
2065331Samw /*
2075331Samw  * Invoked at user logoff due to SmbLogoffX.  If this is the final
2085331Samw  * logoff for this user on the session, audit the event and terminate
2095331Samw  * the audit session.
2105331Samw  */
2115331Samw void
smbd_user_auth_logoff(uint32_t audit_sid)2125331Samw smbd_user_auth_logoff(uint32_t audit_sid)
2135331Samw {
2145331Samw 	smb_audit_t *entry;
2155331Samw 	adt_session_data_t *ah;
2165331Samw 	adt_event_data_t *event;
217*12065SKeyur.Desai@Sun.COM 	struct passwd pw;
218*12065SKeyur.Desai@Sun.COM 	char buf[NSS_LINELEN_PASSWD];
2195331Samw 
2205331Samw 	if ((entry = smbd_audit_unlink(audit_sid)) == NULL)
2215331Samw 		return;
2225331Samw 
223*12065SKeyur.Desai@Sun.COM 	if (IDMAP_ID_IS_EPHEMERAL(entry->sa_uid)) {
224*12065SKeyur.Desai@Sun.COM 		smb_autohome_remove(entry->sa_username);
225*12065SKeyur.Desai@Sun.COM 	} else {
226*12065SKeyur.Desai@Sun.COM 		if (getpwuid_r(entry->sa_uid, &pw, buf, sizeof (buf)) == NULL)
227*12065SKeyur.Desai@Sun.COM 			return;
228*12065SKeyur.Desai@Sun.COM 
229*12065SKeyur.Desai@Sun.COM 		smb_autohome_remove(pw.pw_name);
230*12065SKeyur.Desai@Sun.COM 	}
2315331Samw 
2325331Samw 	ah = entry->sa_handle;
2335331Samw 
2345331Samw 	if ((event = adt_alloc_event(ah, ADT_smbd_logoff)) == NULL) {
2355331Samw 		syslog(LOG_AUTH | LOG_ALERT,
2365331Samw 		    "adt_alloc_event(ADT_smbd_logoff): %m");
2375331Samw 	} else {
2385331Samw 		event->adt_smbd_logoff.domain = entry->sa_domain;
2395331Samw 		event->adt_smbd_logoff.username = entry->sa_username;
2405331Samw 
2415331Samw 		if (adt_put_event(event, ADT_SUCCESS, ADT_SUCCESS))
2425331Samw 			syslog(LOG_AUTH | LOG_ALERT, "adt_put_event: %m");
2435331Samw 
2445331Samw 		adt_free_event(event);
2455331Samw 	}
2465331Samw 
2475331Samw 	(void) adt_end_session(ah);
2485331Samw 
2495331Samw 	free(entry->sa_username);
2505331Samw 	free(entry->sa_domain);
2515331Samw 	free(entry);
2525331Samw }
2535331Samw 
2545331Samw /*
2555331Samw  * Allocate an id and link an audit handle onto the global list.
2565331Samw  */
2575331Samw static void
smbd_audit_link(smb_audit_t * entry)2585331Samw smbd_audit_link(smb_audit_t *entry)
2595331Samw {
2605331Samw 	(void) mutex_lock(&smbd_audit_lock);
2615331Samw 
2625331Samw 	do {
2635331Samw 		++smbd_audit_sid;
2645331Samw 	} while ((smbd_audit_sid == 0) || (smbd_audit_sid == (uint32_t)-1));
2655331Samw 
2665331Samw 	entry->sa_audit_sid = smbd_audit_sid;
2675331Samw 	entry->sa_refcnt = 1;
2685331Samw 	entry->sa_next = smbd_audit_list;
2695331Samw 	smbd_audit_list = entry;
2705331Samw 
2715331Samw 	(void) mutex_unlock(&smbd_audit_lock);
2725331Samw }
2735331Samw 
2745331Samw /*
2755331Samw  * Unlink an audit handle.  If the reference count reaches 0, the entry
2765331Samw  * is removed from the list and returned.  Otherwise the entry remains
2775331Samw  * on the list and a null pointer is returned.
2785331Samw  */
2795331Samw static smb_audit_t *
smbd_audit_unlink(uint32_t audit_sid)2805331Samw smbd_audit_unlink(uint32_t audit_sid)
2815331Samw {
2825331Samw 	smb_audit_t *entry;
2835331Samw 	smb_audit_t **ppe;
2845331Samw 
2855331Samw 	(void) mutex_lock(&smbd_audit_lock);
2865331Samw 	ppe = &smbd_audit_list;
2875331Samw 
2885331Samw 	while (*ppe) {
2895331Samw 		entry = *ppe;
2905331Samw 
2915331Samw 		if (entry->sa_audit_sid == audit_sid) {
2925331Samw 			if (entry->sa_refcnt == 0)
2935331Samw 				break;
2945331Samw 
2955331Samw 			if ((--entry->sa_refcnt) != 0)
2965331Samw 				break;
2975331Samw 
2985331Samw 			*ppe = entry->sa_next;
2995331Samw 			(void) mutex_unlock(&smbd_audit_lock);
3005331Samw 			return (entry);
3015331Samw 		}
3025331Samw 
3035331Samw 		ppe = &(*ppe)->sa_next;
3045331Samw 	}
3055331Samw 
3065331Samw 	(void) mutex_unlock(&smbd_audit_lock);
3075331Samw 	return (NULL);
3085331Samw }
309