xref: /titanic_44/usr/src/lib/smbsrv/libsmbns/common/smbns_ads.c (revision b819cea2f73f98c5662230cc9affc8cc84f77fcf)
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.
231ed6b69aSGordon Ross  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw #include <sys/param.h>
27da6c28aaSamw #include <ldap.h>
28da6c28aaSamw #include <stdlib.h>
29da6c28aaSamw #include <sys/types.h>
30da6c28aaSamw #include <sys/socket.h>
31da6c28aaSamw #include <netinet/in.h>
32da6c28aaSamw #include <arpa/inet.h>
33da6c28aaSamw #include <sys/time.h>
34da6c28aaSamw #include <netdb.h>
35da6c28aaSamw #include <pthread.h>
36da6c28aaSamw #include <unistd.h>
37da6c28aaSamw #include <arpa/nameser.h>
38da6c28aaSamw #include <resolv.h>
39da6c28aaSamw #include <sys/synch.h>
40da6c28aaSamw #include <string.h>
41da6c28aaSamw #include <strings.h>
42da6c28aaSamw #include <fcntl.h>
43da6c28aaSamw #include <sys/types.h>
44da6c28aaSamw #include <sys/stat.h>
45b89a8333Snatalie li - Sun Microsystems - Irvine United States #include <assert.h>
46a0aa776eSAlan Wright #include <sasl/sasl.h>
47a0aa776eSAlan Wright #include <note.h>
4877191e87SShawn Emery #include <errno.h>
4977191e87SShawn Emery #include <cryptoutil.h>
50da6c28aaSamw 
51da6c28aaSamw #include <smbsrv/libsmbns.h>
52da6c28aaSamw #include <smbns_dyndns.h>
53da6c28aaSamw #include <smbns_krb.h>
54da6c28aaSamw 
5596a62adaSjoyce mcintosh #define	SMB_ADS_AF_UNKNOWN(x)	(((x)->ipaddr.a_family != AF_INET) && \
5696a62adaSjoyce mcintosh 	((x)->ipaddr.a_family != AF_INET6))
5796a62adaSjoyce mcintosh 
5829bd2886SAlan Wright #define	SMB_ADS_MAXBUFLEN 100
593db3f65cSamw #define	SMB_ADS_DN_MAX	300
603db3f65cSamw #define	SMB_ADS_MAXMSGLEN 512
613db3f65cSamw #define	SMB_ADS_COMPUTERS_CN "Computers"
623db3f65cSamw #define	SMB_ADS_COMPUTER_NUM_ATTR 8
633db3f65cSamw #define	SMB_ADS_SHARE_NUM_ATTR 3
643db3f65cSamw #define	SMB_ADS_SITE_MAX MAXHOSTNAMELEN
653db3f65cSamw 
663db3f65cSamw #define	SMB_ADS_MSDCS_SRV_DC_RR		"_ldap._tcp.dc._msdcs"
673db3f65cSamw #define	SMB_ADS_MSDCS_SRV_SITE_RR	"_ldap._tcp.%s._sites.dc._msdcs"
683db3f65cSamw 
693db3f65cSamw /*
703db3f65cSamw  * domainControllerFunctionality
713db3f65cSamw  *
723db3f65cSamw  * This rootDSE attribute indicates the functional level of the DC.
733db3f65cSamw  */
743db3f65cSamw #define	SMB_ADS_ATTR_DCLEVEL	"domainControllerFunctionality"
753db3f65cSamw #define	SMB_ADS_DCLEVEL_W2K	0
763db3f65cSamw #define	SMB_ADS_DCLEVEL_W2K3	2
773db3f65cSamw #define	SMB_ADS_DCLEVEL_W2K8	3
78b1352070SAlan Wright #define	SMB_ADS_DCLEVEL_W2K8_R2 4
793db3f65cSamw 
803db3f65cSamw /*
813db3f65cSamw  * msDs-supportedEncryptionTypes (Windows Server 2008 only)
823db3f65cSamw  *
833db3f65cSamw  * This attribute defines the encryption types supported by the system.
843db3f65cSamw  * Encryption Types:
853db3f65cSamw  *  - DES cbc mode with CRC-32
863db3f65cSamw  *  - DES cbc mode with RSA-MD5
873db3f65cSamw  *  - ArcFour with HMAC/md5
883db3f65cSamw  *  - AES-128
893db3f65cSamw  *  - AES-256
903db3f65cSamw  */
913db3f65cSamw #define	SMB_ADS_ATTR_ENCTYPES	"msDs-supportedEncryptionTypes"
923db3f65cSamw #define	SMB_ADS_ENC_DES_CRC	1
933db3f65cSamw #define	SMB_ADS_ENC_DES_MD5	2
943db3f65cSamw #define	SMB_ADS_ENC_RC4		4
953db3f65cSamw #define	SMB_ADS_ENC_AES128	8
963db3f65cSamw #define	SMB_ADS_ENC_AES256	16
973db3f65cSamw 
98148c5f43SAlan Wright static krb5_enctype w2k8enctypes[] = {
99148c5f43SAlan Wright     ENCTYPE_AES256_CTS_HMAC_SHA1_96,
100148c5f43SAlan Wright     ENCTYPE_AES128_CTS_HMAC_SHA1_96,
101148c5f43SAlan Wright     ENCTYPE_ARCFOUR_HMAC,
102148c5f43SAlan Wright     ENCTYPE_DES_CBC_CRC,
103148c5f43SAlan Wright     ENCTYPE_DES_CBC_MD5,
104148c5f43SAlan Wright };
105148c5f43SAlan Wright 
106148c5f43SAlan Wright static krb5_enctype pre_w2k8enctypes[] = {
107148c5f43SAlan Wright     ENCTYPE_ARCFOUR_HMAC,
108148c5f43SAlan Wright     ENCTYPE_DES_CBC_CRC,
109148c5f43SAlan Wright     ENCTYPE_DES_CBC_MD5,
110148c5f43SAlan Wright };
111148c5f43SAlan Wright 
1123db3f65cSamw #define	SMB_ADS_ATTR_SAMACCT	"sAMAccountName"
1133db3f65cSamw #define	SMB_ADS_ATTR_UPN	"userPrincipalName"
1143db3f65cSamw #define	SMB_ADS_ATTR_SPN	"servicePrincipalName"
1153db3f65cSamw #define	SMB_ADS_ATTR_CTL	"userAccountControl"
1163db3f65cSamw #define	SMB_ADS_ATTR_DNSHOST	"dNSHostName"
1173db3f65cSamw #define	SMB_ADS_ATTR_KVNO	"msDS-KeyVersionNumber"
118c8ec8eeaSjose borrego #define	SMB_ADS_ATTR_DN		"distinguishedName"
119da6c28aaSamw 
120b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
12129bd2886SAlan Wright  * UserAccountControl flags: manipulate user account properties.
12229bd2886SAlan Wright  *
12329bd2886SAlan Wright  * The hexadecimal value of the following property flags are based on MSDN
12429bd2886SAlan Wright  * article # 305144.
12529bd2886SAlan Wright  */
12629bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_SCRIPT				0x00000001
12729bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_ACCOUNTDISABLE			0x00000002
12829bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_HOMEDIR_REQUIRED			0x00000008
12929bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_LOCKOUT				0x00000010
13029bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_PASSWD_NOTREQD			0x00000020
13129bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_PASSWD_CANT_CHANGE		0x00000040
13229bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_ENCRYPTED_TEXT_PWD_ALLOWED	0x00000080
13329bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_TMP_DUP_ACCT			0x00000100
13429bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_NORMAL_ACCT			0x00000200
13529bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_INTERDOMAIN_TRUST_ACCT		0x00000800
13629bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT		0x00001000
13729bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_SRV_TRUST_ACCT			0x00002000
13829bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_DONT_EXPIRE_PASSWD		0x00010000
13929bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_MNS_LOGON_ACCT			0x00020000
14029bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_SMARTCARD_REQUIRED		0x00040000
14129bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_TRUSTED_FOR_DELEGATION		0x00080000
14229bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_NOT_DELEGATED			0x00100000
14329bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_USE_DES_KEY_ONLY			0x00200000
14429bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_DONT_REQ_PREAUTH			0x00400000
14529bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_PASSWD_EXPIRED			0x00800000
14629bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_TRUSTED_TO_AUTH_FOR_DELEGATION	0x01000000
14729bd2886SAlan Wright 
14829bd2886SAlan Wright /*
149b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Length of "dc=" prefix.
150b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
151b89a8333Snatalie li - Sun Microsystems - Irvine United States #define	SMB_ADS_DN_PREFIX_LEN	3
152b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1537f667e74Sjose borrego static char *smb_ads_computer_objcls[] = {
1547f667e74Sjose borrego 	"top", "person", "organizationalPerson",
1557f667e74Sjose borrego 	"user", "computer", NULL
1567f667e74Sjose borrego };
1577f667e74Sjose borrego 
1587f667e74Sjose borrego static char *smb_ads_share_objcls[] = {
1597f667e74Sjose borrego 	"top", "leaf", "connectionPoint", "volume", NULL
1607f667e74Sjose borrego };
1617f667e74Sjose borrego 
162b89a8333Snatalie li - Sun Microsystems - Irvine United States /* Cached ADS server to communicate with */
163b89a8333Snatalie li - Sun Microsystems - Irvine United States static smb_ads_host_info_t *smb_ads_cached_host_info = NULL;
164b89a8333Snatalie li - Sun Microsystems - Irvine United States static mutex_t smb_ads_cached_host_mtx;
165b89a8333Snatalie li - Sun Microsystems - Irvine United States 
16629bd2886SAlan Wright /*
16729bd2886SAlan Wright  * SMB ADS config cache is maintained to facilitate the detection of
16829bd2886SAlan Wright  * changes in configuration that is relevant to AD selection.
16929bd2886SAlan Wright  */
17029bd2886SAlan Wright typedef struct smb_ads_config {
17129bd2886SAlan Wright 	char c_site[SMB_ADS_SITE_MAX];
17229bd2886SAlan Wright 	smb_inaddr_t c_pdc;
17329bd2886SAlan Wright 	mutex_t c_mtx;
17429bd2886SAlan Wright } smb_ads_config_t;
17529bd2886SAlan Wright 
17629bd2886SAlan Wright static smb_ads_config_t smb_ads_cfg;
17729bd2886SAlan Wright 
178dc20a302Sas200622 
179b89a8333Snatalie li - Sun Microsystems - Irvine United States /* attribute/value pair */
180b89a8333Snatalie li - Sun Microsystems - Irvine United States typedef struct smb_ads_avpair {
181b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *avp_attr;
182b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *avp_val;
183b89a8333Snatalie li - Sun Microsystems - Irvine United States } smb_ads_avpair_t;
184b89a8333Snatalie li - Sun Microsystems - Irvine United States 
185b89a8333Snatalie li - Sun Microsystems - Irvine United States /* query status */
186b89a8333Snatalie li - Sun Microsystems - Irvine United States typedef enum smb_ads_qstat {
187b89a8333Snatalie li - Sun Microsystems - Irvine United States 	SMB_ADS_STAT_ERR = -2,
188b89a8333Snatalie li - Sun Microsystems - Irvine United States 	SMB_ADS_STAT_DUP,
189b89a8333Snatalie li - Sun Microsystems - Irvine United States 	SMB_ADS_STAT_NOT_FOUND,
190b89a8333Snatalie li - Sun Microsystems - Irvine United States 	SMB_ADS_STAT_FOUND
191b89a8333Snatalie li - Sun Microsystems - Irvine United States } smb_ads_qstat_t;
192b89a8333Snatalie li - Sun Microsystems - Irvine United States 
19329bd2886SAlan Wright typedef struct smb_ads_host_list {
19429bd2886SAlan Wright 	int ah_cnt;
19529bd2886SAlan Wright 	smb_ads_host_info_t *ah_list;
19629bd2886SAlan Wright } smb_ads_host_list_t;
19729bd2886SAlan Wright 
198c8ec8eeaSjose borrego static smb_ads_handle_t *smb_ads_open_main(char *, char *, char *);
199c8ec8eeaSjose borrego static int smb_ads_add_computer(smb_ads_handle_t *, int, char *);
200c8ec8eeaSjose borrego static int smb_ads_modify_computer(smb_ads_handle_t *, int, char *);
201c8ec8eeaSjose borrego static int smb_ads_computer_op(smb_ads_handle_t *, int, int, char *);
202b89a8333Snatalie li - Sun Microsystems - Irvine United States static smb_ads_qstat_t smb_ads_lookup_computer_n_attr(smb_ads_handle_t *,
203b89a8333Snatalie li - Sun Microsystems - Irvine United States     smb_ads_avpair_t *, int, char *);
204c8ec8eeaSjose borrego static int smb_ads_update_computer_cntrl_attr(smb_ads_handle_t *, int, char *);
205c8ec8eeaSjose borrego static krb5_kvno smb_ads_lookup_computer_attr_kvno(smb_ads_handle_t *, char *);
206b89a8333Snatalie li - Sun Microsystems - Irvine United States static void smb_ads_free_cached_host(void);
207c8ec8eeaSjose borrego static int smb_ads_alloc_attr(LDAPMod **, int);
208c8ec8eeaSjose borrego static void smb_ads_free_attr(LDAPMod **);
209c8ec8eeaSjose borrego static int smb_ads_get_dc_level(smb_ads_handle_t *);
210c8ec8eeaSjose borrego static smb_ads_host_info_t *smb_ads_select_dc(smb_ads_host_list_t *);
211b89a8333Snatalie li - Sun Microsystems - Irvine United States static smb_ads_qstat_t smb_ads_find_computer(smb_ads_handle_t *, char *);
212b89a8333Snatalie li - Sun Microsystems - Irvine United States static smb_ads_qstat_t smb_ads_getattr(LDAP *, LDAPMessage *,
213b89a8333Snatalie li - Sun Microsystems - Irvine United States     smb_ads_avpair_t *);
214b89a8333Snatalie li - Sun Microsystems - Irvine United States static smb_ads_qstat_t smb_ads_get_qstat(smb_ads_handle_t *, LDAPMessage *,
215b89a8333Snatalie li - Sun Microsystems - Irvine United States     smb_ads_avpair_t *);
21629bd2886SAlan Wright static boolean_t smb_ads_match_pdc(smb_ads_host_info_t *);
21729bd2886SAlan Wright static boolean_t smb_ads_is_sought_host(smb_ads_host_info_t *, char *);
21829bd2886SAlan Wright static boolean_t smb_ads_is_same_domain(char *, char *);
21929bd2886SAlan Wright static boolean_t smb_ads_is_pdc_configured(void);
22029bd2886SAlan Wright static smb_ads_host_info_t *smb_ads_dup_host_info(smb_ads_host_info_t *);
221fe1c642dSBill Krier static char *smb_ads_get_sharedn(const char *, const char *, const char *);
222148c5f43SAlan Wright static krb5_enctype *smb_ads_get_enctypes(int, int *);
223dc20a302Sas200622 
224dc20a302Sas200622 /*
2253db3f65cSamw  * smb_ads_init
226dc20a302Sas200622  *
22729bd2886SAlan Wright  * Initializes the ADS config cache.
228dc20a302Sas200622  */
229dc20a302Sas200622 void
smb_ads_init(void)2303db3f65cSamw smb_ads_init(void)
231dc20a302Sas200622 {
23229bd2886SAlan Wright 	(void) mutex_lock(&smb_ads_cfg.c_mtx);
233b89a8333Snatalie li - Sun Microsystems - Irvine United States 	(void) smb_config_getstr(SMB_CI_ADS_SITE,
23429bd2886SAlan Wright 	    smb_ads_cfg.c_site, SMB_ADS_SITE_MAX);
23529bd2886SAlan Wright 	(void) smb_config_getip(SMB_CI_DOMAIN_SRV, &smb_ads_cfg.c_pdc);
23629bd2886SAlan Wright 	(void) mutex_unlock(&smb_ads_cfg.c_mtx);
23729bd2886SAlan Wright }
23829bd2886SAlan Wright 
23929bd2886SAlan Wright void
smb_ads_fini(void)24029bd2886SAlan Wright smb_ads_fini(void)
24129bd2886SAlan Wright {
24229bd2886SAlan Wright 	smb_ads_free_cached_host();
243dc20a302Sas200622 }
244dc20a302Sas200622 
245dc20a302Sas200622 /*
2463db3f65cSamw  * smb_ads_refresh
247dc20a302Sas200622  *
24829bd2886SAlan Wright  * This function will be called when smb/server SMF service is refreshed.
24929bd2886SAlan Wright  * Clearing the smb_ads_cached_host_info would allow the next DC
25029bd2886SAlan Wright  * discovery process to pick up an AD based on the new AD configuration.
251dc20a302Sas200622  */
252dc20a302Sas200622 void
smb_ads_refresh(void)2533db3f65cSamw smb_ads_refresh(void)
254dc20a302Sas200622 {
2553db3f65cSamw 	char new_site[SMB_ADS_SITE_MAX];
25629bd2886SAlan Wright 	smb_inaddr_t new_pdc;
25729bd2886SAlan Wright 	boolean_t purge = B_FALSE;
258dc20a302Sas200622 
25929bd2886SAlan Wright 	(void) smb_config_getstr(SMB_CI_ADS_SITE, new_site, SMB_ADS_SITE_MAX);
26029bd2886SAlan Wright 	(void) smb_config_getip(SMB_CI_DOMAIN_SRV, &new_pdc);
26129bd2886SAlan Wright 	(void) mutex_lock(&smb_ads_cfg.c_mtx);
262bbf6f00cSJordan Brown 	if (smb_strcasecmp(smb_ads_cfg.c_site, new_site, 0)) {
26329bd2886SAlan Wright 		(void) strlcpy(smb_ads_cfg.c_site, new_site, SMB_ADS_SITE_MAX);
26429bd2886SAlan Wright 		purge = B_TRUE;
26529bd2886SAlan Wright 	}
26629bd2886SAlan Wright 
26729bd2886SAlan Wright 	smb_ads_cfg.c_pdc = new_pdc;
26829bd2886SAlan Wright 	(void) mutex_unlock(&smb_ads_cfg.c_mtx);
26929bd2886SAlan Wright 
27029bd2886SAlan Wright 	(void) mutex_lock(&smb_ads_cached_host_mtx);
27129bd2886SAlan Wright 	if (smb_ads_cached_host_info &&
27229bd2886SAlan Wright 	    smb_ads_is_pdc_configured() &&
27329bd2886SAlan Wright 	    !smb_ads_match_pdc(smb_ads_cached_host_info))
27429bd2886SAlan Wright 		purge = B_TRUE;
27529bd2886SAlan Wright 	(void) mutex_unlock(&smb_ads_cached_host_mtx);
27629bd2886SAlan Wright 
27729bd2886SAlan Wright 	if (purge)
278b89a8333Snatalie li - Sun Microsystems - Irvine United States 		smb_ads_free_cached_host();
279dc20a302Sas200622 }
28029bd2886SAlan Wright 
28129bd2886SAlan Wright 
28229bd2886SAlan Wright 
28329bd2886SAlan Wright static boolean_t
smb_ads_is_pdc_configured(void)28429bd2886SAlan Wright smb_ads_is_pdc_configured(void)
28529bd2886SAlan Wright {
28629bd2886SAlan Wright 	boolean_t configured;
28729bd2886SAlan Wright 
28829bd2886SAlan Wright 	(void) mutex_lock(&smb_ads_cfg.c_mtx);
28929bd2886SAlan Wright 	configured = !smb_inet_iszero(&smb_ads_cfg.c_pdc);
29029bd2886SAlan Wright 	(void) mutex_unlock(&smb_ads_cfg.c_mtx);
29129bd2886SAlan Wright 
29229bd2886SAlan Wright 	return (configured);
293dc20a302Sas200622 }
294da6c28aaSamw 
295da6c28aaSamw /*
2963db3f65cSamw  * smb_ads_build_unc_name
297da6c28aaSamw  *
298da6c28aaSamw  * Construct the UNC name of the share object in the format of
299da6c28aaSamw  * \\hostname.domain\shareUNC
300da6c28aaSamw  *
301da6c28aaSamw  * Returns 0 on success, -1 on error.
302da6c28aaSamw  */
303da6c28aaSamw int
smb_ads_build_unc_name(char * unc_name,int maxlen,const char * hostname,const char * shareUNC)3043db3f65cSamw smb_ads_build_unc_name(char *unc_name, int maxlen,
305da6c28aaSamw     const char *hostname, const char *shareUNC)
306da6c28aaSamw {
307dc20a302Sas200622 	char my_domain[MAXHOSTNAMELEN];
308da6c28aaSamw 
309dc20a302Sas200622 	if (smb_getfqdomainname(my_domain, sizeof (my_domain)) != 0)
310da6c28aaSamw 		return (-1);
311da6c28aaSamw 
312da6c28aaSamw 	(void) snprintf(unc_name, maxlen, "\\\\%s.%s\\%s",
313da6c28aaSamw 	    hostname, my_domain, shareUNC);
314da6c28aaSamw 	return (0);
315da6c28aaSamw }
316da6c28aaSamw 
317da6c28aaSamw /*
318c8ec8eeaSjose borrego  * smb_ads_ldap_ping
3193db3f65cSamw  *
320c8ec8eeaSjose borrego  * This is used to bind to an ADS server to see
321c8ec8eeaSjose borrego  * if it is still alive.
322c8ec8eeaSjose borrego  *
323da6c28aaSamw  * Returns:
324da6c28aaSamw  *   -1: error
325da6c28aaSamw  *    0: successful
326da6c28aaSamw  */
327da6c28aaSamw /*ARGSUSED*/
328da6c28aaSamw static int
smb_ads_ldap_ping(smb_ads_host_info_t * ads_host)329c8ec8eeaSjose borrego smb_ads_ldap_ping(smb_ads_host_info_t *ads_host)
330da6c28aaSamw {
331c8ec8eeaSjose borrego 	int ldversion = LDAP_VERSION3, status, timeoutms = 5 * 1000;
332c8ec8eeaSjose borrego 	LDAP *ld = NULL;
333c8ec8eeaSjose borrego 
3347f667e74Sjose borrego 	ld = ldap_init(ads_host->name, ads_host->port);
335c8ec8eeaSjose borrego 	if (ld == NULL)
336c8ec8eeaSjose borrego 		return (-1);
337c8ec8eeaSjose borrego 
338c8ec8eeaSjose borrego 	ldversion = LDAP_VERSION3;
339c8ec8eeaSjose borrego 	(void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldversion);
340c8ec8eeaSjose borrego 	/* setup TCP/IP connect timeout */
341c8ec8eeaSjose borrego 	(void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeoutms);
342c8ec8eeaSjose borrego 
343c8ec8eeaSjose borrego 	status = ldap_bind_s(ld, "", NULL, LDAP_AUTH_SIMPLE);
344c8ec8eeaSjose borrego 
345c8ec8eeaSjose borrego 	if (status != LDAP_SUCCESS) {
346c8ec8eeaSjose borrego 		(void) ldap_unbind(ld);
347c8ec8eeaSjose borrego 		return (-1);
348c8ec8eeaSjose borrego 	}
349c8ec8eeaSjose borrego 
350c8ec8eeaSjose borrego 	(void) ldap_unbind(ld);
351c8ec8eeaSjose borrego 
352da6c28aaSamw 	return (0);
353da6c28aaSamw }
354da6c28aaSamw 
355da6c28aaSamw /*
35629bd2886SAlan Wright  * The cached ADS host is no longer valid if one of the following criteria
35729bd2886SAlan Wright  * is satisfied:
358b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
35929bd2886SAlan Wright  * 1) not in the specified domain
36029bd2886SAlan Wright  * 2) not the sought host (if specified)
36129bd2886SAlan Wright  * 3) not reachable
36229bd2886SAlan Wright  *
36329bd2886SAlan Wright  * The caller is responsible for acquiring the smb_ads_cached_host_mtx lock
36429bd2886SAlan Wright  * prior to calling this function.
36529bd2886SAlan Wright  *
36629bd2886SAlan Wright  * Return B_TRUE if the cache host is still valid. Otherwise, return B_FALSE.
367da6c28aaSamw  */
36829bd2886SAlan Wright static boolean_t
smb_ads_validate_cache_host(char * domain,char * srv)36929bd2886SAlan Wright smb_ads_validate_cache_host(char *domain, char *srv)
370da6c28aaSamw {
371b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (!smb_ads_cached_host_info)
37229bd2886SAlan Wright 		return (B_FALSE);
37329bd2886SAlan Wright 
37429bd2886SAlan Wright 	if (!smb_ads_is_same_domain(smb_ads_cached_host_info->name, domain))
37529bd2886SAlan Wright 		return (B_FALSE);
37629bd2886SAlan Wright 
37729bd2886SAlan Wright 	if (smb_ads_ldap_ping(smb_ads_cached_host_info) == 0) {
37829bd2886SAlan Wright 		if (!srv)
37929bd2886SAlan Wright 			return (B_TRUE);
38029bd2886SAlan Wright 
38129bd2886SAlan Wright 		if (smb_ads_is_sought_host(smb_ads_cached_host_info, srv))
38229bd2886SAlan Wright 			return (B_TRUE);
383da6c28aaSamw 	}
384da6c28aaSamw 
38529bd2886SAlan Wright 	return (B_FALSE);
386da6c28aaSamw }
3873db3f65cSamw 
388da6c28aaSamw /*
389b89a8333Snatalie li - Sun Microsystems - Irvine United States  * smb_ads_is_sought_host
390b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
391b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Returns true, if the sought host name matches the input host (host) name.
392b89a8333Snatalie li - Sun Microsystems - Irvine United States  * The sought host is expected to be in Fully Qualified Domain Name (FQDN)
393b89a8333Snatalie li - Sun Microsystems - Irvine United States  * format.
394b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
395b89a8333Snatalie li - Sun Microsystems - Irvine United States static boolean_t
smb_ads_is_sought_host(smb_ads_host_info_t * host,char * sought_host_name)396b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_is_sought_host(smb_ads_host_info_t *host, char *sought_host_name)
397b89a8333Snatalie li - Sun Microsystems - Irvine United States {
398b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if ((host == NULL) || (sought_host_name == NULL))
399b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (B_FALSE);
400b89a8333Snatalie li - Sun Microsystems - Irvine United States 
401bbf6f00cSJordan Brown 	if (smb_strcasecmp(host->name, sought_host_name, 0))
402b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (B_FALSE);
403b89a8333Snatalie li - Sun Microsystems - Irvine United States 
404b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (B_TRUE);
405b89a8333Snatalie li - Sun Microsystems - Irvine United States }
406b89a8333Snatalie li - Sun Microsystems - Irvine United States 
407b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
408b89a8333Snatalie li - Sun Microsystems - Irvine United States  * smb_ads_match_hosts_same_domain
409b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
410b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Returns true, if the cached ADS host is in the same domain as the
411b89a8333Snatalie li - Sun Microsystems - Irvine United States  * current (given) domain.
412b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
413b89a8333Snatalie li - Sun Microsystems - Irvine United States static boolean_t
smb_ads_is_same_domain(char * cached_host_name,char * current_domain)414b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_is_same_domain(char *cached_host_name, char *current_domain)
415b89a8333Snatalie li - Sun Microsystems - Irvine United States {
416b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *cached_host_domain;
417b89a8333Snatalie li - Sun Microsystems - Irvine United States 
418b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if ((cached_host_name == NULL) || (current_domain == NULL))
419b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (B_FALSE);
420b89a8333Snatalie li - Sun Microsystems - Irvine United States 
421b89a8333Snatalie li - Sun Microsystems - Irvine United States 	cached_host_domain = strchr(cached_host_name, '.');
422b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (cached_host_domain == NULL)
423b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (B_FALSE);
424b89a8333Snatalie li - Sun Microsystems - Irvine United States 
425b89a8333Snatalie li - Sun Microsystems - Irvine United States 	++cached_host_domain;
426bbf6f00cSJordan Brown 	if (smb_strcasecmp(cached_host_domain, current_domain, 0))
427b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (B_FALSE);
428b89a8333Snatalie li - Sun Microsystems - Irvine United States 
429b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (B_TRUE);
430b89a8333Snatalie li - Sun Microsystems - Irvine United States }
431b89a8333Snatalie li - Sun Microsystems - Irvine United States 
432b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
4333db3f65cSamw  * smb_ads_skip_ques_sec
4343db3f65cSamw  * Skips the question section.
4353db3f65cSamw  */
4363db3f65cSamw static int
smb_ads_skip_ques_sec(int qcnt,uchar_t ** ptr,uchar_t * eom)4373db3f65cSamw smb_ads_skip_ques_sec(int qcnt, uchar_t **ptr, uchar_t *eom)
4383db3f65cSamw {
4393db3f65cSamw 	int i, len;
4403db3f65cSamw 
4413db3f65cSamw 	for (i = 0; i < qcnt; i++) {
442b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if ((len = dn_skipname(*ptr, eom)) < 0)
4433db3f65cSamw 			return (-1);
444b89a8333Snatalie li - Sun Microsystems - Irvine United States 
4453db3f65cSamw 		*ptr += len + QFIXEDSZ;
4463db3f65cSamw 	}
4473db3f65cSamw 
4483db3f65cSamw 	return (0);
4493db3f65cSamw }
4503db3f65cSamw 
4513db3f65cSamw /*
4523db3f65cSamw  * smb_ads_decode_host_ans_sec
453c8ec8eeaSjose borrego  * Decodes ADS hosts, priority, weight and port number from the answer
454c8ec8eeaSjose borrego  * section based on the current buffer pointer.
4553db3f65cSamw  */
4563db3f65cSamw static int
smb_ads_decode_host_ans_sec(int ans_cnt,uchar_t ** ptr,uchar_t * eom,uchar_t * buf,smb_ads_host_info_t * ads_host_list)4573db3f65cSamw smb_ads_decode_host_ans_sec(int ans_cnt, uchar_t **ptr, uchar_t *eom,
4583db3f65cSamw     uchar_t *buf, smb_ads_host_info_t *ads_host_list)
4593db3f65cSamw {
4603db3f65cSamw 	int i, len;
4613db3f65cSamw 	smb_ads_host_info_t *ads_host;
4623db3f65cSamw 
4633db3f65cSamw 	for (i = 0; i < ans_cnt; i++) {
4643db3f65cSamw 		ads_host = &ads_host_list[i];
4653db3f65cSamw 
466b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if ((len = dn_skipname(*ptr, eom)) < 0)
4673db3f65cSamw 			return (-1);
468b89a8333Snatalie li - Sun Microsystems - Irvine United States 
4693db3f65cSamw 
4703db3f65cSamw 		*ptr += len;
4713db3f65cSamw 
4723db3f65cSamw 		/* skip type, class, ttl */
4733db3f65cSamw 		*ptr += 8;
4743db3f65cSamw 		/* data size */
4753db3f65cSamw 		*ptr += 2;
4763db3f65cSamw 
477c8ec8eeaSjose borrego 		/* Get priority, weight */
478c8ec8eeaSjose borrego 		/* LINTED: E_CONSTANT_CONDITION */
479c8ec8eeaSjose borrego 		NS_GET16(ads_host->priority, *ptr);
480c8ec8eeaSjose borrego 		/* LINTED: E_CONSTANT_CONDITION */
481c8ec8eeaSjose borrego 		NS_GET16(ads_host->weight, *ptr);
482c8ec8eeaSjose borrego 
4833db3f65cSamw 		/* port */
4843db3f65cSamw 		/* LINTED: E_CONSTANT_CONDITION */
4853db3f65cSamw 		NS_GET16(ads_host->port, *ptr);
4863db3f65cSamw 		/* domain name */
4873db3f65cSamw 		len = dn_expand(buf, eom, *ptr, ads_host->name, MAXHOSTNAMELEN);
488b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (len < 0)
4893db3f65cSamw 			return (-1);
490b89a8333Snatalie li - Sun Microsystems - Irvine United States 
4913db3f65cSamw 		*ptr += len;
4923db3f65cSamw 	}
4933db3f65cSamw 
4943db3f65cSamw 	return (0);
4953db3f65cSamw }
4963db3f65cSamw 
4973db3f65cSamw /*
4983db3f65cSamw  * smb_ads_skip_auth_sec
4993db3f65cSamw  * Skips the authority section.
5003db3f65cSamw  */
5013db3f65cSamw static int
smb_ads_skip_auth_sec(int ns_cnt,uchar_t ** ptr,uchar_t * eom)5023db3f65cSamw smb_ads_skip_auth_sec(int ns_cnt, uchar_t **ptr, uchar_t *eom)
5033db3f65cSamw {
5043db3f65cSamw 	int i, len;
5053db3f65cSamw 	uint16_t size;
5063db3f65cSamw 
5073db3f65cSamw 	for (i = 0; i < ns_cnt; i++) {
508b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if ((len = dn_skipname(*ptr, eom)) < 0)
5093db3f65cSamw 			return (-1);
510b89a8333Snatalie li - Sun Microsystems - Irvine United States 
5113db3f65cSamw 		*ptr += len;
5123db3f65cSamw 		/* skip type, class, ttl */
5133db3f65cSamw 		*ptr += 8;
5143db3f65cSamw 		/* get len of data */
5153db3f65cSamw 		/* LINTED: E_CONSTANT_CONDITION */
5163db3f65cSamw 		NS_GET16(size, *ptr);
517b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if ((*ptr + size) > eom)
5183db3f65cSamw 			return (-1);
5193db3f65cSamw 
5203db3f65cSamw 		*ptr += size;
5213db3f65cSamw 	}
5223db3f65cSamw 
5233db3f65cSamw 	return (0);
5243db3f65cSamw }
5253db3f65cSamw 
5263db3f65cSamw /*
527b89a8333Snatalie li - Sun Microsystems - Irvine United States  * smb_ads_decode_host_ip
528b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
5293db3f65cSamw  * Decodes ADS hosts and IP Addresses from the additional section based
5303db3f65cSamw  * on the current buffer pointer.
5313db3f65cSamw  */
5323db3f65cSamw static int
smb_ads_decode_host_ip(int addit_cnt,int ans_cnt,uchar_t ** ptr,uchar_t * eom,uchar_t * buf,smb_ads_host_info_t * ads_host_list)533b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_decode_host_ip(int addit_cnt, int ans_cnt, uchar_t **ptr,
534b89a8333Snatalie li - Sun Microsystems - Irvine United States     uchar_t *eom, uchar_t *buf, smb_ads_host_info_t *ads_host_list)
5353db3f65cSamw {
536b89a8333Snatalie li - Sun Microsystems - Irvine United States 	int i, j, len;
5377f667e74Sjose borrego 	smb_inaddr_t ipaddr;
538b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char hostname[MAXHOSTNAMELEN];
539b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *name;
5407f667e74Sjose borrego 	uint16_t size = 0;
5413db3f65cSamw 
5423db3f65cSamw 	for (i = 0; i < addit_cnt; i++) {
5433db3f65cSamw 
5443db3f65cSamw 		/* domain name */
545b89a8333Snatalie li - Sun Microsystems - Irvine United States 		len = dn_expand(buf, eom, *ptr, hostname, MAXHOSTNAMELEN);
546b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (len < 0)
5473db3f65cSamw 			return (-1);
548b89a8333Snatalie li - Sun Microsystems - Irvine United States 
5493db3f65cSamw 		*ptr += len;
5503db3f65cSamw 
5513db3f65cSamw 		/* skip type, class, TTL, data len */
5527f667e74Sjose borrego 		*ptr += 8;
5533db3f65cSamw 		/* LINTED: E_CONSTANT_CONDITION */
5547f667e74Sjose borrego 		NS_GET16(size, *ptr);
5557f667e74Sjose borrego 
556*b819cea2SGordon Ross 		if (size == NS_INADDRSZ) {
5577f667e74Sjose borrego 			/* LINTED: E_CONSTANT_CONDITION */
5587f667e74Sjose borrego 			NS_GET32(ipaddr.a_ipv4, *ptr);
5597f667e74Sjose borrego 			ipaddr.a_ipv4 = htonl(ipaddr.a_ipv4);
5607f667e74Sjose borrego 			ipaddr.a_family = AF_INET;
561*b819cea2SGordon Ross 		} else if (size == NS_IN6ADDRSZ) {
5627f667e74Sjose borrego #ifdef BIG_ENDIAN
563*b819cea2SGordon Ross 			bcopy(*ptr, &ipaddr.a_ipv6, NS_IN6ADDRSZ);
5647f667e74Sjose borrego #else
565*b819cea2SGordon Ross 			for (i = 0; i < NS_IN6ADDRSZ; i++)
5667f667e74Sjose borrego 				(uint8_t *)(ipaddr.a_ipv6)
567*b819cea2SGordon Ross 				    [NS_IN6ADDRSZ-1-i] = *(*ptr+i);
5687f667e74Sjose borrego #endif
5697f667e74Sjose borrego 			ipaddr.a_family = AF_INET6;
570c5866007SKeyur Desai 			*ptr += size;
5717f667e74Sjose borrego 		}
5723db3f65cSamw 
573b89a8333Snatalie li - Sun Microsystems - Irvine United States 		/*
574b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * find the host in the list of DC records from
575b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * the answer section, that matches the host in the
576b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * additional section, and set its IP address.
577b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 */
578b89a8333Snatalie li - Sun Microsystems - Irvine United States 		for (j = 0; j < ans_cnt; j++) {
579b89a8333Snatalie li - Sun Microsystems - Irvine United States 			if ((name = ads_host_list[j].name) == NULL)
580b89a8333Snatalie li - Sun Microsystems - Irvine United States 				continue;
581bbf6f00cSJordan Brown 			if (smb_strcasecmp(name, hostname, 0) == 0) {
5827f667e74Sjose borrego 				ads_host_list[j].ipaddr = ipaddr;
583b89a8333Snatalie li - Sun Microsystems - Irvine United States 			}
5843db3f65cSamw 		}
5857f667e74Sjose borrego 	}
5863db3f65cSamw 	return (0);
5873db3f65cSamw }
5883db3f65cSamw 
589b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
590b89a8333Snatalie li - Sun Microsystems - Irvine United States  * smb_ads_dup_host_info
591b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
592b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Duplicates the passed smb_ads_host_info_t structure.
593b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Caller must free memory allocated by this method.
594b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
595b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Returns a reference to the duplicated smb_ads_host_info_t structure.
596b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Returns NULL on error.
597b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
598b89a8333Snatalie li - Sun Microsystems - Irvine United States static smb_ads_host_info_t *
smb_ads_dup_host_info(smb_ads_host_info_t * ads_host)599b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_dup_host_info(smb_ads_host_info_t *ads_host)
6003db3f65cSamw {
601b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_host_info_t *dup_host;
602b89a8333Snatalie li - Sun Microsystems - Irvine United States 
603b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (ads_host == NULL)
604b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (NULL);
605b89a8333Snatalie li - Sun Microsystems - Irvine United States 
606b89a8333Snatalie li - Sun Microsystems - Irvine United States 	dup_host = malloc(sizeof (smb_ads_host_info_t));
607b89a8333Snatalie li - Sun Microsystems - Irvine United States 
608b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (dup_host != NULL)
609b89a8333Snatalie li - Sun Microsystems - Irvine United States 		bcopy(ads_host, dup_host, sizeof (smb_ads_host_info_t));
610b89a8333Snatalie li - Sun Microsystems - Irvine United States 
611b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (dup_host);
612c8ec8eeaSjose borrego }
6133db3f65cSamw 
614c8ec8eeaSjose borrego /*
615c8ec8eeaSjose borrego  * smb_ads_hlist_alloc
616c8ec8eeaSjose borrego  */
617a0aa776eSAlan Wright static smb_ads_host_list_t *
smb_ads_hlist_alloc(int count)618c8ec8eeaSjose borrego smb_ads_hlist_alloc(int count)
619c8ec8eeaSjose borrego {
620c8ec8eeaSjose borrego 	int size;
621c8ec8eeaSjose borrego 	smb_ads_host_list_t *hlist;
622c8ec8eeaSjose borrego 
623b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (count == 0)
624b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (NULL);
625b89a8333Snatalie li - Sun Microsystems - Irvine United States 
626c8ec8eeaSjose borrego 	size = sizeof (smb_ads_host_info_t) * count;
627c8ec8eeaSjose borrego 	hlist = (smb_ads_host_list_t *)malloc(sizeof (smb_ads_host_list_t));
628c8ec8eeaSjose borrego 	if (hlist == NULL)
629c8ec8eeaSjose borrego 		return (NULL);
630c8ec8eeaSjose borrego 
631c8ec8eeaSjose borrego 	hlist->ah_cnt = count;
632c8ec8eeaSjose borrego 	hlist->ah_list = (smb_ads_host_info_t *)malloc(size);
633c8ec8eeaSjose borrego 	if (hlist->ah_list == NULL) {
634c8ec8eeaSjose borrego 		free(hlist);
635c8ec8eeaSjose borrego 		return (NULL);
636c8ec8eeaSjose borrego 	}
637c8ec8eeaSjose borrego 
638c8ec8eeaSjose borrego 	bzero(hlist->ah_list, size);
639c8ec8eeaSjose borrego 	return (hlist);
640c8ec8eeaSjose borrego }
641c8ec8eeaSjose borrego 
642c8ec8eeaSjose borrego /*
643c8ec8eeaSjose borrego  * smb_ads_hlist_free
644c8ec8eeaSjose borrego  */
645c8ec8eeaSjose borrego static void
smb_ads_hlist_free(smb_ads_host_list_t * host_list)646c8ec8eeaSjose borrego smb_ads_hlist_free(smb_ads_host_list_t *host_list)
647c8ec8eeaSjose borrego {
648c8ec8eeaSjose borrego 	if (host_list == NULL)
649c8ec8eeaSjose borrego 		return;
650c8ec8eeaSjose borrego 
651c8ec8eeaSjose borrego 	free(host_list->ah_list);
652c8ec8eeaSjose borrego 	free(host_list);
6533db3f65cSamw }
6543db3f65cSamw 
6553db3f65cSamw /*
656b89a8333Snatalie li - Sun Microsystems - Irvine United States  * smb_ads_query_dns_server
657c8ec8eeaSjose borrego  *
6583db3f65cSamw  * This routine sends a DNS service location (SRV) query message to the
6593db3f65cSamw  * DNS server via TCP to query it for a list of ADS server(s). Once a reply
660b89a8333Snatalie li - Sun Microsystems - Irvine United States  * is received, the reply message is parsed to get the hostname. If there are IP
6613db3f65cSamw  * addresses populated in the additional section then the additional section
6623db3f65cSamw  * is parsed to obtain the IP addresses.
663da6c28aaSamw  *
664da6c28aaSamw  * The service location of _ldap._tcp.dc.msdcs.<ADS domain> is used to
665da6c28aaSamw  * guarantee that Microsoft domain controllers are returned.  Microsoft domain
666da6c28aaSamw  * controllers are also ADS servers.
667da6c28aaSamw  *
668da6c28aaSamw  * The ADS hostnames are stored in the answer section of the DNS reply message.
6693db3f65cSamw  * The IP addresses are stored in the additional section.
670da6c28aaSamw  *
671da6c28aaSamw  * The DNS reply message may be in compress formed.  The compression is done
672da6c28aaSamw  * on repeating domain name label in the message.  i.e hostname.
673c8ec8eeaSjose borrego  *
674b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Upon successful completion, host list of ADS server(s) is returned.
675da6c28aaSamw  */
676b89a8333Snatalie li - Sun Microsystems - Irvine United States static smb_ads_host_list_t *
smb_ads_query_dns_server(char * domain,char * msdcs_svc_name)677b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_query_dns_server(char *domain, char *msdcs_svc_name)
678da6c28aaSamw {
679b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_host_list_t *hlist = NULL;
6803db3f65cSamw 	int len, qcnt, ans_cnt, ns_cnt, addit_cnt;
6813db3f65cSamw 	uchar_t *ptr, *eom;
6823db3f65cSamw 	struct __res_state res_state;
6833db3f65cSamw 	union {
6843db3f65cSamw 		HEADER hdr;
6853db3f65cSamw 		uchar_t buf[NS_MAXMSG];
6863db3f65cSamw 	} msg;
687faa1795aSjb150015 
6883db3f65cSamw 	bzero(&res_state, sizeof (struct __res_state));
6893db3f65cSamw 	if (res_ninit(&res_state) < 0)
690da6c28aaSamw 		return (NULL);
691da6c28aaSamw 
6923db3f65cSamw 	/* use TCP */
6933db3f65cSamw 	res_state.options |= RES_USEVC;
694da6c28aaSamw 
695b89a8333Snatalie li - Sun Microsystems - Irvine United States 	len = res_nquerydomain(&res_state, msdcs_svc_name, domain,
6963db3f65cSamw 	    C_IN, T_SRV, msg.buf, sizeof (msg.buf));
6973db3f65cSamw 
6983db3f65cSamw 	if (len < 0) {
699fc724630SAlan Wright 		syslog(LOG_NOTICE, "DNS query for %s failed: %s",
700b89a8333Snatalie li - Sun Microsystems - Irvine United States 		    msdcs_svc_name, hstrerror(res_state.res_h_errno));
701b89a8333Snatalie li - Sun Microsystems - Irvine United States 		res_ndestroy(&res_state);
702b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (NULL);
7033db3f65cSamw 	}
704b89a8333Snatalie li - Sun Microsystems - Irvine United States 
7053db3f65cSamw 	if (len > sizeof (msg.buf)) {
706fc724630SAlan Wright 		syslog(LOG_NOTICE,
707fc724630SAlan Wright 		    "DNS query for %s failed: too big", msdcs_svc_name);
708b89a8333Snatalie li - Sun Microsystems - Irvine United States 		res_ndestroy(&res_state);
709b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (NULL);
7103db3f65cSamw 	}
7113db3f65cSamw 
712b89a8333Snatalie li - Sun Microsystems - Irvine United States 	/* parse the reply, skip header and question sections */
7133db3f65cSamw 	ptr = msg.buf + sizeof (msg.hdr);
7143db3f65cSamw 	eom = msg.buf + len;
7153db3f65cSamw 
7163db3f65cSamw 	/* check truncated message bit */
7173db3f65cSamw 	if (msg.hdr.tc)
718fc724630SAlan Wright 		syslog(LOG_NOTICE,
719fc724630SAlan Wright 		    "DNS query for %s failed: truncated", msdcs_svc_name);
7203db3f65cSamw 
7213db3f65cSamw 	qcnt = ntohs(msg.hdr.qdcount);
7223db3f65cSamw 	ans_cnt = ntohs(msg.hdr.ancount);
7233db3f65cSamw 	ns_cnt = ntohs(msg.hdr.nscount);
7243db3f65cSamw 	addit_cnt = ntohs(msg.hdr.arcount);
7253db3f65cSamw 
7263db3f65cSamw 	if (smb_ads_skip_ques_sec(qcnt, &ptr, eom) != 0) {
7273db3f65cSamw 		res_ndestroy(&res_state);
728da6c28aaSamw 		return (NULL);
729da6c28aaSamw 	}
730da6c28aaSamw 
731b89a8333Snatalie li - Sun Microsystems - Irvine United States 	hlist = smb_ads_hlist_alloc(ans_cnt);
732b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (hlist == NULL) {
7333db3f65cSamw 		res_ndestroy(&res_state);
734da6c28aaSamw 		return (NULL);
735da6c28aaSamw 	}
736da6c28aaSamw 
737b89a8333Snatalie li - Sun Microsystems - Irvine United States 	/* walk through the answer section */
7383db3f65cSamw 	if (smb_ads_decode_host_ans_sec(ans_cnt, &ptr, eom, msg.buf,
739b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    hlist->ah_list) != 0) {
740b89a8333Snatalie li - Sun Microsystems - Irvine United States 		smb_ads_hlist_free(hlist);
7413db3f65cSamw 		res_ndestroy(&res_state);
742da6c28aaSamw 		return (NULL);
743da6c28aaSamw 	}
744da6c28aaSamw 
745da6c28aaSamw 	/* check authority section */
746c8ec8eeaSjose borrego 	if (ns_cnt > 0) {
7473db3f65cSamw 		if (smb_ads_skip_auth_sec(ns_cnt, &ptr, eom) != 0) {
748b89a8333Snatalie li - Sun Microsystems - Irvine United States 			smb_ads_hlist_free(hlist);
7493db3f65cSamw 			res_ndestroy(&res_state);
7503db3f65cSamw 			return (NULL);
751da6c28aaSamw 		}
752c8ec8eeaSjose borrego 	}
753da6c28aaSamw 
7540dcb3379Sjb150015 	/*
7550dcb3379Sjb150015 	 * Check additional section to get IP address of ADS host.
7560dcb3379Sjb150015 	 */
757dc20a302Sas200622 	if (addit_cnt > 0) {
758b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (smb_ads_decode_host_ip(addit_cnt, ans_cnt,
759b89a8333Snatalie li - Sun Microsystems - Irvine United States 		    &ptr, eom, msg.buf, hlist->ah_list) != 0) {
760b89a8333Snatalie li - Sun Microsystems - Irvine United States 			smb_ads_hlist_free(hlist);
7613db3f65cSamw 			res_ndestroy(&res_state);
762da6c28aaSamw 			return (NULL);
763da6c28aaSamw 		}
764b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
765da6c28aaSamw 
7663db3f65cSamw 	res_ndestroy(&res_state);
767b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (hlist);
768da6c28aaSamw }
769da6c28aaSamw 
770da6c28aaSamw /*
771fc724630SAlan Wright  * smb_ads_get_site_service
772b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
773fc724630SAlan Wright  * Gets the msdcs SRV RR for the specified site.
774da6c28aaSamw  */
775dc20a302Sas200622 static void
smb_ads_get_site_service(char * site_service,size_t len)776fc724630SAlan Wright smb_ads_get_site_service(char *site_service, size_t len)
777da6c28aaSamw {
77829bd2886SAlan Wright 	(void) mutex_lock(&smb_ads_cfg.c_mtx);
77929bd2886SAlan Wright 	if (*smb_ads_cfg.c_site == '\0')
780b89a8333Snatalie li - Sun Microsystems - Irvine United States 		*site_service = '\0';
781b89a8333Snatalie li - Sun Microsystems - Irvine United States 	else
782fc724630SAlan Wright 		(void) snprintf(site_service, len,
78329bd2886SAlan Wright 		    SMB_ADS_MSDCS_SRV_SITE_RR, smb_ads_cfg.c_site);
784fc724630SAlan Wright 
78529bd2886SAlan Wright 	(void) mutex_unlock(&smb_ads_cfg.c_mtx);
786da6c28aaSamw }
787b89a8333Snatalie li - Sun Microsystems - Irvine United States 
788b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
789b89a8333Snatalie li - Sun Microsystems - Irvine United States  * smb_ads_getipnodebyname
790b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
791b89a8333Snatalie li - Sun Microsystems - Irvine United States  * This method gets the IP address by doing a host name lookup.
792b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
793b89a8333Snatalie li - Sun Microsystems - Irvine United States static int
smb_ads_getipnodebyname(smb_ads_host_info_t * hentry)794b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_getipnodebyname(smb_ads_host_info_t *hentry)
795b89a8333Snatalie li - Sun Microsystems - Irvine United States {
796b89a8333Snatalie li - Sun Microsystems - Irvine United States 	struct hostent *h;
797b89a8333Snatalie li - Sun Microsystems - Irvine United States 	int error;
798b89a8333Snatalie li - Sun Microsystems - Irvine United States 
7997f667e74Sjose borrego 	switch (hentry->ipaddr.a_family) {
8007f667e74Sjose borrego 	case AF_INET6:
8017f667e74Sjose borrego 		h = getipnodebyname(hentry->name, hentry->ipaddr.a_family,
8027f667e74Sjose borrego 		    AI_DEFAULT, &error);
803*b819cea2SGordon Ross 		if (h == NULL || h->h_length != NS_IN6ADDRSZ)
804b89a8333Snatalie li - Sun Microsystems - Irvine United States 			return (-1);
8057f667e74Sjose borrego 		break;
806b89a8333Snatalie li - Sun Microsystems - Irvine United States 
8077f667e74Sjose borrego 	case AF_INET:
8087f667e74Sjose borrego 		h = getipnodebyname(hentry->name, hentry->ipaddr.a_family,
8097f667e74Sjose borrego 		    0, &error);
810*b819cea2SGordon Ross 		if (h == NULL || h->h_length != NS_INADDRSZ)
8117f667e74Sjose borrego 			return (-1);
8127f667e74Sjose borrego 		break;
813b89a8333Snatalie li - Sun Microsystems - Irvine United States 
8147f667e74Sjose borrego 	default:
8157f667e74Sjose borrego 		return (-1);
8167f667e74Sjose borrego 	}
8177f667e74Sjose borrego 	bcopy(*(h->h_addr_list), &hentry->ipaddr.a_ip, h->h_length);
818b89a8333Snatalie li - Sun Microsystems - Irvine United States 	freehostent(h);
819b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (0);
820b89a8333Snatalie li - Sun Microsystems - Irvine United States }
821b89a8333Snatalie li - Sun Microsystems - Irvine United States 
822b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
82396a62adaSjoyce mcintosh  *  Checks the IP address to see if it is zero.  If so, then do a host
82496a62adaSjoyce mcintosh  *  lookup by hostname to get the IP address based on the IP family.
82596a62adaSjoyce mcintosh  *
82696a62adaSjoyce mcintosh  *  If the family is unknown then do a lookup by hostame based on the
82796a62adaSjoyce mcintosh  *  setting of the SMB_CI_IPV6_ENABLE property.
82896a62adaSjoyce mcintosh  */
82996a62adaSjoyce mcintosh static int
smb_ads_set_ipaddr(smb_ads_host_info_t * hentry)83096a62adaSjoyce mcintosh smb_ads_set_ipaddr(smb_ads_host_info_t *hentry)
83196a62adaSjoyce mcintosh {
83296a62adaSjoyce mcintosh 	if (smb_inet_iszero(&hentry->ipaddr)) {
83396a62adaSjoyce mcintosh 		if (smb_ads_getipnodebyname(hentry) < 0)
83496a62adaSjoyce mcintosh 			return (-1);
83596a62adaSjoyce mcintosh 	} else if (SMB_ADS_AF_UNKNOWN(hentry)) {
83696a62adaSjoyce mcintosh 		hentry->ipaddr.a_family =
83796a62adaSjoyce mcintosh 		    smb_config_getbool(SMB_CI_IPV6_ENABLE) ? AF_INET6 : AF_INET;
83896a62adaSjoyce mcintosh 
83996a62adaSjoyce mcintosh 		if (smb_ads_getipnodebyname(hentry) < 0) {
84096a62adaSjoyce mcintosh 			hentry->ipaddr.a_family = 0;
84196a62adaSjoyce mcintosh 			return (-1);
84296a62adaSjoyce mcintosh 		}
84396a62adaSjoyce mcintosh 	}
84496a62adaSjoyce mcintosh 
84596a62adaSjoyce mcintosh 	return (0);
84696a62adaSjoyce mcintosh }
84796a62adaSjoyce mcintosh 
84896a62adaSjoyce mcintosh /*
849b89a8333Snatalie li - Sun Microsystems - Irvine United States  * smb_ads_find_host
850b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
85129bd2886SAlan Wright  * Finds an ADS host in a given domain.
85229bd2886SAlan Wright  *
85329bd2886SAlan Wright  * If the cached host is valid, it will be used. Otherwise, a DC will
85429bd2886SAlan Wright  * be selected based on the following criteria:
85529bd2886SAlan Wright  *
85629bd2886SAlan Wright  * 1) pdc (aka preferred DC) configuration
85729bd2886SAlan Wright  * 2) AD site configuration - the scope of the DNS lookup will be
85829bd2886SAlan Wright  * restricted to the specified site.
85929bd2886SAlan Wright  * 3) DC on the same subnet
86029bd2886SAlan Wright  * 4) DC with the lowest priority/highest weight
86129bd2886SAlan Wright  *
86229bd2886SAlan Wright  * The above items are listed in decreasing preference order. The selected
86329bd2886SAlan Wright  * DC must be online.
86429bd2886SAlan Wright  *
86529bd2886SAlan Wright  * If this function is called during domain join, the specified kpasswd server
86629bd2886SAlan Wright  * takes precedence over preferred DC, AD site, and so on.
867b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
868b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Parameters:
86929bd2886SAlan Wright  *   domain: fully-qualified domain name.
87029bd2886SAlan Wright  *   kpasswd_srv: fully-quailifed hostname of the kpasswd server.
871b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
872b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Returns:
87329bd2886SAlan Wright  *   A copy of the cached host info is returned. The caller is responsible
87429bd2886SAlan Wright  *   for deallocating the memory returned by this function.
875b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
876b89a8333Snatalie li - Sun Microsystems - Irvine United States /*ARGSUSED*/
877b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_host_info_t *
smb_ads_find_host(char * domain,char * kpasswd_srv)87829bd2886SAlan Wright smb_ads_find_host(char *domain, char *kpasswd_srv)
879b89a8333Snatalie li - Sun Microsystems - Irvine United States {
880b89a8333Snatalie li - Sun Microsystems - Irvine United States 	int i;
881b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char site_service[MAXHOSTNAMELEN];
88229bd2886SAlan Wright 	smb_ads_host_list_t *hlist, *hlist2;
88329bd2886SAlan Wright 	smb_ads_host_info_t *hlistp = NULL, *host = NULL;
88429bd2886SAlan Wright 	smb_ads_host_info_t *found_kpasswd_srv = NULL;
88529bd2886SAlan Wright 	smb_ads_host_info_t *found_pdc = NULL;
886b89a8333Snatalie li - Sun Microsystems - Irvine United States 
88729bd2886SAlan Wright 	if ((kpasswd_srv) && (*kpasswd_srv == '\0'))
88829bd2886SAlan Wright 		kpasswd_srv = NULL;
889b89a8333Snatalie li - Sun Microsystems - Irvine United States 
89029bd2886SAlan Wright 	(void) mutex_lock(&smb_ads_cached_host_mtx);
89129bd2886SAlan Wright 	if (smb_ads_validate_cache_host(domain, kpasswd_srv)) {
89229bd2886SAlan Wright 		host = smb_ads_dup_host_info(smb_ads_cached_host_info);
89329bd2886SAlan Wright 		(void) mutex_unlock(&smb_ads_cached_host_mtx);
894b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (host);
895b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
896b89a8333Snatalie li - Sun Microsystems - Irvine United States 
89729bd2886SAlan Wright 	(void) mutex_unlock(&smb_ads_cached_host_mtx);
898b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_free_cached_host();
899b89a8333Snatalie li - Sun Microsystems - Irvine United States 
900b89a8333Snatalie li - Sun Microsystems - Irvine United States 	/*
901b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * First look for ADS hosts in ADS site if configured.  Then try
902b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 * without ADS site info.
903b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 */
904fc724630SAlan Wright 	hlist = NULL;
905fc724630SAlan Wright 	smb_ads_get_site_service(site_service, MAXHOSTNAMELEN);
90629bd2886SAlan Wright 
90729bd2886SAlan Wright 	/*
90829bd2886SAlan Wright 	 * If we're given an AD, the DNS SRV RR lookup should not be restricted
90929bd2886SAlan Wright 	 * to the specified site since there is no guarantee that the specified
91029bd2886SAlan Wright 	 * AD is in the specified site.
91129bd2886SAlan Wright 	 */
91229bd2886SAlan Wright 	if (*site_service != '\0' && !kpasswd_srv &&
91329bd2886SAlan Wright 	    !smb_ads_is_pdc_configured())
914fc724630SAlan Wright 		hlist = smb_ads_query_dns_server(domain, site_service);
915b89a8333Snatalie li - Sun Microsystems - Irvine United States 
916fc724630SAlan Wright 	if (!hlist)
917fc724630SAlan Wright 		hlist = smb_ads_query_dns_server(domain,
918fc724630SAlan Wright 		    SMB_ADS_MSDCS_SRV_DC_RR);
919b89a8333Snatalie li - Sun Microsystems - Irvine United States 
920b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if ((hlist == NULL) || (hlist->ah_list == NULL) || (hlist->ah_cnt == 0))
921b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (NULL);
922b89a8333Snatalie li - Sun Microsystems - Irvine United States 
92329bd2886SAlan Wright 	for (i = 0, hlistp = hlist->ah_list; i < hlist->ah_cnt; i++) {
92496a62adaSjoyce mcintosh 		if (smb_ads_set_ipaddr(&hlistp[i]) < 0)
925b89a8333Snatalie li - Sun Microsystems - Irvine United States 			continue;
926b89a8333Snatalie li - Sun Microsystems - Irvine United States 
92729bd2886SAlan Wright 		if (smb_ads_is_sought_host(&hlistp[i], kpasswd_srv))
92829bd2886SAlan Wright 			found_kpasswd_srv = &hlistp[i];
92929bd2886SAlan Wright 
93029bd2886SAlan Wright 		if (smb_ads_match_pdc(&hlistp[i]))
93129bd2886SAlan Wright 			found_pdc = &hlistp[i];
93229bd2886SAlan Wright 	}
93329bd2886SAlan Wright 
93429bd2886SAlan Wright 	if (found_kpasswd_srv && smb_ads_ldap_ping(found_kpasswd_srv) == 0) {
93529bd2886SAlan Wright 		host = found_kpasswd_srv;
93629bd2886SAlan Wright 		goto update_cache;
93729bd2886SAlan Wright 	}
93829bd2886SAlan Wright 
93929bd2886SAlan Wright 	if (found_pdc && smb_ads_ldap_ping(found_pdc) == 0) {
94029bd2886SAlan Wright 		host = found_pdc;
94129bd2886SAlan Wright 		goto update_cache;
94229bd2886SAlan Wright 	}
94329bd2886SAlan Wright 
94429bd2886SAlan Wright 	/*
94529bd2886SAlan Wright 	 * If the specified DC (kpasswd_srv or pdc) is not found, fallback
94629bd2886SAlan Wright 	 * to find a DC in the specified AD site.
94729bd2886SAlan Wright 	 */
94829bd2886SAlan Wright 	if (*site_service != '\0' &&
94929bd2886SAlan Wright 	    (kpasswd_srv || smb_ads_is_pdc_configured())) {
95029bd2886SAlan Wright 		hlist2 = smb_ads_query_dns_server(domain, site_service);
95129bd2886SAlan Wright 		if (hlist2 && hlist2->ah_list && hlist2->ah_cnt != 0) {
952b89a8333Snatalie li - Sun Microsystems - Irvine United States 			smb_ads_hlist_free(hlist);
95329bd2886SAlan Wright 			hlist = hlist2;
95429bd2886SAlan Wright 			hlistp = hlist->ah_list;
95529bd2886SAlan Wright 
95696a62adaSjoyce mcintosh 			for (i = 0; i < hlist->ah_cnt; i++)
95796a62adaSjoyce mcintosh 				(void) smb_ads_set_ipaddr(&hlistp[i]);
958b89a8333Snatalie li - Sun Microsystems - Irvine United States 		}
959b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
960b89a8333Snatalie li - Sun Microsystems - Irvine United States 
961b89a8333Snatalie li - Sun Microsystems - Irvine United States 	/* Select DC from DC list */
96229bd2886SAlan Wright 	host = smb_ads_select_dc(hlist);
96329bd2886SAlan Wright 
96429bd2886SAlan Wright update_cache:
96529bd2886SAlan Wright 	if (host) {
96629bd2886SAlan Wright 		(void) mutex_lock(&smb_ads_cached_host_mtx);
96729bd2886SAlan Wright 		if (!smb_ads_cached_host_info)
96829bd2886SAlan Wright 			smb_ads_cached_host_info = smb_ads_dup_host_info(host);
96929bd2886SAlan Wright 		host = smb_ads_dup_host_info(smb_ads_cached_host_info);
97029bd2886SAlan Wright 		(void) mutex_unlock(&smb_ads_cached_host_mtx);
971b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
972b89a8333Snatalie li - Sun Microsystems - Irvine United States 
973b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_hlist_free(hlist);
97429bd2886SAlan Wright 	return (host);
975b89a8333Snatalie li - Sun Microsystems - Irvine United States }
976b89a8333Snatalie li - Sun Microsystems - Irvine United States 
977b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
978b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Return the number of dots in a string.
979b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
980b89a8333Snatalie li - Sun Microsystems - Irvine United States static int
smb_ads_count_dots(const char * s)981b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_count_dots(const char *s)
982b89a8333Snatalie li - Sun Microsystems - Irvine United States {
983b89a8333Snatalie li - Sun Microsystems - Irvine United States 	int ndots = 0;
984b89a8333Snatalie li - Sun Microsystems - Irvine United States 
985b89a8333Snatalie li - Sun Microsystems - Irvine United States 	while (*s) {
986b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (*s++ == '.')
987b89a8333Snatalie li - Sun Microsystems - Irvine United States 			ndots++;
988b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
989b89a8333Snatalie li - Sun Microsystems - Irvine United States 
990b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (ndots);
991b89a8333Snatalie li - Sun Microsystems - Irvine United States }
992b89a8333Snatalie li - Sun Microsystems - Irvine United States 
993b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
994b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Convert a domain name in dot notation to distinguished name format,
995b89a8333Snatalie li - Sun Microsystems - Irvine United States  * for example: sun.com -> dc=sun,dc=com.
996b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
997b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Returns a pointer to an allocated buffer containing the distinguished
998b89a8333Snatalie li - Sun Microsystems - Irvine United States  * name.
999b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
1000b89a8333Snatalie li - Sun Microsystems - Irvine United States static char *
smb_ads_convert_domain(const char * domain_name)1001b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_convert_domain(const char *domain_name)
1002b89a8333Snatalie li - Sun Microsystems - Irvine United States {
1003b89a8333Snatalie li - Sun Microsystems - Irvine United States 	const char *s;
1004b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *dn_name;
1005b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char buf[2];
1006b89a8333Snatalie li - Sun Microsystems - Irvine United States 	int ndots;
1007b89a8333Snatalie li - Sun Microsystems - Irvine United States 	int len;
1008b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1009b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (domain_name == NULL || *domain_name == 0)
1010b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (NULL);
1011b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1012b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ndots = smb_ads_count_dots(domain_name);
1013b89a8333Snatalie li - Sun Microsystems - Irvine United States 	++ndots;
1014b89a8333Snatalie li - Sun Microsystems - Irvine United States 	len = strlen(domain_name) + (ndots * SMB_ADS_DN_PREFIX_LEN) + 1;
1015b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1016b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if ((dn_name = malloc(len)) == NULL)
1017b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (NULL);
1018b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1019b89a8333Snatalie li - Sun Microsystems - Irvine United States 	bzero(dn_name, len);
1020b89a8333Snatalie li - Sun Microsystems - Irvine United States 	(void) strlcpy(dn_name, "dc=", len);
1021b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1022b89a8333Snatalie li - Sun Microsystems - Irvine United States 	buf[1] = '\0';
1023b89a8333Snatalie li - Sun Microsystems - Irvine United States 	s = domain_name;
1024b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1025b89a8333Snatalie li - Sun Microsystems - Irvine United States 	while (*s) {
1026b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (*s == '.') {
1027b89a8333Snatalie li - Sun Microsystems - Irvine United States 			(void) strlcat(dn_name, ",dc=", len);
1028b89a8333Snatalie li - Sun Microsystems - Irvine United States 		} else {
1029b89a8333Snatalie li - Sun Microsystems - Irvine United States 			buf[0] = *s;
1030b89a8333Snatalie li - Sun Microsystems - Irvine United States 			(void) strlcat(dn_name, buf, len);
1031b89a8333Snatalie li - Sun Microsystems - Irvine United States 		}
1032b89a8333Snatalie li - Sun Microsystems - Irvine United States 		++s;
1033b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
1034b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1035b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (dn_name);
1036b89a8333Snatalie li - Sun Microsystems - Irvine United States }
1037b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1038b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
1039b89a8333Snatalie li - Sun Microsystems - Irvine United States  * smb_ads_free_cached_host
1040b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
1041b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Free the memory use by the global smb_ads_cached_host_info & set it to NULL.
1042b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
1043b89a8333Snatalie li - Sun Microsystems - Irvine United States static void
smb_ads_free_cached_host(void)1044b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_free_cached_host(void)
1045b89a8333Snatalie li - Sun Microsystems - Irvine United States {
1046b89a8333Snatalie li - Sun Microsystems - Irvine United States 	(void) mutex_lock(&smb_ads_cached_host_mtx);
1047b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (smb_ads_cached_host_info) {
1048b89a8333Snatalie li - Sun Microsystems - Irvine United States 		free(smb_ads_cached_host_info);
1049b89a8333Snatalie li - Sun Microsystems - Irvine United States 		smb_ads_cached_host_info = NULL;
1050b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
1051b89a8333Snatalie li - Sun Microsystems - Irvine United States 	(void) mutex_unlock(&smb_ads_cached_host_mtx);
1052da6c28aaSamw }
1053da6c28aaSamw 
1054da6c28aaSamw /*
10553db3f65cSamw  * smb_ads_open
105655bf511dSas200622  * Open a LDAP connection to an ADS server if the system is in domain mode.
105755bf511dSas200622  * Acquire both Kerberos TGT and LDAP service tickets for the host principal.
105855bf511dSas200622  *
105955bf511dSas200622  * This function should only be called after the system is successfully joined
106055bf511dSas200622  * to a domain.
106155bf511dSas200622  */
10623db3f65cSamw smb_ads_handle_t *
smb_ads_open(void)10633db3f65cSamw smb_ads_open(void)
106455bf511dSas200622 {
1065dc20a302Sas200622 	char domain[MAXHOSTNAMELEN];
106655bf511dSas200622 
1067dc20a302Sas200622 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
106855bf511dSas200622 		return (NULL);
106955bf511dSas200622 
1070dc20a302Sas200622 	if (smb_getfqdomainname(domain, MAXHOSTNAMELEN) != 0)
1071dc20a302Sas200622 		return (NULL);
1072dc20a302Sas200622 
10733db3f65cSamw 	return (smb_ads_open_main(domain, NULL, NULL));
107455bf511dSas200622 }
107555bf511dSas200622 
1076a0aa776eSAlan Wright static int
smb_ads_saslcallback(LDAP * ld,unsigned flags,void * defaults,void * prompts)1077a0aa776eSAlan Wright smb_ads_saslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts)
1078a0aa776eSAlan Wright {
1079a0aa776eSAlan Wright 	NOTE(ARGUNUSED(ld, defaults));
1080a0aa776eSAlan Wright 	sasl_interact_t *interact;
1081a0aa776eSAlan Wright 
1082a0aa776eSAlan Wright 	if (prompts == NULL || flags != LDAP_SASL_INTERACTIVE)
1083a0aa776eSAlan Wright 		return (LDAP_PARAM_ERROR);
1084a0aa776eSAlan Wright 
1085a0aa776eSAlan Wright 	/* There should be no extra arguemnts for SASL/GSSAPI authentication */
1086a0aa776eSAlan Wright 	for (interact = prompts; interact->id != SASL_CB_LIST_END;
1087a0aa776eSAlan Wright 	    interact++) {
1088a0aa776eSAlan Wright 		interact->result = NULL;
1089a0aa776eSAlan Wright 		interact->len = 0;
1090a0aa776eSAlan Wright 	}
1091a0aa776eSAlan Wright 	return (LDAP_SUCCESS);
1092a0aa776eSAlan Wright }
1093a0aa776eSAlan Wright 
109455bf511dSas200622 /*
10953db3f65cSamw  * smb_ads_open_main
1096da6c28aaSamw  * Open a LDAP connection to an ADS server.
109755bf511dSas200622  * If ADS is enabled and the administrative username, password, and
1098da6c28aaSamw  * ADS domain are defined then query DNS to find an ADS server if this is the
1099da6c28aaSamw  * very first call to this routine.  After an ADS server is found then this
1100da6c28aaSamw  * server will be used everytime this routine is called until the system is
1101da6c28aaSamw  * rebooted or the ADS server becomes unavailable then an ADS server will
11023db3f65cSamw  * be queried again.  After the connection is made then an ADS handle
1103da6c28aaSamw  * is created to be returned.
1104da6c28aaSamw  *
1105da6c28aaSamw  * After the LDAP connection, the LDAP version will be set to 3 using
1106da6c28aaSamw  * ldap_set_option().
1107da6c28aaSamw  *
1108a0aa776eSAlan Wright  * The LDAP connection is bound before the ADS handle is returned.
1109da6c28aaSamw  * Parameters:
1110dc20a302Sas200622  *   domain - fully-qualified domain name
1111dc20a302Sas200622  *   user   - the user account for whom the Kerberos TGT ticket and ADS
1112dc20a302Sas200622  *            service tickets are acquired.
1113dc20a302Sas200622  *   password - password of the specified user
1114dc20a302Sas200622  *
1115da6c28aaSamw  * Returns:
1116da6c28aaSamw  *   NULL              : can't connect to ADS server or other errors
11173db3f65cSamw  *   smb_ads_handle_t* : handle to ADS server
1118da6c28aaSamw  */
11193db3f65cSamw static smb_ads_handle_t *
smb_ads_open_main(char * domain,char * user,char * password)11203db3f65cSamw smb_ads_open_main(char *domain, char *user, char *password)
1121da6c28aaSamw {
11223db3f65cSamw 	smb_ads_handle_t *ah;
1123da6c28aaSamw 	LDAP *ld;
1124b89a8333Snatalie li - Sun Microsystems - Irvine United States 	int version = 3;
11253db3f65cSamw 	smb_ads_host_info_t *ads_host = NULL;
1126a0aa776eSAlan Wright 	int rc;
1127a0aa776eSAlan Wright 
1128a0aa776eSAlan Wright 	if (user != NULL) {
1129a0aa776eSAlan Wright 		if (smb_kinit(user, password) == 0)
1130a0aa776eSAlan Wright 			return (NULL);
1131a0aa776eSAlan Wright 		user = NULL;
1132a0aa776eSAlan Wright 		password = NULL;
1133a0aa776eSAlan Wright 	}
1134da6c28aaSamw 
1135b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ads_host = smb_ads_find_host(domain, NULL);
1136b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (ads_host == NULL)
1137da6c28aaSamw 		return (NULL);
1138b89a8333Snatalie li - Sun Microsystems - Irvine United States 
11393db3f65cSamw 	ah = (smb_ads_handle_t *)malloc(sizeof (smb_ads_handle_t));
114029bd2886SAlan Wright 	if (ah == NULL) {
114129bd2886SAlan Wright 		free(ads_host);
1142da6c28aaSamw 		return (NULL);
114329bd2886SAlan Wright 	}
114429bd2886SAlan Wright 
11453db3f65cSamw 	(void) memset(ah, 0, sizeof (smb_ads_handle_t));
1146da6c28aaSamw 
11477f667e74Sjose borrego 	if ((ld = ldap_init(ads_host->name, ads_host->port)) == NULL) {
1148b89a8333Snatalie li - Sun Microsystems - Irvine United States 		smb_ads_free_cached_host();
1149da6c28aaSamw 		free(ah);
115029bd2886SAlan Wright 		free(ads_host);
1151da6c28aaSamw 		return (NULL);
1152da6c28aaSamw 	}
1153da6c28aaSamw 
1154da6c28aaSamw 	if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version)
1155da6c28aaSamw 	    != LDAP_SUCCESS) {
1156b89a8333Snatalie li - Sun Microsystems - Irvine United States 		smb_ads_free_cached_host();
1157da6c28aaSamw 		free(ah);
115829bd2886SAlan Wright 		free(ads_host);
1159da6c28aaSamw 		(void) ldap_unbind(ld);
1160da6c28aaSamw 		return (NULL);
1161da6c28aaSamw 	}
1162da6c28aaSamw 
1163c8ec8eeaSjose borrego 	(void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
1164da6c28aaSamw 	ah->ld = ld;
1165da6c28aaSamw 	ah->domain = strdup(domain);
1166da6c28aaSamw 
116755bf511dSas200622 	if (ah->domain == NULL) {
11683db3f65cSamw 		smb_ads_close(ah);
116929bd2886SAlan Wright 		free(ads_host);
1170da6c28aaSamw 		return (NULL);
1171da6c28aaSamw 	}
1172da6c28aaSamw 
11739fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	/*
11749fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	 * ah->domain is often used for generating service principal name.
11759fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	 * Convert it to lower case for RFC 4120 section 6.2.1 conformance.
11769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	 */
11779fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	(void) smb_strlwr(ah->domain);
11783db3f65cSamw 	ah->domain_dn = smb_ads_convert_domain(domain);
1179da6c28aaSamw 	if (ah->domain_dn == NULL) {
11803db3f65cSamw 		smb_ads_close(ah);
118129bd2886SAlan Wright 		free(ads_host);
1182da6c28aaSamw 		return (NULL);
1183da6c28aaSamw 	}
1184da6c28aaSamw 
1185da6c28aaSamw 	ah->hostname = strdup(ads_host->name);
1186da6c28aaSamw 	if (ah->hostname == NULL) {
11873db3f65cSamw 		smb_ads_close(ah);
118829bd2886SAlan Wright 		free(ads_host);
1189da6c28aaSamw 		return (NULL);
1190da6c28aaSamw 	}
119129bd2886SAlan Wright 	(void) mutex_lock(&smb_ads_cfg.c_mtx);
119229bd2886SAlan Wright 	if (*smb_ads_cfg.c_site != '\0') {
119329bd2886SAlan Wright 		if ((ah->site = strdup(smb_ads_cfg.c_site)) == NULL) {
11943db3f65cSamw 			smb_ads_close(ah);
119529bd2886SAlan Wright 			(void) mutex_unlock(&smb_ads_cfg.c_mtx);
119629bd2886SAlan Wright 			free(ads_host);
1197da6c28aaSamw 			return (NULL);
1198da6c28aaSamw 		}
1199da6c28aaSamw 	} else {
1200da6c28aaSamw 		ah->site = NULL;
1201da6c28aaSamw 	}
120229bd2886SAlan Wright 	(void) mutex_unlock(&smb_ads_cfg.c_mtx);
1203da6c28aaSamw 
1204a0aa776eSAlan Wright 	rc = ldap_sasl_interactive_bind_s(ah->ld, "", "GSSAPI", NULL, NULL,
1205a0aa776eSAlan Wright 	    LDAP_SASL_INTERACTIVE, &smb_ads_saslcallback, NULL);
1206a0aa776eSAlan Wright 	if (rc != LDAP_SUCCESS) {
1207a0aa776eSAlan Wright 		syslog(LOG_ERR, "ldal_sasl_interactive_bind_s failed (%s)",
1208a0aa776eSAlan Wright 		    ldap_err2string(rc));
12093db3f65cSamw 		smb_ads_close(ah);
121029bd2886SAlan Wright 		free(ads_host);
1211da6c28aaSamw 		return (NULL);
1212da6c28aaSamw 	}
1213da6c28aaSamw 
121429bd2886SAlan Wright 	free(ads_host);
1215da6c28aaSamw 	return (ah);
1216da6c28aaSamw }
1217da6c28aaSamw 
1218da6c28aaSamw /*
12193db3f65cSamw  * smb_ads_close
1220da6c28aaSamw  * Close connection to ADS server and free memory allocated for ADS handle.
1221da6c28aaSamw  * LDAP unbind is called here.
1222da6c28aaSamw  * Parameters:
1223da6c28aaSamw  *   ah: handle to ADS server
1224da6c28aaSamw  * Returns:
1225da6c28aaSamw  *   void
1226da6c28aaSamw  */
1227da6c28aaSamw void
smb_ads_close(smb_ads_handle_t * ah)12283db3f65cSamw smb_ads_close(smb_ads_handle_t *ah)
1229da6c28aaSamw {
1230da6c28aaSamw 	if (ah == NULL)
1231da6c28aaSamw 		return;
1232da6c28aaSamw 	/* close and free connection resources */
1233da6c28aaSamw 	if (ah->ld)
1234da6c28aaSamw 		(void) ldap_unbind(ah->ld);
1235da6c28aaSamw 
1236da6c28aaSamw 	free(ah->domain);
1237da6c28aaSamw 	free(ah->domain_dn);
1238da6c28aaSamw 	free(ah->hostname);
1239da6c28aaSamw 	free(ah->site);
1240da6c28aaSamw 	free(ah);
1241da6c28aaSamw }
1242da6c28aaSamw 
1243da6c28aaSamw /*
12443db3f65cSamw  * smb_ads_alloc_attr
12456537f381Sas200622  *
12466537f381Sas200622  * Since the attrs is a null-terminated array, all elements
12476537f381Sas200622  * in the array (except the last one) will point to allocated
12486537f381Sas200622  * memory.
12496537f381Sas200622  */
12506537f381Sas200622 static int
smb_ads_alloc_attr(LDAPMod * attrs[],int num)12513db3f65cSamw smb_ads_alloc_attr(LDAPMod *attrs[], int num)
12526537f381Sas200622 {
12536537f381Sas200622 	int i;
12546537f381Sas200622 
12556537f381Sas200622 	bzero(attrs, num * sizeof (LDAPMod *));
12566537f381Sas200622 	for (i = 0; i < (num - 1); i++) {
12576537f381Sas200622 		attrs[i] = (LDAPMod *)malloc(sizeof (LDAPMod));
12586537f381Sas200622 		if (attrs[i] == NULL) {
12593db3f65cSamw 			smb_ads_free_attr(attrs);
12606537f381Sas200622 			return (-1);
12616537f381Sas200622 		}
12626537f381Sas200622 	}
12636537f381Sas200622 
12646537f381Sas200622 	return (0);
12656537f381Sas200622 }
12666537f381Sas200622 
12676537f381Sas200622 /*
12683db3f65cSamw  * smb_ads_free_attr
1269da6c28aaSamw  * Free memory allocated when publishing a share.
1270da6c28aaSamw  * Parameters:
127155bf511dSas200622  *   attrs: an array of LDAPMod pointers
1272da6c28aaSamw  * Returns:
1273da6c28aaSamw  *   None
1274da6c28aaSamw  */
1275da6c28aaSamw static void
smb_ads_free_attr(LDAPMod * attrs[])12763db3f65cSamw smb_ads_free_attr(LDAPMod *attrs[])
1277da6c28aaSamw {
1278da6c28aaSamw 	int i;
127955bf511dSas200622 	for (i = 0; attrs[i]; i++) {
128055bf511dSas200622 		free(attrs[i]);
1281da6c28aaSamw 	}
1282da6c28aaSamw }
1283da6c28aaSamw 
1284da6c28aaSamw /*
1285fe1c642dSBill Krier  * Returns share DN in an allocated buffer.  The format of the DN is
1286fe1c642dSBill Krier  * cn=<sharename>,<container RDNs>,<domain DN>
1287fe1c642dSBill Krier  *
1288fe1c642dSBill Krier  * If the domain DN is not included in the container parameter,
1289fe1c642dSBill Krier  * then it will be appended to create the share DN.
1290fe1c642dSBill Krier  *
1291fe1c642dSBill Krier  * The caller must free the allocated buffer.
1292fe1c642dSBill Krier  */
1293fe1c642dSBill Krier static char *
smb_ads_get_sharedn(const char * sharename,const char * container,const char * domain_dn)1294fe1c642dSBill Krier smb_ads_get_sharedn(const char *sharename, const char *container,
1295fe1c642dSBill Krier     const char *domain_dn)
1296fe1c642dSBill Krier {
1297fe1c642dSBill Krier 	char *share_dn;
1298fe1c642dSBill Krier 	int rc, offset, container_len, domain_len;
1299fe1c642dSBill Krier 	boolean_t append_domain = B_TRUE;
1300fe1c642dSBill Krier 
1301fe1c642dSBill Krier 	container_len = strlen(container);
1302fe1c642dSBill Krier 	domain_len = strlen(domain_dn);
1303fe1c642dSBill Krier 
1304fe1c642dSBill Krier 	if (container_len >= domain_len) {
1305fe1c642dSBill Krier 
1306fe1c642dSBill Krier 		/* offset to last domain_len characters */
1307fe1c642dSBill Krier 		offset = container_len - domain_len;
1308fe1c642dSBill Krier 
1309fe1c642dSBill Krier 		if (smb_strcasecmp(container + offset,
1310fe1c642dSBill Krier 		    domain_dn, domain_len) == 0)
1311fe1c642dSBill Krier 			append_domain = B_FALSE;
1312fe1c642dSBill Krier 	}
1313fe1c642dSBill Krier 
1314fe1c642dSBill Krier 	if (append_domain)
1315fe1c642dSBill Krier 		rc = asprintf(&share_dn, "cn=%s,%s,%s", sharename,
1316fe1c642dSBill Krier 		    container, domain_dn);
1317fe1c642dSBill Krier 	else
1318fe1c642dSBill Krier 		rc = asprintf(&share_dn, "cn=%s,%s", sharename,
1319fe1c642dSBill Krier 		    container);
1320fe1c642dSBill Krier 
1321fe1c642dSBill Krier 	return ((rc == -1) ? NULL : share_dn);
1322fe1c642dSBill Krier }
1323fe1c642dSBill Krier 
1324fe1c642dSBill Krier /*
13253db3f65cSamw  * smb_ads_add_share
13263db3f65cSamw  * Call by smb_ads_publish_share to create share object in ADS.
1327da6c28aaSamw  * This routine specifies the attributes of an ADS LDAP share object. The first
1328da6c28aaSamw  * attribute and values define the type of ADS object, the share object.  The
1329da6c28aaSamw  * second attribute and value define the UNC of the share data for the share
1330da6c28aaSamw  * object. The LDAP synchronous add command is used to add the object into ADS.
1331da6c28aaSamw  * The container location to add the object needs to specified.
1332da6c28aaSamw  * Parameters:
1333da6c28aaSamw  *   ah          : handle to ADS server
1334da6c28aaSamw  *   adsShareName: name of share object to be created in ADS
1335da6c28aaSamw  *   shareUNC    : share name on NetForce
1336da6c28aaSamw  *   adsContainer: location in ADS to create share object
1337da6c28aaSamw  *
1338da6c28aaSamw  * Returns:
1339da6c28aaSamw  *   -1          : error
1340da6c28aaSamw  *    0          : success
1341da6c28aaSamw  */
1342da6c28aaSamw int
smb_ads_add_share(smb_ads_handle_t * ah,const char * adsShareName,const char * unc_name,const char * adsContainer)13433db3f65cSamw smb_ads_add_share(smb_ads_handle_t *ah, const char *adsShareName,
1344da6c28aaSamw     const char *unc_name, const char *adsContainer)
1345da6c28aaSamw {
13463db3f65cSamw 	LDAPMod *attrs[SMB_ADS_SHARE_NUM_ATTR];
134755bf511dSas200622 	int j = 0;
1348da6c28aaSamw 	char *share_dn;
1349fe1c642dSBill Krier 	int ret;
13507f667e74Sjose borrego 	char *unc_names[] = {(char *)unc_name, NULL};
1351da6c28aaSamw 
1352fe1c642dSBill Krier 	if ((share_dn = smb_ads_get_sharedn(adsShareName, adsContainer,
1353fe1c642dSBill Krier 	    ah->domain_dn)) == NULL)
1354da6c28aaSamw 		return (-1);
1355da6c28aaSamw 
13563db3f65cSamw 	if (smb_ads_alloc_attr(attrs, SMB_ADS_SHARE_NUM_ATTR) != 0) {
135755bf511dSas200622 		free(share_dn);
135855bf511dSas200622 		return (-1);
135955bf511dSas200622 	}
136055bf511dSas200622 
136155bf511dSas200622 	attrs[j]->mod_op = LDAP_MOD_ADD;
136255bf511dSas200622 	attrs[j]->mod_type = "objectClass";
13637f667e74Sjose borrego 	attrs[j]->mod_values = smb_ads_share_objcls;
1364da6c28aaSamw 
136555bf511dSas200622 	attrs[++j]->mod_op = LDAP_MOD_ADD;
136655bf511dSas200622 	attrs[j]->mod_type = "uNCName";
13677f667e74Sjose borrego 	attrs[j]->mod_values = unc_names;
1368da6c28aaSamw 
136955bf511dSas200622 	if ((ret = ldap_add_s(ah->ld, share_dn, attrs)) != LDAP_SUCCESS) {
13709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		if (ret == LDAP_NO_SUCH_OBJECT) {
13719fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			syslog(LOG_ERR, "Failed to publish share %s in" \
13729fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			    " AD.  Container does not exist: %s.\n",
13739fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			    adsShareName, share_dn);
13749fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
13759fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		} else {
13769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			syslog(LOG_ERR, "Failed to publish share %s in" \
13779fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			    " AD: %s (%s).\n", adsShareName, share_dn,
13789fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			    ldap_err2string(ret));
13799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		}
13803db3f65cSamw 		smb_ads_free_attr(attrs);
1381da6c28aaSamw 		free(share_dn);
1382da6c28aaSamw 		return (ret);
1383da6c28aaSamw 	}
1384da6c28aaSamw 	free(share_dn);
13853db3f65cSamw 	smb_ads_free_attr(attrs);
1386da6c28aaSamw 
1387da6c28aaSamw 	return (0);
1388da6c28aaSamw }
1389da6c28aaSamw 
1390da6c28aaSamw /*
13913db3f65cSamw  * smb_ads_del_share
13923db3f65cSamw  * Call by smb_ads_remove_share to remove share object from ADS.  The container
1393da6c28aaSamw  * location to remove the object needs to specified.  The LDAP synchronous
1394da6c28aaSamw  * delete command is used.
1395da6c28aaSamw  * Parameters:
1396da6c28aaSamw  *   ah          : handle to ADS server
1397da6c28aaSamw  *   adsShareName: name of share object in ADS to be removed
1398da6c28aaSamw  *   adsContainer: location of share object in ADS
1399da6c28aaSamw  * Returns:
1400da6c28aaSamw  *   -1          : error
1401da6c28aaSamw  *    0          : success
1402da6c28aaSamw  */
1403da6c28aaSamw static int
smb_ads_del_share(smb_ads_handle_t * ah,const char * adsShareName,const char * adsContainer)14043db3f65cSamw smb_ads_del_share(smb_ads_handle_t *ah, const char *adsShareName,
1405da6c28aaSamw     const char *adsContainer)
1406da6c28aaSamw {
1407b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *share_dn;
1408fe1c642dSBill Krier 	int ret;
1409da6c28aaSamw 
1410fe1c642dSBill Krier 	if ((share_dn = smb_ads_get_sharedn(adsShareName, adsContainer,
1411fe1c642dSBill Krier 	    ah->domain_dn)) == NULL)
1412da6c28aaSamw 		return (-1);
1413da6c28aaSamw 
1414da6c28aaSamw 	if ((ret = ldap_delete_s(ah->ld, share_dn)) != LDAP_SUCCESS) {
1415fc724630SAlan Wright 		smb_tracef("ldap_delete: %s", ldap_err2string(ret));
1416da6c28aaSamw 		free(share_dn);
1417da6c28aaSamw 		return (-1);
1418da6c28aaSamw 	}
1419da6c28aaSamw 	free(share_dn);
1420da6c28aaSamw 
1421da6c28aaSamw 	return (0);
1422da6c28aaSamw }
1423da6c28aaSamw 
1424da6c28aaSamw 
1425da6c28aaSamw /*
14263db3f65cSamw  * smb_ads_escape_search_filter_chars
1427da6c28aaSamw  *
1428da6c28aaSamw  * This routine will escape the special characters found in a string
1429da6c28aaSamw  * that will later be passed to the ldap search filter.
1430da6c28aaSamw  *
1431da6c28aaSamw  * RFC 1960 - A String Representation of LDAP Search Filters
1432da6c28aaSamw  * 3.  String Search Filter Definition
1433da6c28aaSamw  * If a value must contain one of the characters '*' OR '(' OR ')',
1434da6c28aaSamw  * these characters
1435da6c28aaSamw  * should be escaped by preceding them with the backslash '\' character.
1436da6c28aaSamw  *
1437da6c28aaSamw  * RFC 2252 - LDAP Attribute Syntax Definitions
1438da6c28aaSamw  * a backslash quoting mechanism is used to escape
1439da6c28aaSamw  * the following separator symbol character (such as "'", "$" or "#") if
1440da6c28aaSamw  * it should occur in that string.
1441da6c28aaSamw  */
1442da6c28aaSamw static int
smb_ads_escape_search_filter_chars(const char * src,char * dst)14433db3f65cSamw smb_ads_escape_search_filter_chars(const char *src, char *dst)
1444da6c28aaSamw {
14453db3f65cSamw 	int avail = SMB_ADS_MAXBUFLEN - 1; /* reserve a space for NULL char */
1446da6c28aaSamw 
1447da6c28aaSamw 	if (src == NULL || dst == NULL)
1448da6c28aaSamw 		return (-1);
1449da6c28aaSamw 
1450da6c28aaSamw 	while (*src) {
1451da6c28aaSamw 		if (!avail) {
1452da6c28aaSamw 			*dst = 0;
1453da6c28aaSamw 			return (-1);
1454da6c28aaSamw 		}
1455da6c28aaSamw 
1456da6c28aaSamw 		switch (*src) {
1457da6c28aaSamw 		case '\\':
1458da6c28aaSamw 		case '\'':
1459da6c28aaSamw 		case '$':
1460da6c28aaSamw 		case '#':
1461da6c28aaSamw 		case '*':
1462da6c28aaSamw 		case '(':
1463da6c28aaSamw 		case ')':
1464da6c28aaSamw 			*dst++ = '\\';
1465da6c28aaSamw 			avail--;
1466da6c28aaSamw 			/* fall through */
1467da6c28aaSamw 
1468da6c28aaSamw 		default:
1469da6c28aaSamw 			*dst++ = *src++;
1470da6c28aaSamw 			avail--;
1471da6c28aaSamw 		}
1472da6c28aaSamw 	}
1473da6c28aaSamw 
1474da6c28aaSamw 	*dst = 0;
1475da6c28aaSamw 
1476da6c28aaSamw 	return (0);
1477da6c28aaSamw }
1478da6c28aaSamw 
1479da6c28aaSamw /*
14803db3f65cSamw  * smb_ads_lookup_share
1481da6c28aaSamw  * The search filter is set to search for a specific share name in the
1482da6c28aaSamw  * specified ADS container.  The LDSAP synchronous search command is used.
1483da6c28aaSamw  * Parameters:
1484da6c28aaSamw  *   ah          : handle to ADS server
1485da6c28aaSamw  *   adsShareName: name of share object in ADS to be searched
1486da6c28aaSamw  *   adsContainer: location of share object in ADS
1487da6c28aaSamw  * Returns:
1488da6c28aaSamw  *   -1          : error
1489da6c28aaSamw  *    0          : not found
1490da6c28aaSamw  *    1          : found
1491da6c28aaSamw  */
1492da6c28aaSamw int
smb_ads_lookup_share(smb_ads_handle_t * ah,const char * adsShareName,const char * adsContainer,char * unc_name)14933db3f65cSamw smb_ads_lookup_share(smb_ads_handle_t *ah, const char *adsShareName,
1494da6c28aaSamw     const char *adsContainer, char *unc_name)
1495da6c28aaSamw {
14963db3f65cSamw 	char *attrs[4], filter[SMB_ADS_MAXBUFLEN];
1497da6c28aaSamw 	char *share_dn;
1498fe1c642dSBill Krier 	int ret;
1499da6c28aaSamw 	LDAPMessage *res;
15003db3f65cSamw 	char tmpbuf[SMB_ADS_MAXBUFLEN];
1501da6c28aaSamw 
1502da6c28aaSamw 	if (adsShareName == NULL || adsContainer == NULL)
1503da6c28aaSamw 		return (-1);
1504da6c28aaSamw 
1505fe1c642dSBill Krier 	if ((share_dn = smb_ads_get_sharedn(adsShareName, adsContainer,
1506fe1c642dSBill Krier 	    ah->domain_dn)) == NULL)
1507da6c28aaSamw 		return (-1);
1508da6c28aaSamw 
1509da6c28aaSamw 	res = NULL;
1510da6c28aaSamw 	attrs[0] = "cn";
1511da6c28aaSamw 	attrs[1] = "objectClass";
1512da6c28aaSamw 	attrs[2] = "uNCName";
1513da6c28aaSamw 	attrs[3] = NULL;
1514da6c28aaSamw 
15153db3f65cSamw 	if (smb_ads_escape_search_filter_chars(unc_name, tmpbuf) != 0) {
1516da6c28aaSamw 		free(share_dn);
1517da6c28aaSamw 		return (-1);
1518da6c28aaSamw 	}
1519da6c28aaSamw 
1520da6c28aaSamw 	(void) snprintf(filter, sizeof (filter),
1521da6c28aaSamw 	    "(&(objectClass=volume)(uNCName=%s))", tmpbuf);
1522da6c28aaSamw 
1523da6c28aaSamw 	if ((ret = ldap_search_s(ah->ld, share_dn,
1524da6c28aaSamw 	    LDAP_SCOPE_BASE, filter, attrs, 0, &res)) != LDAP_SUCCESS) {
1525b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (ret != LDAP_NO_SUCH_OBJECT)
1526fc724630SAlan Wright 			smb_tracef("%s: ldap_search: %s", share_dn,
1527fc724630SAlan Wright 			    ldap_err2string(ret));
1528b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1529da6c28aaSamw 		(void) ldap_msgfree(res);
1530da6c28aaSamw 		free(share_dn);
1531da6c28aaSamw 		return (0);
1532da6c28aaSamw 	}
1533da6c28aaSamw 
1534da6c28aaSamw 	(void) free(share_dn);
1535da6c28aaSamw 
1536da6c28aaSamw 	/* no match is found */
1537da6c28aaSamw 	if (ldap_count_entries(ah->ld, res) == 0) {
1538da6c28aaSamw 		(void) ldap_msgfree(res);
1539da6c28aaSamw 		return (0);
1540da6c28aaSamw 	}
1541da6c28aaSamw 
1542da6c28aaSamw 	/* free the search results */
1543da6c28aaSamw 	(void) ldap_msgfree(res);
1544da6c28aaSamw 
1545da6c28aaSamw 	return (1);
1546da6c28aaSamw }
1547da6c28aaSamw 
1548da6c28aaSamw /*
15493db3f65cSamw  * smb_ads_publish_share
1550da6c28aaSamw  * Publish share into ADS.  If a share name already exist in ADS in the same
1551da6c28aaSamw  * container then the existing share object is removed before adding the new
1552da6c28aaSamw  * share object.
1553da6c28aaSamw  * Parameters:
15543db3f65cSamw  *   ah          : handle return from smb_ads_open
1555da6c28aaSamw  *   adsShareName: name of share to be added to ADS directory
1556da6c28aaSamw  *   shareUNC    : name of share on client, can be NULL to use the same name
1557da6c28aaSamw  *                 as adsShareName
1558da6c28aaSamw  *   adsContainer: location for share to be added in ADS directory, ie
1559da6c28aaSamw  *                   ou=share_folder
1560da6c28aaSamw  *   uncType     : use UNC_HOSTNAME to use hostname for UNC, use UNC_HOSTADDR
1561da6c28aaSamw  *                   to use host ip addr for UNC.
1562da6c28aaSamw  * Returns:
1563da6c28aaSamw  *   -1          : error
1564da6c28aaSamw  *    0          : success
1565da6c28aaSamw  */
1566da6c28aaSamw int
smb_ads_publish_share(smb_ads_handle_t * ah,const char * adsShareName,const char * shareUNC,const char * adsContainer,const char * hostname)15673db3f65cSamw smb_ads_publish_share(smb_ads_handle_t *ah, const char *adsShareName,
1568da6c28aaSamw     const char *shareUNC, const char *adsContainer, const char *hostname)
1569da6c28aaSamw {
1570da6c28aaSamw 	int ret;
15713db3f65cSamw 	char unc_name[SMB_ADS_MAXBUFLEN];
1572da6c28aaSamw 
1573da6c28aaSamw 	if (adsShareName == NULL || adsContainer == NULL)
1574da6c28aaSamw 		return (-1);
1575da6c28aaSamw 
1576da6c28aaSamw 	if (shareUNC == 0 || *shareUNC == 0)
1577da6c28aaSamw 		shareUNC = adsShareName;
1578da6c28aaSamw 
15793db3f65cSamw 	if (smb_ads_build_unc_name(unc_name, sizeof (unc_name),
1580b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    hostname, shareUNC) < 0)
1581da6c28aaSamw 		return (-1);
1582da6c28aaSamw 
15833db3f65cSamw 	ret = smb_ads_lookup_share(ah, adsShareName, adsContainer, unc_name);
1584da6c28aaSamw 
1585da6c28aaSamw 	switch (ret) {
1586da6c28aaSamw 	case 1:
15873db3f65cSamw 		(void) smb_ads_del_share(ah, adsShareName, adsContainer);
15883db3f65cSamw 		ret = smb_ads_add_share(ah, adsShareName, unc_name,
15893db3f65cSamw 		    adsContainer);
1590da6c28aaSamw 		break;
1591da6c28aaSamw 
1592da6c28aaSamw 	case 0:
15933db3f65cSamw 		ret = smb_ads_add_share(ah, adsShareName, unc_name,
15943db3f65cSamw 		    adsContainer);
1595b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (ret == LDAP_ALREADY_EXISTS)
1596da6c28aaSamw 			ret = -1;
1597b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1598da6c28aaSamw 		break;
1599da6c28aaSamw 
1600da6c28aaSamw 	case -1:
1601da6c28aaSamw 	default:
1602da6c28aaSamw 		/* return with error code */
1603da6c28aaSamw 		ret = -1;
1604da6c28aaSamw 	}
1605da6c28aaSamw 
1606da6c28aaSamw 	return (ret);
1607da6c28aaSamw }
1608da6c28aaSamw 
1609da6c28aaSamw /*
16103db3f65cSamw  * smb_ads_remove_share
1611da6c28aaSamw  * Remove share from ADS.  A search is done first before explicitly removing
1612da6c28aaSamw  * the share.
1613da6c28aaSamw  * Parameters:
16143db3f65cSamw  *   ah          : handle return from smb_ads_open
1615da6c28aaSamw  *   adsShareName: name of share to be removed from ADS directory
1616da6c28aaSamw  *   adsContainer: location for share to be removed from ADS directory, ie
1617da6c28aaSamw  *                   ou=share_folder
1618da6c28aaSamw  * Returns:
1619da6c28aaSamw  *   -1          : error
1620da6c28aaSamw  *    0          : success
1621da6c28aaSamw  */
1622da6c28aaSamw int
smb_ads_remove_share(smb_ads_handle_t * ah,const char * adsShareName,const char * shareUNC,const char * adsContainer,const char * hostname)16233db3f65cSamw smb_ads_remove_share(smb_ads_handle_t *ah, const char *adsShareName,
16243db3f65cSamw     const char *shareUNC, const char *adsContainer, const char *hostname)
1625da6c28aaSamw {
1626da6c28aaSamw 	int ret;
16273db3f65cSamw 	char unc_name[SMB_ADS_MAXBUFLEN];
1628da6c28aaSamw 
1629da6c28aaSamw 	if (adsShareName == NULL || adsContainer == NULL)
1630da6c28aaSamw 		return (-1);
1631da6c28aaSamw 	if (shareUNC == 0 || *shareUNC == 0)
1632da6c28aaSamw 		shareUNC = adsShareName;
1633da6c28aaSamw 
16343db3f65cSamw 	if (smb_ads_build_unc_name(unc_name, sizeof (unc_name),
1635b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    hostname, shareUNC) < 0)
1636da6c28aaSamw 		return (-1);
1637da6c28aaSamw 
16383db3f65cSamw 	ret = smb_ads_lookup_share(ah, adsShareName, adsContainer, unc_name);
1639da6c28aaSamw 	if (ret == 0)
1640da6c28aaSamw 		return (0);
1641da6c28aaSamw 	if (ret == -1)
1642da6c28aaSamw 		return (-1);
1643da6c28aaSamw 
16443db3f65cSamw 	return (smb_ads_del_share(ah, adsShareName, adsContainer));
1645da6c28aaSamw }
1646da6c28aaSamw 
1647da6c28aaSamw /*
1648b89a8333Snatalie li - Sun Microsystems - Irvine United States  * smb_ads_get_default_comp_container_dn
1649da6c28aaSamw  *
1650b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Build the distinguished name for the default computer conatiner (i.e. the
1651b89a8333Snatalie li - Sun Microsystems - Irvine United States  * pre-defined Computers container).
1652da6c28aaSamw  */
1653da6c28aaSamw static void
smb_ads_get_default_comp_container_dn(smb_ads_handle_t * ah,char * buf,size_t buflen)1654b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_get_default_comp_container_dn(smb_ads_handle_t *ah, char *buf,
1655b89a8333Snatalie li - Sun Microsystems - Irvine United States     size_t buflen)
1656da6c28aaSamw {
1657b89a8333Snatalie li - Sun Microsystems - Irvine United States 	(void) snprintf(buf, buflen, "cn=%s,%s", SMB_ADS_COMPUTERS_CN,
1658b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    ah->domain_dn);
1659b89a8333Snatalie li - Sun Microsystems - Irvine United States }
1660da6c28aaSamw 
1661b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
1662b89a8333Snatalie li - Sun Microsystems - Irvine United States  * smb_ads_get_default_comp_dn
1663b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
1664b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Build the distinguished name for this system.
1665b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
1666b89a8333Snatalie li - Sun Microsystems - Irvine United States static void
smb_ads_get_default_comp_dn(smb_ads_handle_t * ah,char * buf,size_t buflen)1667b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_get_default_comp_dn(smb_ads_handle_t *ah, char *buf, size_t buflen)
1668b89a8333Snatalie li - Sun Microsystems - Irvine United States {
1669b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char nbname[NETBIOS_NAME_SZ];
1670b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char container_dn[SMB_ADS_DN_MAX];
1671b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1672b89a8333Snatalie li - Sun Microsystems - Irvine United States 	(void) smb_getnetbiosname(nbname, sizeof (nbname));
1673b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_get_default_comp_container_dn(ah, container_dn, SMB_ADS_DN_MAX);
1674b89a8333Snatalie li - Sun Microsystems - Irvine United States 	(void) snprintf(buf, buflen, "cn=%s,%s", nbname, container_dn);
1675da6c28aaSamw }
1676da6c28aaSamw 
1677da6c28aaSamw /*
16783db3f65cSamw  * smb_ads_add_computer
1679da6c28aaSamw  *
1680da6c28aaSamw  * Returns 0 upon success. Otherwise, returns -1.
1681da6c28aaSamw  */
1682da6c28aaSamw static int
smb_ads_add_computer(smb_ads_handle_t * ah,int dclevel,char * dn)1683c8ec8eeaSjose borrego smb_ads_add_computer(smb_ads_handle_t *ah, int dclevel, char *dn)
1684da6c28aaSamw {
1685c8ec8eeaSjose borrego 	return (smb_ads_computer_op(ah, LDAP_MOD_ADD, dclevel, dn));
168655bf511dSas200622 }
168755bf511dSas200622 
168855bf511dSas200622 /*
16893db3f65cSamw  * smb_ads_modify_computer
169055bf511dSas200622  *
169155bf511dSas200622  * Returns 0 upon success. Otherwise, returns -1.
169255bf511dSas200622  */
169355bf511dSas200622 static int
smb_ads_modify_computer(smb_ads_handle_t * ah,int dclevel,char * dn)1694c8ec8eeaSjose borrego smb_ads_modify_computer(smb_ads_handle_t *ah, int dclevel, char *dn)
169555bf511dSas200622 {
1696c8ec8eeaSjose borrego 	return (smb_ads_computer_op(ah, LDAP_MOD_REPLACE, dclevel, dn));
16973db3f65cSamw }
16983db3f65cSamw 
16993db3f65cSamw /*
17003db3f65cSamw  * smb_ads_get_dc_level
17013db3f65cSamw  *
17023db3f65cSamw  * Returns the functional level of the DC upon success.
17033db3f65cSamw  * Otherwise, -1 is returned.
17043db3f65cSamw  */
17053db3f65cSamw static int
smb_ads_get_dc_level(smb_ads_handle_t * ah)17063db3f65cSamw smb_ads_get_dc_level(smb_ads_handle_t *ah)
17073db3f65cSamw {
17083db3f65cSamw 	LDAPMessage *res, *entry;
17093db3f65cSamw 	char *attr[2];
17103db3f65cSamw 	char **vals;
17113db3f65cSamw 	int rc = -1;
17123db3f65cSamw 
17133db3f65cSamw 	res = NULL;
17143db3f65cSamw 	attr[0] = SMB_ADS_ATTR_DCLEVEL;
17153db3f65cSamw 	attr[1] = NULL;
17163db3f65cSamw 	if (ldap_search_s(ah->ld, "", LDAP_SCOPE_BASE, NULL, attr,
17173db3f65cSamw 	    0, &res) != LDAP_SUCCESS) {
17183db3f65cSamw 		(void) ldap_msgfree(res);
17193db3f65cSamw 		return (-1);
17203db3f65cSamw 	}
17213db3f65cSamw 
17223db3f65cSamw 	/* no match for the specified attribute is found */
17233db3f65cSamw 	if (ldap_count_entries(ah->ld, res) == 0) {
17243db3f65cSamw 		(void) ldap_msgfree(res);
17253db3f65cSamw 		return (-1);
17263db3f65cSamw 	}
17273db3f65cSamw 
17283db3f65cSamw 	entry = ldap_first_entry(ah->ld, res);
17293db3f65cSamw 	if (entry) {
17303db3f65cSamw 		if ((vals = ldap_get_values(ah->ld, entry,
17313db3f65cSamw 		    SMB_ADS_ATTR_DCLEVEL)) == NULL) {
17323db3f65cSamw 			/*
17333db3f65cSamw 			 * Observed the values aren't populated
17343db3f65cSamw 			 * by the Windows 2000 server.
17353db3f65cSamw 			 */
17363db3f65cSamw 			(void) ldap_msgfree(res);
17373db3f65cSamw 			return (SMB_ADS_DCLEVEL_W2K);
17383db3f65cSamw 		}
17393db3f65cSamw 
17403db3f65cSamw 		if (vals[0] != NULL)
17413db3f65cSamw 			rc = atoi(vals[0]);
17423db3f65cSamw 
17433db3f65cSamw 		ldap_value_free(vals);
17443db3f65cSamw 	}
17453db3f65cSamw 
17463db3f65cSamw 	(void) ldap_msgfree(res);
17473db3f65cSamw 	return (rc);
174855bf511dSas200622 }
174955bf511dSas200622 
17509fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /*
17519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * The fully-qualified hostname returned by this function is often used for
17529fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * constructing service principal name.  Return the fully-qualified hostname
17539fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * in lower case for RFC 4120 section 6.2.1 conformance.
17549fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  */
175555bf511dSas200622 static int
smb_ads_getfqhostname(smb_ads_handle_t * ah,char * fqhost,int len)1756b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_getfqhostname(smb_ads_handle_t *ah, char *fqhost, int len)
1757b89a8333Snatalie li - Sun Microsystems - Irvine United States {
17589fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_gethostname(fqhost, len, SMB_CASE_LOWER) != 0)
1759b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (-1);
1760b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1761b89a8333Snatalie li - Sun Microsystems - Irvine United States 	(void) snprintf(fqhost, len, "%s.%s", fqhost,
1762b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    ah->domain);
1763b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1764b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (0);
1765b89a8333Snatalie li - Sun Microsystems - Irvine United States }
1766b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1767b89a8333Snatalie li - Sun Microsystems - Irvine United States static int
smb_ads_computer_op(smb_ads_handle_t * ah,int op,int dclevel,char * dn)1768c8ec8eeaSjose borrego smb_ads_computer_op(smb_ads_handle_t *ah, int op, int dclevel, char *dn)
176955bf511dSas200622 {
17703db3f65cSamw 	LDAPMod *attrs[SMB_ADS_COMPUTER_NUM_ATTR];
1771148c5f43SAlan Wright 	char *sam_val[2];
1772148c5f43SAlan Wright 	char *ctl_val[2], *fqh_val[2];
17733db3f65cSamw 	char *encrypt_val[2];
17746537f381Sas200622 	int j = -1;
1775da6c28aaSamw 	int ret, usrctl_flags = 0;
1776b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char sam_acct[SMB_SAMACCT_MAXLEN];
1777da6c28aaSamw 	char fqhost[MAXHOSTNAMELEN];
1778da6c28aaSamw 	char usrctl_buf[16];
17793db3f65cSamw 	char encrypt_buf[16];
178055bf511dSas200622 	int max;
1781148c5f43SAlan Wright 	smb_krb5_pn_set_t spn, upn;
1782da6c28aaSamw 
1783b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (smb_getsamaccount(sam_acct, sizeof (sam_acct)) != 0)
1784da6c28aaSamw 		return (-1);
1785da6c28aaSamw 
1786b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (smb_ads_getfqhostname(ah, fqhost, MAXHOSTNAMELEN))
1787b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (-1);
1788da6c28aaSamw 
1789148c5f43SAlan Wright 	/* The SPN attribute is multi-valued and must be 1 or greater */
1790148c5f43SAlan Wright 	if (smb_krb5_get_pn_set(&spn, SMB_PN_SPN_ATTR, ah->domain) == 0)
17916537f381Sas200622 		return (-1);
17926537f381Sas200622 
1793148c5f43SAlan Wright 	/* The UPN attribute is single-valued and cannot be zero */
1794148c5f43SAlan Wright 	if (smb_krb5_get_pn_set(&upn, SMB_PN_UPN_ATTR, ah->domain) != 1) {
1795148c5f43SAlan Wright 		smb_krb5_free_pn_set(&spn);
1796148c5f43SAlan Wright 		smb_krb5_free_pn_set(&upn);
1797da6c28aaSamw 		return (-1);
1798da6c28aaSamw 	}
1799da6c28aaSamw 
18003db3f65cSamw 	max = (SMB_ADS_COMPUTER_NUM_ATTR - ((op != LDAP_MOD_ADD) ? 1 : 0))
1801b1352070SAlan Wright 	    - (dclevel >= SMB_ADS_DCLEVEL_W2K8 ?  0 : 1);
18026537f381Sas200622 
18033db3f65cSamw 	if (smb_ads_alloc_attr(attrs, max) != 0) {
1804148c5f43SAlan Wright 		smb_krb5_free_pn_set(&spn);
1805148c5f43SAlan Wright 		smb_krb5_free_pn_set(&upn);
180655bf511dSas200622 		return (-1);
180755bf511dSas200622 	}
180855bf511dSas200622 
180955bf511dSas200622 	/* objectClass attribute is not modifiable. */
181055bf511dSas200622 	if (op == LDAP_MOD_ADD) {
181155bf511dSas200622 		attrs[++j]->mod_op = op;
181255bf511dSas200622 		attrs[j]->mod_type = "objectClass";
18137f667e74Sjose borrego 		attrs[j]->mod_values = smb_ads_computer_objcls;
181455bf511dSas200622 	}
1815da6c28aaSamw 
181655bf511dSas200622 	attrs[++j]->mod_op = op;
18173db3f65cSamw 	attrs[j]->mod_type = SMB_ADS_ATTR_SAMACCT;
1818da6c28aaSamw 	sam_val[0] = sam_acct;
1819da6c28aaSamw 	sam_val[1] = 0;
182055bf511dSas200622 	attrs[j]->mod_values = sam_val;
1821da6c28aaSamw 
182255bf511dSas200622 	attrs[++j]->mod_op = op;
18233db3f65cSamw 	attrs[j]->mod_type = SMB_ADS_ATTR_UPN;
1824148c5f43SAlan Wright 	attrs[j]->mod_values = upn.s_pns;
1825da6c28aaSamw 
182655bf511dSas200622 	attrs[++j]->mod_op = op;
18273db3f65cSamw 	attrs[j]->mod_type = SMB_ADS_ATTR_SPN;
1828148c5f43SAlan Wright 	attrs[j]->mod_values =  spn.s_pns;
1829da6c28aaSamw 
183055bf511dSas200622 	attrs[++j]->mod_op = op;
18313db3f65cSamw 	attrs[j]->mod_type = SMB_ADS_ATTR_CTL;
18323db3f65cSamw 	usrctl_flags |= (SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT |
18333db3f65cSamw 	    SMB_ADS_USER_ACCT_CTL_PASSWD_NOTREQD |
18343db3f65cSamw 	    SMB_ADS_USER_ACCT_CTL_ACCOUNTDISABLE);
1835da6c28aaSamw 	(void) snprintf(usrctl_buf, sizeof (usrctl_buf), "%d", usrctl_flags);
1836da6c28aaSamw 	ctl_val[0] = usrctl_buf;
1837da6c28aaSamw 	ctl_val[1] = 0;
183855bf511dSas200622 	attrs[j]->mod_values = ctl_val;
1839da6c28aaSamw 
184055bf511dSas200622 	attrs[++j]->mod_op = op;
18413db3f65cSamw 	attrs[j]->mod_type = SMB_ADS_ATTR_DNSHOST;
1842da6c28aaSamw 	fqh_val[0] = fqhost;
1843da6c28aaSamw 	fqh_val[1] = 0;
184455bf511dSas200622 	attrs[j]->mod_values = fqh_val;
1845da6c28aaSamw 
18463db3f65cSamw 	/* enctypes support starting in Windows Server 2008 */
18473db3f65cSamw 	if (dclevel > SMB_ADS_DCLEVEL_W2K3) {
18483db3f65cSamw 		attrs[++j]->mod_op = op;
18493db3f65cSamw 		attrs[j]->mod_type = SMB_ADS_ATTR_ENCTYPES;
18503db3f65cSamw 		(void) snprintf(encrypt_buf, sizeof (encrypt_buf), "%d",
18513db3f65cSamw 		    SMB_ADS_ENC_AES256 + SMB_ADS_ENC_AES128 + SMB_ADS_ENC_RC4 +
18523db3f65cSamw 		    SMB_ADS_ENC_DES_MD5 + SMB_ADS_ENC_DES_CRC);
18533db3f65cSamw 		encrypt_val[0] = encrypt_buf;
18543db3f65cSamw 		encrypt_val[1] = 0;
18553db3f65cSamw 		attrs[j]->mod_values = encrypt_val;
18563db3f65cSamw 	}
18573db3f65cSamw 
185855bf511dSas200622 	switch (op) {
185955bf511dSas200622 	case LDAP_MOD_ADD:
186055bf511dSas200622 		if ((ret = ldap_add_s(ah->ld, dn, attrs)) != LDAP_SUCCESS) {
1861fc724630SAlan Wright 			syslog(LOG_NOTICE, "ldap_add: %s",
186255bf511dSas200622 			    ldap_err2string(ret));
1863da6c28aaSamw 			ret = -1;
1864da6c28aaSamw 		}
186555bf511dSas200622 		break;
1866da6c28aaSamw 
186755bf511dSas200622 	case LDAP_MOD_REPLACE:
186855bf511dSas200622 		if ((ret = ldap_modify_s(ah->ld, dn, attrs)) != LDAP_SUCCESS) {
1869fc724630SAlan Wright 			syslog(LOG_NOTICE, "ldap_modify: %s",
187055bf511dSas200622 			    ldap_err2string(ret));
187155bf511dSas200622 			ret = -1;
187255bf511dSas200622 		}
187355bf511dSas200622 		break;
187455bf511dSas200622 
187555bf511dSas200622 	default:
187655bf511dSas200622 		ret = -1;
187755bf511dSas200622 
187855bf511dSas200622 	}
187955bf511dSas200622 
18803db3f65cSamw 	smb_ads_free_attr(attrs);
1881148c5f43SAlan Wright 	smb_krb5_free_pn_set(&spn);
1882148c5f43SAlan Wright 	smb_krb5_free_pn_set(&upn);
1883da6c28aaSamw 
1884da6c28aaSamw 	return (ret);
1885da6c28aaSamw }
1886da6c28aaSamw 
1887da6c28aaSamw /*
1888da6c28aaSamw  * Delete an ADS computer account.
1889da6c28aaSamw  */
1890da6c28aaSamw static void
smb_ads_del_computer(smb_ads_handle_t * ah,char * dn)1891c8ec8eeaSjose borrego smb_ads_del_computer(smb_ads_handle_t *ah, char *dn)
1892da6c28aaSamw {
1893da6c28aaSamw 	int rc;
1894da6c28aaSamw 
18953db3f65cSamw 	if ((rc = ldap_delete_s(ah->ld, dn)) != LDAP_SUCCESS)
1896fc724630SAlan Wright 		smb_tracef("ldap_delete: %s", ldap_err2string(rc));
1897b89a8333Snatalie li - Sun Microsystems - Irvine United States }
1898b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1899b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
1900b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Gets the value of the given attribute.
1901b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
1902b89a8333Snatalie li - Sun Microsystems - Irvine United States static smb_ads_qstat_t
smb_ads_getattr(LDAP * ld,LDAPMessage * entry,smb_ads_avpair_t * avpair)1903b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_getattr(LDAP *ld, LDAPMessage *entry, smb_ads_avpair_t *avpair)
1904b89a8333Snatalie li - Sun Microsystems - Irvine United States {
1905b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char **vals;
1906b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_qstat_t rc = SMB_ADS_STAT_FOUND;
1907b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1908b89a8333Snatalie li - Sun Microsystems - Irvine United States 	assert(avpair);
1909b89a8333Snatalie li - Sun Microsystems - Irvine United States 	avpair->avp_val = NULL;
1910b89a8333Snatalie li - Sun Microsystems - Irvine United States 	vals = ldap_get_values(ld, entry, avpair->avp_attr);
1911b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (!vals)
1912b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (SMB_ADS_STAT_NOT_FOUND);
1913b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1914b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (!vals[0]) {
1915b89a8333Snatalie li - Sun Microsystems - Irvine United States 		ldap_value_free(vals);
1916b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (SMB_ADS_STAT_NOT_FOUND);
1917b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
1918b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1919b89a8333Snatalie li - Sun Microsystems - Irvine United States 	avpair->avp_val = strdup(vals[0]);
1920b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (!avpair->avp_val)
1921b89a8333Snatalie li - Sun Microsystems - Irvine United States 		rc = SMB_ADS_STAT_ERR;
1922b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1923b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ldap_value_free(vals);
1924b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (rc);
1925b89a8333Snatalie li - Sun Microsystems - Irvine United States }
1926b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1927b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
1928b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Process query's result.
1929b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
1930b89a8333Snatalie li - Sun Microsystems - Irvine United States static smb_ads_qstat_t
smb_ads_get_qstat(smb_ads_handle_t * ah,LDAPMessage * res,smb_ads_avpair_t * avpair)1931b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_get_qstat(smb_ads_handle_t *ah, LDAPMessage *res,
1932b89a8333Snatalie li - Sun Microsystems - Irvine United States     smb_ads_avpair_t *avpair)
1933b89a8333Snatalie li - Sun Microsystems - Irvine United States {
1934b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char fqhost[MAXHOSTNAMELEN];
1935b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_avpair_t dnshost_avp;
1936b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_qstat_t rc = SMB_ADS_STAT_FOUND;
1937b89a8333Snatalie li - Sun Microsystems - Irvine United States 	LDAPMessage *entry;
1938b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1939b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (smb_ads_getfqhostname(ah, fqhost, MAXHOSTNAMELEN))
1940b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (SMB_ADS_STAT_ERR);
1941b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1942b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (ldap_count_entries(ah->ld, res) == 0)
1943b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (SMB_ADS_STAT_NOT_FOUND);
1944b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1945b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if ((entry = ldap_first_entry(ah->ld, res)) == NULL)
1946b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (SMB_ADS_STAT_ERR);
1947b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1948b89a8333Snatalie li - Sun Microsystems - Irvine United States 	dnshost_avp.avp_attr = SMB_ADS_ATTR_DNSHOST;
1949b89a8333Snatalie li - Sun Microsystems - Irvine United States 	rc = smb_ads_getattr(ah->ld, entry, &dnshost_avp);
1950b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1951b89a8333Snatalie li - Sun Microsystems - Irvine United States 	switch (rc) {
1952b89a8333Snatalie li - Sun Microsystems - Irvine United States 	case SMB_ADS_STAT_FOUND:
1953b89a8333Snatalie li - Sun Microsystems - Irvine United States 		/*
1954b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * Returns SMB_ADS_STAT_DUP to avoid overwriting
1955b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * the computer account of another system whose
1956b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * NetBIOS name collides with that of the current
1957b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * system.
1958b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 */
1959b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (strcasecmp(dnshost_avp.avp_val, fqhost))
1960b89a8333Snatalie li - Sun Microsystems - Irvine United States 			rc = SMB_ADS_STAT_DUP;
1961b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1962b89a8333Snatalie li - Sun Microsystems - Irvine United States 		free(dnshost_avp.avp_val);
1963b89a8333Snatalie li - Sun Microsystems - Irvine United States 		break;
1964b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1965b89a8333Snatalie li - Sun Microsystems - Irvine United States 	case SMB_ADS_STAT_NOT_FOUND:
1966b89a8333Snatalie li - Sun Microsystems - Irvine United States 		/*
1967b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * Pre-created computer account doesn't have
1968b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * the dNSHostname attribute. It's been observed
1969b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * that the dNSHostname attribute is only set after
1970b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * a successful domain join.
1971b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * Returns SMB_ADS_STAT_FOUND as the account is
1972b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 * pre-created for the current system.
1973b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 */
1974b89a8333Snatalie li - Sun Microsystems - Irvine United States 		rc = SMB_ADS_STAT_FOUND;
1975b89a8333Snatalie li - Sun Microsystems - Irvine United States 		break;
1976b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1977b89a8333Snatalie li - Sun Microsystems - Irvine United States 	default:
1978b89a8333Snatalie li - Sun Microsystems - Irvine United States 		break;
1979b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
1980b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1981b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (rc != SMB_ADS_STAT_FOUND)
1982b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (rc);
1983b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1984b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (avpair)
1985b89a8333Snatalie li - Sun Microsystems - Irvine United States 		rc = smb_ads_getattr(ah->ld, entry, avpair);
1986b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1987b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (rc);
1988b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1989da6c28aaSamw }
1990da6c28aaSamw 
1991da6c28aaSamw /*
19923db3f65cSamw  * smb_ads_lookup_computer_n_attr
1993da6c28aaSamw  *
1994b89a8333Snatalie li - Sun Microsystems - Irvine United States  * If avpair is NULL, checks the status of the specified computer account.
1995b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Otherwise, looks up the value of the specified computer account's attribute.
1996b89a8333Snatalie li - Sun Microsystems - Irvine United States  * If found, the value field of the avpair will be allocated and set. The
1997b89a8333Snatalie li - Sun Microsystems - Irvine United States  * caller should free the allocated buffer.
1998da6c28aaSamw  *
1999da6c28aaSamw  * Return:
2000b89a8333Snatalie li - Sun Microsystems - Irvine United States  *  SMB_ADS_STAT_FOUND  - if both the computer and the specified attribute is
2001b89a8333Snatalie li - Sun Microsystems - Irvine United States  *                        found.
2002b89a8333Snatalie li - Sun Microsystems - Irvine United States  *  SMB_ADS_STAT_NOT_FOUND - if either the computer or the specified attribute
2003b89a8333Snatalie li - Sun Microsystems - Irvine United States  *                           is not found.
2004b89a8333Snatalie li - Sun Microsystems - Irvine United States  *  SMB_ADS_STAT_DUP - if the computer account is already used by other systems
2005b89a8333Snatalie li - Sun Microsystems - Irvine United States  *                     in the AD. This could happen if the hostname of multiple
2006b89a8333Snatalie li - Sun Microsystems - Irvine United States  *                     systems resolved to the same NetBIOS name.
2007b89a8333Snatalie li - Sun Microsystems - Irvine United States  *  SMB_ADS_STAT_ERR - any failure.
2008da6c28aaSamw  */
2009b89a8333Snatalie li - Sun Microsystems - Irvine United States static smb_ads_qstat_t
smb_ads_lookup_computer_n_attr(smb_ads_handle_t * ah,smb_ads_avpair_t * avpair,int scope,char * dn)2010b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_lookup_computer_n_attr(smb_ads_handle_t *ah, smb_ads_avpair_t *avpair,
2011c8ec8eeaSjose borrego     int scope, char *dn)
2012da6c28aaSamw {
2013b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *attrs[3], filter[SMB_ADS_MAXBUFLEN];
2014b89a8333Snatalie li - Sun Microsystems - Irvine United States 	LDAPMessage *res;
2015b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char sam_acct[SMB_SAMACCT_MAXLEN], sam_acct2[SMB_SAMACCT_MAXLEN];
2016b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_qstat_t rc;
2017da6c28aaSamw 
2018b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (smb_getsamaccount(sam_acct, sizeof (sam_acct)) != 0)
2019b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (SMB_ADS_STAT_ERR);
2020da6c28aaSamw 
2021da6c28aaSamw 	res = NULL;
2022b89a8333Snatalie li - Sun Microsystems - Irvine United States 	attrs[0] = SMB_ADS_ATTR_DNSHOST;
2023da6c28aaSamw 	attrs[1] = NULL;
2024b89a8333Snatalie li - Sun Microsystems - Irvine United States 	attrs[2] = NULL;
2025da6c28aaSamw 
2026b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (avpair) {
2027b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (!avpair->avp_attr)
2028b89a8333Snatalie li - Sun Microsystems - Irvine United States 			return (SMB_ADS_STAT_ERR);
2029b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2030b89a8333Snatalie li - Sun Microsystems - Irvine United States 		attrs[1] = avpair->avp_attr;
2031b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
2032b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2033b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (smb_ads_escape_search_filter_chars(sam_acct, sam_acct2) != 0)
2034b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (SMB_ADS_STAT_ERR);
2035da6c28aaSamw 
2036c8ec8eeaSjose borrego 	(void) snprintf(filter, sizeof (filter),
2037b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    "(&(objectClass=computer)(%s=%s))", SMB_ADS_ATTR_SAMACCT,
2038b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    sam_acct2);
2039da6c28aaSamw 
2040c8ec8eeaSjose borrego 	if (ldap_search_s(ah->ld, dn, scope, filter, attrs, 0,
2041da6c28aaSamw 	    &res) != LDAP_SUCCESS) {
2042da6c28aaSamw 		(void) ldap_msgfree(res);
2043b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (SMB_ADS_STAT_NOT_FOUND);
2044da6c28aaSamw 	}
2045da6c28aaSamw 
2046b89a8333Snatalie li - Sun Microsystems - Irvine United States 	rc = smb_ads_get_qstat(ah, res, avpair);
2047da6c28aaSamw 	/* free the search results */
2048da6c28aaSamw 	(void) ldap_msgfree(res);
2049b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (rc);
2050da6c28aaSamw }
2051da6c28aaSamw 
2052da6c28aaSamw /*
20533db3f65cSamw  * smb_ads_find_computer
2054da6c28aaSamw  *
2055c8ec8eeaSjose borrego  * Starts by searching for the system's AD computer object in the default
2056c8ec8eeaSjose borrego  * container (i.e. cn=Computers).  If not found, searches the entire directory.
2057b89a8333Snatalie li - Sun Microsystems - Irvine United States  * If found, 'dn' will be set to the distinguished name of the system's AD
2058b89a8333Snatalie li - Sun Microsystems - Irvine United States  * computer object.
2059da6c28aaSamw  */
2060b89a8333Snatalie li - Sun Microsystems - Irvine United States static smb_ads_qstat_t
smb_ads_find_computer(smb_ads_handle_t * ah,char * dn)2061c8ec8eeaSjose borrego smb_ads_find_computer(smb_ads_handle_t *ah, char *dn)
2062da6c28aaSamw {
2063b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_qstat_t stat;
2064b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_avpair_t avpair;
2065c8ec8eeaSjose borrego 
2066b89a8333Snatalie li - Sun Microsystems - Irvine United States 	avpair.avp_attr = SMB_ADS_ATTR_DN;
2067b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_get_default_comp_container_dn(ah, dn, SMB_ADS_DN_MAX);
2068b89a8333Snatalie li - Sun Microsystems - Irvine United States 	stat = smb_ads_lookup_computer_n_attr(ah, &avpair, LDAP_SCOPE_ONELEVEL,
2069b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    dn);
2070c8ec8eeaSjose borrego 
2071b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (stat == SMB_ADS_STAT_NOT_FOUND) {
2072c8ec8eeaSjose borrego 		(void) strlcpy(dn, ah->domain_dn, SMB_ADS_DN_MAX);
2073b89a8333Snatalie li - Sun Microsystems - Irvine United States 		stat = smb_ads_lookup_computer_n_attr(ah, &avpair,
2074b89a8333Snatalie li - Sun Microsystems - Irvine United States 		    LDAP_SCOPE_SUBTREE, dn);
2075c8ec8eeaSjose borrego 	}
2076c8ec8eeaSjose borrego 
2077b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (stat == SMB_ADS_STAT_FOUND) {
2078b89a8333Snatalie li - Sun Microsystems - Irvine United States 		(void) strlcpy(dn, avpair.avp_val, SMB_ADS_DN_MAX);
2079b89a8333Snatalie li - Sun Microsystems - Irvine United States 		free(avpair.avp_val);
2080b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
2081b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2082b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (stat);
2083da6c28aaSamw }
2084da6c28aaSamw 
2085da6c28aaSamw /*
20863db3f65cSamw  * smb_ads_update_computer_cntrl_attr
2087da6c28aaSamw  *
2088da6c28aaSamw  * Modify the user account control attribute of an existing computer
2089da6c28aaSamw  * object on AD.
2090da6c28aaSamw  *
20917f667e74Sjose borrego  * Returns LDAP error code.
2092da6c28aaSamw  */
2093da6c28aaSamw static int
smb_ads_update_computer_cntrl_attr(smb_ads_handle_t * ah,int flags,char * dn)20947f667e74Sjose borrego smb_ads_update_computer_cntrl_attr(smb_ads_handle_t *ah, int flags, char *dn)
2095da6c28aaSamw {
20966537f381Sas200622 	LDAPMod *attrs[2];
2097da6c28aaSamw 	char *ctl_val[2];
20987f667e74Sjose borrego 	int ret = 0;
2099da6c28aaSamw 	char usrctl_buf[16];
2100da6c28aaSamw 
21013db3f65cSamw 	if (smb_ads_alloc_attr(attrs, sizeof (attrs) / sizeof (LDAPMod *)) != 0)
21027f667e74Sjose borrego 		return (LDAP_NO_MEMORY);
21036537f381Sas200622 
21046537f381Sas200622 	attrs[0]->mod_op = LDAP_MOD_REPLACE;
21053db3f65cSamw 	attrs[0]->mod_type = SMB_ADS_ATTR_CTL;
2106da6c28aaSamw 
21077f667e74Sjose borrego 	(void) snprintf(usrctl_buf, sizeof (usrctl_buf), "%d", flags);
2108da6c28aaSamw 	ctl_val[0] = usrctl_buf;
2109da6c28aaSamw 	ctl_val[1] = 0;
21106537f381Sas200622 	attrs[0]->mod_values = ctl_val;
2111da6c28aaSamw 	if ((ret = ldap_modify_s(ah->ld, dn, attrs)) != LDAP_SUCCESS) {
2112fc724630SAlan Wright 		syslog(LOG_NOTICE, "ldap_modify: %s", ldap_err2string(ret));
2113da6c28aaSamw 	}
2114da6c28aaSamw 
21153db3f65cSamw 	smb_ads_free_attr(attrs);
2116da6c28aaSamw 	return (ret);
2117da6c28aaSamw }
2118da6c28aaSamw 
2119da6c28aaSamw /*
21203db3f65cSamw  * smb_ads_lookup_computer_attr_kvno
2121da6c28aaSamw  *
2122da6c28aaSamw  * Lookup the value of the Kerberos version number attribute of the computer
2123da6c28aaSamw  * account.
2124da6c28aaSamw  */
2125da6c28aaSamw static krb5_kvno
smb_ads_lookup_computer_attr_kvno(smb_ads_handle_t * ah,char * dn)2126c8ec8eeaSjose borrego smb_ads_lookup_computer_attr_kvno(smb_ads_handle_t *ah, char *dn)
2127da6c28aaSamw {
2128b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_avpair_t avpair;
2129da6c28aaSamw 	int kvno = 1;
2130da6c28aaSamw 
2131b89a8333Snatalie li - Sun Microsystems - Irvine United States 	avpair.avp_attr = SMB_ADS_ATTR_KVNO;
2132b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (smb_ads_lookup_computer_n_attr(ah, &avpair,
2133b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    LDAP_SCOPE_BASE, dn) == SMB_ADS_STAT_FOUND) {
2134b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kvno = atoi(avpair.avp_val);
2135b89a8333Snatalie li - Sun Microsystems - Irvine United States 		free(avpair.avp_val);
2136da6c28aaSamw 	}
2137da6c28aaSamw 
2138da6c28aaSamw 	return (kvno);
2139da6c28aaSamw }
2140da6c28aaSamw 
2141da6c28aaSamw /*
21423db3f65cSamw  * smb_ads_join
2143da6c28aaSamw  *
2144da6c28aaSamw  * Besides the NT-4 style domain join (using MS-RPC), CIFS server also
2145da6c28aaSamw  * provides the domain join using Kerberos Authentication, Keberos
214655bf511dSas200622  * Change & Set password, and LDAP protocols. Basically, AD join
2147da6c28aaSamw  * operation would require the following tickets to be acquired for the
2148da6c28aaSamw  * the user account that is provided for the domain join.
2149da6c28aaSamw  *
2150da6c28aaSamw  * 1) a Keberos TGT ticket,
2151da6c28aaSamw  * 2) a ldap service ticket, and
2152da6c28aaSamw  * 3) kadmin/changpw service ticket
2153da6c28aaSamw  *
2154da6c28aaSamw  * The ADS client first sends a ldap search request to find out whether
2155da6c28aaSamw  * or not the workstation trust account already exists in the Active Directory.
2156da6c28aaSamw  * The existing computer object for this workstation will be removed and
2157da6c28aaSamw  * a new one will be added. The machine account password is randomly
21583db3f65cSamw  * generated and set for the newly created computer object using KPASSWD
2159da6c28aaSamw  * protocol (See RFC 3244). Once the password is set, our ADS client
2160da6c28aaSamw  * finalizes the machine account by modifying the user acount control
2161da6c28aaSamw  * attribute of the computer object. Kerberos keys derived from the machine
2162da6c28aaSamw  * account password will be stored locally in /etc/krb5/krb5.keytab file.
2163da6c28aaSamw  * That would be needed while acquiring Kerberos TGT ticket for the host
2164da6c28aaSamw  * principal after the domain join operation.
2165da6c28aaSamw  */
21663db3f65cSamw smb_adjoin_status_t
smb_ads_join(char * domain,char * user,char * usr_passwd,char * machine_passwd)21671ed6b69aSGordon Ross smb_ads_join(char *domain, char *user, char *usr_passwd, char *machine_passwd)
2168da6c28aaSamw {
21693db3f65cSamw 	smb_ads_handle_t *ah = NULL;
2170da6c28aaSamw 	krb5_context ctx = NULL;
2171148c5f43SAlan Wright 	krb5_principal *krb5princs = NULL;
2172da6c28aaSamw 	krb5_kvno kvno;
2173cbfb650aScp160787 	boolean_t des_only, delete = B_TRUE;
21743db3f65cSamw 	smb_adjoin_status_t rc = SMB_ADJOIN_SUCCESS;
217555bf511dSas200622 	boolean_t new_acct;
21767f667e74Sjose borrego 	int dclevel, num, usrctl_flags = 0;
2177b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_qstat_t qstat;
2178c8ec8eeaSjose borrego 	char dn[SMB_ADS_DN_MAX];
2179c28afb19SYuri Pankov 	char tmpfile[] = SMBNS_KRB5_KEYTAB_TMP;
2180148c5f43SAlan Wright 	int cnt;
2181148c5f43SAlan Wright 	smb_krb5_pn_set_t spns;
21823db3f65cSamw 
21833db3f65cSamw 	krb5_enctype *encptr;
21843db3f65cSamw 
21853db3f65cSamw 	if ((ah = smb_ads_open_main(domain, user, usr_passwd)) == NULL) {
2186faa1795aSjb150015 		smb_ccache_remove(SMB_CCACHE_PATH);
21873db3f65cSamw 		return (SMB_ADJOIN_ERR_GET_HANDLE);
218855bf511dSas200622 	}
218955bf511dSas200622 
21903db3f65cSamw 	if ((dclevel = smb_ads_get_dc_level(ah)) == -1) {
21913db3f65cSamw 		smb_ads_close(ah);
21923db3f65cSamw 		smb_ccache_remove(SMB_CCACHE_PATH);
21933db3f65cSamw 		return (SMB_ADJOIN_ERR_GET_DCLEVEL);
21943db3f65cSamw 	}
21953db3f65cSamw 
2196b89a8333Snatalie li - Sun Microsystems - Irvine United States 	qstat = smb_ads_find_computer(ah, dn);
2197b89a8333Snatalie li - Sun Microsystems - Irvine United States 	switch (qstat) {
2198b89a8333Snatalie li - Sun Microsystems - Irvine United States 	case SMB_ADS_STAT_FOUND:
219955bf511dSas200622 		new_acct = B_FALSE;
2200c8ec8eeaSjose borrego 		if (smb_ads_modify_computer(ah, dclevel, dn) != 0) {
22013db3f65cSamw 			smb_ads_close(ah);
2202faa1795aSjb150015 			smb_ccache_remove(SMB_CCACHE_PATH);
22033db3f65cSamw 			return (SMB_ADJOIN_ERR_MOD_TRUST_ACCT);
220455bf511dSas200622 		}
2205b89a8333Snatalie li - Sun Microsystems - Irvine United States 		break;
2206b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2207b89a8333Snatalie li - Sun Microsystems - Irvine United States 	case SMB_ADS_STAT_NOT_FOUND:
220855bf511dSas200622 		new_acct = B_TRUE;
2209b89a8333Snatalie li - Sun Microsystems - Irvine United States 		smb_ads_get_default_comp_dn(ah, dn, SMB_ADS_DN_MAX);
2210c8ec8eeaSjose borrego 		if (smb_ads_add_computer(ah, dclevel, dn) != 0) {
22113db3f65cSamw 			smb_ads_close(ah);
2212faa1795aSjb150015 			smb_ccache_remove(SMB_CCACHE_PATH);
22133db3f65cSamw 			return (SMB_ADJOIN_ERR_ADD_TRUST_ACCT);
221455bf511dSas200622 		}
2215b89a8333Snatalie li - Sun Microsystems - Irvine United States 		break;
2216b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2217b89a8333Snatalie li - Sun Microsystems - Irvine United States 	default:
2218b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (qstat == SMB_ADS_STAT_DUP)
2219b89a8333Snatalie li - Sun Microsystems - Irvine United States 			rc = SMB_ADJOIN_ERR_DUP_TRUST_ACCT;
2220b89a8333Snatalie li - Sun Microsystems - Irvine United States 		else
2221b89a8333Snatalie li - Sun Microsystems - Irvine United States 			rc = SMB_ADJOIN_ERR_TRUST_ACCT;
2222b89a8333Snatalie li - Sun Microsystems - Irvine United States 		smb_ads_close(ah);
2223b89a8333Snatalie li - Sun Microsystems - Irvine United States 		smb_ccache_remove(SMB_CCACHE_PATH);
2224b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (rc);
222555bf511dSas200622 	}
222655bf511dSas200622 
222755bf511dSas200622 	des_only = B_FALSE;
2228da6c28aaSamw 
2229da6c28aaSamw 	if (smb_krb5_ctx_init(&ctx) != 0) {
22303db3f65cSamw 		rc = SMB_ADJOIN_ERR_INIT_KRB_CTX;
2231da6c28aaSamw 		goto adjoin_cleanup;
2232da6c28aaSamw 	}
2233da6c28aaSamw 
2234148c5f43SAlan Wright 	if (smb_krb5_get_pn_set(&spns, SMB_PN_KEYTAB_ENTRY, ah->domain) == 0) {
22353db3f65cSamw 		rc = SMB_ADJOIN_ERR_GET_SPNS;
2236da6c28aaSamw 		goto adjoin_cleanup;
2237da6c28aaSamw 	}
2238da6c28aaSamw 
2239148c5f43SAlan Wright 	if (smb_krb5_get_kprincs(ctx, spns.s_pns, spns.s_cnt, &krb5princs)
2240148c5f43SAlan Wright 	    != 0) {
2241148c5f43SAlan Wright 		smb_krb5_free_pn_set(&spns);
2242148c5f43SAlan Wright 		rc = SMB_ADJOIN_ERR_GET_SPNS;
2243148c5f43SAlan Wright 		goto adjoin_cleanup;
2244148c5f43SAlan Wright 	}
2245148c5f43SAlan Wright 
2246148c5f43SAlan Wright 	cnt = spns.s_cnt;
2247148c5f43SAlan Wright 	smb_krb5_free_pn_set(&spns);
2248148c5f43SAlan Wright 
22491ed6b69aSGordon Ross 	/* New machine_passwd was filled in by our caller. */
2250148c5f43SAlan Wright 	if (smb_krb5_setpwd(ctx, ah->domain, machine_passwd) != 0) {
22513db3f65cSamw 		rc = SMB_ADJOIN_ERR_KSETPWD;
2252da6c28aaSamw 		goto adjoin_cleanup;
2253da6c28aaSamw 	}
2254da6c28aaSamw 
2255c8ec8eeaSjose borrego 	kvno = smb_ads_lookup_computer_attr_kvno(ah, dn);
225655bf511dSas200622 
22577f667e74Sjose borrego 	/*
22587f667e74Sjose borrego 	 * Only members of Domain Admins and Enterprise Admins can set
22597f667e74Sjose borrego 	 * the TRUSTED_FOR_DELEGATION userAccountControl flag.
22607f667e74Sjose borrego 	 */
22617f667e74Sjose borrego 	if (smb_ads_update_computer_cntrl_attr(ah,
2262037cac00Sjoyce mcintosh 	    SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT |
22637f667e74Sjose borrego 	    SMB_ADS_USER_ACCT_CTL_TRUSTED_FOR_DELEGATION, dn)
22647f667e74Sjose borrego 	    == LDAP_INSUFFICIENT_ACCESS) {
22657f667e74Sjose borrego 		usrctl_flags |= (SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT |
22667f667e74Sjose borrego 		    SMB_ADS_USER_ACCT_CTL_DONT_EXPIRE_PASSWD);
22677f667e74Sjose borrego 
2268fc724630SAlan Wright 		syslog(LOG_NOTICE, "Unable to set the "
22697f667e74Sjose borrego 		    "TRUSTED_FOR_DELEGATION userAccountControl flag on "
22707f667e74Sjose borrego 		    "the machine account in Active Directory.  Please refer "
22717f667e74Sjose borrego 		    "to the Troubleshooting guide for more information.");
22727f667e74Sjose borrego 
22737f667e74Sjose borrego 	} else {
22747f667e74Sjose borrego 		usrctl_flags |= (SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT |
22757f667e74Sjose borrego 		    SMB_ADS_USER_ACCT_CTL_TRUSTED_FOR_DELEGATION |
22767f667e74Sjose borrego 		    SMB_ADS_USER_ACCT_CTL_DONT_EXPIRE_PASSWD);
22777f667e74Sjose borrego 	}
22787f667e74Sjose borrego 
22797f667e74Sjose borrego 	if (des_only)
22807f667e74Sjose borrego 		usrctl_flags |= SMB_ADS_USER_ACCT_CTL_USE_DES_KEY_ONLY;
22817f667e74Sjose borrego 
22827f667e74Sjose borrego 	if (smb_ads_update_computer_cntrl_attr(ah, usrctl_flags, dn)
2283c8ec8eeaSjose borrego 	    != 0) {
22843db3f65cSamw 		rc = SMB_ADJOIN_ERR_UPDATE_CNTRL_ATTR;
2285da6c28aaSamw 		goto adjoin_cleanup;
2286da6c28aaSamw 	}
228755bf511dSas200622 
2288c28afb19SYuri Pankov 	if (mktemp(tmpfile) == NULL) {
2289c28afb19SYuri Pankov 		rc = SMB_ADJOIN_ERR_WRITE_KEYTAB;
2290c28afb19SYuri Pankov 		goto adjoin_cleanup;
2291c28afb19SYuri Pankov 	}
22928d7e4166Sjose borrego 
2293148c5f43SAlan Wright 	encptr = smb_ads_get_enctypes(dclevel, &num);
2294148c5f43SAlan Wright 	if (smb_krb5_kt_populate(ctx, ah->domain, krb5princs, cnt,
2295148c5f43SAlan Wright 	    tmpfile, kvno, machine_passwd, encptr, num) != 0) {
22963db3f65cSamw 		rc = SMB_ADJOIN_ERR_WRITE_KEYTAB;
2297da6c28aaSamw 		goto adjoin_cleanup;
2298da6c28aaSamw 	}
2299da6c28aaSamw 
230055bf511dSas200622 	delete = B_FALSE;
2301da6c28aaSamw adjoin_cleanup:
230255bf511dSas200622 	if (new_acct && delete)
2303c8ec8eeaSjose borrego 		smb_ads_del_computer(ah, dn);
2304da6c28aaSamw 
23053db3f65cSamw 	if (rc != SMB_ADJOIN_ERR_INIT_KRB_CTX) {
23063db3f65cSamw 		if (rc != SMB_ADJOIN_ERR_GET_SPNS)
2307148c5f43SAlan Wright 			smb_krb5_free_kprincs(ctx, krb5princs, cnt);
2308da6c28aaSamw 		smb_krb5_ctx_fini(ctx);
2309cbfb650aScp160787 	}
2310da6c28aaSamw 
23118d7e4166Sjose borrego 	/* commit keytab file */
23128d7e4166Sjose borrego 	if (rc == SMB_ADJOIN_SUCCESS) {
23138d7e4166Sjose borrego 		if (rename(tmpfile, SMBNS_KRB5_KEYTAB) != 0) {
23148d7e4166Sjose borrego 			(void) unlink(tmpfile);
23158d7e4166Sjose borrego 			rc = SMB_ADJOIN_ERR_COMMIT_KEYTAB;
23168d7e4166Sjose borrego 		}
23178d7e4166Sjose borrego 	} else {
23188d7e4166Sjose borrego 		(void) unlink(tmpfile);
23198d7e4166Sjose borrego 	}
23208d7e4166Sjose borrego 
23213db3f65cSamw 	smb_ads_close(ah);
2322faa1795aSjb150015 	smb_ccache_remove(SMB_CCACHE_PATH);
2323da6c28aaSamw 	return (rc);
2324da6c28aaSamw }
2325da6c28aaSamw 
2326da6c28aaSamw /*
2327fc724630SAlan Wright  * smb_ads_join_errmsg
2328da6c28aaSamw  *
2329da6c28aaSamw  * Display error message for the specific adjoin error code.
2330da6c28aaSamw  */
2331fc724630SAlan Wright void
smb_ads_join_errmsg(smb_adjoin_status_t status)2332fc724630SAlan Wright smb_ads_join_errmsg(smb_adjoin_status_t status)
2333da6c28aaSamw {
2334fc724630SAlan Wright 	int i;
2335fc724630SAlan Wright 	struct xlate_table {
2336fc724630SAlan Wright 		smb_adjoin_status_t status;
2337fc724630SAlan Wright 		char *msg;
2338fc724630SAlan Wright 	} adjoin_table[] = {
2339fc724630SAlan Wright 		{ SMB_ADJOIN_ERR_GET_HANDLE, "Failed to connect to an "
2340fc724630SAlan Wright 		    "Active Directory server." },
234177191e87SShawn Emery 		{ SMB_ADJOIN_ERR_GEN_PWD, "Failed to generate machine "
234277191e87SShawn Emery 		    "password." },
2343fc724630SAlan Wright 		{ SMB_ADJOIN_ERR_GET_DCLEVEL, "Unknown functional level of "
2344fc724630SAlan Wright 		    "the domain controller. The rootDSE attribute named "
2345fc724630SAlan Wright 		    "\"domainControllerFunctionality\" is missing from the "
2346fc724630SAlan Wright 		    "Active Directory." },
2347fc724630SAlan Wright 		{ SMB_ADJOIN_ERR_ADD_TRUST_ACCT, "Failed to create the "
2348fc724630SAlan Wright 		    "workstation trust account." },
2349fc724630SAlan Wright 		{ SMB_ADJOIN_ERR_MOD_TRUST_ACCT, "Failed to modify the "
2350fc724630SAlan Wright 		    "workstation trust account." },
2351fc724630SAlan Wright 		{ SMB_ADJOIN_ERR_DUP_TRUST_ACCT, "Failed to create the "
2352fc724630SAlan Wright 		    "workstation trust account because its name is already "
2353fc724630SAlan Wright 		    "in use." },
2354fc724630SAlan Wright 		{ SMB_ADJOIN_ERR_TRUST_ACCT, "Error in querying the "
2355fc724630SAlan Wright 		    "workstation trust account" },
2356fc724630SAlan Wright 		{ SMB_ADJOIN_ERR_INIT_KRB_CTX, "Failed to initialize Kerberos "
2357fc724630SAlan Wright 		    "context." },
2358fc724630SAlan Wright 		{ SMB_ADJOIN_ERR_GET_SPNS, "Failed to get Kerberos "
2359fc724630SAlan Wright 		    "principals." },
2360fc724630SAlan Wright 		{ SMB_ADJOIN_ERR_KSETPWD, "Failed to set machine password." },
2361fc724630SAlan Wright 		{ SMB_ADJOIN_ERR_UPDATE_CNTRL_ATTR,  "Failed to modify "
2362fc724630SAlan Wright 		    "userAccountControl attribute of the workstation trust "
2363fc724630SAlan Wright 		    "account." },
2364fc724630SAlan Wright 		{ SMB_ADJOIN_ERR_WRITE_KEYTAB, "Error in writing to local "
2365fc724630SAlan Wright 		    "keytab file (i.e /etc/krb5/krb5.keytab)." },
2366fc724630SAlan Wright 		{ SMB_ADJOIN_ERR_IDMAP_SET_DOMAIN, "Failed to update idmap "
2367fc724630SAlan Wright 		    "configuration." },
2368fc724630SAlan Wright 		{ SMB_ADJOIN_ERR_IDMAP_REFRESH, "Failed to refresh idmap "
2369fc724630SAlan Wright 		    "service." },
2370fc724630SAlan Wright 		{ SMB_ADJOIN_ERR_COMMIT_KEYTAB, "Failed to commit changes to "
2371fc724630SAlan Wright 		    "local keytab file (i.e. /etc/krb5/krb5.keytab)." }
2372fc724630SAlan Wright 	};
2373da6c28aaSamw 
2374fc724630SAlan Wright 	for (i = 0; i < sizeof (adjoin_table) / sizeof (adjoin_table[0]); i++) {
2375fc724630SAlan Wright 		if (adjoin_table[i].status == status)
2376fc724630SAlan Wright 			syslog(LOG_NOTICE, "%s", adjoin_table[i].msg);
2377fc724630SAlan Wright 	}
2378da6c28aaSamw }
2379c8ec8eeaSjose borrego 
2380c8ec8eeaSjose borrego /*
238129bd2886SAlan Wright  * smb_ads_match_pdc
2382b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
238329bd2886SAlan Wright  * Returns B_TRUE if the given host's IP address matches the preferred DC's
238429bd2886SAlan Wright  * IP address. Otherwise, returns B_FALSE.
2385b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
238629bd2886SAlan Wright static boolean_t
smb_ads_match_pdc(smb_ads_host_info_t * host)238729bd2886SAlan Wright smb_ads_match_pdc(smb_ads_host_info_t *host)
2388b89a8333Snatalie li - Sun Microsystems - Irvine United States {
238929bd2886SAlan Wright 	boolean_t match = B_FALSE;
2390b89a8333Snatalie li - Sun Microsystems - Irvine United States 
239129bd2886SAlan Wright 	if (!host)
239229bd2886SAlan Wright 		return (match);
2393b89a8333Snatalie li - Sun Microsystems - Irvine United States 
239429bd2886SAlan Wright 	(void) mutex_lock(&smb_ads_cfg.c_mtx);
239529bd2886SAlan Wright 	if (smb_inet_equal(&host->ipaddr, &smb_ads_cfg.c_pdc))
239629bd2886SAlan Wright 		match = B_TRUE;
239729bd2886SAlan Wright 	(void) mutex_unlock(&smb_ads_cfg.c_mtx);
2398b89a8333Snatalie li - Sun Microsystems - Irvine United States 
239929bd2886SAlan Wright 	return (match);
2400b89a8333Snatalie li - Sun Microsystems - Irvine United States }
2401b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2402b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
2403b89a8333Snatalie li - Sun Microsystems - Irvine United States  * smb_ads_select_dcfromsubnet
2404b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
2405b89a8333Snatalie li - Sun Microsystems - Irvine United States  * This method walks the list of DCs and returns the first DC record that
2406b89a8333Snatalie li - Sun Microsystems - Irvine United States  * responds to ldap ping and is in the same subnet as the host.
2407b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
2408b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Returns a pointer to the found DC record.
2409b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Returns NULL, on error or if no DC record is found.
2410b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
2411b89a8333Snatalie li - Sun Microsystems - Irvine United States static smb_ads_host_info_t *
smb_ads_select_dcfromsubnet(smb_ads_host_list_t * hlist)2412b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_select_dcfromsubnet(smb_ads_host_list_t *hlist)
2413b89a8333Snatalie li - Sun Microsystems - Irvine United States {
2414b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_host_info_t *hentry;
2415b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_nic_t *lnic;
2416b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_niciter_t ni;
2417b89a8333Snatalie li - Sun Microsystems - Irvine United States 	size_t cnt;
2418b89a8333Snatalie li - Sun Microsystems - Irvine United States 	int i;
2419b89a8333Snatalie li - Sun Microsystems - Irvine United States 
24209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_nic_getfirst(&ni) != SMB_NIC_SUCCESS)
2421b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (NULL);
2422b89a8333Snatalie li - Sun Microsystems - Irvine United States 	do {
2423b89a8333Snatalie li - Sun Microsystems - Irvine United States 		lnic = &ni.ni_nic;
2424b89a8333Snatalie li - Sun Microsystems - Irvine United States 		cnt = hlist->ah_cnt;
2425b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2426b89a8333Snatalie li - Sun Microsystems - Irvine United States 		for (i = 0; i < cnt; i++) {
2427b89a8333Snatalie li - Sun Microsystems - Irvine United States 			hentry = &hlist->ah_list[i];
24287f667e74Sjose borrego 			if ((hentry->ipaddr.a_family == AF_INET) &&
24297f667e74Sjose borrego 			    (lnic->nic_ip.a_family == AF_INET)) {
24307f667e74Sjose borrego 				if ((hentry->ipaddr.a_ipv4 &
24317f667e74Sjose borrego 				    lnic->nic_mask) ==
24327f667e74Sjose borrego 				    (lnic->nic_ip.a_ipv4 &
24337f667e74Sjose borrego 				    lnic->nic_mask))
2434b89a8333Snatalie li - Sun Microsystems - Irvine United States 					if (smb_ads_ldap_ping(hentry) == 0)
2435b89a8333Snatalie li - Sun Microsystems - Irvine United States 						return (hentry);
2436b89a8333Snatalie li - Sun Microsystems - Irvine United States 			}
24377f667e74Sjose borrego 		}
24389fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	} while (smb_nic_getnext(&ni) == SMB_NIC_SUCCESS);
2439b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2440b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (NULL);
2441b89a8333Snatalie li - Sun Microsystems - Irvine United States }
2442b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2443b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
2444b89a8333Snatalie li - Sun Microsystems - Irvine United States  * smb_ads_select_dcfromlist
2445b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
2446b89a8333Snatalie li - Sun Microsystems - Irvine United States  * This method walks the list of DCs and returns the first DC that
2447b89a8333Snatalie li - Sun Microsystems - Irvine United States  * responds to ldap ping.
2448b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
2449b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Returns a pointer to the found DC record.
2450b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Returns NULL if no DC record is found.
2451b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
2452b89a8333Snatalie li - Sun Microsystems - Irvine United States static smb_ads_host_info_t *
smb_ads_select_dcfromlist(smb_ads_host_list_t * hlist)2453b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_select_dcfromlist(smb_ads_host_list_t *hlist)
2454b89a8333Snatalie li - Sun Microsystems - Irvine United States {
2455b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_host_info_t *hentry;
2456b89a8333Snatalie li - Sun Microsystems - Irvine United States 	size_t cnt;
2457b89a8333Snatalie li - Sun Microsystems - Irvine United States 	int i;
2458b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2459b89a8333Snatalie li - Sun Microsystems - Irvine United States 	cnt = hlist->ah_cnt;
2460b89a8333Snatalie li - Sun Microsystems - Irvine United States 	for (i = 0; i < cnt; i++) {
2461b89a8333Snatalie li - Sun Microsystems - Irvine United States 		hentry = &hlist->ah_list[i];
2462b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (smb_ads_ldap_ping(hentry) == 0)
2463b89a8333Snatalie li - Sun Microsystems - Irvine United States 			return (hentry);
2464b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
2465b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2466b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (NULL);
2467b89a8333Snatalie li - Sun Microsystems - Irvine United States }
2468b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2469b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
2470c8ec8eeaSjose borrego  * smb_ads_dc_compare
2471c8ec8eeaSjose borrego  *
2472c8ec8eeaSjose borrego  * Comparision function for sorting host entries (SRV records of DC) via qsort.
2473b89a8333Snatalie li - Sun Microsystems - Irvine United States  * RFC 2052/2782 are taken as reference, while implementing this algorithm.
2474b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
2475b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Domain Controllers(DCs) with lowest priority in their SRV DNS records
2476b89a8333Snatalie li - Sun Microsystems - Irvine United States  * are selected first. If they have equal priorities, then DC with highest
2477b89a8333Snatalie li - Sun Microsystems - Irvine United States  * weight in its SRV DNS record is selected. If the priority and weight are
2478b89a8333Snatalie li - Sun Microsystems - Irvine United States  * both equal, then the DC at the top of the list is selected.
2479c8ec8eeaSjose borrego  */
2480c8ec8eeaSjose borrego static int
smb_ads_dc_compare(const void * p,const void * q)2481c8ec8eeaSjose borrego smb_ads_dc_compare(const void *p, const void *q)
2482c8ec8eeaSjose borrego {
2483c8ec8eeaSjose borrego 	smb_ads_host_info_t *h1 = (smb_ads_host_info_t *)p;
2484c8ec8eeaSjose borrego 	smb_ads_host_info_t *h2 = (smb_ads_host_info_t *)q;
2485c8ec8eeaSjose borrego 
2486c8ec8eeaSjose borrego 	if (h1->priority < h2->priority)
2487c8ec8eeaSjose borrego 		return (-1);
2488c8ec8eeaSjose borrego 	if (h1->priority > h2->priority)
2489c8ec8eeaSjose borrego 		return (1);
2490c8ec8eeaSjose borrego 
2491c8ec8eeaSjose borrego 	/* Priorities are equal */
2492c8ec8eeaSjose borrego 	if (h1->weight < h2->weight)
2493c8ec8eeaSjose borrego 		return (1);
2494c8ec8eeaSjose borrego 	if (h1->weight > h2->weight)
2495c8ec8eeaSjose borrego 		return (-1);
2496c8ec8eeaSjose borrego 
2497c8ec8eeaSjose borrego 	return (0);
2498c8ec8eeaSjose borrego }
2499c8ec8eeaSjose borrego 
2500c8ec8eeaSjose borrego /*
2501c8ec8eeaSjose borrego  * smb_ads_select_dc
2502c8ec8eeaSjose borrego  *
2503b89a8333Snatalie li - Sun Microsystems - Irvine United States  * The list of ADS hosts returned by ADS lookup, is sorted by lowest priority
2504b89a8333Snatalie li - Sun Microsystems - Irvine United States  * and highest weight. On this sorted list, following additional rules are
2505b89a8333Snatalie li - Sun Microsystems - Irvine United States  * applied, to select a DC.
2506c8ec8eeaSjose borrego  *
2507b89a8333Snatalie li - Sun Microsystems - Irvine United States  *  - If there is a DC in the same subnet, then return the DC,
2508b89a8333Snatalie li - Sun Microsystems - Irvine United States  *    if it responds to ldap ping.
2509b89a8333Snatalie li - Sun Microsystems - Irvine United States  *  - Else, return first DC that responds to ldap ping.
2510b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
2511b89a8333Snatalie li - Sun Microsystems - Irvine United States  * A reference to the host entry from input host list is returned.
2512c8ec8eeaSjose borrego  *
2513c8ec8eeaSjose borrego  * Returns NULL on error.
2514c8ec8eeaSjose borrego  */
2515c8ec8eeaSjose borrego static smb_ads_host_info_t *
smb_ads_select_dc(smb_ads_host_list_t * hlist)2516c8ec8eeaSjose borrego smb_ads_select_dc(smb_ads_host_list_t *hlist)
2517c8ec8eeaSjose borrego {
2518b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_host_info_t *hentry = NULL;
2519c8ec8eeaSjose borrego 
2520b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (hlist->ah_cnt == 0)
2521c8ec8eeaSjose borrego 		return (NULL);
2522c8ec8eeaSjose borrego 
2523b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (hlist->ah_cnt == 1) {
2524b89a8333Snatalie li - Sun Microsystems - Irvine United States 		hentry = hlist->ah_list;
2525b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (smb_ads_ldap_ping(hentry) == 0)
2526b89a8333Snatalie li - Sun Microsystems - Irvine United States 			return (hentry);
2527c8ec8eeaSjose borrego 	}
2528c8ec8eeaSjose borrego 
2529b89a8333Snatalie li - Sun Microsystems - Irvine United States 	/* Sort the list by priority and weight */
2530b89a8333Snatalie li - Sun Microsystems - Irvine United States 	qsort(hlist->ah_list, hlist->ah_cnt,
2531b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    sizeof (smb_ads_host_info_t), smb_ads_dc_compare);
2532c8ec8eeaSjose borrego 
2533b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if ((hentry = smb_ads_select_dcfromsubnet(hlist)) != NULL)
2534b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (hentry);
2535b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2536b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if ((hentry = smb_ads_select_dcfromlist(hlist)) != NULL)
2537b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (hentry);
2538b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2539c8ec8eeaSjose borrego 	return (NULL);
2540c8ec8eeaSjose borrego }
25418d7e4166Sjose borrego 
25428d7e4166Sjose borrego /*
25438d7e4166Sjose borrego  * smb_ads_lookup_msdcs
25448d7e4166Sjose borrego  *
25458d7e4166Sjose borrego  * If server argument is set, try to locate the specified DC.
25468d7e4166Sjose borrego  * If it is set to empty string, locate any DCs in the specified domain.
25478d7e4166Sjose borrego  * Returns the discovered DC via buf.
25488d7e4166Sjose borrego  *
25498d7e4166Sjose borrego  * fqdn	  - fully-qualified domain name
25508d7e4166Sjose borrego  * server - fully-qualifed hostname of a DC
25518d7e4166Sjose borrego  * buf    - the hostname of the discovered DC
25528d7e4166Sjose borrego  */
25538d7e4166Sjose borrego boolean_t
smb_ads_lookup_msdcs(char * fqdn,char * server,char * buf,uint32_t buflen)25548d7e4166Sjose borrego smb_ads_lookup_msdcs(char *fqdn, char *server, char *buf, uint32_t buflen)
25558d7e4166Sjose borrego {
25568d7e4166Sjose borrego 	smb_ads_host_info_t *hinfo = NULL;
25578d7e4166Sjose borrego 	char *p;
25588d7e4166Sjose borrego 	char *sought_host;
25597f667e74Sjose borrego 	char ipstr[INET6_ADDRSTRLEN];
25608d7e4166Sjose borrego 
25618d7e4166Sjose borrego 	if (!fqdn || !buf)
25628d7e4166Sjose borrego 		return (B_FALSE);
25638d7e4166Sjose borrego 
256432b8d01aSChristopher Parker 	ipstr[0] = '\0';
25658d7e4166Sjose borrego 	*buf = '\0';
25668d7e4166Sjose borrego 	sought_host = (*server == 0 ? NULL : server);
25678d7e4166Sjose borrego 	if ((hinfo = smb_ads_find_host(fqdn, sought_host)) == NULL)
25688d7e4166Sjose borrego 		return (B_FALSE);
25698d7e4166Sjose borrego 
257032b8d01aSChristopher Parker 	(void) smb_inet_ntop(&hinfo->ipaddr, ipstr,
257132b8d01aSChristopher Parker 	    SMB_IPSTRLEN(hinfo->ipaddr.a_family));
257232b8d01aSChristopher Parker 	smb_tracef("msdcsLookupADS: %s [%s]", hinfo->name, ipstr);
25738d7e4166Sjose borrego 
25748d7e4166Sjose borrego 	(void) strlcpy(buf, hinfo->name, buflen);
25758d7e4166Sjose borrego 	/*
25768d7e4166Sjose borrego 	 * Remove the domain extension
25778d7e4166Sjose borrego 	 */
25788d7e4166Sjose borrego 	if ((p = strchr(buf, '.')) != 0)
25798d7e4166Sjose borrego 		*p = '\0';
25808d7e4166Sjose borrego 
258129bd2886SAlan Wright 	free(hinfo);
25828d7e4166Sjose borrego 	return (B_TRUE);
25838d7e4166Sjose borrego }
2584148c5f43SAlan Wright 
2585148c5f43SAlan Wright static krb5_enctype *
smb_ads_get_enctypes(int dclevel,int * num)2586148c5f43SAlan Wright smb_ads_get_enctypes(int dclevel, int *num)
2587148c5f43SAlan Wright {
2588148c5f43SAlan Wright 	krb5_enctype *encptr;
2589148c5f43SAlan Wright 
2590148c5f43SAlan Wright 	if (dclevel >= SMB_ADS_DCLEVEL_W2K8) {
2591148c5f43SAlan Wright 		*num = sizeof (w2k8enctypes) / sizeof (krb5_enctype);
2592148c5f43SAlan Wright 		encptr = w2k8enctypes;
2593148c5f43SAlan Wright 	} else {
2594148c5f43SAlan Wright 		*num = sizeof (pre_w2k8enctypes) / sizeof (krb5_enctype);
2595148c5f43SAlan Wright 		encptr = pre_w2k8enctypes;
2596148c5f43SAlan Wright 	}
2597148c5f43SAlan Wright 
2598148c5f43SAlan Wright 	return (encptr);
2599148c5f43SAlan Wright }
2600