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.
23*549ab26fSMatt Barden  * Copyright 2022 Tintri by DDN, Inc. All rights reserved.
246a23a4b8SGordon Ross  * Copyright 2021 RackTop Systems, Inc.
25da6c28aaSamw  */
26da6c28aaSamw 
27da6c28aaSamw #include <sys/param.h>
28da6c28aaSamw #include <ldap.h>
29da6c28aaSamw #include <stdlib.h>
30da6c28aaSamw #include <sys/types.h>
31da6c28aaSamw #include <sys/socket.h>
32da6c28aaSamw #include <netinet/in.h>
33da6c28aaSamw #include <arpa/inet.h>
34da6c28aaSamw #include <sys/time.h>
35da6c28aaSamw #include <netdb.h>
36da6c28aaSamw #include <pthread.h>
37da6c28aaSamw #include <unistd.h>
38da6c28aaSamw #include <arpa/nameser.h>
39da6c28aaSamw #include <resolv.h>
40da6c28aaSamw #include <sys/synch.h>
41da6c28aaSamw #include <string.h>
42da6c28aaSamw #include <strings.h>
43da6c28aaSamw #include <fcntl.h>
44da6c28aaSamw #include <sys/types.h>
45da6c28aaSamw #include <sys/stat.h>
46b89a8333Snatalie li - Sun Microsystems - Irvine United States #include <assert.h>
47a0aa776eSAlan Wright #include <sasl/sasl.h>
48a0aa776eSAlan Wright #include <note.h>
4977191e87SShawn Emery #include <errno.h>
5077191e87SShawn Emery #include <cryptoutil.h>
51b3700b07SGordon Ross #include <ads/dsgetdc.h>
52da6c28aaSamw 
53da6c28aaSamw #include <smbsrv/libsmbns.h>
54da6c28aaSamw #include <smbns_dyndns.h>
55da6c28aaSamw #include <smbns_krb.h>
56da6c28aaSamw 
5796a62adaSjoyce mcintosh #define	SMB_ADS_AF_UNKNOWN(x)	(((x)->ipaddr.a_family != AF_INET) && \
5896a62adaSjoyce mcintosh 	((x)->ipaddr.a_family != AF_INET6))
5996a62adaSjoyce mcintosh 
6029bd2886SAlan Wright #define	SMB_ADS_MAXBUFLEN 100
613db3f65cSamw #define	SMB_ADS_DN_MAX	300
623db3f65cSamw #define	SMB_ADS_MAXMSGLEN 512
633db3f65cSamw #define	SMB_ADS_COMPUTERS_CN "Computers"
643db3f65cSamw #define	SMB_ADS_COMPUTER_NUM_ATTR 8
653db3f65cSamw #define	SMB_ADS_SHARE_NUM_ATTR 3
663db3f65cSamw #define	SMB_ADS_SITE_MAX MAXHOSTNAMELEN
673db3f65cSamw 
683db3f65cSamw #define	SMB_ADS_MSDCS_SRV_DC_RR		"_ldap._tcp.dc._msdcs"
693db3f65cSamw #define	SMB_ADS_MSDCS_SRV_SITE_RR	"_ldap._tcp.%s._sites.dc._msdcs"
703db3f65cSamw 
713db3f65cSamw /*
723db3f65cSamw  * domainControllerFunctionality
733db3f65cSamw  *
743db3f65cSamw  * This rootDSE attribute indicates the functional level of the DC.
753db3f65cSamw  */
763db3f65cSamw #define	SMB_ADS_ATTR_DCLEVEL	"domainControllerFunctionality"
773db3f65cSamw #define	SMB_ADS_DCLEVEL_W2K	0
783db3f65cSamw #define	SMB_ADS_DCLEVEL_W2K3	2
793db3f65cSamw #define	SMB_ADS_DCLEVEL_W2K8	3
80b1352070SAlan Wright #define	SMB_ADS_DCLEVEL_W2K8_R2 4
813db3f65cSamw 
823db3f65cSamw /*
833db3f65cSamw  * msDs-supportedEncryptionTypes (Windows Server 2008 only)
843db3f65cSamw  *
853db3f65cSamw  * This attribute defines the encryption types supported by the system.
863db3f65cSamw  * Encryption Types:
873db3f65cSamw  *  - DES cbc mode with CRC-32
883db3f65cSamw  *  - DES cbc mode with RSA-MD5
893db3f65cSamw  *  - ArcFour with HMAC/md5
903db3f65cSamw  *  - AES-128
913db3f65cSamw  *  - AES-256
923db3f65cSamw  */
933db3f65cSamw #define	SMB_ADS_ATTR_ENCTYPES	"msDs-supportedEncryptionTypes"
943db3f65cSamw #define	SMB_ADS_ENC_DES_CRC	1
953db3f65cSamw #define	SMB_ADS_ENC_DES_MD5	2
963db3f65cSamw #define	SMB_ADS_ENC_RC4		4
973db3f65cSamw #define	SMB_ADS_ENC_AES128	8
983db3f65cSamw #define	SMB_ADS_ENC_AES256	16
993db3f65cSamw 
100148c5f43SAlan Wright static krb5_enctype w2k8enctypes[] = {
101148c5f43SAlan Wright     ENCTYPE_AES256_CTS_HMAC_SHA1_96,
102148c5f43SAlan Wright     ENCTYPE_AES128_CTS_HMAC_SHA1_96,
103148c5f43SAlan Wright     ENCTYPE_ARCFOUR_HMAC,
104148c5f43SAlan Wright     ENCTYPE_DES_CBC_CRC,
105148c5f43SAlan Wright     ENCTYPE_DES_CBC_MD5,
106148c5f43SAlan Wright };
107148c5f43SAlan Wright 
108148c5f43SAlan Wright static krb5_enctype pre_w2k8enctypes[] = {
109148c5f43SAlan Wright     ENCTYPE_ARCFOUR_HMAC,
110148c5f43SAlan Wright     ENCTYPE_DES_CBC_CRC,
111148c5f43SAlan Wright     ENCTYPE_DES_CBC_MD5,
112148c5f43SAlan Wright };
113148c5f43SAlan Wright 
1143db3f65cSamw #define	SMB_ADS_ATTR_SAMACCT	"sAMAccountName"
1153db3f65cSamw #define	SMB_ADS_ATTR_UPN	"userPrincipalName"
1163db3f65cSamw #define	SMB_ADS_ATTR_SPN	"servicePrincipalName"
1173db3f65cSamw #define	SMB_ADS_ATTR_CTL	"userAccountControl"
1183db3f65cSamw #define	SMB_ADS_ATTR_DNSHOST	"dNSHostName"
1193db3f65cSamw #define	SMB_ADS_ATTR_KVNO	"msDS-KeyVersionNumber"
120c8ec8eeaSjose borrego #define	SMB_ADS_ATTR_DN		"distinguishedName"
121da6c28aaSamw 
12229bd2886SAlan Wright /*
12329bd2886SAlan Wright  * UserAccountControl flags: manipulate user account properties.
12429bd2886SAlan Wright  *
12529bd2886SAlan Wright  * The hexadecimal value of the following property flags are based on MSDN
12629bd2886SAlan Wright  * article # 305144.
12729bd2886SAlan Wright  */
12829bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_SCRIPT				0x00000001
12929bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_ACCOUNTDISABLE			0x00000002
13029bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_HOMEDIR_REQUIRED			0x00000008
13129bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_LOCKOUT				0x00000010
13229bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_PASSWD_NOTREQD			0x00000020
13329bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_PASSWD_CANT_CHANGE		0x00000040
13429bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_ENCRYPTED_TEXT_PWD_ALLOWED	0x00000080
13529bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_TMP_DUP_ACCT			0x00000100
13629bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_NORMAL_ACCT			0x00000200
13729bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_INTERDOMAIN_TRUST_ACCT		0x00000800
13829bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT		0x00001000
13929bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_SRV_TRUST_ACCT			0x00002000
14029bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_DONT_EXPIRE_PASSWD		0x00010000
14129bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_MNS_LOGON_ACCT			0x00020000
14229bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_SMARTCARD_REQUIRED		0x00040000
14329bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_TRUSTED_FOR_DELEGATION		0x00080000
14429bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_NOT_DELEGATED			0x00100000
14529bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_USE_DES_KEY_ONLY			0x00200000
14629bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_DONT_REQ_PREAUTH			0x00400000
14729bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_PASSWD_EXPIRED			0x00800000
14829bd2886SAlan Wright #define	SMB_ADS_USER_ACCT_CTL_TRUSTED_TO_AUTH_FOR_DELEGATION	0x01000000
14929bd2886SAlan Wright 
150b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
151b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Length of "dc=" prefix.
152b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
153b89a8333Snatalie li - Sun Microsystems - Irvine United States #define	SMB_ADS_DN_PREFIX_LEN	3
154b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1557f667e74Sjose borrego static char *smb_ads_computer_objcls[] = {
1567f667e74Sjose borrego 	"top", "person", "organizationalPerson",
1577f667e74Sjose borrego 	"user", "computer", NULL
1587f667e74Sjose borrego };
1597f667e74Sjose borrego 
1607f667e74Sjose borrego static char *smb_ads_share_objcls[] = {
1617f667e74Sjose borrego 	"top", "leaf", "connectionPoint", "volume", NULL
1627f667e74Sjose borrego };
1637f667e74Sjose borrego 
164b89a8333Snatalie li - Sun Microsystems - Irvine United States /* Cached ADS server to communicate with */
165b89a8333Snatalie li - Sun Microsystems - Irvine United States static smb_ads_host_info_t *smb_ads_cached_host_info = NULL;
166b89a8333Snatalie li - Sun Microsystems - Irvine United States static mutex_t smb_ads_cached_host_mtx;
167b89a8333Snatalie li - Sun Microsystems - Irvine United States 
16829bd2886SAlan Wright /*
16929bd2886SAlan Wright  * SMB ADS config cache is maintained to facilitate the detection of
17029bd2886SAlan Wright  * changes in configuration that is relevant to AD selection.
17129bd2886SAlan Wright  */
17229bd2886SAlan Wright typedef struct smb_ads_config {
17329bd2886SAlan Wright 	char c_site[SMB_ADS_SITE_MAX];
17429bd2886SAlan Wright 	mutex_t c_mtx;
17529bd2886SAlan Wright } smb_ads_config_t;
17629bd2886SAlan Wright 
17729bd2886SAlan Wright static smb_ads_config_t smb_ads_cfg;
17829bd2886SAlan Wright 
179dc20a302Sas 
180b89a8333Snatalie li - Sun Microsystems - Irvine United States /* attribute/value pair */
181b89a8333Snatalie li - Sun Microsystems - Irvine United States typedef struct smb_ads_avpair {
182b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *avp_attr;
183b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *avp_val;
184b89a8333Snatalie li - Sun Microsystems - Irvine United States } smb_ads_avpair_t;
185b89a8333Snatalie li - Sun Microsystems - Irvine United States 
186b89a8333Snatalie li - Sun Microsystems - Irvine United States /* query status */
187b89a8333Snatalie li - Sun Microsystems - Irvine United States typedef enum smb_ads_qstat {
188b89a8333Snatalie li - Sun Microsystems - Irvine United States 	SMB_ADS_STAT_ERR = -2,
189b89a8333Snatalie li - Sun Microsystems - Irvine United States 	SMB_ADS_STAT_DUP,
190b89a8333Snatalie li - Sun Microsystems - Irvine United States 	SMB_ADS_STAT_NOT_FOUND,
191b89a8333Snatalie li - Sun Microsystems - Irvine United States 	SMB_ADS_STAT_FOUND
192b89a8333Snatalie li - Sun Microsystems - Irvine United States } smb_ads_qstat_t;
193b89a8333Snatalie li - Sun Microsystems - Irvine United States 
19429bd2886SAlan Wright typedef struct smb_ads_host_list {
19529bd2886SAlan Wright 	int ah_cnt;
19629bd2886SAlan Wright 	smb_ads_host_info_t *ah_list;
19729bd2886SAlan Wright } smb_ads_host_list_t;
19829bd2886SAlan Wright 
199b3700b07SGordon Ross static int smb_ads_open_main(smb_ads_handle_t **, char *, char *, char *);
200c8ec8eeaSjose borrego static int smb_ads_add_computer(smb_ads_handle_t *, int, char *);
201c8ec8eeaSjose borrego static int smb_ads_modify_computer(smb_ads_handle_t *, int, char *);
202c8ec8eeaSjose borrego static int smb_ads_computer_op(smb_ads_handle_t *, int, int, char *);
203b89a8333Snatalie li - Sun Microsystems - Irvine United States static smb_ads_qstat_t smb_ads_lookup_computer_n_attr(smb_ads_handle_t *,
204b89a8333Snatalie li - Sun Microsystems - Irvine United States     smb_ads_avpair_t *, int, char *);
205c8ec8eeaSjose borrego static int smb_ads_update_computer_cntrl_attr(smb_ads_handle_t *, int, char *);
206c8ec8eeaSjose borrego static krb5_kvno smb_ads_lookup_computer_attr_kvno(smb_ads_handle_t *, char *);
207b89a8333Snatalie li - Sun Microsystems - Irvine United States static void smb_ads_free_cached_host(void);
208c8ec8eeaSjose borrego static int smb_ads_alloc_attr(LDAPMod **, int);
209c8ec8eeaSjose borrego static void smb_ads_free_attr(LDAPMod **);
210c8ec8eeaSjose borrego static int smb_ads_get_dc_level(smb_ads_handle_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_is_same_domain(char *, char *);
21729bd2886SAlan Wright static smb_ads_host_info_t *smb_ads_dup_host_info(smb_ads_host_info_t *);
218fe1c642dSBill Krier static char *smb_ads_get_sharedn(const char *, const char *, const char *);
219148c5f43SAlan Wright static krb5_enctype *smb_ads_get_enctypes(int, int *);
220dc20a302Sas 
221dc20a302Sas /*
2223db3f65cSamw  * smb_ads_init
223dc20a302Sas  *
22429bd2886SAlan Wright  * Initializes the ADS config cache.
225dc20a302Sas  */
226dc20a302Sas void
smb_ads_init(void)2273db3f65cSamw smb_ads_init(void)
228dc20a302Sas {
22929bd2886SAlan Wright 	(void) mutex_lock(&smb_ads_cfg.c_mtx);
230b89a8333Snatalie li - Sun Microsystems - Irvine United States 	(void) smb_config_getstr(SMB_CI_ADS_SITE,
23129bd2886SAlan Wright 	    smb_ads_cfg.c_site, SMB_ADS_SITE_MAX);
23229bd2886SAlan Wright 	(void) mutex_unlock(&smb_ads_cfg.c_mtx);
233b3700b07SGordon Ross 
234b3700b07SGordon Ross 	/* Force -lads to load, for dtrace. */
235b3700b07SGordon Ross 	DsFreeDcInfo(NULL);
23629bd2886SAlan Wright }
23729bd2886SAlan Wright 
23829bd2886SAlan Wright void
smb_ads_fini(void)23929bd2886SAlan Wright smb_ads_fini(void)
24029bd2886SAlan Wright {
24129bd2886SAlan Wright 	smb_ads_free_cached_host();
242dc20a302Sas }
243dc20a302Sas 
244dc20a302Sas /*
2453db3f65cSamw  * smb_ads_refresh
246dc20a302Sas  *
24729bd2886SAlan Wright  * This function will be called when smb/server SMF service is refreshed.
248b3700b07SGordon Ross  * (See smbd_join.c)
249b3700b07SGordon Ross  *
25029bd2886SAlan Wright  * Clearing the smb_ads_cached_host_info would allow the next DC
25129bd2886SAlan Wright  * discovery process to pick up an AD based on the new AD configuration.
252dc20a302Sas  */
253dc20a302Sas void
smb_ads_refresh(boolean_t force_rediscovery)254b3700b07SGordon Ross smb_ads_refresh(boolean_t force_rediscovery)
255dc20a302Sas {
2563db3f65cSamw 	char new_site[SMB_ADS_SITE_MAX];
257dc20a302Sas 
25829bd2886SAlan Wright 	(void) smb_config_getstr(SMB_CI_ADS_SITE, new_site, SMB_ADS_SITE_MAX);
25929bd2886SAlan Wright 	(void) mutex_lock(&smb_ads_cfg.c_mtx);
260b3700b07SGordon Ross 	(void) strlcpy(smb_ads_cfg.c_site, new_site, SMB_ADS_SITE_MAX);
26129bd2886SAlan Wright 	(void) mutex_unlock(&smb_ads_cfg.c_mtx);
26229bd2886SAlan Wright 
263b3700b07SGordon Ross 	smb_ads_free_cached_host();
26429bd2886SAlan Wright 
265b3700b07SGordon Ross 	if (force_rediscovery) {
266b3700b07SGordon Ross 		(void) _DsForceRediscovery(NULL, 0);
267b3700b07SGordon Ross 	}
26829bd2886SAlan Wright }
26929bd2886SAlan Wright 
27029bd2886SAlan Wright 
271da6c28aaSamw /*
2723db3f65cSamw  * smb_ads_build_unc_name
273da6c28aaSamw  *
274da6c28aaSamw  * Construct the UNC name of the share object in the format of
275da6c28aaSamw  * \\hostname.domain\shareUNC
276da6c28aaSamw  *
277da6c28aaSamw  * Returns 0 on success, -1 on error.
278da6c28aaSamw  */
279da6c28aaSamw int
smb_ads_build_unc_name(char * unc_name,int maxlen,const char * hostname,const char * shareUNC)2803db3f65cSamw smb_ads_build_unc_name(char *unc_name, int maxlen,
281da6c28aaSamw     const char *hostname, const char *shareUNC)
282da6c28aaSamw {
283dc20a302Sas 	char my_domain[MAXHOSTNAMELEN];
284da6c28aaSamw 
285dc20a302Sas 	if (smb_getfqdomainname(my_domain, sizeof (my_domain)) != 0)
286da6c28aaSamw 		return (-1);
287da6c28aaSamw 
288da6c28aaSamw 	(void) snprintf(unc_name, maxlen, "\\\\%s.%s\\%s",
289da6c28aaSamw 	    hostname, my_domain, shareUNC);
290da6c28aaSamw 	return (0);
291da6c28aaSamw }
292da6c28aaSamw 
2933db3f65cSamw /*
29429bd2886SAlan Wright  * The cached ADS host is no longer valid if one of the following criteria
29529bd2886SAlan Wright  * is satisfied:
296b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
29729bd2886SAlan Wright  * 1) not in the specified domain
29829bd2886SAlan Wright  * 2) not the sought host (if specified)
29929bd2886SAlan Wright  * 3) not reachable
30029bd2886SAlan Wright  *
30129bd2886SAlan Wright  * The caller is responsible for acquiring the smb_ads_cached_host_mtx lock
30229bd2886SAlan Wright  * prior to calling this function.
30329bd2886SAlan Wright  *
30429bd2886SAlan Wright  * Return B_TRUE if the cache host is still valid. Otherwise, return B_FALSE.
305da6c28aaSamw  */
30629bd2886SAlan Wright static boolean_t
smb_ads_validate_cache_host(char * domain)307b3700b07SGordon Ross smb_ads_validate_cache_host(char *domain)
308da6c28aaSamw {
309b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (!smb_ads_cached_host_info)
31029bd2886SAlan Wright 		return (B_FALSE);
311da6c28aaSamw 
31229bd2886SAlan Wright 	if (!smb_ads_is_same_domain(smb_ads_cached_host_info->name, domain))
31329bd2886SAlan Wright 		return (B_FALSE);
314da6c28aaSamw 
315b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (B_TRUE);
316b89a8333Snatalie li - Sun Microsystems - Irvine United States }
317b89a8333Snatalie li - Sun Microsystems - Irvine United States 
318b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
319b89a8333Snatalie li - Sun Microsystems - Irvine United States  * smb_ads_match_hosts_same_domain
320b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
321b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Returns true, if the cached ADS host is in the same domain as the
322b89a8333Snatalie li - Sun Microsystems - Irvine United States  * current (given) domain.
323b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
324b89a8333Snatalie li - Sun Microsystems - Irvine United States static boolean_t
smb_ads_is_same_domain(char * cached_host_name,char * current_domain)325b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_is_same_domain(char *cached_host_name, char *current_domain)
326b89a8333Snatalie li - Sun Microsystems - Irvine United States {
327b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *cached_host_domain;
328b89a8333Snatalie li - Sun Microsystems - Irvine United States 
329b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if ((cached_host_name == NULL) || (current_domain == NULL))
330b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (B_FALSE);
331b89a8333Snatalie li - Sun Microsystems - Irvine United States 
332b89a8333Snatalie li - Sun Microsystems - Irvine United States 	cached_host_domain = strchr(cached_host_name, '.');
333b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (cached_host_domain == NULL)
334b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (B_FALSE);
335b89a8333Snatalie li - Sun Microsystems - Irvine United States 
336b89a8333Snatalie li - Sun Microsystems - Irvine United States 	++cached_host_domain;
337bbf6f00cSJordan Brown 	if (smb_strcasecmp(cached_host_domain, current_domain, 0))
338b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (B_FALSE);
339b89a8333Snatalie li - Sun Microsystems - Irvine United States 
340b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (B_TRUE);
341b89a8333Snatalie li - Sun Microsystems - Irvine United States }
342b89a8333Snatalie li - Sun Microsystems - Irvine United States 
343b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
344b89a8333Snatalie li - Sun Microsystems - Irvine United States  * smb_ads_dup_host_info
345b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
346b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Duplicates the passed smb_ads_host_info_t structure.
347b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Caller must free memory allocated by this method.
348b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
349b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Returns a reference to the duplicated smb_ads_host_info_t structure.
350b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Returns NULL on error.
351b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
352b89a8333Snatalie li - Sun Microsystems - Irvine United States static smb_ads_host_info_t *
smb_ads_dup_host_info(smb_ads_host_info_t * ads_host)353b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_dup_host_info(smb_ads_host_info_t *ads_host)
354da6c28aaSamw {
355b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_host_info_t *dup_host;
356b89a8333Snatalie li - Sun Microsystems - Irvine United States 
357b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (ads_host == NULL)
358b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (NULL);
359b89a8333Snatalie li - Sun Microsystems - Irvine United States 
360b89a8333Snatalie li - Sun Microsystems - Irvine United States 	dup_host = malloc(sizeof (smb_ads_host_info_t));
361b89a8333Snatalie li - Sun Microsystems - Irvine United States 
362b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (dup_host != NULL)
363b89a8333Snatalie li - Sun Microsystems - Irvine United States 		bcopy(ads_host, dup_host, sizeof (smb_ads_host_info_t));
364b89a8333Snatalie li - Sun Microsystems - Irvine United States 
365b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (dup_host);
366c8ec8eeaSjose borrego }
367c8ec8eeaSjose borrego 
368b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
369b89a8333Snatalie li - Sun Microsystems - Irvine United States  * smb_ads_find_host
370b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
37129bd2886SAlan Wright  * Finds an ADS host in a given domain.
372b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
37329bd2886SAlan Wright  * If the cached host is valid, it will be used. Otherwise, a DC will
37429bd2886SAlan Wright  * be selected based on the following criteria:
37529bd2886SAlan Wright  *
37629bd2886SAlan Wright  * 1) pdc (aka preferred DC) configuration
37729bd2886SAlan Wright  * 2) AD site configuration - the scope of the DNS lookup will be
37829bd2886SAlan Wright  * restricted to the specified site.
37929bd2886SAlan Wright  * 3) DC on the same subnet
38029bd2886SAlan Wright  * 4) DC with the lowest priority/highest weight
38129bd2886SAlan Wright  *
38229bd2886SAlan Wright  * The above items are listed in decreasing preference order. The selected
38329bd2886SAlan Wright  * DC must be online.
384b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
38529bd2886SAlan Wright  * If this function is called during domain join, the specified kpasswd server
38629bd2886SAlan Wright  * takes precedence over preferred DC, AD site, and so on.
387b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
38829bd2886SAlan Wright  * Parameters:
38929bd2886SAlan Wright  *   domain: fully-qualified domain name.
390b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
391b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Returns:
39229bd2886SAlan Wright  *   A copy of the cached host info is returned. The caller is responsible
39329bd2886SAlan Wright  *   for deallocating the memory returned by this function.
394b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
395b89a8333Snatalie li - Sun Microsystems - Irvine United States /*ARGSUSED*/
396b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_host_info_t *
smb_ads_find_host(char * domain)397b3700b07SGordon Ross smb_ads_find_host(char *domain)
398b89a8333Snatalie li - Sun Microsystems - Irvine United States {
399b3700b07SGordon Ross 	smb_ads_host_info_t *host = NULL;
400b3700b07SGordon Ross 	DOMAIN_CONTROLLER_INFO *dci = NULL;
401b3700b07SGordon Ross 	struct sockaddr_storage *ss;
402b3700b07SGordon Ross 	uint32_t flags = DS_DS_FLAG;
403b3700b07SGordon Ross 	uint32_t status;
404b3700b07SGordon Ross 	int tries;
405b89a8333Snatalie li - Sun Microsystems - Irvine United States 
40629bd2886SAlan Wright 	(void) mutex_lock(&smb_ads_cached_host_mtx);
407b3700b07SGordon Ross 	if (smb_ads_validate_cache_host(domain)) {
40829bd2886SAlan Wright 		host = smb_ads_dup_host_info(smb_ads_cached_host_info);
40929bd2886SAlan Wright 		(void) mutex_unlock(&smb_ads_cached_host_mtx);
41029bd2886SAlan Wright 		return (host);
411b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
412c8ec8eeaSjose borrego 
41329bd2886SAlan Wright 	(void) mutex_unlock(&smb_ads_cached_host_mtx);
41429bd2886SAlan Wright 	smb_ads_free_cached_host();
415c8ec8eeaSjose borrego 
416b89a8333Snatalie li - Sun Microsystems - Irvine United States 	/*
417b3700b07SGordon Ross 	 * The _real_ DC Locator is over in idmapd.
418b3700b07SGordon Ross 	 * Door call over there to get it.
419b89a8333Snatalie li - Sun Microsystems - Irvine United States 	 */
420b3700b07SGordon Ross 	tries = 15;
421b3700b07SGordon Ross again:
422b3700b07SGordon Ross 	status = _DsGetDcName(
423b3700b07SGordon Ross 	    NULL,	/* ComputerName */
424b3700b07SGordon Ross 	    domain,
425b3700b07SGordon Ross 	    NULL,	/* DomainGuid */
4266a23a4b8SGordon Ross 	    NULL,	/* SiteName */
427b3700b07SGordon Ross 	    flags,
428b3700b07SGordon Ross 	    &dci);
429b3700b07SGordon Ross 	switch (status) {
430b3700b07SGordon Ross 	case 0:
431b3700b07SGordon Ross 		break;
43229bd2886SAlan Wright 	/*
433b3700b07SGordon Ross 	 * We can see these errors when joining a domain, if we race
434b3700b07SGordon Ross 	 * asking idmap for the DC before it knows the new domain.
43529bd2886SAlan Wright 	 */
436b3700b07SGordon Ross 	case NT_STATUS_NO_SUCH_DOMAIN:	/* Specified domain unknown */
437b3700b07SGordon Ross 	case NT_STATUS_INVALID_SERVER_STATE:	/*  not in domain mode. */
438b3700b07SGordon Ross 		if (--tries > 0) {
439b3700b07SGordon Ross 			(void) sleep(1);
440b3700b07SGordon Ross 			goto again;
441b3700b07SGordon Ross 		}
442b3700b07SGordon Ross 		/* FALLTHROUGH */
443b3700b07SGordon Ross 	case NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND:
444b3700b07SGordon Ross 	case NT_STATUS_CANT_WAIT:	/* timeout over in idmap */
445b3700b07SGordon Ross 	default:
446b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (NULL);
44729bd2886SAlan Wright 	}
44829bd2886SAlan Wright 
449b3700b07SGordon Ross 	host = calloc(1, sizeof (*host));
450b3700b07SGordon Ross 	if (host == NULL)
451b3700b07SGordon Ross 		goto out;
45229bd2886SAlan Wright 
453b3700b07SGordon Ross 	(void) strlcpy(host->name, dci->DomainControllerName, MAXHOSTNAMELEN);
454b3700b07SGordon Ross 	ss = (void *)dci->_sockaddr;
455b3700b07SGordon Ross 	switch (ss->ss_family) {
456b3700b07SGordon Ross 	case AF_INET: {
457b3700b07SGordon Ross 		struct sockaddr_in *sin = (void *)ss;
458b3700b07SGordon Ross 		host->port = ntohs(sin->sin_port);
459b3700b07SGordon Ross 		host->ipaddr.a_family = AF_INET;
460b3700b07SGordon Ross 		(void) memcpy(&host->ipaddr.a_ipv4, &sin->sin_addr,
461b3700b07SGordon Ross 		    sizeof (in_addr_t));
462b3700b07SGordon Ross 		break;
46329bd2886SAlan Wright 	}
464b3700b07SGordon Ross 	case AF_INET6: {
465b3700b07SGordon Ross 		struct sockaddr_in6 *sin6 = (void *)ss;
466b3700b07SGordon Ross 		host->port = ntohs(sin6->sin6_port);
467b3700b07SGordon Ross 		host->ipaddr.a_family = AF_INET6;
468b3700b07SGordon Ross 		(void) memcpy(&host->ipaddr.a_ipv6, &sin6->sin6_addr,
469b3700b07SGordon Ross 		    sizeof (in6_addr_t));
470b3700b07SGordon Ross 		break;
471da6c28aaSamw 	}
472b3700b07SGordon Ross 	default:
473b3700b07SGordon Ross 		syslog(LOG_ERR, "no addr for DC %s",
474b3700b07SGordon Ross 		    dci->DomainControllerName);
475b3700b07SGordon Ross 		free(host);
476b3700b07SGordon Ross 		host = NULL;
477b3700b07SGordon Ross 		goto out;
478b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
479b89a8333Snatalie li - Sun Microsystems - Irvine United States 
480bdc3270fSMatt Barden 	host->flags = dci->Flags;
481bdc3270fSMatt Barden 
482b3700b07SGordon Ross 	(void) mutex_lock(&smb_ads_cached_host_mtx);
483b3700b07SGordon Ross 	if (!smb_ads_cached_host_info)
484b3700b07SGordon Ross 		smb_ads_cached_host_info = smb_ads_dup_host_info(host);
485b3700b07SGordon Ross 	(void) mutex_unlock(&smb_ads_cached_host_mtx);
486b3700b07SGordon Ross 
487b3700b07SGordon Ross out:
488b3700b07SGordon Ross 	DsFreeDcInfo(dci);
48929bd2886SAlan Wright 	return (host);
490da6c28aaSamw }
491da6c28aaSamw 
492da6c28aaSamw /*
493b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Return the number of dots in a string.
494b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
495b89a8333Snatalie li - Sun Microsystems - Irvine United States static int
smb_ads_count_dots(const char * s)496b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_count_dots(const char *s)
497b89a8333Snatalie li - Sun Microsystems - Irvine United States {
498b89a8333Snatalie li - Sun Microsystems - Irvine United States 	int ndots = 0;
499b89a8333Snatalie li - Sun Microsystems - Irvine United States 
500b89a8333Snatalie li - Sun Microsystems - Irvine United States 	while (*s) {
501b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (*s++ == '.')
502b89a8333Snatalie li - Sun Microsystems - Irvine United States 			ndots++;
503b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
504b89a8333Snatalie li - Sun Microsystems - Irvine United States 
505b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (ndots);
506b89a8333Snatalie li - Sun Microsystems - Irvine United States }
507b89a8333Snatalie li - Sun Microsystems - Irvine United States 
508b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
509b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Convert a domain name in dot notation to distinguished name format,
510b89a8333Snatalie li - Sun Microsystems - Irvine United States  * for example: sun.com -> dc=sun,dc=com.
511b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
512b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Returns a pointer to an allocated buffer containing the distinguished
513b89a8333Snatalie li - Sun Microsystems - Irvine United States  * name.
514da6c28aaSamw  */
515da6c28aaSamw static char *
smb_ads_convert_domain(const char * domain_name)516b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_convert_domain(const char *domain_name)
517da6c28aaSamw {
518b89a8333Snatalie li - Sun Microsystems - Irvine United States 	const char *s;
519b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *dn_name;
520b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char buf[2];
521b89a8333Snatalie li - Sun Microsystems - Irvine United States 	int ndots;
522b89a8333Snatalie li - Sun Microsystems - Irvine United States 	int len;
523da6c28aaSamw 
524b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (domain_name == NULL || *domain_name == 0)
525da6c28aaSamw 		return (NULL);
526da6c28aaSamw 
527b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ndots = smb_ads_count_dots(domain_name);
528b89a8333Snatalie li - Sun Microsystems - Irvine United States 	++ndots;
529b89a8333Snatalie li - Sun Microsystems - Irvine United States 	len = strlen(domain_name) + (ndots * SMB_ADS_DN_PREFIX_LEN) + 1;
530da6c28aaSamw 
531b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if ((dn_name = malloc(len)) == NULL)
532da6c28aaSamw 		return (NULL);
533da6c28aaSamw 
534b89a8333Snatalie li - Sun Microsystems - Irvine United States 	bzero(dn_name, len);
535b89a8333Snatalie li - Sun Microsystems - Irvine United States 	(void) strlcpy(dn_name, "dc=", len);
536b89a8333Snatalie li - Sun Microsystems - Irvine United States 
537b89a8333Snatalie li - Sun Microsystems - Irvine United States 	buf[1] = '\0';
538b89a8333Snatalie li - Sun Microsystems - Irvine United States 	s = domain_name;
539da6c28aaSamw 
540da6c28aaSamw 	while (*s) {
541da6c28aaSamw 		if (*s == '.') {
542b89a8333Snatalie li - Sun Microsystems - Irvine United States 			(void) strlcat(dn_name, ",dc=", len);
543da6c28aaSamw 		} else {
544b89a8333Snatalie li - Sun Microsystems - Irvine United States 			buf[0] = *s;
545b89a8333Snatalie li - Sun Microsystems - Irvine United States 			(void) strlcat(dn_name, buf, len);
546da6c28aaSamw 		}
547b89a8333Snatalie li - Sun Microsystems - Irvine United States 		++s;
548da6c28aaSamw 	}
549b89a8333Snatalie li - Sun Microsystems - Irvine United States 
550b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (dn_name);
551da6c28aaSamw }
552da6c28aaSamw 
553da6c28aaSamw /*
554b89a8333Snatalie li - Sun Microsystems - Irvine United States  * smb_ads_free_cached_host
555b89a8333Snatalie li - Sun Microsystems - Irvine United States  *
556b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Free the memory use by the global smb_ads_cached_host_info & set it to NULL.
557da6c28aaSamw  */
558dc20a302Sas static void
smb_ads_free_cached_host(void)559b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_free_cached_host(void)
560da6c28aaSamw {
561b89a8333Snatalie li - Sun Microsystems - Irvine United States 	(void) mutex_lock(&smb_ads_cached_host_mtx);
562b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (smb_ads_cached_host_info) {
563b89a8333Snatalie li - Sun Microsystems - Irvine United States 		free(smb_ads_cached_host_info);
564b89a8333Snatalie li - Sun Microsystems - Irvine United States 		smb_ads_cached_host_info = NULL;
565da6c28aaSamw 	}
566b89a8333Snatalie li - Sun Microsystems - Irvine United States 	(void) mutex_unlock(&smb_ads_cached_host_mtx);
567da6c28aaSamw }
568da6c28aaSamw 
569da6c28aaSamw /*
5703db3f65cSamw  * smb_ads_open
57155bf511dSas  * Open a LDAP connection to an ADS server if the system is in domain mode.
57255bf511dSas  * Acquire both Kerberos TGT and LDAP service tickets for the host principal.
57355bf511dSas  *
57455bf511dSas  * This function should only be called after the system is successfully joined
57555bf511dSas  * to a domain.
57655bf511dSas  */
5773db3f65cSamw smb_ads_handle_t *
smb_ads_open(void)5783db3f65cSamw smb_ads_open(void)
57955bf511dSas {
580dc20a302Sas 	char domain[MAXHOSTNAMELEN];
581b3700b07SGordon Ross 	smb_ads_handle_t *h;
582b3700b07SGordon Ross 	smb_ads_status_t err;
58355bf511dSas 
584dc20a302Sas 	if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
58555bf511dSas 		return (NULL);
58655bf511dSas 
587dc20a302Sas 	if (smb_getfqdomainname(domain, MAXHOSTNAMELEN) != 0)
588dc20a302Sas 		return (NULL);
589dc20a302Sas 
590b3700b07SGordon Ross 	err = smb_ads_open_main(&h, domain, NULL, NULL);
591b3700b07SGordon Ross 	if (err != 0) {
592b3700b07SGordon Ross 		smb_ads_log_errmsg(err);
593b3700b07SGordon Ross 		return (NULL);
594b3700b07SGordon Ross 	}
595b3700b07SGordon Ross 
596b3700b07SGordon Ross 	return (h);
59755bf511dSas }
59855bf511dSas 
599a0aa776eSAlan Wright static int
smb_ads_saslcallback(LDAP * ld,unsigned flags,void * defaults,void * prompts)600a0aa776eSAlan Wright smb_ads_saslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts)
601a0aa776eSAlan Wright {
602a0aa776eSAlan Wright 	NOTE(ARGUNUSED(ld, defaults));
603a0aa776eSAlan Wright 	sasl_interact_t *interact;
604a0aa776eSAlan Wright 
605a0aa776eSAlan Wright 	if (prompts == NULL || flags != LDAP_SASL_INTERACTIVE)
606a0aa776eSAlan Wright 		return (LDAP_PARAM_ERROR);
607a0aa776eSAlan Wright 
608a0aa776eSAlan Wright 	/* There should be no extra arguemnts for SASL/GSSAPI authentication */
609a0aa776eSAlan Wright 	for (interact = prompts; interact->id != SASL_CB_LIST_END;
610a0aa776eSAlan Wright 	    interact++) {
611a0aa776eSAlan Wright 		interact->result = NULL;
612a0aa776eSAlan Wright 		interact->len = 0;
613a0aa776eSAlan Wright 	}
614a0aa776eSAlan Wright 	return (LDAP_SUCCESS);
615a0aa776eSAlan Wright }
616a0aa776eSAlan Wright 
61755bf511dSas /*
6183db3f65cSamw  * smb_ads_open_main
619da6c28aaSamw  * Open a LDAP connection to an ADS server.
62055bf511dSas  * If ADS is enabled and the administrative username, password, and
621da6c28aaSamw  * ADS domain are defined then query DNS to find an ADS server if this is the
622da6c28aaSamw  * very first call to this routine.  After an ADS server is found then this
623da6c28aaSamw  * server will be used everytime this routine is called until the system is
624da6c28aaSamw  * rebooted or the ADS server becomes unavailable then an ADS server will
6253db3f65cSamw  * be queried again.  After the connection is made then an ADS handle
626da6c28aaSamw  * is created to be returned.
627da6c28aaSamw  *
628da6c28aaSamw  * After the LDAP connection, the LDAP version will be set to 3 using
629da6c28aaSamw  * ldap_set_option().
630da6c28aaSamw  *
631a0aa776eSAlan Wright  * The LDAP connection is bound before the ADS handle is returned.
632da6c28aaSamw  * Parameters:
633dc20a302Sas  *   domain - fully-qualified domain name
634dc20a302Sas  *   user   - the user account for whom the Kerberos TGT ticket and ADS
635dc20a302Sas  *            service tickets are acquired.
636dc20a302Sas  *   password - password of the specified user
637dc20a302Sas  *
638da6c28aaSamw  * Returns:
6393db3f65cSamw  *   NULL              : can't connect to ADS server or other errors
6403db3f65cSamw  *   smb_ads_handle_t* : handle to ADS server
641da6c28aaSamw  */
642b3700b07SGordon Ross static int
smb_ads_open_main(smb_ads_handle_t ** hp,char * domain,char * user,char * password)643b3700b07SGordon Ross smb_ads_open_main(smb_ads_handle_t **hp, char *domain, char *user,
644b3700b07SGordon Ross     char *password)
645da6c28aaSamw {
6463db3f65cSamw 	smb_ads_handle_t *ah;
647da6c28aaSamw 	LDAP *ld;
648b89a8333Snatalie li - Sun Microsystems - Irvine United States 	int version = 3;
6493db3f65cSamw 	smb_ads_host_info_t *ads_host = NULL;
650b3700b07SGordon Ross 	int err, rc;
651b3700b07SGordon Ross 
652b3700b07SGordon Ross 	*hp = NULL;
653a0aa776eSAlan Wright 
654a0aa776eSAlan Wright 	if (user != NULL) {
655b3700b07SGordon Ross 		err = smb_kinit(domain, user, password);
6566a23a4b8SGordon Ross 		if (err != 0) {
6576a23a4b8SGordon Ross 			syslog(LOG_ERR, "smbns: kinit failed");
658b3700b07SGordon Ross 			return (err);
6596a23a4b8SGordon Ross 		}
660a0aa776eSAlan Wright 		user = NULL;
661a0aa776eSAlan Wright 		password = NULL;
662a0aa776eSAlan Wright 	}
663da6c28aaSamw 
664b3700b07SGordon Ross 	ads_host = smb_ads_find_host(domain);
665b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (ads_host == NULL)
666b3700b07SGordon Ross 		return (SMB_ADS_CANT_LOCATE_DC);
667b89a8333Snatalie li - Sun Microsystems - Irvine United States 
6683db3f65cSamw 	ah = (smb_ads_handle_t *)malloc(sizeof (smb_ads_handle_t));
66929bd2886SAlan Wright 	if (ah == NULL) {
67029bd2886SAlan Wright 		free(ads_host);
671b3700b07SGordon Ross 		return (ENOMEM);
67229bd2886SAlan Wright 	}
67329bd2886SAlan Wright 
6743db3f65cSamw 	(void) memset(ah, 0, sizeof (smb_ads_handle_t));
675da6c28aaSamw 
6767f667e74Sjose borrego 	if ((ld = ldap_init(ads_host->name, ads_host->port)) == NULL) {
677b3700b07SGordon Ross 		syslog(LOG_ERR, "smbns: ldap_init failed");
678b89a8333Snatalie li - Sun Microsystems - Irvine United States 		smb_ads_free_cached_host();
679da6c28aaSamw 		free(ah);
68029bd2886SAlan Wright 		free(ads_host);
681b3700b07SGordon Ross 		return (SMB_ADS_LDAP_INIT);
682da6c28aaSamw 	}
683da6c28aaSamw 
684da6c28aaSamw 	if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version)
685da6c28aaSamw 	    != LDAP_SUCCESS) {
686b89a8333Snatalie li - Sun Microsystems - Irvine United States 		smb_ads_free_cached_host();
687da6c28aaSamw 		free(ah);
68829bd2886SAlan Wright 		free(ads_host);
689da6c28aaSamw 		(void) ldap_unbind(ld);
690b3700b07SGordon Ross 		return (SMB_ADS_LDAP_SETOPT);
691da6c28aaSamw 	}
692da6c28aaSamw 
693c8ec8eeaSjose borrego 	(void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
694da6c28aaSamw 	ah->ld = ld;
695da6c28aaSamw 	ah->domain = strdup(domain);
696da6c28aaSamw 
69755bf511dSas 	if (ah->domain == NULL) {
6983db3f65cSamw 		smb_ads_close(ah);
69929bd2886SAlan Wright 		free(ads_host);
700b3700b07SGordon Ross 		return (SMB_ADS_LDAP_SETOPT);
701da6c28aaSamw 	}
702da6c28aaSamw 
7039fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	/*
7049fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	 * ah->domain is often used for generating service principal name.
7059fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	 * Convert it to lower case for RFC 4120 section 6.2.1 conformance.
7069fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	 */
7079fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	(void) smb_strlwr(ah->domain);
7083db3f65cSamw 	ah->domain_dn = smb_ads_convert_domain(domain);
709da6c28aaSamw 	if (ah->domain_dn == NULL) {
7103db3f65cSamw 		smb_ads_close(ah);
71129bd2886SAlan Wright 		free(ads_host);
712b3700b07SGordon Ross 		return (SMB_ADS_LDAP_SET_DOM);
713da6c28aaSamw 	}
714da6c28aaSamw 
715da6c28aaSamw 	ah->hostname = strdup(ads_host->name);
716da6c28aaSamw 	if (ah->hostname == NULL) {
7173db3f65cSamw 		smb_ads_close(ah);
71829bd2886SAlan Wright 		free(ads_host);
719b3700b07SGordon Ross 		return (ENOMEM);
720da6c28aaSamw 	}
72129bd2886SAlan Wright 	(void) mutex_lock(&smb_ads_cfg.c_mtx);
72229bd2886SAlan Wright 	if (*smb_ads_cfg.c_site != '\0') {
72329bd2886SAlan Wright 		if ((ah->site = strdup(smb_ads_cfg.c_site)) == NULL) {
7243db3f65cSamw 			smb_ads_close(ah);
72529bd2886SAlan Wright 			(void) mutex_unlock(&smb_ads_cfg.c_mtx);
72629bd2886SAlan Wright 			free(ads_host);
727b3700b07SGordon Ross 			return (ENOMEM);
728da6c28aaSamw 		}
729da6c28aaSamw 	} else {
730da6c28aaSamw 		ah->site = NULL;
731da6c28aaSamw 	}
73229bd2886SAlan Wright 	(void) mutex_unlock(&smb_ads_cfg.c_mtx);
733da6c28aaSamw 
7346a23a4b8SGordon Ross 	syslog(LOG_DEBUG, "smbns: smb_ads_open_main");
7356a23a4b8SGordon Ross 	syslog(LOG_DEBUG, "smbns: domain: %s", ah->domain);
7366a23a4b8SGordon Ross 	syslog(LOG_DEBUG, "smbns: domain_dn: %s", ah->domain_dn);
7376a23a4b8SGordon Ross 	syslog(LOG_DEBUG, "smbns: ip_addr: %s", ah->ip_addr);
7386a23a4b8SGordon Ross 	syslog(LOG_DEBUG, "smbns: hostname: %s", ah->hostname);
7396a23a4b8SGordon Ross 	syslog(LOG_DEBUG, "smbns: site: %s",
7406a23a4b8SGordon Ross 	    (ah->site != NULL) ? ah->site : "");
7416a23a4b8SGordon Ross 
742a0aa776eSAlan Wright 	rc = ldap_sasl_interactive_bind_s(ah->ld, "", "GSSAPI", NULL, NULL,
743a0aa776eSAlan Wright 	    LDAP_SASL_INTERACTIVE, &smb_ads_saslcallback, NULL);
744a0aa776eSAlan Wright 	if (rc != LDAP_SUCCESS) {
745b3700b07SGordon Ross 		syslog(LOG_ERR, "smbns: ldap_sasl_..._bind_s failed (%s)",
746a0aa776eSAlan Wright 		    ldap_err2string(rc));
7473db3f65cSamw 		smb_ads_close(ah);
74829bd2886SAlan Wright 		free(ads_host);
749b3700b07SGordon Ross 		return (SMB_ADS_LDAP_SASL_BIND);
750da6c28aaSamw 	}
7516a23a4b8SGordon Ross 	syslog(LOG_DEBUG, "smbns: ldap_sasl_..._bind_s success");
752da6c28aaSamw 
75329bd2886SAlan Wright 	free(ads_host);
754b3700b07SGordon Ross 	*hp = ah;
755b3700b07SGordon Ross 
756b3700b07SGordon Ross 	return (SMB_ADS_SUCCESS);
757da6c28aaSamw }
758da6c28aaSamw 
759da6c28aaSamw /*
7603db3f65cSamw  * smb_ads_close
761da6c28aaSamw  * Close connection to ADS server and free memory allocated for ADS handle.
762da6c28aaSamw  * LDAP unbind is called here.
763da6c28aaSamw  * Parameters:
764da6c28aaSamw  *   ah: handle to ADS server
765da6c28aaSamw  * Returns:
766da6c28aaSamw  *   void
767da6c28aaSamw  */
768da6c28aaSamw void
smb_ads_close(smb_ads_handle_t * ah)7693db3f65cSamw smb_ads_close(smb_ads_handle_t *ah)
770da6c28aaSamw {
771da6c28aaSamw 	if (ah == NULL)
772da6c28aaSamw 		return;
773da6c28aaSamw 	/* close and free connection resources */
774da6c28aaSamw 	if (ah->ld)
775da6c28aaSamw 		(void) ldap_unbind(ah->ld);
776da6c28aaSamw 
777da6c28aaSamw 	free(ah->domain);
778da6c28aaSamw 	free(ah->domain_dn);
779da6c28aaSamw 	free(ah->hostname);
780da6c28aaSamw 	free(ah->site);
781da6c28aaSamw 	free(ah);
782da6c28aaSamw }
783da6c28aaSamw 
784da6c28aaSamw /*
7853db3f65cSamw  * smb_ads_alloc_attr
7866537f381Sas  *
7876537f381Sas  * Since the attrs is a null-terminated array, all elements
7886537f381Sas  * in the array (except the last one) will point to allocated
7896537f381Sas  * memory.
7906537f381Sas  */
7916537f381Sas static int
smb_ads_alloc_attr(LDAPMod * attrs[],int num)7923db3f65cSamw smb_ads_alloc_attr(LDAPMod *attrs[], int num)
7936537f381Sas {
7946537f381Sas 	int i;
7956537f381Sas 
7966537f381Sas 	bzero(attrs, num * sizeof (LDAPMod *));
7976537f381Sas 	for (i = 0; i < (num - 1); i++) {
7986537f381Sas 		attrs[i] = (LDAPMod *)malloc(sizeof (LDAPMod));
7996537f381Sas 		if (attrs[i] == NULL) {
8003db3f65cSamw 			smb_ads_free_attr(attrs);
8016537f381Sas 			return (-1);
8026537f381Sas 		}
8036537f381Sas 	}
8046537f381Sas 
8056537f381Sas 	return (0);
8066537f381Sas }
8076537f381Sas 
8086537f381Sas /*
8093db3f65cSamw  * smb_ads_free_attr
810da6c28aaSamw  * Free memory allocated when publishing a share.
811da6c28aaSamw  * Parameters:
81255bf511dSas  *   attrs: an array of LDAPMod pointers
813da6c28aaSamw  * Returns:
814da6c28aaSamw  *   None
815da6c28aaSamw  */
816da6c28aaSamw static void
smb_ads_free_attr(LDAPMod * attrs[])8173db3f65cSamw smb_ads_free_attr(LDAPMod *attrs[])
818da6c28aaSamw {
819da6c28aaSamw 	int i;
82055bf511dSas 	for (i = 0; attrs[i]; i++) {
82155bf511dSas 		free(attrs[i]);
822da6c28aaSamw 	}
823da6c28aaSamw }
824da6c28aaSamw 
825fe1c642dSBill Krier /*
826fe1c642dSBill Krier  * Returns share DN in an allocated buffer.  The format of the DN is
827fe1c642dSBill Krier  * cn=<sharename>,<container RDNs>,<domain DN>
828fe1c642dSBill Krier  *
829fe1c642dSBill Krier  * If the domain DN is not included in the container parameter,
830fe1c642dSBill Krier  * then it will be appended to create the share DN.
831fe1c642dSBill Krier  *
832fe1c642dSBill Krier  * The caller must free the allocated buffer.
833fe1c642dSBill Krier  */
834fe1c642dSBill Krier static char *
smb_ads_get_sharedn(const char * sharename,const char * container,const char * domain_dn)835fe1c642dSBill Krier smb_ads_get_sharedn(const char *sharename, const char *container,
836fe1c642dSBill Krier     const char *domain_dn)
837fe1c642dSBill Krier {
838fe1c642dSBill Krier 	char *share_dn;
839fe1c642dSBill Krier 	int rc, offset, container_len, domain_len;
840fe1c642dSBill Krier 	boolean_t append_domain = B_TRUE;
841fe1c642dSBill Krier 
842fe1c642dSBill Krier 	container_len = strlen(container);
843fe1c642dSBill Krier 	domain_len = strlen(domain_dn);
844fe1c642dSBill Krier 
845fe1c642dSBill Krier 	if (container_len >= domain_len) {
846fe1c642dSBill Krier 
847fe1c642dSBill Krier 		/* offset to last domain_len characters */
848fe1c642dSBill Krier 		offset = container_len - domain_len;
849fe1c642dSBill Krier 
850fe1c642dSBill Krier 		if (smb_strcasecmp(container + offset,
851fe1c642dSBill Krier 		    domain_dn, domain_len) == 0)
852fe1c642dSBill Krier 			append_domain = B_FALSE;
853fe1c642dSBill Krier 	}
854fe1c642dSBill Krier 
855fe1c642dSBill Krier 	if (append_domain)
856fe1c642dSBill Krier 		rc = asprintf(&share_dn, "cn=%s,%s,%s", sharename,
857fe1c642dSBill Krier 		    container, domain_dn);
858fe1c642dSBill Krier 	else
859fe1c642dSBill Krier 		rc = asprintf(&share_dn, "cn=%s,%s", sharename,
860fe1c642dSBill Krier 		    container);
861fe1c642dSBill Krier 
862fe1c642dSBill Krier 	return ((rc == -1) ? NULL : share_dn);
863fe1c642dSBill Krier }
864fe1c642dSBill Krier 
865da6c28aaSamw /*
8663db3f65cSamw  * smb_ads_add_share
8673db3f65cSamw  * Call by smb_ads_publish_share to create share object in ADS.
868da6c28aaSamw  * This routine specifies the attributes of an ADS LDAP share object. The first
869da6c28aaSamw  * attribute and values define the type of ADS object, the share object.  The
870da6c28aaSamw  * second attribute and value define the UNC of the share data for the share
871da6c28aaSamw  * object. The LDAP synchronous add command is used to add the object into ADS.
872da6c28aaSamw  * The container location to add the object needs to specified.
873da6c28aaSamw  * Parameters:
874da6c28aaSamw  *   ah          : handle to ADS server
875da6c28aaSamw  *   adsShareName: name of share object to be created in ADS
876da6c28aaSamw  *   shareUNC    : share name on NetForce
877da6c28aaSamw  *   adsContainer: location in ADS to create share object
878da6c28aaSamw  *
879da6c28aaSamw  * Returns:
880da6c28aaSamw  *   -1          : error
881da6c28aaSamw  *    0          : success
882da6c28aaSamw  */
883da6c28aaSamw int
smb_ads_add_share(smb_ads_handle_t * ah,const char * adsShareName,const char * unc_name,const char * adsContainer)8843db3f65cSamw smb_ads_add_share(smb_ads_handle_t *ah, const char *adsShareName,
885da6c28aaSamw     const char *unc_name, const char *adsContainer)
886da6c28aaSamw {
8873db3f65cSamw 	LDAPMod *attrs[SMB_ADS_SHARE_NUM_ATTR];
88855bf511dSas 	int j = 0;
889da6c28aaSamw 	char *share_dn;
890fe1c642dSBill Krier 	int ret;
8917f667e74Sjose borrego 	char *unc_names[] = {(char *)unc_name, NULL};
892da6c28aaSamw 
893fe1c642dSBill Krier 	if ((share_dn = smb_ads_get_sharedn(adsShareName, adsContainer,
894fe1c642dSBill Krier 	    ah->domain_dn)) == NULL)
895da6c28aaSamw 		return (-1);
896da6c28aaSamw 
8973db3f65cSamw 	if (smb_ads_alloc_attr(attrs, SMB_ADS_SHARE_NUM_ATTR) != 0) {
8986537f381Sas 		free(share_dn);
8996537f381Sas 		return (-1);
90055bf511dSas 	}
90155bf511dSas 
90255bf511dSas 	attrs[j]->mod_op = LDAP_MOD_ADD;
90355bf511dSas 	attrs[j]->mod_type = "objectClass";
9047f667e74Sjose borrego 	attrs[j]->mod_values = smb_ads_share_objcls;
905da6c28aaSamw 
90655bf511dSas 	attrs[++j]->mod_op = LDAP_MOD_ADD;
90755bf511dSas 	attrs[j]->mod_type = "uNCName";
9087f667e74Sjose borrego 	attrs[j]->mod_values = unc_names;
909da6c28aaSamw 
91055bf511dSas 	if ((ret = ldap_add_s(ah->ld, share_dn, attrs)) != LDAP_SUCCESS) {
9119fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		if (ret == LDAP_NO_SUCH_OBJECT) {
9129fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			syslog(LOG_ERR, "Failed to publish share %s in" \
9139fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			    " AD.  Container does not exist: %s.\n",
9149fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			    adsShareName, share_dn);
9159fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
9169fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		} else {
9179fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			syslog(LOG_ERR, "Failed to publish share %s in" \
9189fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			    " AD: %s (%s).\n", adsShareName, share_dn,
9199fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			    ldap_err2string(ret));
9209fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		}
9213db3f65cSamw 		smb_ads_free_attr(attrs);
922da6c28aaSamw 		free(share_dn);
923da6c28aaSamw 		return (ret);
924da6c28aaSamw 	}
925da6c28aaSamw 	free(share_dn);
9263db3f65cSamw 	smb_ads_free_attr(attrs);
927da6c28aaSamw 
928da6c28aaSamw 	return (0);
929da6c28aaSamw }
930da6c28aaSamw 
931da6c28aaSamw /*
9323db3f65cSamw  * smb_ads_del_share
9333db3f65cSamw  * Call by smb_ads_remove_share to remove share object from ADS.  The container
934da6c28aaSamw  * location to remove the object needs to specified.  The LDAP synchronous
935da6c28aaSamw  * delete command is used.
936da6c28aaSamw  * Parameters:
937da6c28aaSamw  *   ah          : handle to ADS server
938da6c28aaSamw  *   adsShareName: name of share object in ADS to be removed
939da6c28aaSamw  *   adsContainer: location of share object in ADS
940da6c28aaSamw  * Returns:
941da6c28aaSamw  *   -1          : error
942da6c28aaSamw  *    0          : success
943da6c28aaSamw  */
944da6c28aaSamw static int
smb_ads_del_share(smb_ads_handle_t * ah,const char * adsShareName,const char * adsContainer)9453db3f65cSamw smb_ads_del_share(smb_ads_handle_t *ah, const char *adsShareName,
946da6c28aaSamw     const char *adsContainer)
947da6c28aaSamw {
948b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *share_dn;
949fe1c642dSBill Krier 	int ret;
950da6c28aaSamw 
951fe1c642dSBill Krier 	if ((share_dn = smb_ads_get_sharedn(adsShareName, adsContainer,
952fe1c642dSBill Krier 	    ah->domain_dn)) == NULL)
953da6c28aaSamw 		return (-1);
954da6c28aaSamw 
955da6c28aaSamw 	if ((ret = ldap_delete_s(ah->ld, share_dn)) != LDAP_SUCCESS) {
956fc724630SAlan Wright 		smb_tracef("ldap_delete: %s", ldap_err2string(ret));
957da6c28aaSamw 		free(share_dn);
958da6c28aaSamw 		return (-1);
959da6c28aaSamw 	}
960da6c28aaSamw 	free(share_dn);
961da6c28aaSamw 
962da6c28aaSamw 	return (0);
963da6c28aaSamw }
964da6c28aaSamw 
965da6c28aaSamw 
966da6c28aaSamw /*
9673db3f65cSamw  * smb_ads_escape_search_filter_chars
968da6c28aaSamw  *
969da6c28aaSamw  * This routine will escape the special characters found in a string
970da6c28aaSamw  * that will later be passed to the ldap search filter.
971da6c28aaSamw  *
972da6c28aaSamw  * RFC 1960 - A String Representation of LDAP Search Filters
973da6c28aaSamw  * 3.  String Search Filter Definition
974da6c28aaSamw  * If a value must contain one of the characters '*' OR '(' OR ')',
975da6c28aaSamw  * these characters
976da6c28aaSamw  * should be escaped by preceding them with the backslash '\' character.
977da6c28aaSamw  *
978da6c28aaSamw  * RFC 2252 - LDAP Attribute Syntax Definitions
979da6c28aaSamw  * a backslash quoting mechanism is used to escape
980da6c28aaSamw  * the following separator symbol character (such as "'", "$" or "#") if
981da6c28aaSamw  * it should occur in that string.
982da6c28aaSamw  */
983da6c28aaSamw static int
smb_ads_escape_search_filter_chars(const char * src,char * dst)9843db3f65cSamw smb_ads_escape_search_filter_chars(const char *src, char *dst)
985da6c28aaSamw {
9863db3f65cSamw 	int avail = SMB_ADS_MAXBUFLEN - 1; /* reserve a space for NULL char */
987da6c28aaSamw 
988da6c28aaSamw 	if (src == NULL || dst == NULL)
989da6c28aaSamw 		return (-1);
990da6c28aaSamw 
991da6c28aaSamw 	while (*src) {
992da6c28aaSamw 		if (!avail) {
993da6c28aaSamw 			*dst = 0;
994da6c28aaSamw 			return (-1);
995da6c28aaSamw 		}
996da6c28aaSamw 
997da6c28aaSamw 		switch (*src) {
998da6c28aaSamw 		case '\\':
999da6c28aaSamw 		case '\'':
1000da6c28aaSamw 		case '$':
1001da6c28aaSamw 		case '#':
1002da6c28aaSamw 		case '*':
1003da6c28aaSamw 		case '(':
1004da6c28aaSamw 		case ')':
1005da6c28aaSamw 			*dst++ = '\\';
1006da6c28aaSamw 			avail--;
1007da6c28aaSamw 			/* fall through */
1008da6c28aaSamw 
1009da6c28aaSamw 		default:
1010da6c28aaSamw 			*dst++ = *src++;
1011da6c28aaSamw 			avail--;
1012da6c28aaSamw 		}
1013da6c28aaSamw 	}
1014da6c28aaSamw 
1015da6c28aaSamw 	*dst = 0;
1016da6c28aaSamw 
1017da6c28aaSamw 	return (0);
1018da6c28aaSamw }
1019da6c28aaSamw 
1020da6c28aaSamw /*
10213db3f65cSamw  * smb_ads_lookup_share
1022da6c28aaSamw  * The search filter is set to search for a specific share name in the
1023da6c28aaSamw  * specified ADS container.  The LDSAP synchronous search command is used.
1024da6c28aaSamw  * Parameters:
1025da6c28aaSamw  *   ah          : handle to ADS server
1026da6c28aaSamw  *   adsShareName: name of share object in ADS to be searched
1027da6c28aaSamw  *   adsContainer: location of share object in ADS
1028da6c28aaSamw  * Returns:
1029da6c28aaSamw  *   -1          : error
1030da6c28aaSamw  *    0          : not found
1031da6c28aaSamw  *    1          : found
1032da6c28aaSamw  */
1033da6c28aaSamw int
smb_ads_lookup_share(smb_ads_handle_t * ah,const char * adsShareName,const char * adsContainer,char * unc_name)10343db3f65cSamw smb_ads_lookup_share(smb_ads_handle_t *ah, const char *adsShareName,
1035da6c28aaSamw     const char *adsContainer, char *unc_name)
1036da6c28aaSamw {
10373db3f65cSamw 	char *attrs[4], filter[SMB_ADS_MAXBUFLEN];
1038da6c28aaSamw 	char *share_dn;
1039fe1c642dSBill Krier 	int ret;
1040da6c28aaSamw 	LDAPMessage *res;
10413db3f65cSamw 	char tmpbuf[SMB_ADS_MAXBUFLEN];
1042da6c28aaSamw 
1043da6c28aaSamw 	if (adsShareName == NULL || adsContainer == NULL)
1044da6c28aaSamw 		return (-1);
1045da6c28aaSamw 
1046fe1c642dSBill Krier 	if ((share_dn = smb_ads_get_sharedn(adsShareName, adsContainer,
1047fe1c642dSBill Krier 	    ah->domain_dn)) == NULL)
1048da6c28aaSamw 		return (-1);
1049da6c28aaSamw 
1050da6c28aaSamw 	res = NULL;
1051da6c28aaSamw 	attrs[0] = "cn";
1052da6c28aaSamw 	attrs[1] = "objectClass";
1053da6c28aaSamw 	attrs[2] = "uNCName";
1054da6c28aaSamw 	attrs[3] = NULL;
1055da6c28aaSamw 
10563db3f65cSamw 	if (smb_ads_escape_search_filter_chars(unc_name, tmpbuf) != 0) {
1057da6c28aaSamw 		free(share_dn);
1058da6c28aaSamw 		return (-1);
1059da6c28aaSamw 	}
1060da6c28aaSamw 
1061da6c28aaSamw 	(void) snprintf(filter, sizeof (filter),
1062da6c28aaSamw 	    "(&(objectClass=volume)(uNCName=%s))", tmpbuf);
1063da6c28aaSamw 
1064da6c28aaSamw 	if ((ret = ldap_search_s(ah->ld, share_dn,
1065da6c28aaSamw 	    LDAP_SCOPE_BASE, filter, attrs, 0, &res)) != LDAP_SUCCESS) {
1066b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (ret != LDAP_NO_SUCH_OBJECT)
1067fc724630SAlan Wright 			smb_tracef("%s: ldap_search: %s", share_dn,
1068fc724630SAlan Wright 			    ldap_err2string(ret));
1069b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1070da6c28aaSamw 		(void) ldap_msgfree(res);
1071da6c28aaSamw 		free(share_dn);
1072da6c28aaSamw 		return (0);
1073da6c28aaSamw 	}
1074da6c28aaSamw 
1075da6c28aaSamw 	(void) free(share_dn);
1076da6c28aaSamw 
1077da6c28aaSamw 	/* no match is found */
1078da6c28aaSamw 	if (ldap_count_entries(ah->ld, res) == 0) {
1079da6c28aaSamw 		(void) ldap_msgfree(res);
1080da6c28aaSamw 		return (0);
1081da6c28aaSamw 	}
1082da6c28aaSamw 
1083da6c28aaSamw 	/* free the search results */
1084da6c28aaSamw 	(void) ldap_msgfree(res);
1085da6c28aaSamw 
1086da6c28aaSamw 	return (1);
1087da6c28aaSamw }
1088da6c28aaSamw 
1089da6c28aaSamw /*
10903db3f65cSamw  * smb_ads_publish_share
1091da6c28aaSamw  * Publish share into ADS.  If a share name already exist in ADS in the same
1092da6c28aaSamw  * container then the existing share object is removed before adding the new
1093da6c28aaSamw  * share object.
1094da6c28aaSamw  * Parameters:
10953db3f65cSamw  *   ah          : handle return from smb_ads_open
1096da6c28aaSamw  *   adsShareName: name of share to be added to ADS directory
1097da6c28aaSamw  *   shareUNC    : name of share on client, can be NULL to use the same name
1098da6c28aaSamw  *                 as adsShareName
1099da6c28aaSamw  *   adsContainer: location for share to be added in ADS directory, ie
1100da6c28aaSamw  *                   ou=share_folder
1101da6c28aaSamw  *   uncType     : use UNC_HOSTNAME to use hostname for UNC, use UNC_HOSTADDR
1102da6c28aaSamw  *                   to use host ip addr for UNC.
1103da6c28aaSamw  * Returns:
1104da6c28aaSamw  *   -1          : error
1105da6c28aaSamw  *    0          : success
1106da6c28aaSamw  */
1107da6c28aaSamw int
smb_ads_publish_share(smb_ads_handle_t * ah,const char * adsShareName,const char * shareUNC,const char * adsContainer,const char * hostname)11083db3f65cSamw smb_ads_publish_share(smb_ads_handle_t *ah, const char *adsShareName,
1109da6c28aaSamw     const char *shareUNC, const char *adsContainer, const char *hostname)
1110da6c28aaSamw {
1111da6c28aaSamw 	int ret;
11123db3f65cSamw 	char unc_name[SMB_ADS_MAXBUFLEN];
1113da6c28aaSamw 
1114da6c28aaSamw 	if (adsShareName == NULL || adsContainer == NULL)
1115da6c28aaSamw 		return (-1);
1116da6c28aaSamw 
1117da6c28aaSamw 	if (shareUNC == 0 || *shareUNC == 0)
1118da6c28aaSamw 		shareUNC = adsShareName;
1119da6c28aaSamw 
11203db3f65cSamw 	if (smb_ads_build_unc_name(unc_name, sizeof (unc_name),
1121b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    hostname, shareUNC) < 0)
1122da6c28aaSamw 		return (-1);
1123da6c28aaSamw 
11243db3f65cSamw 	ret = smb_ads_lookup_share(ah, adsShareName, adsContainer, unc_name);
1125da6c28aaSamw 
1126da6c28aaSamw 	switch (ret) {
1127da6c28aaSamw 	case 1:
11283db3f65cSamw 		(void) smb_ads_del_share(ah, adsShareName, adsContainer);
11293db3f65cSamw 		ret = smb_ads_add_share(ah, adsShareName, unc_name,
11303db3f65cSamw 		    adsContainer);
1131da6c28aaSamw 		break;
1132da6c28aaSamw 
1133da6c28aaSamw 	case 0:
11343db3f65cSamw 		ret = smb_ads_add_share(ah, adsShareName, unc_name,
11353db3f65cSamw 		    adsContainer);
1136b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (ret == LDAP_ALREADY_EXISTS)
1137da6c28aaSamw 			ret = -1;
1138b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1139da6c28aaSamw 		break;
1140da6c28aaSamw 
1141da6c28aaSamw 	case -1:
1142da6c28aaSamw 	default:
1143da6c28aaSamw 		/* return with error code */
1144da6c28aaSamw 		ret = -1;
1145da6c28aaSamw 	}
1146da6c28aaSamw 
1147da6c28aaSamw 	return (ret);
1148da6c28aaSamw }
1149da6c28aaSamw 
1150da6c28aaSamw /*
11513db3f65cSamw  * smb_ads_remove_share
1152da6c28aaSamw  * Remove share from ADS.  A search is done first before explicitly removing
1153da6c28aaSamw  * the share.
1154da6c28aaSamw  * Parameters:
11553db3f65cSamw  *   ah          : handle return from smb_ads_open
1156da6c28aaSamw  *   adsShareName: name of share to be removed from ADS directory
1157da6c28aaSamw  *   adsContainer: location for share to be removed from ADS directory, ie
1158da6c28aaSamw  *                   ou=share_folder
1159da6c28aaSamw  * Returns:
1160da6c28aaSamw  *   -1          : error
1161da6c28aaSamw  *    0          : success
1162da6c28aaSamw  */
1163da6c28aaSamw int
smb_ads_remove_share(smb_ads_handle_t * ah,const char * adsShareName,const char * shareUNC,const char * adsContainer,const char * hostname)11643db3f65cSamw smb_ads_remove_share(smb_ads_handle_t *ah, const char *adsShareName,
11653db3f65cSamw     const char *shareUNC, const char *adsContainer, const char *hostname)
1166da6c28aaSamw {
1167da6c28aaSamw 	int ret;
11683db3f65cSamw 	char unc_name[SMB_ADS_MAXBUFLEN];
1169da6c28aaSamw 
1170da6c28aaSamw 	if (adsShareName == NULL || adsContainer == NULL)
1171da6c28aaSamw 		return (-1);
1172da6c28aaSamw 	if (shareUNC == 0 || *shareUNC == 0)
1173da6c28aaSamw 		shareUNC = adsShareName;
1174da6c28aaSamw 
11753db3f65cSamw 	if (smb_ads_build_unc_name(unc_name, sizeof (unc_name),
1176b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    hostname, shareUNC) < 0)
1177da6c28aaSamw 		return (-1);
1178da6c28aaSamw 
11793db3f65cSamw 	ret = smb_ads_lookup_share(ah, adsShareName, adsContainer, unc_name);
1180da6c28aaSamw 	if (ret == 0)
1181da6c28aaSamw 		return (0);
1182da6c28aaSamw 	if (ret == -1)
1183da6c28aaSamw 		return (-1);
1184da6c28aaSamw 
11853db3f65cSamw 	return (smb_ads_del_share(ah, adsShareName, adsContainer));
1186da6c28aaSamw }
1187da6c28aaSamw 
1188da6c28aaSamw /*
1189857c33c4SGordon Ross  * smb_ads_get_new_comp_dn
1190da6c28aaSamw  *
1191857c33c4SGordon Ross  * Build the distinguished name for a new machine account
1192857c33c4SGordon Ross  * prepend: cn=SamAccountName, cn=Computers, ...domain_dn...
1193da6c28aaSamw  */
1194da6c28aaSamw static void
smb_ads_get_new_comp_dn(smb_ads_handle_t * ah,char * buf,size_t buflen,char * container)1195857c33c4SGordon Ross smb_ads_get_new_comp_dn(smb_ads_handle_t *ah, char *buf, size_t buflen,
1196857c33c4SGordon Ross     char *container)
1197b89a8333Snatalie li - Sun Microsystems - Irvine United States {
1198b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char nbname[NETBIOS_NAME_SZ];
1199857c33c4SGordon Ross 	if (container == NULL)
1200857c33c4SGordon Ross 		container = "cn=" SMB_ADS_COMPUTERS_CN;
1201b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1202b89a8333Snatalie li - Sun Microsystems - Irvine United States 	(void) smb_getnetbiosname(nbname, sizeof (nbname));
1203857c33c4SGordon Ross 	(void) snprintf(buf, buflen, "cn=%s,%s,%s",
1204857c33c4SGordon Ross 	    nbname, container, ah->domain_dn);
1205da6c28aaSamw }
1206da6c28aaSamw 
1207da6c28aaSamw /*
12083db3f65cSamw  * smb_ads_add_computer
1209da6c28aaSamw  *
1210da6c28aaSamw  * Returns 0 upon success. Otherwise, returns -1.
1211da6c28aaSamw  */
1212da6c28aaSamw static int
smb_ads_add_computer(smb_ads_handle_t * ah,int dclevel,char * dn)1213c8ec8eeaSjose borrego smb_ads_add_computer(smb_ads_handle_t *ah, int dclevel, char *dn)
1214da6c28aaSamw {
1215c8ec8eeaSjose borrego 	return (smb_ads_computer_op(ah, LDAP_MOD_ADD, dclevel, dn));
121655bf511dSas }
121755bf511dSas 
121855bf511dSas /*
12193db3f65cSamw  * smb_ads_modify_computer
122055bf511dSas  *
122155bf511dSas  * Returns 0 upon success. Otherwise, returns -1.
122255bf511dSas  */
122355bf511dSas static int
smb_ads_modify_computer(smb_ads_handle_t * ah,int dclevel,char * dn)1224c8ec8eeaSjose borrego smb_ads_modify_computer(smb_ads_handle_t *ah, int dclevel, char *dn)
122555bf511dSas {
1226c8ec8eeaSjose borrego 	return (smb_ads_computer_op(ah, LDAP_MOD_REPLACE, dclevel, dn));
122755bf511dSas }
122855bf511dSas 
12293db3f65cSamw /*
12303db3f65cSamw  * smb_ads_get_dc_level
12313db3f65cSamw  *
12323db3f65cSamw  * Returns the functional level of the DC upon success.
12333db3f65cSamw  * Otherwise, -1 is returned.
12343db3f65cSamw  */
123555bf511dSas static int
smb_ads_get_dc_level(smb_ads_handle_t * ah)12363db3f65cSamw smb_ads_get_dc_level(smb_ads_handle_t *ah)
123755bf511dSas {
12383db3f65cSamw 	LDAPMessage *res, *entry;
12393db3f65cSamw 	char *attr[2];
12403db3f65cSamw 	char **vals;
12416a23a4b8SGordon Ross 	int rc;
12423db3f65cSamw 
12433db3f65cSamw 	res = NULL;
12443db3f65cSamw 	attr[0] = SMB_ADS_ATTR_DCLEVEL;
12453db3f65cSamw 	attr[1] = NULL;
12466a23a4b8SGordon Ross 	rc = ldap_search_s(ah->ld, "", LDAP_SCOPE_BASE, NULL, attr, 0, &res);
12476a23a4b8SGordon Ross 	if (rc != LDAP_SUCCESS) {
12486a23a4b8SGordon Ross 		syslog(LOG_ERR, "smb_ads_get_dc_level: "
12496a23a4b8SGordon Ross 		    "LDAP search,  error %s", ldap_err2string(rc));
12503db3f65cSamw 		(void) ldap_msgfree(res);
12513db3f65cSamw 		return (-1);
12523db3f65cSamw 	}
12533db3f65cSamw 
12543db3f65cSamw 	/* no match for the specified attribute is found */
12553db3f65cSamw 	if (ldap_count_entries(ah->ld, res) == 0) {
12563db3f65cSamw 		(void) ldap_msgfree(res);
12573db3f65cSamw 		return (-1);
12583db3f65cSamw 	}
12593db3f65cSamw 
12606a23a4b8SGordon Ross 	rc = -1;
12613db3f65cSamw 	entry = ldap_first_entry(ah->ld, res);
12623db3f65cSamw 	if (entry) {
12633db3f65cSamw 		if ((vals = ldap_get_values(ah->ld, entry,
12643db3f65cSamw 		    SMB_ADS_ATTR_DCLEVEL)) == NULL) {
12653db3f65cSamw 			/*
12663db3f65cSamw 			 * Observed the values aren't populated
12673db3f65cSamw 			 * by the Windows 2000 server.
12683db3f65cSamw 			 */
12696a23a4b8SGordon Ross 			syslog(LOG_DEBUG, "smb_ads_get_dc_level: "
12706a23a4b8SGordon Ross 			    "LDAP values missing, assume W2K");
12713db3f65cSamw 			(void) ldap_msgfree(res);
12723db3f65cSamw 			return (SMB_ADS_DCLEVEL_W2K);
12733db3f65cSamw 		}
12743db3f65cSamw 
12756a23a4b8SGordon Ross 		if (vals[0] != NULL) {
12763db3f65cSamw 			rc = atoi(vals[0]);
12776a23a4b8SGordon Ross 			syslog(LOG_DEBUG, "smb_ads_get_dc_level: "
12786a23a4b8SGordon Ross 			    "LDAP value %d", rc);
12796a23a4b8SGordon Ross 		}
12803db3f65cSamw 		ldap_value_free(vals);
12813db3f65cSamw 	}
12823db3f65cSamw 
12833db3f65cSamw 	(void) ldap_msgfree(res);
12843db3f65cSamw 	return (rc);
12853db3f65cSamw }
12863db3f65cSamw 
12879fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /*
12889fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * The fully-qualified hostname returned by this function is often used for
12899fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * constructing service principal name.  Return the fully-qualified hostname
12909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * in lower case for RFC 4120 section 6.2.1 conformance.
12919fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  */
1292b89a8333Snatalie li - Sun Microsystems - Irvine United States static int
smb_ads_getfqhostname(smb_ads_handle_t * ah,char * fqhost,int len)1293b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_getfqhostname(smb_ads_handle_t *ah, char *fqhost, int len)
1294b89a8333Snatalie li - Sun Microsystems - Irvine United States {
12959fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_gethostname(fqhost, len, SMB_CASE_LOWER) != 0)
1296b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (-1);
1297b89a8333Snatalie li - Sun Microsystems - Irvine United States 
129879059601SToomas Soome 	(void) strlcat(fqhost, ".", len);
129979059601SToomas Soome 	(void) strlcat(fqhost, ah->domain, len);
1300b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1301b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (0);
1302b89a8333Snatalie li - Sun Microsystems - Irvine United States }
1303b89a8333Snatalie li - Sun Microsystems - Irvine United States 
13043db3f65cSamw static int
smb_ads_computer_op(smb_ads_handle_t * ah,int op,int dclevel,char * dn)1305c8ec8eeaSjose borrego smb_ads_computer_op(smb_ads_handle_t *ah, int op, int dclevel, char *dn)
13063db3f65cSamw {
13073db3f65cSamw 	LDAPMod *attrs[SMB_ADS_COMPUTER_NUM_ATTR];
1308148c5f43SAlan Wright 	char *sam_val[2];
1309148c5f43SAlan Wright 	char *ctl_val[2], *fqh_val[2];
13103db3f65cSamw 	char *encrypt_val[2];
13116537f381Sas 	int j = -1;
1312da6c28aaSamw 	int ret, usrctl_flags = 0;
1313b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char sam_acct[SMB_SAMACCT_MAXLEN];
1314da6c28aaSamw 	char fqhost[MAXHOSTNAMELEN];
1315da6c28aaSamw 	char usrctl_buf[16];
13163db3f65cSamw 	char encrypt_buf[16];
131755bf511dSas 	int max;
1318148c5f43SAlan Wright 	smb_krb5_pn_set_t spn, upn;
1319da6c28aaSamw 
13206a23a4b8SGordon Ross 	syslog(LOG_DEBUG, "smb_ads_computer_op, op=%s dn=%s",
13216a23a4b8SGordon Ross 	    (op == LDAP_MOD_ADD) ? "add" : "replace", dn);
13226a23a4b8SGordon Ross 
1323b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (smb_getsamaccount(sam_acct, sizeof (sam_acct)) != 0)
1324da6c28aaSamw 		return (-1);
1325da6c28aaSamw 
1326b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (smb_ads_getfqhostname(ah, fqhost, MAXHOSTNAMELEN))
1327b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (-1);
1328da6c28aaSamw 
1329148c5f43SAlan Wright 	/* The SPN attribute is multi-valued and must be 1 or greater */
1330148c5f43SAlan Wright 	if (smb_krb5_get_pn_set(&spn, SMB_PN_SPN_ATTR, ah->domain) == 0)
13316537f381Sas 		return (-1);
13326537f381Sas 
1333148c5f43SAlan Wright 	/* The UPN attribute is single-valued and cannot be zero */
1334148c5f43SAlan Wright 	if (smb_krb5_get_pn_set(&upn, SMB_PN_UPN_ATTR, ah->domain) != 1) {
1335148c5f43SAlan Wright 		smb_krb5_free_pn_set(&spn);
1336148c5f43SAlan Wright 		smb_krb5_free_pn_set(&upn);
1337da6c28aaSamw 		return (-1);
1338da6c28aaSamw 	}
1339da6c28aaSamw 
13403db3f65cSamw 	max = (SMB_ADS_COMPUTER_NUM_ATTR - ((op != LDAP_MOD_ADD) ? 1 : 0))
1341b1352070SAlan Wright 	    - (dclevel >= SMB_ADS_DCLEVEL_W2K8 ?  0 : 1);
13426537f381Sas 
13433db3f65cSamw 	if (smb_ads_alloc_attr(attrs, max) != 0) {
1344148c5f43SAlan Wright 		smb_krb5_free_pn_set(&spn);
1345148c5f43SAlan Wright 		smb_krb5_free_pn_set(&upn);
13466537f381Sas 		return (-1);
134755bf511dSas 	}
1348da6c28aaSamw 
134955bf511dSas 	/* objectClass attribute is not modifiable. */
135055bf511dSas 	if (op == LDAP_MOD_ADD) {
135155bf511dSas 		attrs[++j]->mod_op = op;
135255bf511dSas 		attrs[j]->mod_type = "objectClass";
13537f667e74Sjose borrego 		attrs[j]->mod_values = smb_ads_computer_objcls;
135455bf511dSas 	}
135555bf511dSas 
135655bf511dSas 	attrs[++j]->mod_op = op;
13573db3f65cSamw 	attrs[j]->mod_type = SMB_ADS_ATTR_SAMACCT;
1358da6c28aaSamw 	sam_val[0] = sam_acct;
1359da6c28aaSamw 	sam_val[1] = 0;
136055bf511dSas 	attrs[j]->mod_values = sam_val;
1361da6c28aaSamw 
136255bf511dSas 	attrs[++j]->mod_op = op;
13633db3f65cSamw 	attrs[j]->mod_type = SMB_ADS_ATTR_UPN;
1364148c5f43SAlan Wright 	attrs[j]->mod_values = upn.s_pns;
1365da6c28aaSamw 
136655bf511dSas 	attrs[++j]->mod_op = op;
13673db3f65cSamw 	attrs[j]->mod_type = SMB_ADS_ATTR_SPN;
1368148c5f43SAlan Wright 	attrs[j]->mod_values =  spn.s_pns;
1369da6c28aaSamw 
137055bf511dSas 	attrs[++j]->mod_op = op;
13713db3f65cSamw 	attrs[j]->mod_type = SMB_ADS_ATTR_CTL;
13723db3f65cSamw 	usrctl_flags |= (SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT |
13733db3f65cSamw 	    SMB_ADS_USER_ACCT_CTL_PASSWD_NOTREQD |
13743db3f65cSamw 	    SMB_ADS_USER_ACCT_CTL_ACCOUNTDISABLE);
1375da6c28aaSamw 	(void) snprintf(usrctl_buf, sizeof (usrctl_buf), "%d", usrctl_flags);
1376da6c28aaSamw 	ctl_val[0] = usrctl_buf;
1377da6c28aaSamw 	ctl_val[1] = 0;
137855bf511dSas 	attrs[j]->mod_values = ctl_val;
1379da6c28aaSamw 
138055bf511dSas 	attrs[++j]->mod_op = op;
13813db3f65cSamw 	attrs[j]->mod_type = SMB_ADS_ATTR_DNSHOST;
1382da6c28aaSamw 	fqh_val[0] = fqhost;
1383da6c28aaSamw 	fqh_val[1] = 0;
138455bf511dSas 	attrs[j]->mod_values = fqh_val;
138555bf511dSas 
13863db3f65cSamw 	/* enctypes support starting in Windows Server 2008 */
13873db3f65cSamw 	if (dclevel > SMB_ADS_DCLEVEL_W2K3) {
13883db3f65cSamw 		attrs[++j]->mod_op = op;
13893db3f65cSamw 		attrs[j]->mod_type = SMB_ADS_ATTR_ENCTYPES;
13903db3f65cSamw 		(void) snprintf(encrypt_buf, sizeof (encrypt_buf), "%d",
13913db3f65cSamw 		    SMB_ADS_ENC_AES256 + SMB_ADS_ENC_AES128 + SMB_ADS_ENC_RC4 +
13923db3f65cSamw 		    SMB_ADS_ENC_DES_MD5 + SMB_ADS_ENC_DES_CRC);
13933db3f65cSamw 		encrypt_val[0] = encrypt_buf;
13943db3f65cSamw 		encrypt_val[1] = 0;
13953db3f65cSamw 		attrs[j]->mod_values = encrypt_val;
13963db3f65cSamw 	}
13973db3f65cSamw 
139855bf511dSas 	switch (op) {
139955bf511dSas 	case LDAP_MOD_ADD:
140055bf511dSas 		if ((ret = ldap_add_s(ah->ld, dn, attrs)) != LDAP_SUCCESS) {
1401fc724630SAlan Wright 			syslog(LOG_NOTICE, "ldap_add: %s",
140255bf511dSas 			    ldap_err2string(ret));
140355bf511dSas 			ret = -1;
140455bf511dSas 		}
140555bf511dSas 		break;
140655bf511dSas 
140755bf511dSas 	case LDAP_MOD_REPLACE:
140855bf511dSas 		if ((ret = ldap_modify_s(ah->ld, dn, attrs)) != LDAP_SUCCESS) {
1409fc724630SAlan Wright 			syslog(LOG_NOTICE, "ldap_modify: %s",
141055bf511dSas 			    ldap_err2string(ret));
141155bf511dSas 			ret = -1;
141255bf511dSas 		}
141355bf511dSas 		break;
1414da6c28aaSamw 
141555bf511dSas 	default:
1416da6c28aaSamw 		ret = -1;
141755bf511dSas 
1418da6c28aaSamw 	}
1419da6c28aaSamw 
14203db3f65cSamw 	smb_ads_free_attr(attrs);
1421148c5f43SAlan Wright 	smb_krb5_free_pn_set(&spn);
1422148c5f43SAlan Wright 	smb_krb5_free_pn_set(&upn);
1423da6c28aaSamw 
1424da6c28aaSamw 	return (ret);
1425da6c28aaSamw }
1426da6c28aaSamw 
1427da6c28aaSamw /*
1428da6c28aaSamw  * Delete an ADS computer account.
1429da6c28aaSamw  */
1430da6c28aaSamw static void
smb_ads_del_computer(smb_ads_handle_t * ah,char * dn)1431c8ec8eeaSjose borrego smb_ads_del_computer(smb_ads_handle_t *ah, char *dn)
1432da6c28aaSamw {
1433da6c28aaSamw 	int rc;
1434da6c28aaSamw 
14353db3f65cSamw 	if ((rc = ldap_delete_s(ah->ld, dn)) != LDAP_SUCCESS)
1436fc724630SAlan Wright 		smb_tracef("ldap_delete: %s", ldap_err2string(rc));
1437b89a8333Snatalie li - Sun Microsystems - Irvine United States }
1438b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1439b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
1440b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Gets the value of the given attribute.
1441b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
1442b89a8333Snatalie li - Sun Microsystems - Irvine United States static smb_ads_qstat_t
smb_ads_getattr(LDAP * ld,LDAPMessage * entry,smb_ads_avpair_t * avpair)1443b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_getattr(LDAP *ld, LDAPMessage *entry, smb_ads_avpair_t *avpair)
1444b89a8333Snatalie li - Sun Microsystems - Irvine United States {
1445b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char **vals;
1446b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_qstat_t rc = SMB_ADS_STAT_FOUND;
1447b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1448b89a8333Snatalie li - Sun Microsystems - Irvine United States 	assert(avpair);
1449b89a8333Snatalie li - Sun Microsystems - Irvine United States 	avpair->avp_val = NULL;
14506a23a4b8SGordon Ross 
14516a23a4b8SGordon Ross 	syslog(LOG_DEBUG, "smbns: ads_getattr (%s)", avpair->avp_attr);
1452b89a8333Snatalie li - Sun Microsystems - Irvine United States 	vals = ldap_get_values(ld, entry, avpair->avp_attr);
14536a23a4b8SGordon Ross 	if (!vals) {
14546a23a4b8SGordon Ross 		syslog(LOG_DEBUG, "smbns: ads_getattr err: no vals");
1455b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (SMB_ADS_STAT_NOT_FOUND);
14566a23a4b8SGordon Ross 	}
1457b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (!vals[0]) {
14586a23a4b8SGordon Ross 		syslog(LOG_DEBUG, "smbns: ads_getattr err: no vals[0]");
1459b89a8333Snatalie li - Sun Microsystems - Irvine United States 		ldap_value_free(vals);
1460b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (SMB_ADS_STAT_NOT_FOUND);
1461b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
1462b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1463b89a8333Snatalie li - Sun Microsystems - Irvine United States 	avpair->avp_val = strdup(vals[0]);
14646a23a4b8SGordon Ross 	if (!avpair->avp_val) {
14656a23a4b8SGordon Ross 		syslog(LOG_DEBUG, "smbns: ads_getattr err: no mem");
1466b89a8333Snatalie li - Sun Microsystems - Irvine United States 		rc = SMB_ADS_STAT_ERR;
14676a23a4b8SGordon Ross 	} else {
14686a23a4b8SGordon Ross 		syslog(LOG_DEBUG, "smbns: ads_getattr (%s) OK, val=%s",
14696a23a4b8SGordon Ross 		    avpair->avp_attr, avpair->avp_val);
14706a23a4b8SGordon Ross 	}
1471b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1472b89a8333Snatalie li - Sun Microsystems - Irvine United States 	ldap_value_free(vals);
1473b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (rc);
1474b89a8333Snatalie li - Sun Microsystems - Irvine United States }
1475b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1476b89a8333Snatalie li - Sun Microsystems - Irvine United States /*
14776a23a4b8SGordon Ross  * Process query's result, making sure we have what we need.
14786a23a4b8SGordon Ross  *
14796a23a4b8SGordon Ross  * There's some non-obvious logic here for checking the returned
14806a23a4b8SGordon Ross  * DNS name for the machine account, trying to avoid modifying
14816a23a4b8SGordon Ross  * someone else's machine account.  When we search for a machine
14826a23a4b8SGordon Ross  * account we always ask for the DNS name.  For a pre-created
14836a23a4b8SGordon Ross  * machine account, the DNS name will be not set, and that's OK.
14846a23a4b8SGordon Ross  * If we see a DNS name and it doesn't match our DNS name, we'll
14856a23a4b8SGordon Ross  * assume the account belongs to someone else and return "DUP".
1486857c33c4SGordon Ross  *
1487857c33c4SGordon Ross  * Only do the DNS name check for our initial search for the
1488857c33c4SGordon Ross  * machine account, which has avpair->avp_attr = SMB_ADS_ATTR_DN
1489b89a8333Snatalie li - Sun Microsystems - Irvine United States  */
1490b89a8333Snatalie 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)1491b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_get_qstat(smb_ads_handle_t *ah, LDAPMessage *res,
1492b89a8333Snatalie li - Sun Microsystems - Irvine United States     smb_ads_avpair_t *avpair)
1493b89a8333Snatalie li - Sun Microsystems - Irvine United States {
1494b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_qstat_t rc = SMB_ADS_STAT_FOUND;
1495b89a8333Snatalie li - Sun Microsystems - Irvine United States 	LDAPMessage *entry;
1496b89a8333Snatalie li - Sun Microsystems - Irvine United States 
14976a23a4b8SGordon Ross 	if (ldap_count_entries(ah->ld, res) == 0) {
14986a23a4b8SGordon Ross 		syslog(LOG_DEBUG, "smbns: find_computer, "
14996a23a4b8SGordon Ross 		    "ldap_count_entries zero");
1500b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (SMB_ADS_STAT_NOT_FOUND);
15016a23a4b8SGordon Ross 	}
1502b89a8333Snatalie li - Sun Microsystems - Irvine United States 
15036a23a4b8SGordon Ross 	if ((entry = ldap_first_entry(ah->ld, res)) == NULL) {
15046a23a4b8SGordon Ross 		syslog(LOG_DEBUG, "smbns: find_computer, "
15056a23a4b8SGordon Ross 		    "ldap_first_entry error");
1506b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (SMB_ADS_STAT_ERR);
15076a23a4b8SGordon Ross 	}
1508b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1509857c33c4SGordon Ross 	/* Have an LDAP entry (found something) */
1510857c33c4SGordon Ross 	syslog(LOG_DEBUG, "smbns: find_computer, have LDAP resp.");
1511b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1512857c33c4SGordon Ross 	if (avpair != NULL &&
1513857c33c4SGordon Ross 	    strcmp(avpair->avp_attr, SMB_ADS_ATTR_DN) == 0) {
1514857c33c4SGordon Ross 		char fqhost[MAXHOSTNAMELEN];
1515857c33c4SGordon Ross 		smb_ads_avpair_t dnshost_avp;
1516857c33c4SGordon Ross 
1517857c33c4SGordon Ross 		syslog(LOG_DEBUG, "smbns: find_computer, check DNS name");
1518857c33c4SGordon Ross 
1519857c33c4SGordon Ross 		if (smb_ads_getfqhostname(ah, fqhost, MAXHOSTNAMELEN))
1520857c33c4SGordon Ross 			return (SMB_ADS_STAT_ERR);
1521857c33c4SGordon Ross 
1522857c33c4SGordon Ross 		dnshost_avp.avp_attr = SMB_ADS_ATTR_DNSHOST;
1523857c33c4SGordon Ross 		dnshost_avp.avp_val = NULL;
1524857c33c4SGordon Ross 		rc = smb_ads_getattr(ah->ld, entry, &dnshost_avp);
1525b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1526b89a8333Snatalie li - Sun Microsystems - Irvine United States 		/*
1527857c33c4SGordon Ross 		 * Status from finding the DNS name value
1528b89a8333Snatalie li - Sun Microsystems - Irvine United States 		 */
1529857c33c4SGordon Ross 		switch (rc) {
1530857c33c4SGordon Ross 		case SMB_ADS_STAT_FOUND:
1531857c33c4SGordon Ross 			/*
1532857c33c4SGordon Ross 			 * Found a DNS name.  If it doesn't match ours,
1533857c33c4SGordon Ross 			 * returns SMB_ADS_STAT_DUP to avoid overwriting
1534857c33c4SGordon Ross 			 * the computer account of another system whose
1535857c33c4SGordon Ross 			 * NetBIOS name collides with that of the current
1536857c33c4SGordon Ross 			 * system.
1537857c33c4SGordon Ross 			 */
1538857c33c4SGordon Ross 			if (strcasecmp(dnshost_avp.avp_val, fqhost)) {
1539857c33c4SGordon Ross 				syslog(LOG_DEBUG, "smbns: find_computer, "
1540857c33c4SGordon Ross 				    "duplicate name (%s)",
1541857c33c4SGordon Ross 				    dnshost_avp.avp_val);
1542857c33c4SGordon Ross 				rc = SMB_ADS_STAT_DUP;
1543857c33c4SGordon Ross 			}
1544857c33c4SGordon Ross 			free(dnshost_avp.avp_val);
1545857c33c4SGordon Ross 			break;
1546857c33c4SGordon Ross 
1547857c33c4SGordon Ross 		case SMB_ADS_STAT_NOT_FOUND:
1548857c33c4SGordon Ross 			/*
1549857c33c4SGordon Ross 			 * No dNSHostname attribute, so probably a
1550857c33c4SGordon Ross 			 * pre-created computer account.  Use it.
1551857c33c4SGordon Ross 			 *
1552857c33c4SGordon Ross 			 * Returns SMB_ADS_STAT_FOUND for the status
1553857c33c4SGordon Ross 			 * of finding the machine account.
1554857c33c4SGordon Ross 			 */
1555857c33c4SGordon Ross 			rc = SMB_ADS_STAT_FOUND;
1556857c33c4SGordon Ross 			break;
1557b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1558857c33c4SGordon Ross 		default:
1559857c33c4SGordon Ross 			break;
1560857c33c4SGordon Ross 		}
1561b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1562857c33c4SGordon Ross 		if (rc != SMB_ADS_STAT_FOUND)
1563857c33c4SGordon Ross 			return (rc);
1564857c33c4SGordon Ross 	}
1565b89a8333Snatalie li - Sun Microsystems - Irvine United States 
15666a23a4b8SGordon Ross 	if (avpair) {
15676a23a4b8SGordon Ross 		syslog(LOG_DEBUG, "smbns: find_computer, check %s",
15686a23a4b8SGordon Ross 		    avpair->avp_attr);
1569b89a8333Snatalie li - Sun Microsystems - Irvine United States 		rc = smb_ads_getattr(ah->ld, entry, avpair);
15706a23a4b8SGordon Ross 	}
1571b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1572b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (rc);
1573da6c28aaSamw }
1574da6c28aaSamw 
1575da6c28aaSamw /*
15763db3f65cSamw  * smb_ads_lookup_computer_n_attr
1577da6c28aaSamw  *
1578b89a8333Snatalie li - Sun Microsystems - Irvine United States  * If avpair is NULL, checks the status of the specified computer account.
1579b89a8333Snatalie li - Sun Microsystems - Irvine United States  * Otherwise, looks up the value of the specified computer account's attribute.
1580b89a8333Snatalie li - Sun Microsystems - Irvine United States  * If found, the value field of the avpair will be allocated and set. The
15816a23a4b8SGordon Ross  * caller should free the allocated buffer.  Caller avpair requests are:
15826a23a4b8SGordon Ross  *   smb_ads_find_computer() asks for SMB_ADS_ATTR_DN
15836a23a4b8SGordon Ross  *   smb_ads_lookup_computer_attr_kvno() SMB_ADS_ATTR_KVNO
1584da6c28aaSamw  *
1585da6c28aaSamw  * Return:
1586b89a8333Snatalie li - Sun Microsystems - Irvine United States  *  SMB_ADS_STAT_FOUND  - if both the computer and the specified attribute is
1587b89a8333Snatalie li - Sun Microsystems - Irvine United States  *                        found.
1588b89a8333Snatalie li - Sun Microsystems - Irvine United States  *  SMB_ADS_STAT_NOT_FOUND - if either the computer or the specified attribute
1589b89a8333Snatalie li - Sun Microsystems - Irvine United States  *                           is not found.
1590b89a8333Snatalie li - Sun Microsystems - Irvine United States  *  SMB_ADS_STAT_DUP - if the computer account is already used by other systems
1591b89a8333Snatalie li - Sun Microsystems - Irvine United States  *                     in the AD. This could happen if the hostname of multiple
1592b89a8333Snatalie li - Sun Microsystems - Irvine United States  *                     systems resolved to the same NetBIOS name.
1593b89a8333Snatalie li - Sun Microsystems - Irvine United States  *  SMB_ADS_STAT_ERR - any failure.
1594da6c28aaSamw  */
1595b89a8333Snatalie 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)1596b89a8333Snatalie li - Sun Microsystems - Irvine United States smb_ads_lookup_computer_n_attr(smb_ads_handle_t *ah, smb_ads_avpair_t *avpair,
1597c8ec8eeaSjose borrego     int scope, char *dn)
1598da6c28aaSamw {
1599b89a8333Snatalie li - Sun Microsystems - Irvine United States 	char *attrs[3], filter[SMB_ADS_MAXBUFLEN];
1600b89a8333Snatalie li - Sun Microsystems - Irvine United States 	LDAPMessage *res;
160111fb28bcSGordon Ross 	char sam_acct[SMB_SAMACCT_MAXLEN];
160211fb28bcSGordon Ross 	char tmpbuf[SMB_ADS_MAXBUFLEN];
1603b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_qstat_t rc;
16046a23a4b8SGordon Ross 	int err;
1605da6c28aaSamw 
1606b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (smb_getsamaccount(sam_acct, sizeof (sam_acct)) != 0)
1607b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (SMB_ADS_STAT_ERR);
1608da6c28aaSamw 
1609da6c28aaSamw 	res = NULL;
1610b89a8333Snatalie li - Sun Microsystems - Irvine United States 	attrs[0] = SMB_ADS_ATTR_DNSHOST;
1611da6c28aaSamw 	attrs[1] = NULL;
1612b89a8333Snatalie li - Sun Microsystems - Irvine United States 	attrs[2] = NULL;
1613da6c28aaSamw 
1614b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (avpair) {
1615b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (!avpair->avp_attr)
1616b89a8333Snatalie li - Sun Microsystems - Irvine United States 			return (SMB_ADS_STAT_ERR);
1617b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1618b89a8333Snatalie li - Sun Microsystems - Irvine United States 		attrs[1] = avpair->avp_attr;
1619b89a8333Snatalie li - Sun Microsystems - Irvine United States 	}
1620b89a8333Snatalie li - Sun Microsystems - Irvine United States 
162111fb28bcSGordon Ross 	if (smb_ads_escape_search_filter_chars(sam_acct, tmpbuf) != 0)
1622b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (SMB_ADS_STAT_ERR);
1623da6c28aaSamw 
1624c8ec8eeaSjose borrego 	(void) snprintf(filter, sizeof (filter),
162511fb28bcSGordon Ross 	    "(&(objectClass=computer)(%s=%s))",
162611fb28bcSGordon Ross 	    SMB_ADS_ATTR_SAMACCT, tmpbuf);
1627da6c28aaSamw 
16286a23a4b8SGordon Ross 	syslog(LOG_DEBUG, "smbns: lookup_computer, "
16296a23a4b8SGordon Ross 	    "dn=%s, scope=%d", dn, scope);
16306a23a4b8SGordon Ross 	syslog(LOG_DEBUG, "smbns: lookup_computer, "
16316a23a4b8SGordon Ross 	    "filter=%s", filter);
16326a23a4b8SGordon Ross 	syslog(LOG_DEBUG, "smbns: lookup_computer, "
16336a23a4b8SGordon Ross 	    "attrs[0]=%s", attrs[0]);
16346a23a4b8SGordon Ross 	syslog(LOG_DEBUG, "smbns: lookup_computer, "
16356a23a4b8SGordon Ross 	    "attrs[1]=%s", attrs[1] ? attrs[1] : "");
16366a23a4b8SGordon Ross 
16376a23a4b8SGordon Ross 	err = ldap_search_s(ah->ld, dn, scope, filter, attrs, 0, &res);
16386a23a4b8SGordon Ross 	if (err != LDAP_SUCCESS) {
16396a23a4b8SGordon Ross 		syslog(LOG_DEBUG, "smbns: lookup_computer, "
16406a23a4b8SGordon Ross 		    "LDAP search failed, dn=(%s), scope=%d, err=%s",
16416a23a4b8SGordon Ross 		    dn, scope, ldap_err2string(err));
1642da6c28aaSamw 		(void) ldap_msgfree(res);
1643b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (SMB_ADS_STAT_NOT_FOUND);
1644da6c28aaSamw 	}
16456a23a4b8SGordon Ross 	syslog(LOG_DEBUG, "smbns: find_computer, ldap_search OK");
1646da6c28aaSamw 
1647b89a8333Snatalie li - Sun Microsystems - Irvine United States 	rc = smb_ads_get_qstat(ah, res, avpair);
16486a23a4b8SGordon Ross 	if (rc == SMB_ADS_STAT_FOUND) {
16496a23a4b8SGordon Ross 		syslog(LOG_DEBUG, "smbns: find_computer, attr %s = %s",
16506a23a4b8SGordon Ross 		    avpair->avp_attr, avpair->avp_val);
16516a23a4b8SGordon Ross 	} else {
16526a23a4b8SGordon Ross 		syslog(LOG_DEBUG, "smbns: find_computer, "
16536a23a4b8SGordon Ross 		    "get query status, error %d", rc);
16546a23a4b8SGordon Ross 	}
16556a23a4b8SGordon Ross 
1656da6c28aaSamw 	/* free the search results */
1657da6c28aaSamw 	(void) ldap_msgfree(res);
16586a23a4b8SGordon Ross 
1659b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (rc);
1660da6c28aaSamw }
1661da6c28aaSamw 
1662da6c28aaSamw /*
16633db3f65cSamw  * smb_ads_find_computer
1664da6c28aaSamw  *
1665857c33c4SGordon Ross  * Searches the directory for the machine account (SamAccountName)
1666857c33c4SGordon Ross  * If found, 'dn' will be set to the distinguished name of the system's
1667857c33c4SGordon Ross  * AD computer object.
1668da6c28aaSamw  */
1669b89a8333Snatalie li - Sun Microsystems - Irvine United States static smb_ads_qstat_t
smb_ads_find_computer(smb_ads_handle_t * ah,char * dn)1670c8ec8eeaSjose borrego smb_ads_find_computer(smb_ads_handle_t *ah, char *dn)
1671da6c28aaSamw {
1672b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_qstat_t stat;
1673b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_avpair_t avpair;
1674c8ec8eeaSjose borrego 
1675b89a8333Snatalie li - Sun Microsystems - Irvine United States 	avpair.avp_attr = SMB_ADS_ATTR_DN;
16766a23a4b8SGordon Ross 	avpair.avp_val = NULL;
16776a23a4b8SGordon Ross 
1678857c33c4SGordon Ross 	(void) strlcpy(dn, ah->domain_dn, SMB_ADS_DN_MAX);
1679857c33c4SGordon Ross 	stat = smb_ads_lookup_computer_n_attr(ah, &avpair,
1680857c33c4SGordon Ross 	    LDAP_SCOPE_SUBTREE, dn);
1681c8ec8eeaSjose borrego 
1682b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (stat == SMB_ADS_STAT_FOUND) {
1683b89a8333Snatalie li - Sun Microsystems - Irvine United States 		(void) strlcpy(dn, avpair.avp_val, SMB_ADS_DN_MAX);
1684b89a8333Snatalie li - Sun Microsystems - Irvine United States 		free(avpair.avp_val);
1685c8ec8eeaSjose borrego 	}
1686c8ec8eeaSjose borrego 
1687b89a8333Snatalie li - Sun Microsystems - Irvine United States 	return (stat);
1688da6c28aaSamw }
1689da6c28aaSamw 
1690da6c28aaSamw /*
16913db3f65cSamw  * smb_ads_update_computer_cntrl_attr
1692da6c28aaSamw  *
1693da6c28aaSamw  * Modify the user account control attribute of an existing computer
1694da6c28aaSamw  * object on AD.
1695da6c28aaSamw  *
16967f667e74Sjose borrego  * Returns LDAP error code.
1697da6c28aaSamw  */
1698da6c28aaSamw static int
smb_ads_update_computer_cntrl_attr(smb_ads_handle_t * ah,int flags,char * dn)16997f667e74Sjose borrego smb_ads_update_computer_cntrl_attr(smb_ads_handle_t *ah, int flags, char *dn)
1700da6c28aaSamw {
17016537f381Sas 	LDAPMod *attrs[2];
1702da6c28aaSamw 	char *ctl_val[2];
17037f667e74Sjose borrego 	int ret = 0;
1704da6c28aaSamw 	char usrctl_buf[16];
1705da6c28aaSamw 
17063db3f65cSamw 	if (smb_ads_alloc_attr(attrs, sizeof (attrs) / sizeof (LDAPMod *)) != 0)
17077f667e74Sjose borrego 		return (LDAP_NO_MEMORY);
17086537f381Sas 
17096537f381Sas 	attrs[0]->mod_op = LDAP_MOD_REPLACE;
17103db3f65cSamw 	attrs[0]->mod_type = SMB_ADS_ATTR_CTL;
1711da6c28aaSamw 
17127f667e74Sjose borrego 	(void) snprintf(usrctl_buf, sizeof (usrctl_buf), "%d", flags);
1713da6c28aaSamw 	ctl_val[0] = usrctl_buf;
1714da6c28aaSamw 	ctl_val[1] = 0;
17156537f381Sas 	attrs[0]->mod_values = ctl_val;
1716da6c28aaSamw 	if ((ret = ldap_modify_s(ah->ld, dn, attrs)) != LDAP_SUCCESS) {
1717fc724630SAlan Wright 		syslog(LOG_NOTICE, "ldap_modify: %s", ldap_err2string(ret));
1718da6c28aaSamw 	}
1719da6c28aaSamw 
17203db3f65cSamw 	smb_ads_free_attr(attrs);
1721da6c28aaSamw 	return (ret);
1722da6c28aaSamw }
1723da6c28aaSamw 
1724da6c28aaSamw /*
17253db3f65cSamw  * smb_ads_lookup_computer_attr_kvno
1726da6c28aaSamw  *
1727da6c28aaSamw  * Lookup the value of the Kerberos version number attribute of the computer
1728da6c28aaSamw  * account.
1729da6c28aaSamw  */
1730da6c28aaSamw static krb5_kvno
smb_ads_lookup_computer_attr_kvno(smb_ads_handle_t * ah,char * dn)1731c8ec8eeaSjose borrego smb_ads_lookup_computer_attr_kvno(smb_ads_handle_t *ah, char *dn)
1732da6c28aaSamw {
1733b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_avpair_t avpair;
1734da6c28aaSamw 	int kvno = 1;
1735da6c28aaSamw 
1736b89a8333Snatalie li - Sun Microsystems - Irvine United States 	avpair.avp_attr = SMB_ADS_ATTR_KVNO;
17376a23a4b8SGordon Ross 	avpair.avp_val = NULL;
1738b89a8333Snatalie li - Sun Microsystems - Irvine United States 	if (smb_ads_lookup_computer_n_attr(ah, &avpair,
1739b89a8333Snatalie li - Sun Microsystems - Irvine United States 	    LDAP_SCOPE_BASE, dn) == SMB_ADS_STAT_FOUND) {
1740b89a8333Snatalie li - Sun Microsystems - Irvine United States 		kvno = atoi(avpair.avp_val);
1741b89a8333Snatalie li - Sun Microsystems - Irvine United States 		free(avpair.avp_val);
1742da6c28aaSamw 	}
1743da6c28aaSamw 
1744da6c28aaSamw 	return (kvno);
1745da6c28aaSamw }
1746da6c28aaSamw 
174755bf511dSas /*
17483db3f65cSamw  * smb_ads_join
1749da6c28aaSamw  *
1750da6c28aaSamw  * Besides the NT-4 style domain join (using MS-RPC), CIFS server also
1751da6c28aaSamw  * provides the domain join using Kerberos Authentication, Keberos
175255bf511dSas  * Change & Set password, and LDAP protocols. Basically, AD join
1753da6c28aaSamw  * operation would require the following tickets to be acquired for the
1754da6c28aaSamw  * the user account that is provided for the domain join.
1755da6c28aaSamw  *
1756da6c28aaSamw  * 1) a Keberos TGT ticket,
1757da6c28aaSamw  * 2) a ldap service ticket, and
1758da6c28aaSamw  * 3) kadmin/changpw service ticket
1759da6c28aaSamw  *
1760da6c28aaSamw  * The ADS client first sends a ldap search request to find out whether
1761da6c28aaSamw  * or not the workstation trust account already exists in the Active Directory.
1762da6c28aaSamw  * The existing computer object for this workstation will be removed and
1763da6c28aaSamw  * a new one will be added. The machine account password is randomly
17643db3f65cSamw  * generated and set for the newly created computer object using KPASSWD
1765da6c28aaSamw  * protocol (See RFC 3244). Once the password is set, our ADS client
1766da6c28aaSamw  * finalizes the machine account by modifying the user acount control
1767da6c28aaSamw  * attribute of the computer object. Kerberos keys derived from the machine
1768da6c28aaSamw  * account password will be stored locally in /etc/krb5/krb5.keytab file.
1769da6c28aaSamw  * That would be needed while acquiring Kerberos TGT ticket for the host
1770da6c28aaSamw  * principal after the domain join operation.
1771da6c28aaSamw  */
1772b3700b07SGordon Ross smb_ads_status_t
smb_ads_join(char * domain,char * container,char * user,char * usr_passwd,char * machine_passwd)1773857c33c4SGordon Ross smb_ads_join(char *domain, char *container,
1774857c33c4SGordon Ross     char *user, char *usr_passwd, char *machine_passwd)
1775da6c28aaSamw {
17763db3f65cSamw 	smb_ads_handle_t *ah = NULL;
1777da6c28aaSamw 	krb5_context ctx = NULL;
1778148c5f43SAlan Wright 	krb5_principal *krb5princs = NULL;
1779da6c28aaSamw 	krb5_kvno kvno;
1780b3700b07SGordon Ross 	boolean_t delete = B_TRUE;
1781b3700b07SGordon Ross 	smb_ads_status_t rc;
178255bf511dSas 	boolean_t new_acct;
17837f667e74Sjose borrego 	int dclevel, num, usrctl_flags = 0;
1784b89a8333Snatalie li - Sun Microsystems - Irvine United States 	smb_ads_qstat_t qstat;
1785c8ec8eeaSjose borrego 	char dn[SMB_ADS_DN_MAX];
1786c28afb19SYuri Pankov 	char tmpfile[] = SMBNS_KRB5_KEYTAB_TMP;
1787b3700b07SGordon Ross 	int cnt, x;
1788148c5f43SAlan Wright 	smb_krb5_pn_set_t spns;
17893db3f65cSamw 	krb5_enctype *encptr;
17903db3f65cSamw 
1791b3700b07SGordon Ross 	rc = smb_ads_open_main(&ah, domain, user, usr_passwd);
1792b3700b07SGordon Ross 	if (rc != 0) {
17936a23a4b8SGordon Ross 		const char *s = smb_ads_strerror(rc);
17946a23a4b8SGordon Ross 		syslog(LOG_ERR, "smb_ads_join: open_main, error %s", s);
17953db3f65cSamw 		smb_ccache_remove(SMB_CCACHE_PATH);
1796b3700b07SGordon Ross 		return (rc);
17973db3f65cSamw 	}
179855bf511dSas 
17993db3f65cSamw 	if ((dclevel = smb_ads_get_dc_level(ah)) == -1) {
18003db3f65cSamw 		smb_ads_close(ah);
1801faa1795aSjb 		smb_ccache_remove(SMB_CCACHE_PATH);
18023db3f65cSamw 		return (SMB_ADJOIN_ERR_GET_DCLEVEL);
180355bf511dSas 	}
1804da6c28aaSamw 
1805b89a8333Snatalie li - Sun Microsystems - Irvine United States 	qstat = smb_ads_find_computer(ah, dn);
1806b89a8333Snatalie li - Sun Microsystems - Irvine United States 	switch (qstat) {
1807b89a8333Snatalie li - Sun Microsystems - Irvine United States 	case SMB_ADS_STAT_FOUND:
180855bf511dSas 		new_acct = B_FALSE;
18096a23a4b8SGordon Ross 		syslog(LOG_INFO, "smb_ads_join: machine account found."
18106a23a4b8SGordon Ross 		    " Updating: %s", dn);
1811c8ec8eeaSjose borrego 		if (smb_ads_modify_computer(ah, dclevel, dn) != 0) {
18123db3f65cSamw 			smb_ads_close(ah);
1813faa1795aSjb 			smb_ccache_remove(SMB_CCACHE_PATH);
18143db3f65cSamw 			return (SMB_ADJOIN_ERR_MOD_TRUST_ACCT);
181555bf511dSas 		}
1816b89a8333Snatalie li - Sun Microsystems - Irvine United States 		break;
1817b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1818b89a8333Snatalie li - Sun Microsystems - Irvine United States 	case SMB_ADS_STAT_NOT_FOUND:
181955bf511dSas 		new_acct = B_TRUE;
1820857c33c4SGordon Ross 		smb_ads_get_new_comp_dn(ah, dn, SMB_ADS_DN_MAX, container);
18216a23a4b8SGordon Ross 		syslog(LOG_INFO, "smb_ads_join: machine account not found."
18226a23a4b8SGordon Ross 		    " Creating: %s", dn);
1823c8ec8eeaSjose borrego 		if (smb_ads_add_computer(ah, dclevel, dn) != 0) {
18243db3f65cSamw 			smb_ads_close(ah);
1825faa1795aSjb 			smb_ccache_remove(SMB_CCACHE_PATH);
18263db3f65cSamw 			return (SMB_ADJOIN_ERR_ADD_TRUST_ACCT);
182755bf511dSas 		}
1828b89a8333Snatalie li - Sun Microsystems - Irvine United States 		break;
1829b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1830b89a8333Snatalie li - Sun Microsystems - Irvine United States 	default:
18316a23a4b8SGordon Ross 		syslog(LOG_INFO, "smb_ads_find_computer, rc=%d", qstat);
1832b89a8333Snatalie li - Sun Microsystems - Irvine United States 		if (qstat == SMB_ADS_STAT_DUP)
1833b89a8333Snatalie li - Sun Microsystems - Irvine United States 			rc = SMB_ADJOIN_ERR_DUP_TRUST_ACCT;
1834b89a8333Snatalie li - Sun Microsystems - Irvine United States 		else
1835b89a8333Snatalie li - Sun Microsystems - Irvine United States 			rc = SMB_ADJOIN_ERR_TRUST_ACCT;
1836b89a8333Snatalie li - Sun Microsystems - Irvine United States 		smb_ads_close(ah);
1837b89a8333Snatalie li - Sun Microsystems - Irvine United States 		smb_ccache_remove(SMB_CCACHE_PATH);
1838b89a8333Snatalie li - Sun Microsystems - Irvine United States 		return (rc);
183955bf511dSas 	}
184055bf511dSas 
1841da6c28aaSamw 	if (smb_krb5_ctx_init(&ctx) != 0) {
18423db3f65cSamw 		rc = SMB_ADJOIN_ERR_INIT_KRB_CTX;
1843da6c28aaSamw 		goto adjoin_cleanup;
1844da6c28aaSamw 	}
1845da6c28aaSamw 
1846148c5f43SAlan Wright 	if (smb_krb5_get_pn_set(&spns, SMB_PN_KEYTAB_ENTRY, ah->domain) == 0) {
18473db3f65cSamw 		rc = SMB_ADJOIN_ERR_GET_SPNS;
1848da6c28aaSamw 		goto adjoin_cleanup;
1849da6c28aaSamw 	}
1850da6c28aaSamw 
1851148c5f43SAlan Wright 	if (smb_krb5_get_kprincs(ctx, spns.s_pns, spns.s_cnt, &krb5princs)
1852148c5f43SAlan Wright 	    != 0) {
1853148c5f43SAlan Wright 		smb_krb5_free_pn_set(&spns);
1854148c5f43SAlan Wright 		rc = SMB_ADJOIN_ERR_GET_SPNS;
1855148c5f43SAlan Wright 		goto adjoin_cleanup;
1856148c5f43SAlan Wright 	}
1857148c5f43SAlan Wright 
1858148c5f43SAlan Wright 	cnt = spns.s_cnt;
1859148c5f43SAlan Wright 	smb_krb5_free_pn_set(&spns);
1860148c5f43SAlan Wright 
18611ed6b69aSGordon Ross 	/* New machine_passwd was filled in by our caller. */
1862148c5f43SAlan Wright 	if (smb_krb5_setpwd(ctx, ah->domain, machine_passwd) != 0) {
18633db3f65cSamw 		rc = SMB_ADJOIN_ERR_KSETPWD;
1864da6c28aaSamw 		goto adjoin_cleanup;
1865da6c28aaSamw 	}
1866da6c28aaSamw 
1867c8ec8eeaSjose borrego 	kvno = smb_ads_lookup_computer_attr_kvno(ah, dn);
186855bf511dSas 
18697f667e74Sjose borrego 	/*
18707f667e74Sjose borrego 	 * Only members of Domain Admins and Enterprise Admins can set
18717f667e74Sjose borrego 	 * the TRUSTED_FOR_DELEGATION userAccountControl flag.
1872b3700b07SGordon Ross 	 * Try to set this, but don't fail the join if we can't.
1873b3700b07SGordon Ross 	 * Look into just removing this...
18747f667e74Sjose borrego 	 */
1875b3700b07SGordon Ross 	usrctl_flags = (
1876037cac00Sjoyce mcintosh 	    SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT |
1877b3700b07SGordon Ross 	    SMB_ADS_USER_ACCT_CTL_TRUSTED_FOR_DELEGATION |
1878b3700b07SGordon Ross 	    SMB_ADS_USER_ACCT_CTL_DONT_EXPIRE_PASSWD);
1879b3700b07SGordon Ross set_ctl_again:
1880b3700b07SGordon Ross 	x = smb_ads_update_computer_cntrl_attr(ah, usrctl_flags, dn);
1881b3700b07SGordon Ross 	if (x != LDAP_SUCCESS && (usrctl_flags &
1882b3700b07SGordon Ross 	    SMB_ADS_USER_ACCT_CTL_TRUSTED_FOR_DELEGATION) != 0) {
1883fc724630SAlan Wright 		syslog(LOG_NOTICE, "Unable to set the "
1884b3700b07SGordon Ross "TRUSTED_FOR_DELEGATION userAccountControl flag on the "
1885b3700b07SGordon Ross "machine account in Active Directory.  It may be necessary "
1886b3700b07SGordon Ross "to set that via Active Directory administration.");
1887b3700b07SGordon Ross 		usrctl_flags &=
1888b3700b07SGordon Ross 		    ~SMB_ADS_USER_ACCT_CTL_TRUSTED_FOR_DELEGATION;
1889b3700b07SGordon Ross 		goto set_ctl_again;
1890b3700b07SGordon Ross 	}
1891b3700b07SGordon Ross 	if (x != LDAP_SUCCESS) {
18923db3f65cSamw 		rc = SMB_ADJOIN_ERR_UPDATE_CNTRL_ATTR;
1893da6c28aaSamw 		goto adjoin_cleanup;
1894da6c28aaSamw 	}
189555bf511dSas 
1896c28afb19SYuri Pankov 	if (mktemp(tmpfile) == NULL) {
1897c28afb19SYuri Pankov 		rc = SMB_ADJOIN_ERR_WRITE_KEYTAB;
1898c28afb19SYuri Pankov 		goto adjoin_cleanup;
1899c28afb19SYuri Pankov 	}
19008d7e4166Sjose borrego 
1901148c5f43SAlan Wright 	encptr = smb_ads_get_enctypes(dclevel, &num);
1902148c5f43SAlan Wright 	if (smb_krb5_kt_populate(ctx, ah->domain, krb5princs, cnt,
1903148c5f43SAlan Wright 	    tmpfile, kvno, machine_passwd, encptr, num) != 0) {
19043db3f65cSamw 		rc = SMB_ADJOIN_ERR_WRITE_KEYTAB;
1905da6c28aaSamw 		goto adjoin_cleanup;
1906da6c28aaSamw 	}
1907da6c28aaSamw 
190855bf511dSas 	delete = B_FALSE;
1909b3700b07SGordon Ross 	rc = SMB_ADS_SUCCESS;
1910b3700b07SGordon Ross 
1911da6c28aaSamw adjoin_cleanup:
191255bf511dSas 	if (new_acct && delete)
1913c8ec8eeaSjose borrego 		smb_ads_del_computer(ah, dn);
1914da6c28aaSamw 
19153db3f65cSamw 	if (rc != SMB_ADJOIN_ERR_INIT_KRB_CTX) {
19163db3f65cSamw 		if (rc != SMB_ADJOIN_ERR_GET_SPNS)
1917148c5f43SAlan Wright 			smb_krb5_free_kprincs(ctx, krb5princs, cnt);
1918da6c28aaSamw 		smb_krb5_ctx_fini(ctx);
1919cbfb650aScp 	}
1920da6c28aaSamw 
19218d7e4166Sjose borrego 	/* commit keytab file */
1922b3700b07SGordon Ross 	if (rc == SMB_ADS_SUCCESS) {
19238d7e4166Sjose borrego 		if (rename(tmpfile, SMBNS_KRB5_KEYTAB) != 0) {
19248d7e4166Sjose borrego 			(void) unlink(tmpfile);
19258d7e4166Sjose borrego 			rc = SMB_ADJOIN_ERR_COMMIT_KEYTAB;
19268d7e4166Sjose borrego 		}
19278d7e4166Sjose borrego 	} else {
19288d7e4166Sjose borrego 		(void) unlink(tmpfile);
19298d7e4166Sjose borrego 	}
19308d7e4166Sjose borrego 
19313db3f65cSamw 	smb_ads_close(ah);
1932faa1795aSjb 	smb_ccache_remove(SMB_CCACHE_PATH);
1933da6c28aaSamw 	return (rc);
1934da6c28aaSamw }
1935da6c28aaSamw 
1936b3700b07SGordon Ross struct xlate_table {
1937b3700b07SGordon Ross 	int err;
1938f3195b6fSToomas Soome 	const char * const msg;
1939b3700b07SGordon Ross };
1940c8ec8eeaSjose borrego 
1941b3700b07SGordon Ross static const struct xlate_table
1942b3700b07SGordon Ross adjoin_table[] = {
1943b3700b07SGordon Ross 	{ SMB_ADS_SUCCESS, "Success" },
1944b3700b07SGordon Ross 	{ SMB_ADS_KRB5_INIT_CTX,
1945b3700b07SGordon Ross 	    "Failed creating a Kerberos context." },
1946b3700b07SGordon Ross 	{ SMB_ADS_KRB5_CC_DEFAULT,
1947b3700b07SGordon Ross 	    "Failed to resolve default credential cache." },
1948b3700b07SGordon Ross 	{ SMB_ADS_KRB5_PARSE_PRINCIPAL,
1949b3700b07SGordon Ross 	    "Failed parsing the user principal name." },
19507b0b8123SGordon Ross 	{ SMB_ADS_KRB5_GET_INIT_CREDS_OTHER,
19517b0b8123SGordon Ross 	    "Failed getting initial credentials.  (See svc. log)" },
1952b3700b07SGordon Ross 	{ SMB_ADS_KRB5_GET_INIT_CREDS_PW,
1953b3700b07SGordon Ross 	    "Failed getting initial credentials.  (Wrong password?)" },
19547b0b8123SGordon Ross 	{ SMB_ADS_KRB5_GET_INIT_CREDS_SKEW,
19557b0b8123SGordon Ross 	    "Failed getting initial credentials.  (Clock skew too great)" },
1956b3700b07SGordon Ross 	{ SMB_ADS_KRB5_CC_INITIALIZE,
1957b3700b07SGordon Ross 	    "Failed initializing the credential cache." },
1958b3700b07SGordon Ross 	{ SMB_ADS_KRB5_CC_STORE_CRED,
1959b3700b07SGordon Ross 	    "Failed to update the credential cache." },
1960b3700b07SGordon Ross 	{ SMB_ADS_CANT_LOCATE_DC,
1961b3700b07SGordon Ross 	    "Failed to locate a domain controller." },
1962b3700b07SGordon Ross 	{ SMB_ADS_LDAP_INIT,
1963b3700b07SGordon Ross 	    "Failed to create an LDAP handle." },
1964b3700b07SGordon Ross 	{ SMB_ADS_LDAP_SETOPT,
1965b3700b07SGordon Ross 	    "Failed to set an LDAP option." },
1966b3700b07SGordon Ross 	{ SMB_ADS_LDAP_SET_DOM,
1967b3700b07SGordon Ross 	    "Failed to set the LDAP handle DN." },
1968b3700b07SGordon Ross 	{ SMB_ADS_LDAP_SASL_BIND,
1969b3700b07SGordon Ross 	    "Failed to bind the LDAP handle. "
1970b3700b07SGordon Ross 	    "Usually indicates an authentication problem." },
1971b3700b07SGordon Ross 
1972b3700b07SGordon Ross 	{ SMB_ADJOIN_ERR_GEN_PWD,
1973b3700b07SGordon Ross 	    "Failed to generate machine password." },
1974b3700b07SGordon Ross 	{ SMB_ADJOIN_ERR_GET_DCLEVEL, "Unknown functional level of "
1975b3700b07SGordon Ross 	    "the domain controller. The rootDSE attribute named "
1976b3700b07SGordon Ross 	    "\"domainControllerFunctionality\" is missing from the "
1977b3700b07SGordon Ross 	    "Active Directory." },
1978b3700b07SGordon Ross 	{ SMB_ADJOIN_ERR_ADD_TRUST_ACCT, "Failed to create the "
1979b3700b07SGordon Ross 	    "workstation trust account." },
1980b3700b07SGordon Ross 	{ SMB_ADJOIN_ERR_MOD_TRUST_ACCT, "Failed to modify the "
1981b3700b07SGordon Ross 	    "workstation trust account." },
1982b3700b07SGordon Ross 	{ SMB_ADJOIN_ERR_DUP_TRUST_ACCT, "Failed to create the "
1983b3700b07SGordon Ross 	    "workstation trust account because its name is already "
1984b3700b07SGordon Ross 	    "in use." },
1985b3700b07SGordon Ross 	{ SMB_ADJOIN_ERR_TRUST_ACCT, "Error in querying the "
1986b3700b07SGordon Ross 	    "workstation trust account" },
1987b3700b07SGordon Ross 	{ SMB_ADJOIN_ERR_INIT_KRB_CTX, "Failed to initialize Kerberos "
1988b3700b07SGordon Ross 	    "context." },
1989b3700b07SGordon Ross 	{ SMB_ADJOIN_ERR_GET_SPNS, "Failed to get Kerberos "
1990b3700b07SGordon Ross 	    "principals." },
1991b3700b07SGordon Ross 	{ SMB_ADJOIN_ERR_KSETPWD, "Failed to set machine password." },
1992b3700b07SGordon Ross 	{ SMB_ADJOIN_ERR_UPDATE_CNTRL_ATTR,  "Failed to modify "
1993b3700b07SGordon Ross 	    "userAccountControl attribute of the workstation trust "
1994b3700b07SGordon Ross 	    "account." },
1995b3700b07SGordon Ross 	{ SMB_ADJOIN_ERR_WRITE_KEYTAB, "Error in writing to local "
1996b3700b07SGordon Ross 	    "keytab file (i.e /etc/krb5/krb5.keytab)." },
1997b3700b07SGordon Ross 	{ SMB_ADJOIN_ERR_IDMAP_SET_DOMAIN, "Failed to update idmap "
1998b3700b07SGordon Ross 	    "configuration." },
1999b3700b07SGordon Ross 	{ SMB_ADJOIN_ERR_IDMAP_REFRESH, "Failed to refresh idmap "
2000b3700b07SGordon Ross 	    "service." },
2001b3700b07SGordon Ross 	{ SMB_ADJOIN_ERR_COMMIT_KEYTAB, "Failed to commit changes to "
2002b3700b07SGordon Ross 	    "local keytab file (i.e. /etc/krb5/krb5.keytab)." },
2003b3700b07SGordon Ross 	{ SMB_ADJOIN_ERR_AUTH_NETLOGON,
2004b3700b07SGordon Ross 	    "Failed to authenticate using the new computer account." },
2005b3700b07SGordon Ross 	{ SMB_ADJOIN_ERR_STORE_PROPS,
2006b3700b07SGordon Ross 	    "Failed to store computer account information locally." },
2007b3700b07SGordon Ross 	{ 0, NULL }
2008b3700b07SGordon Ross };
2009c8ec8eeaSjose borrego 
2010c8ec8eeaSjose borrego /*
2011b3700b07SGordon Ross  * smb_ads_strerror
2012c8ec8eeaSjose borrego  *
2013b3700b07SGordon Ross  * Lookup an error message for the specific adjoin error code.
2014c8ec8eeaSjose borrego  */
2015b3700b07SGordon Ross const char *
smb_ads_strerror(int err)2016b3700b07SGordon Ross smb_ads_strerror(int err)
2017c8ec8eeaSjose borrego {
2018b3700b07SGordon Ross 	const struct xlate_table *xt;
2019c8ec8eeaSjose borrego 
2020b3700b07SGordon Ross 	if (err > 0 && err < SMB_ADS_ERRNO_GAP)
2021b3700b07SGordon Ross 		return (strerror(err));
2022b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2023b3700b07SGordon Ross 	for (xt = adjoin_table; xt->msg; xt++)
2024b3700b07SGordon Ross 		if (xt->err == err)
2025b3700b07SGordon Ross 			return (xt->msg);
2026b89a8333Snatalie li - Sun Microsystems - Irvine United States 
2027b3700b07SGordon Ross 	return ("Unknown error code.");
2028c8ec8eeaSjose borrego }
2029c8ec8eeaSjose borrego 
2030b3700b07SGordon Ross void
smb_ads_log_errmsg(smb_ads_status_t err)2031b3700b07SGordon Ross smb_ads_log_errmsg(smb_ads_status_t err)
2032c8ec8eeaSjose borrego {
2033b3700b07SGordon Ross 	const char *s = smb_ads_strerror(err);
2034b3700b07SGordon Ross 	syslog(LOG_NOTICE, "%s", s);
2035c8ec8eeaSjose borrego }
2036c8ec8eeaSjose borrego 
20378d7e4166Sjose borrego 
20388d7e4166Sjose borrego /*
20398d7e4166Sjose borrego  * smb_ads_lookup_msdcs
20408d7e4166Sjose borrego  *
20418d7e4166Sjose borrego  * If server argument is set, try to locate the specified DC.
20428d7e4166Sjose borrego  * If it is set to empty string, locate any DCs in the specified domain.
20438d7e4166Sjose borrego  * Returns the discovered DC via buf.
20448d7e4166Sjose borrego  *
20458d7e4166Sjose borrego  * fqdn	  - fully-qualified domain name
2046b3700b07SGordon Ross  * dci    - the name and address of the found DC
20478d7e4166Sjose borrego  */
2048b3700b07SGordon Ross uint32_t
smb_ads_lookup_msdcs(char * fqdn,smb_dcinfo_t * dci)2049b3700b07SGordon Ross smb_ads_lookup_msdcs(char *fqdn, smb_dcinfo_t *dci)
20508d7e4166Sjose borrego {
20518d7e4166Sjose borrego 	smb_ads_host_info_t *hinfo = NULL;
20527f667e74Sjose borrego 	char ipstr[INET6_ADDRSTRLEN];
20538d7e4166Sjose borrego 
2054b3700b07SGordon Ross 	if (!fqdn || !dci)
2055b3700b07SGordon Ross 		return (NT_STATUS_INTERNAL_ERROR);
20568d7e4166Sjose borrego 
205732b8d01aSChristopher Parker 	ipstr[0] = '\0';
2058b3700b07SGordon Ross 	if ((hinfo = smb_ads_find_host(fqdn)) == NULL)
2059b3700b07SGordon Ross 		return (NT_STATUS_DOMAIN_CONTROLLER_NOT_FOUND);
20608d7e4166Sjose borrego 
206132b8d01aSChristopher Parker 	(void) smb_inet_ntop(&hinfo->ipaddr, ipstr,
206232b8d01aSChristopher Parker 	    SMB_IPSTRLEN(hinfo->ipaddr.a_family));
206332b8d01aSChristopher Parker 	smb_tracef("msdcsLookupADS: %s [%s]", hinfo->name, ipstr);
20648d7e4166Sjose borrego 
2065b3700b07SGordon Ross 	(void) strlcpy(dci->dc_name, hinfo->name, sizeof (dci->dc_name));
2066b3700b07SGordon Ross 	dci->dc_addr = hinfo->ipaddr;
2067bdc3270fSMatt Barden 	dci->dc_flags = hinfo->flags;
20688d7e4166Sjose borrego 
206929bd2886SAlan Wright 	free(hinfo);
2070b3700b07SGordon Ross 	return (NT_STATUS_SUCCESS);
20718d7e4166Sjose borrego }
2072148c5f43SAlan Wright 
2073148c5f43SAlan Wright static krb5_enctype *
smb_ads_get_enctypes(int dclevel,int * num)2074148c5f43SAlan Wright smb_ads_get_enctypes(int dclevel, int *num)
2075148c5f43SAlan Wright {
2076148c5f43SAlan Wright 	krb5_enctype *encptr;
2077148c5f43SAlan Wright 
2078148c5f43SAlan Wright 	if (dclevel >= SMB_ADS_DCLEVEL_W2K8) {
2079148c5f43SAlan Wright 		*num = sizeof (w2k8enctypes) / sizeof (krb5_enctype);
2080148c5f43SAlan Wright 		encptr = w2k8enctypes;
2081148c5f43SAlan Wright 	} else {
2082148c5f43SAlan Wright 		*num = sizeof (pre_w2k8enctypes) / sizeof (krb5_enctype);
2083148c5f43SAlan Wright 		encptr = pre_w2k8enctypes;
2084148c5f43SAlan Wright 	}
2085148c5f43SAlan Wright 
2086148c5f43SAlan Wright 	return (encptr);
2087148c5f43SAlan Wright }
2088