15331Samw /*
25331Samw * CDDL HEADER START
35331Samw *
45331Samw * The contents of this file are subject to the terms of the
55331Samw * Common Development and Distribution License (the "License").
65331Samw * You may not use this file except in compliance with the License.
75331Samw *
85331Samw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
95331Samw * or http://www.opensolaris.org/os/licensing.
105331Samw * See the License for the specific language governing permissions
115331Samw * and limitations under the License.
125331Samw *
135331Samw * When distributing Covered Code, include this CDDL HEADER in each
145331Samw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
155331Samw * If applicable, add the following below this CDDL HEADER, with the
165331Samw * fields enclosed by brackets "[]" replaced with your own identifying
175331Samw * information: Portions Copyright [yyyy] [name of copyright owner]
185331Samw *
195331Samw * CDDL HEADER END
205331Samw */
215331Samw /*
2212065SKeyur.Desai@Sun.COM * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
235331Samw */
245331Samw
255331Samw #include <sys/param.h>
265331Samw #include <ldap.h>
275331Samw #include <stdlib.h>
285331Samw #include <sys/types.h>
295331Samw #include <sys/socket.h>
305331Samw #include <netinet/in.h>
315331Samw #include <arpa/inet.h>
325331Samw #include <sys/time.h>
335331Samw #include <netdb.h>
345331Samw #include <pthread.h>
355331Samw #include <unistd.h>
365331Samw #include <arpa/nameser.h>
375331Samw #include <resolv.h>
385331Samw #include <sys/synch.h>
395331Samw #include <string.h>
405331Samw #include <strings.h>
415331Samw #include <fcntl.h>
425331Samw #include <sys/types.h>
435331Samw #include <sys/stat.h>
447961SNatalie.Li@Sun.COM #include <assert.h>
4510717Samw@Sun.COM #include <sasl/sasl.h>
4610717Samw@Sun.COM #include <note.h>
4711571SShawn.Emery@Sun.COM #include <errno.h>
4811571SShawn.Emery@Sun.COM #include <cryptoutil.h>
495331Samw
505331Samw #include <smbsrv/libsmbns.h>
515331Samw #include <smbns_dyndns.h>
525331Samw #include <smbns_krb.h>
535331Samw
5411633SJoyce.McIntosh@Sun.COM #define SMB_ADS_AF_UNKNOWN(x) (((x)->ipaddr.a_family != AF_INET) && \
5511633SJoyce.McIntosh@Sun.COM ((x)->ipaddr.a_family != AF_INET6))
5611633SJoyce.McIntosh@Sun.COM
579832Samw@Sun.COM #define SMB_ADS_MAXBUFLEN 100
587052Samw #define SMB_ADS_DN_MAX 300
597052Samw #define SMB_ADS_MAXMSGLEN 512
607052Samw #define SMB_ADS_COMPUTERS_CN "Computers"
617052Samw #define SMB_ADS_COMPUTER_NUM_ATTR 8
627052Samw #define SMB_ADS_SHARE_NUM_ATTR 3
637052Samw #define SMB_ADS_SITE_MAX MAXHOSTNAMELEN
647052Samw
6511571SShawn.Emery@Sun.COM /*
6611571SShawn.Emery@Sun.COM * [MS-DISO] A machine password is an ASCII string of randomly chosen
6711571SShawn.Emery@Sun.COM * characters. Each character's ASCII code is between 32 and 122 inclusive.
6811571SShawn.Emery@Sun.COM */
6911571SShawn.Emery@Sun.COM #define SMB_ADS_PWD_CHAR_NUM 91
7011571SShawn.Emery@Sun.COM #define SMB_ADS_PWD_CHAR_START 32
7111571SShawn.Emery@Sun.COM
727052Samw #define SMB_ADS_MSDCS_SRV_DC_RR "_ldap._tcp.dc._msdcs"
737052Samw #define SMB_ADS_MSDCS_SRV_SITE_RR "_ldap._tcp.%s._sites.dc._msdcs"
747052Samw
757052Samw /*
767052Samw * domainControllerFunctionality
777052Samw *
787052Samw * This rootDSE attribute indicates the functional level of the DC.
797052Samw */
807052Samw #define SMB_ADS_ATTR_DCLEVEL "domainControllerFunctionality"
817052Samw #define SMB_ADS_DCLEVEL_W2K 0
827052Samw #define SMB_ADS_DCLEVEL_W2K3 2
837052Samw #define SMB_ADS_DCLEVEL_W2K8 3
849914Samw@Sun.COM #define SMB_ADS_DCLEVEL_W2K8_R2 4
857052Samw
867052Samw /*
877052Samw * msDs-supportedEncryptionTypes (Windows Server 2008 only)
887052Samw *
897052Samw * This attribute defines the encryption types supported by the system.
907052Samw * Encryption Types:
917052Samw * - DES cbc mode with CRC-32
927052Samw * - DES cbc mode with RSA-MD5
937052Samw * - ArcFour with HMAC/md5
947052Samw * - AES-128
957052Samw * - AES-256
967052Samw */
977052Samw #define SMB_ADS_ATTR_ENCTYPES "msDs-supportedEncryptionTypes"
987052Samw #define SMB_ADS_ENC_DES_CRC 1
997052Samw #define SMB_ADS_ENC_DES_MD5 2
1007052Samw #define SMB_ADS_ENC_RC4 4
1017052Samw #define SMB_ADS_ENC_AES128 8
1027052Samw #define SMB_ADS_ENC_AES256 16
1037052Samw
104*12508Samw@Sun.COM static krb5_enctype w2k8enctypes[] = {
105*12508Samw@Sun.COM ENCTYPE_AES256_CTS_HMAC_SHA1_96,
106*12508Samw@Sun.COM ENCTYPE_AES128_CTS_HMAC_SHA1_96,
107*12508Samw@Sun.COM ENCTYPE_ARCFOUR_HMAC,
108*12508Samw@Sun.COM ENCTYPE_DES_CBC_CRC,
109*12508Samw@Sun.COM ENCTYPE_DES_CBC_MD5,
110*12508Samw@Sun.COM };
111*12508Samw@Sun.COM
112*12508Samw@Sun.COM static krb5_enctype pre_w2k8enctypes[] = {
113*12508Samw@Sun.COM ENCTYPE_ARCFOUR_HMAC,
114*12508Samw@Sun.COM ENCTYPE_DES_CBC_CRC,
115*12508Samw@Sun.COM ENCTYPE_DES_CBC_MD5,
116*12508Samw@Sun.COM };
117*12508Samw@Sun.COM
1187052Samw #define SMB_ADS_ATTR_SAMACCT "sAMAccountName"
1197052Samw #define SMB_ADS_ATTR_UPN "userPrincipalName"
1207052Samw #define SMB_ADS_ATTR_SPN "servicePrincipalName"
1217052Samw #define SMB_ADS_ATTR_CTL "userAccountControl"
1227052Samw #define SMB_ADS_ATTR_DNSHOST "dNSHostName"
1237052Samw #define SMB_ADS_ATTR_KVNO "msDS-KeyVersionNumber"
1247348SJose.Borrego@Sun.COM #define SMB_ADS_ATTR_DN "distinguishedName"
1255331Samw
1267961SNatalie.Li@Sun.COM /*
1279832Samw@Sun.COM * UserAccountControl flags: manipulate user account properties.
1289832Samw@Sun.COM *
1299832Samw@Sun.COM * The hexadecimal value of the following property flags are based on MSDN
1309832Samw@Sun.COM * article # 305144.
1319832Samw@Sun.COM */
1329832Samw@Sun.COM #define SMB_ADS_USER_ACCT_CTL_SCRIPT 0x00000001
1339832Samw@Sun.COM #define SMB_ADS_USER_ACCT_CTL_ACCOUNTDISABLE 0x00000002
1349832Samw@Sun.COM #define SMB_ADS_USER_ACCT_CTL_HOMEDIR_REQUIRED 0x00000008
1359832Samw@Sun.COM #define SMB_ADS_USER_ACCT_CTL_LOCKOUT 0x00000010
1369832Samw@Sun.COM #define SMB_ADS_USER_ACCT_CTL_PASSWD_NOTREQD 0x00000020
1379832Samw@Sun.COM #define SMB_ADS_USER_ACCT_CTL_PASSWD_CANT_CHANGE 0x00000040
1389832Samw@Sun.COM #define SMB_ADS_USER_ACCT_CTL_ENCRYPTED_TEXT_PWD_ALLOWED 0x00000080
1399832Samw@Sun.COM #define SMB_ADS_USER_ACCT_CTL_TMP_DUP_ACCT 0x00000100
1409832Samw@Sun.COM #define SMB_ADS_USER_ACCT_CTL_NORMAL_ACCT 0x00000200
1419832Samw@Sun.COM #define SMB_ADS_USER_ACCT_CTL_INTERDOMAIN_TRUST_ACCT 0x00000800
1429832Samw@Sun.COM #define SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT 0x00001000
1439832Samw@Sun.COM #define SMB_ADS_USER_ACCT_CTL_SRV_TRUST_ACCT 0x00002000
1449832Samw@Sun.COM #define SMB_ADS_USER_ACCT_CTL_DONT_EXPIRE_PASSWD 0x00010000
1459832Samw@Sun.COM #define SMB_ADS_USER_ACCT_CTL_MNS_LOGON_ACCT 0x00020000
1469832Samw@Sun.COM #define SMB_ADS_USER_ACCT_CTL_SMARTCARD_REQUIRED 0x00040000
1479832Samw@Sun.COM #define SMB_ADS_USER_ACCT_CTL_TRUSTED_FOR_DELEGATION 0x00080000
1489832Samw@Sun.COM #define SMB_ADS_USER_ACCT_CTL_NOT_DELEGATED 0x00100000
1499832Samw@Sun.COM #define SMB_ADS_USER_ACCT_CTL_USE_DES_KEY_ONLY 0x00200000
1509832Samw@Sun.COM #define SMB_ADS_USER_ACCT_CTL_DONT_REQ_PREAUTH 0x00400000
1519832Samw@Sun.COM #define SMB_ADS_USER_ACCT_CTL_PASSWD_EXPIRED 0x00800000
1529832Samw@Sun.COM #define SMB_ADS_USER_ACCT_CTL_TRUSTED_TO_AUTH_FOR_DELEGATION 0x01000000
1539832Samw@Sun.COM
1549832Samw@Sun.COM /*
1557961SNatalie.Li@Sun.COM * Length of "dc=" prefix.
1567961SNatalie.Li@Sun.COM */
1577961SNatalie.Li@Sun.COM #define SMB_ADS_DN_PREFIX_LEN 3
1587961SNatalie.Li@Sun.COM
1598670SJose.Borrego@Sun.COM static char *smb_ads_computer_objcls[] = {
1608670SJose.Borrego@Sun.COM "top", "person", "organizationalPerson",
1618670SJose.Borrego@Sun.COM "user", "computer", NULL
1628670SJose.Borrego@Sun.COM };
1638670SJose.Borrego@Sun.COM
1648670SJose.Borrego@Sun.COM static char *smb_ads_share_objcls[] = {
1658670SJose.Borrego@Sun.COM "top", "leaf", "connectionPoint", "volume", NULL
1668670SJose.Borrego@Sun.COM };
1678670SJose.Borrego@Sun.COM
1687961SNatalie.Li@Sun.COM /* Cached ADS server to communicate with */
1697961SNatalie.Li@Sun.COM static smb_ads_host_info_t *smb_ads_cached_host_info = NULL;
1707961SNatalie.Li@Sun.COM static mutex_t smb_ads_cached_host_mtx;
1717961SNatalie.Li@Sun.COM
1729832Samw@Sun.COM /*
1739832Samw@Sun.COM * SMB ADS config cache is maintained to facilitate the detection of
1749832Samw@Sun.COM * changes in configuration that is relevant to AD selection.
1759832Samw@Sun.COM */
1769832Samw@Sun.COM typedef struct smb_ads_config {
1779832Samw@Sun.COM char c_site[SMB_ADS_SITE_MAX];
1789832Samw@Sun.COM smb_inaddr_t c_pdc;
1799832Samw@Sun.COM mutex_t c_mtx;
1809832Samw@Sun.COM } smb_ads_config_t;
1819832Samw@Sun.COM
1829832Samw@Sun.COM static smb_ads_config_t smb_ads_cfg;
1839832Samw@Sun.COM
1845772Sas200622
1857961SNatalie.Li@Sun.COM /* attribute/value pair */
1867961SNatalie.Li@Sun.COM typedef struct smb_ads_avpair {
1877961SNatalie.Li@Sun.COM char *avp_attr;
1887961SNatalie.Li@Sun.COM char *avp_val;
1897961SNatalie.Li@Sun.COM } smb_ads_avpair_t;
1907961SNatalie.Li@Sun.COM
1917961SNatalie.Li@Sun.COM /* query status */
1927961SNatalie.Li@Sun.COM typedef enum smb_ads_qstat {
1937961SNatalie.Li@Sun.COM SMB_ADS_STAT_ERR = -2,
1947961SNatalie.Li@Sun.COM SMB_ADS_STAT_DUP,
1957961SNatalie.Li@Sun.COM SMB_ADS_STAT_NOT_FOUND,
1967961SNatalie.Li@Sun.COM SMB_ADS_STAT_FOUND
1977961SNatalie.Li@Sun.COM } smb_ads_qstat_t;
1987961SNatalie.Li@Sun.COM
1999832Samw@Sun.COM typedef struct smb_ads_host_list {
2009832Samw@Sun.COM int ah_cnt;
2019832Samw@Sun.COM smb_ads_host_info_t *ah_list;
2029832Samw@Sun.COM } smb_ads_host_list_t;
2039832Samw@Sun.COM
2047348SJose.Borrego@Sun.COM static smb_ads_handle_t *smb_ads_open_main(char *, char *, char *);
2057348SJose.Borrego@Sun.COM static int smb_ads_add_computer(smb_ads_handle_t *, int, char *);
2067348SJose.Borrego@Sun.COM static int smb_ads_modify_computer(smb_ads_handle_t *, int, char *);
2077348SJose.Borrego@Sun.COM static int smb_ads_computer_op(smb_ads_handle_t *, int, int, char *);
2087961SNatalie.Li@Sun.COM static smb_ads_qstat_t smb_ads_lookup_computer_n_attr(smb_ads_handle_t *,
2097961SNatalie.Li@Sun.COM smb_ads_avpair_t *, int, char *);
2107348SJose.Borrego@Sun.COM static int smb_ads_update_computer_cntrl_attr(smb_ads_handle_t *, int, char *);
2117348SJose.Borrego@Sun.COM static krb5_kvno smb_ads_lookup_computer_attr_kvno(smb_ads_handle_t *, char *);
21211571SShawn.Emery@Sun.COM static int smb_ads_gen_machine_passwd(char *, size_t);
2137961SNatalie.Li@Sun.COM static void smb_ads_free_cached_host(void);
2147348SJose.Borrego@Sun.COM static int smb_ads_alloc_attr(LDAPMod **, int);
2157348SJose.Borrego@Sun.COM static void smb_ads_free_attr(LDAPMod **);
2167348SJose.Borrego@Sun.COM static int smb_ads_get_dc_level(smb_ads_handle_t *);
2177348SJose.Borrego@Sun.COM static smb_ads_host_info_t *smb_ads_select_dc(smb_ads_host_list_t *);
2187961SNatalie.Li@Sun.COM static smb_ads_qstat_t smb_ads_find_computer(smb_ads_handle_t *, char *);
2197961SNatalie.Li@Sun.COM static smb_ads_qstat_t smb_ads_getattr(LDAP *, LDAPMessage *,
2207961SNatalie.Li@Sun.COM smb_ads_avpair_t *);
2217961SNatalie.Li@Sun.COM static smb_ads_qstat_t smb_ads_get_qstat(smb_ads_handle_t *, LDAPMessage *,
2227961SNatalie.Li@Sun.COM smb_ads_avpair_t *);
2239832Samw@Sun.COM static boolean_t smb_ads_match_pdc(smb_ads_host_info_t *);
2249832Samw@Sun.COM static boolean_t smb_ads_is_sought_host(smb_ads_host_info_t *, char *);
2259832Samw@Sun.COM static boolean_t smb_ads_is_same_domain(char *, char *);
2269832Samw@Sun.COM static boolean_t smb_ads_is_pdc_configured(void);
2279832Samw@Sun.COM static smb_ads_host_info_t *smb_ads_dup_host_info(smb_ads_host_info_t *);
22811337SWilliam.Krier@Sun.COM static char *smb_ads_get_sharedn(const char *, const char *, const char *);
229*12508Samw@Sun.COM static krb5_enctype *smb_ads_get_enctypes(int, int *);
2305772Sas200622
2315772Sas200622 /*
2327052Samw * smb_ads_init
2335772Sas200622 *
2349832Samw@Sun.COM * Initializes the ADS config cache.
2355772Sas200622 */
2365772Sas200622 void
smb_ads_init(void)2377052Samw smb_ads_init(void)
2385772Sas200622 {
2399832Samw@Sun.COM (void) mutex_lock(&smb_ads_cfg.c_mtx);
2407961SNatalie.Li@Sun.COM (void) smb_config_getstr(SMB_CI_ADS_SITE,
2419832Samw@Sun.COM smb_ads_cfg.c_site, SMB_ADS_SITE_MAX);
2429832Samw@Sun.COM (void) smb_config_getip(SMB_CI_DOMAIN_SRV, &smb_ads_cfg.c_pdc);
2439832Samw@Sun.COM (void) mutex_unlock(&smb_ads_cfg.c_mtx);
2449832Samw@Sun.COM }
2459832Samw@Sun.COM
2469832Samw@Sun.COM void
smb_ads_fini(void)2479832Samw@Sun.COM smb_ads_fini(void)
2489832Samw@Sun.COM {
2499832Samw@Sun.COM smb_ads_free_cached_host();
2505772Sas200622 }
2515772Sas200622
2525772Sas200622 /*
2537052Samw * smb_ads_refresh
2545772Sas200622 *
2559832Samw@Sun.COM * This function will be called when smb/server SMF service is refreshed.
2569832Samw@Sun.COM * Clearing the smb_ads_cached_host_info would allow the next DC
2579832Samw@Sun.COM * discovery process to pick up an AD based on the new AD configuration.
2585772Sas200622 */
2595772Sas200622 void
smb_ads_refresh(void)2607052Samw smb_ads_refresh(void)
2615772Sas200622 {
2627052Samw char new_site[SMB_ADS_SITE_MAX];
2639832Samw@Sun.COM smb_inaddr_t new_pdc;
2649832Samw@Sun.COM boolean_t purge = B_FALSE;
2659832Samw@Sun.COM
2669832Samw@Sun.COM (void) smb_config_getstr(SMB_CI_ADS_SITE, new_site, SMB_ADS_SITE_MAX);
2679832Samw@Sun.COM (void) smb_config_getip(SMB_CI_DOMAIN_SRV, &new_pdc);
2689832Samw@Sun.COM (void) mutex_lock(&smb_ads_cfg.c_mtx);
26910966SJordan.Brown@Sun.COM if (smb_strcasecmp(smb_ads_cfg.c_site, new_site, 0)) {
2709832Samw@Sun.COM (void) strlcpy(smb_ads_cfg.c_site, new_site, SMB_ADS_SITE_MAX);
2719832Samw@Sun.COM purge = B_TRUE;
2729832Samw@Sun.COM }
2739832Samw@Sun.COM
2749832Samw@Sun.COM smb_ads_cfg.c_pdc = new_pdc;
2759832Samw@Sun.COM (void) mutex_unlock(&smb_ads_cfg.c_mtx);
2769832Samw@Sun.COM
2779832Samw@Sun.COM (void) mutex_lock(&smb_ads_cached_host_mtx);
2789832Samw@Sun.COM if (smb_ads_cached_host_info &&
2799832Samw@Sun.COM smb_ads_is_pdc_configured() &&
2809832Samw@Sun.COM !smb_ads_match_pdc(smb_ads_cached_host_info))
2819832Samw@Sun.COM purge = B_TRUE;
2829832Samw@Sun.COM (void) mutex_unlock(&smb_ads_cached_host_mtx);
2839832Samw@Sun.COM
2849832Samw@Sun.COM if (purge)
2857961SNatalie.Li@Sun.COM smb_ads_free_cached_host();
2869832Samw@Sun.COM }
2879832Samw@Sun.COM
2889832Samw@Sun.COM
2899832Samw@Sun.COM
2909832Samw@Sun.COM static boolean_t
smb_ads_is_pdc_configured(void)2919832Samw@Sun.COM smb_ads_is_pdc_configured(void)
2929832Samw@Sun.COM {
2939832Samw@Sun.COM boolean_t configured;
2949832Samw@Sun.COM
2959832Samw@Sun.COM (void) mutex_lock(&smb_ads_cfg.c_mtx);
2969832Samw@Sun.COM configured = !smb_inet_iszero(&smb_ads_cfg.c_pdc);
2979832Samw@Sun.COM (void) mutex_unlock(&smb_ads_cfg.c_mtx);
2989832Samw@Sun.COM
2999832Samw@Sun.COM return (configured);
3005772Sas200622 }
3015331Samw
3025331Samw /*
3037052Samw * smb_ads_build_unc_name
3045331Samw *
3055331Samw * Construct the UNC name of the share object in the format of
3065331Samw * \\hostname.domain\shareUNC
3075331Samw *
3085331Samw * Returns 0 on success, -1 on error.
3095331Samw */
3105331Samw int
smb_ads_build_unc_name(char * unc_name,int maxlen,const char * hostname,const char * shareUNC)3117052Samw smb_ads_build_unc_name(char *unc_name, int maxlen,
3125331Samw const char *hostname, const char *shareUNC)
3135331Samw {
3145772Sas200622 char my_domain[MAXHOSTNAMELEN];
3155331Samw
3165772Sas200622 if (smb_getfqdomainname(my_domain, sizeof (my_domain)) != 0)
3175331Samw return (-1);
3185331Samw
3195331Samw (void) snprintf(unc_name, maxlen, "\\\\%s.%s\\%s",
3205331Samw hostname, my_domain, shareUNC);
3215331Samw return (0);
3225331Samw }
3235331Samw
3245331Samw /*
3257348SJose.Borrego@Sun.COM * smb_ads_ldap_ping
3267052Samw *
3277348SJose.Borrego@Sun.COM * This is used to bind to an ADS server to see
3287348SJose.Borrego@Sun.COM * if it is still alive.
3297348SJose.Borrego@Sun.COM *
3305331Samw * Returns:
3315331Samw * -1: error
3325331Samw * 0: successful
3335331Samw */
3345331Samw /*ARGSUSED*/
3355331Samw static int
smb_ads_ldap_ping(smb_ads_host_info_t * ads_host)3367348SJose.Borrego@Sun.COM smb_ads_ldap_ping(smb_ads_host_info_t *ads_host)
3375331Samw {
3387348SJose.Borrego@Sun.COM int ldversion = LDAP_VERSION3, status, timeoutms = 5 * 1000;
3397348SJose.Borrego@Sun.COM LDAP *ld = NULL;
3407348SJose.Borrego@Sun.COM
3418670SJose.Borrego@Sun.COM ld = ldap_init(ads_host->name, ads_host->port);
3427348SJose.Borrego@Sun.COM if (ld == NULL)
3437348SJose.Borrego@Sun.COM return (-1);
3447348SJose.Borrego@Sun.COM
3457348SJose.Borrego@Sun.COM ldversion = LDAP_VERSION3;
3467348SJose.Borrego@Sun.COM (void) ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &ldversion);
3477348SJose.Borrego@Sun.COM /* setup TCP/IP connect timeout */
3487348SJose.Borrego@Sun.COM (void) ldap_set_option(ld, LDAP_X_OPT_CONNECT_TIMEOUT, &timeoutms);
3497348SJose.Borrego@Sun.COM
3507348SJose.Borrego@Sun.COM status = ldap_bind_s(ld, "", NULL, LDAP_AUTH_SIMPLE);
3517348SJose.Borrego@Sun.COM
3527348SJose.Borrego@Sun.COM if (status != LDAP_SUCCESS) {
3537348SJose.Borrego@Sun.COM (void) ldap_unbind(ld);
3547348SJose.Borrego@Sun.COM return (-1);
3557348SJose.Borrego@Sun.COM }
3567348SJose.Borrego@Sun.COM
3577348SJose.Borrego@Sun.COM (void) ldap_unbind(ld);
3587348SJose.Borrego@Sun.COM
3595331Samw return (0);
3605331Samw }
3615331Samw
3625331Samw /*
3639832Samw@Sun.COM * The cached ADS host is no longer valid if one of the following criteria
3649832Samw@Sun.COM * is satisfied:
3657961SNatalie.Li@Sun.COM *
3669832Samw@Sun.COM * 1) not in the specified domain
3679832Samw@Sun.COM * 2) not the sought host (if specified)
3689832Samw@Sun.COM * 3) not reachable
3699832Samw@Sun.COM *
3709832Samw@Sun.COM * The caller is responsible for acquiring the smb_ads_cached_host_mtx lock
3719832Samw@Sun.COM * prior to calling this function.
3729832Samw@Sun.COM *
3739832Samw@Sun.COM * Return B_TRUE if the cache host is still valid. Otherwise, return B_FALSE.
3745331Samw */
3759832Samw@Sun.COM static boolean_t
smb_ads_validate_cache_host(char * domain,char * srv)3769832Samw@Sun.COM smb_ads_validate_cache_host(char *domain, char *srv)
3775331Samw {
3787961SNatalie.Li@Sun.COM if (!smb_ads_cached_host_info)
3799832Samw@Sun.COM return (B_FALSE);
3809832Samw@Sun.COM
3819832Samw@Sun.COM if (!smb_ads_is_same_domain(smb_ads_cached_host_info->name, domain))
3829832Samw@Sun.COM return (B_FALSE);
3839832Samw@Sun.COM
3849832Samw@Sun.COM if (smb_ads_ldap_ping(smb_ads_cached_host_info) == 0) {
3859832Samw@Sun.COM if (!srv)
3869832Samw@Sun.COM return (B_TRUE);
3879832Samw@Sun.COM
3889832Samw@Sun.COM if (smb_ads_is_sought_host(smb_ads_cached_host_info, srv))
3899832Samw@Sun.COM return (B_TRUE);
3909832Samw@Sun.COM }
3919832Samw@Sun.COM
3929832Samw@Sun.COM return (B_FALSE);
3935331Samw }
3945331Samw
3955331Samw /*
3967961SNatalie.Li@Sun.COM * smb_ads_is_sought_host
3977961SNatalie.Li@Sun.COM *
3987961SNatalie.Li@Sun.COM * Returns true, if the sought host name matches the input host (host) name.
3997961SNatalie.Li@Sun.COM * The sought host is expected to be in Fully Qualified Domain Name (FQDN)
4007961SNatalie.Li@Sun.COM * format.
4015331Samw */
4027961SNatalie.Li@Sun.COM static boolean_t
smb_ads_is_sought_host(smb_ads_host_info_t * host,char * sought_host_name)4037961SNatalie.Li@Sun.COM smb_ads_is_sought_host(smb_ads_host_info_t *host, char *sought_host_name)
4045331Samw {
4057961SNatalie.Li@Sun.COM if ((host == NULL) || (sought_host_name == NULL))
4067961SNatalie.Li@Sun.COM return (B_FALSE);
4077961SNatalie.Li@Sun.COM
40810966SJordan.Brown@Sun.COM if (smb_strcasecmp(host->name, sought_host_name, 0))
4097961SNatalie.Li@Sun.COM return (B_FALSE);
4107961SNatalie.Li@Sun.COM
4117961SNatalie.Li@Sun.COM return (B_TRUE);
4127961SNatalie.Li@Sun.COM }
4137961SNatalie.Li@Sun.COM
4147961SNatalie.Li@Sun.COM /*
4157961SNatalie.Li@Sun.COM * smb_ads_match_hosts_same_domain
4167961SNatalie.Li@Sun.COM *
4177961SNatalie.Li@Sun.COM * Returns true, if the cached ADS host is in the same domain as the
4187961SNatalie.Li@Sun.COM * current (given) domain.
4197961SNatalie.Li@Sun.COM */
4207961SNatalie.Li@Sun.COM static boolean_t
smb_ads_is_same_domain(char * cached_host_name,char * current_domain)4217961SNatalie.Li@Sun.COM smb_ads_is_same_domain(char *cached_host_name, char *current_domain)
4227961SNatalie.Li@Sun.COM {
4237961SNatalie.Li@Sun.COM char *cached_host_domain;
4247961SNatalie.Li@Sun.COM
4257961SNatalie.Li@Sun.COM if ((cached_host_name == NULL) || (current_domain == NULL))
4267961SNatalie.Li@Sun.COM return (B_FALSE);
4277961SNatalie.Li@Sun.COM
4287961SNatalie.Li@Sun.COM cached_host_domain = strchr(cached_host_name, '.');
4297961SNatalie.Li@Sun.COM if (cached_host_domain == NULL)
4307961SNatalie.Li@Sun.COM return (B_FALSE);
4317961SNatalie.Li@Sun.COM
4327961SNatalie.Li@Sun.COM ++cached_host_domain;
43310966SJordan.Brown@Sun.COM if (smb_strcasecmp(cached_host_domain, current_domain, 0))
4347961SNatalie.Li@Sun.COM return (B_FALSE);
4357961SNatalie.Li@Sun.COM
4367961SNatalie.Li@Sun.COM return (B_TRUE);
4375331Samw }
4387052Samw
4395331Samw /*
4407052Samw * smb_ads_skip_ques_sec
4417052Samw * Skips the question section.
4427052Samw */
4437052Samw static int
smb_ads_skip_ques_sec(int qcnt,uchar_t ** ptr,uchar_t * eom)4447052Samw smb_ads_skip_ques_sec(int qcnt, uchar_t **ptr, uchar_t *eom)
4457052Samw {
4467052Samw int i, len;
4477052Samw
4487052Samw for (i = 0; i < qcnt; i++) {
4497961SNatalie.Li@Sun.COM if ((len = dn_skipname(*ptr, eom)) < 0)
4507052Samw return (-1);
4517961SNatalie.Li@Sun.COM
4527052Samw *ptr += len + QFIXEDSZ;
4537052Samw }
4547052Samw
4557052Samw return (0);
4567052Samw }
4577052Samw
4587052Samw /*
4597052Samw * smb_ads_decode_host_ans_sec
4607348SJose.Borrego@Sun.COM * Decodes ADS hosts, priority, weight and port number from the answer
4617348SJose.Borrego@Sun.COM * section based on the current buffer pointer.
4627052Samw */
4637052Samw static int
smb_ads_decode_host_ans_sec(int ans_cnt,uchar_t ** ptr,uchar_t * eom,uchar_t * buf,smb_ads_host_info_t * ads_host_list)4647052Samw smb_ads_decode_host_ans_sec(int ans_cnt, uchar_t **ptr, uchar_t *eom,
4657052Samw uchar_t *buf, smb_ads_host_info_t *ads_host_list)
4667052Samw {
4677052Samw int i, len;
4687052Samw smb_ads_host_info_t *ads_host;
4697052Samw
4707052Samw for (i = 0; i < ans_cnt; i++) {
4717052Samw ads_host = &ads_host_list[i];
4727052Samw
4737961SNatalie.Li@Sun.COM if ((len = dn_skipname(*ptr, eom)) < 0)
4747052Samw return (-1);
4757961SNatalie.Li@Sun.COM
4767052Samw
4777052Samw *ptr += len;
4787052Samw
4797052Samw /* skip type, class, ttl */
4807052Samw *ptr += 8;
4817052Samw /* data size */
4827052Samw *ptr += 2;
4837052Samw
4847348SJose.Borrego@Sun.COM /* Get priority, weight */
4857348SJose.Borrego@Sun.COM /* LINTED: E_CONSTANT_CONDITION */
4867348SJose.Borrego@Sun.COM NS_GET16(ads_host->priority, *ptr);
4877348SJose.Borrego@Sun.COM /* LINTED: E_CONSTANT_CONDITION */
4887348SJose.Borrego@Sun.COM NS_GET16(ads_host->weight, *ptr);
4897348SJose.Borrego@Sun.COM
4907052Samw /* port */
4917052Samw /* LINTED: E_CONSTANT_CONDITION */
4927052Samw NS_GET16(ads_host->port, *ptr);
4937052Samw /* domain name */
4947052Samw len = dn_expand(buf, eom, *ptr, ads_host->name, MAXHOSTNAMELEN);
4957961SNatalie.Li@Sun.COM if (len < 0)
4967052Samw return (-1);
4977961SNatalie.Li@Sun.COM
4987052Samw *ptr += len;
4997052Samw }
5007052Samw
5017052Samw return (0);
5027052Samw }
5037052Samw
5047052Samw /*
5057052Samw * smb_ads_skip_auth_sec
5067052Samw * Skips the authority section.
5077052Samw */
5087052Samw static int
smb_ads_skip_auth_sec(int ns_cnt,uchar_t ** ptr,uchar_t * eom)5097052Samw smb_ads_skip_auth_sec(int ns_cnt, uchar_t **ptr, uchar_t *eom)
5107052Samw {
5117052Samw int i, len;
5127052Samw uint16_t size;
5137052Samw
5147052Samw for (i = 0; i < ns_cnt; i++) {
5157961SNatalie.Li@Sun.COM if ((len = dn_skipname(*ptr, eom)) < 0)
5167052Samw return (-1);
5177961SNatalie.Li@Sun.COM
5187052Samw *ptr += len;
5197052Samw /* skip type, class, ttl */
5207052Samw *ptr += 8;
5217052Samw /* get len of data */
5227052Samw /* LINTED: E_CONSTANT_CONDITION */
5237052Samw NS_GET16(size, *ptr);
5247961SNatalie.Li@Sun.COM if ((*ptr + size) > eom)
5257052Samw return (-1);
5267052Samw
5277052Samw *ptr += size;
5287052Samw }
5297052Samw
5307052Samw return (0);
5317052Samw }
5327052Samw
5337052Samw /*
5347961SNatalie.Li@Sun.COM * smb_ads_decode_host_ip
5357961SNatalie.Li@Sun.COM *
5367052Samw * Decodes ADS hosts and IP Addresses from the additional section based
5377052Samw * on the current buffer pointer.
5387052Samw */
5397052Samw static int
smb_ads_decode_host_ip(int addit_cnt,int ans_cnt,uchar_t ** ptr,uchar_t * eom,uchar_t * buf,smb_ads_host_info_t * ads_host_list)5407961SNatalie.Li@Sun.COM smb_ads_decode_host_ip(int addit_cnt, int ans_cnt, uchar_t **ptr,
5417961SNatalie.Li@Sun.COM uchar_t *eom, uchar_t *buf, smb_ads_host_info_t *ads_host_list)
5427052Samw {
5437961SNatalie.Li@Sun.COM int i, j, len;
5448670SJose.Borrego@Sun.COM smb_inaddr_t ipaddr;
5457961SNatalie.Li@Sun.COM char hostname[MAXHOSTNAMELEN];
5467961SNatalie.Li@Sun.COM char *name;
5478670SJose.Borrego@Sun.COM uint16_t size = 0;
5487052Samw
5497052Samw for (i = 0; i < addit_cnt; i++) {
5507052Samw
5517052Samw /* domain name */
5527961SNatalie.Li@Sun.COM len = dn_expand(buf, eom, *ptr, hostname, MAXHOSTNAMELEN);
5537961SNatalie.Li@Sun.COM if (len < 0)
5547052Samw return (-1);
5557961SNatalie.Li@Sun.COM
5567052Samw *ptr += len;
5577052Samw
5587052Samw /* skip type, class, TTL, data len */
5598670SJose.Borrego@Sun.COM *ptr += 8;
5607052Samw /* LINTED: E_CONSTANT_CONDITION */
5618670SJose.Borrego@Sun.COM NS_GET16(size, *ptr);
5628670SJose.Borrego@Sun.COM
5638670SJose.Borrego@Sun.COM if (size == INADDRSZ) {
5648670SJose.Borrego@Sun.COM /* LINTED: E_CONSTANT_CONDITION */
5658670SJose.Borrego@Sun.COM NS_GET32(ipaddr.a_ipv4, *ptr);
5668670SJose.Borrego@Sun.COM ipaddr.a_ipv4 = htonl(ipaddr.a_ipv4);
5678670SJose.Borrego@Sun.COM ipaddr.a_family = AF_INET;
5688670SJose.Borrego@Sun.COM } else if (size == IN6ADDRSZ) {
5698670SJose.Borrego@Sun.COM #ifdef BIG_ENDIAN
5708670SJose.Borrego@Sun.COM bcopy(*ptr, &ipaddr.a_ipv6, IN6ADDRSZ);
5718670SJose.Borrego@Sun.COM #else
5728670SJose.Borrego@Sun.COM for (i = 0; i < IN6ADDRSZ; i++)
5738670SJose.Borrego@Sun.COM (uint8_t *)(ipaddr.a_ipv6)
5748670SJose.Borrego@Sun.COM [IN6ADDRSZ-1-i] = *(*ptr+i);
5758670SJose.Borrego@Sun.COM #endif
5768670SJose.Borrego@Sun.COM ipaddr.a_family = AF_INET6;
57712065SKeyur.Desai@Sun.COM *ptr += size;
5788670SJose.Borrego@Sun.COM }
5797052Samw
5807961SNatalie.Li@Sun.COM /*
5817961SNatalie.Li@Sun.COM * find the host in the list of DC records from
5827961SNatalie.Li@Sun.COM * the answer section, that matches the host in the
5837961SNatalie.Li@Sun.COM * additional section, and set its IP address.
5847961SNatalie.Li@Sun.COM */
5857961SNatalie.Li@Sun.COM for (j = 0; j < ans_cnt; j++) {
5867961SNatalie.Li@Sun.COM if ((name = ads_host_list[j].name) == NULL)
5877961SNatalie.Li@Sun.COM continue;
58810966SJordan.Brown@Sun.COM if (smb_strcasecmp(name, hostname, 0) == 0) {
5898670SJose.Borrego@Sun.COM ads_host_list[j].ipaddr = ipaddr;
5908670SJose.Borrego@Sun.COM }
5917961SNatalie.Li@Sun.COM }
5927052Samw }
5937052Samw return (0);
5947052Samw }
5957052Samw
5967961SNatalie.Li@Sun.COM /*
5977961SNatalie.Li@Sun.COM * smb_ads_dup_host_info
5987961SNatalie.Li@Sun.COM *
5997961SNatalie.Li@Sun.COM * Duplicates the passed smb_ads_host_info_t structure.
6007961SNatalie.Li@Sun.COM * Caller must free memory allocated by this method.
6017961SNatalie.Li@Sun.COM *
6027961SNatalie.Li@Sun.COM * Returns a reference to the duplicated smb_ads_host_info_t structure.
6037961SNatalie.Li@Sun.COM * Returns NULL on error.
6047961SNatalie.Li@Sun.COM */
6057961SNatalie.Li@Sun.COM static smb_ads_host_info_t *
smb_ads_dup_host_info(smb_ads_host_info_t * ads_host)6067961SNatalie.Li@Sun.COM smb_ads_dup_host_info(smb_ads_host_info_t *ads_host)
6077052Samw {
6087961SNatalie.Li@Sun.COM smb_ads_host_info_t *dup_host;
6097961SNatalie.Li@Sun.COM
6107961SNatalie.Li@Sun.COM if (ads_host == NULL)
6117961SNatalie.Li@Sun.COM return (NULL);
6127961SNatalie.Li@Sun.COM
6137961SNatalie.Li@Sun.COM dup_host = malloc(sizeof (smb_ads_host_info_t));
6147961SNatalie.Li@Sun.COM
6157961SNatalie.Li@Sun.COM if (dup_host != NULL)
6167961SNatalie.Li@Sun.COM bcopy(ads_host, dup_host, sizeof (smb_ads_host_info_t));
6177961SNatalie.Li@Sun.COM
6187961SNatalie.Li@Sun.COM return (dup_host);
6197348SJose.Borrego@Sun.COM }
6207052Samw
6217348SJose.Borrego@Sun.COM /*
6227348SJose.Borrego@Sun.COM * smb_ads_hlist_alloc
6237348SJose.Borrego@Sun.COM */
62410717Samw@Sun.COM static smb_ads_host_list_t *
smb_ads_hlist_alloc(int count)6257348SJose.Borrego@Sun.COM smb_ads_hlist_alloc(int count)
6267348SJose.Borrego@Sun.COM {
6277348SJose.Borrego@Sun.COM int size;
6287348SJose.Borrego@Sun.COM smb_ads_host_list_t *hlist;
6297348SJose.Borrego@Sun.COM
6307961SNatalie.Li@Sun.COM if (count == 0)
6317961SNatalie.Li@Sun.COM return (NULL);
6327961SNatalie.Li@Sun.COM
6337348SJose.Borrego@Sun.COM size = sizeof (smb_ads_host_info_t) * count;
6347348SJose.Borrego@Sun.COM hlist = (smb_ads_host_list_t *)malloc(sizeof (smb_ads_host_list_t));
6357348SJose.Borrego@Sun.COM if (hlist == NULL)
6367052Samw return (NULL);
6377052Samw
6387348SJose.Borrego@Sun.COM hlist->ah_cnt = count;
6397348SJose.Borrego@Sun.COM hlist->ah_list = (smb_ads_host_info_t *)malloc(size);
6407348SJose.Borrego@Sun.COM if (hlist->ah_list == NULL) {
6417348SJose.Borrego@Sun.COM free(hlist);
6427348SJose.Borrego@Sun.COM return (NULL);
6437348SJose.Borrego@Sun.COM }
6447348SJose.Borrego@Sun.COM
6457348SJose.Borrego@Sun.COM bzero(hlist->ah_list, size);
6467348SJose.Borrego@Sun.COM return (hlist);
6477348SJose.Borrego@Sun.COM }
6487052Samw
6497348SJose.Borrego@Sun.COM /*
6507348SJose.Borrego@Sun.COM * smb_ads_hlist_free
6517348SJose.Borrego@Sun.COM */
6527348SJose.Borrego@Sun.COM static void
smb_ads_hlist_free(smb_ads_host_list_t * host_list)6537348SJose.Borrego@Sun.COM smb_ads_hlist_free(smb_ads_host_list_t *host_list)
6547348SJose.Borrego@Sun.COM {
6557348SJose.Borrego@Sun.COM if (host_list == NULL)
6567348SJose.Borrego@Sun.COM return;
6577348SJose.Borrego@Sun.COM
6587348SJose.Borrego@Sun.COM free(host_list->ah_list);
6597348SJose.Borrego@Sun.COM free(host_list);
6607052Samw }
6617052Samw
6627052Samw /*
6637961SNatalie.Li@Sun.COM * smb_ads_query_dns_server
6647348SJose.Borrego@Sun.COM *
6657052Samw * This routine sends a DNS service location (SRV) query message to the
6667961SNatalie.Li@Sun.COM * DNS server via TCP to query it for a list of ADS server(s). Once a reply
6677961SNatalie.Li@Sun.COM * is received, the reply message is parsed to get the hostname. If there are IP
6687052Samw * addresses populated in the additional section then the additional section
6697052Samw * is parsed to obtain the IP addresses.
6705331Samw *
6715331Samw * The service location of _ldap._tcp.dc.msdcs.<ADS domain> is used to
6725331Samw * guarantee that Microsoft domain controllers are returned. Microsoft domain
6735331Samw * controllers are also ADS servers.
6745331Samw *
6755331Samw * The ADS hostnames are stored in the answer section of the DNS reply message.
6767052Samw * The IP addresses are stored in the additional section.
6775331Samw *
6785331Samw * The DNS reply message may be in compress formed. The compression is done
6795331Samw * on repeating domain name label in the message. i.e hostname.
6807348SJose.Borrego@Sun.COM *
6817961SNatalie.Li@Sun.COM * Upon successful completion, host list of ADS server(s) is returned.
6825331Samw */
6837961SNatalie.Li@Sun.COM static smb_ads_host_list_t *
smb_ads_query_dns_server(char * domain,char * msdcs_svc_name)6847961SNatalie.Li@Sun.COM smb_ads_query_dns_server(char *domain, char *msdcs_svc_name)
6855331Samw {
6867961SNatalie.Li@Sun.COM smb_ads_host_list_t *hlist = NULL;
6877052Samw int len, qcnt, ans_cnt, ns_cnt, addit_cnt;
6887052Samw uchar_t *ptr, *eom;
6897052Samw struct __res_state res_state;
6907052Samw union {
6917052Samw HEADER hdr;
6927052Samw uchar_t buf[NS_MAXMSG];
6937052Samw } msg;
6945331Samw
6957052Samw bzero(&res_state, sizeof (struct __res_state));
6967052Samw if (res_ninit(&res_state) < 0)
6975331Samw return (NULL);
6985331Samw
6997052Samw /* use TCP */
7007052Samw res_state.options |= RES_USEVC;
7017052Samw
7027961SNatalie.Li@Sun.COM len = res_nquerydomain(&res_state, msdcs_svc_name, domain,
7037961SNatalie.Li@Sun.COM C_IN, T_SRV, msg.buf, sizeof (msg.buf));
7047961SNatalie.Li@Sun.COM
7057961SNatalie.Li@Sun.COM if (len < 0) {
7069021Samw@Sun.COM syslog(LOG_NOTICE, "DNS query for %s failed: %s",
7077961SNatalie.Li@Sun.COM msdcs_svc_name, hstrerror(res_state.res_h_errno));
7087961SNatalie.Li@Sun.COM res_ndestroy(&res_state);
7097961SNatalie.Li@Sun.COM return (NULL);
7107961SNatalie.Li@Sun.COM }
7117961SNatalie.Li@Sun.COM
7127961SNatalie.Li@Sun.COM if (len > sizeof (msg.buf)) {
7139021Samw@Sun.COM syslog(LOG_NOTICE,
7149021Samw@Sun.COM "DNS query for %s failed: too big", msdcs_svc_name);
7157961SNatalie.Li@Sun.COM res_ndestroy(&res_state);
7167961SNatalie.Li@Sun.COM return (NULL);
7177961SNatalie.Li@Sun.COM }
7187961SNatalie.Li@Sun.COM
7197961SNatalie.Li@Sun.COM /* parse the reply, skip header and question sections */
7207961SNatalie.Li@Sun.COM ptr = msg.buf + sizeof (msg.hdr);
7217961SNatalie.Li@Sun.COM eom = msg.buf + len;
7227961SNatalie.Li@Sun.COM
7237961SNatalie.Li@Sun.COM /* check truncated message bit */
7247961SNatalie.Li@Sun.COM if (msg.hdr.tc)
7259021Samw@Sun.COM syslog(LOG_NOTICE,
7269021Samw@Sun.COM "DNS query for %s failed: truncated", msdcs_svc_name);
7277961SNatalie.Li@Sun.COM
7287961SNatalie.Li@Sun.COM qcnt = ntohs(msg.hdr.qdcount);
7297961SNatalie.Li@Sun.COM ans_cnt = ntohs(msg.hdr.ancount);
7307961SNatalie.Li@Sun.COM ns_cnt = ntohs(msg.hdr.nscount);
7317961SNatalie.Li@Sun.COM addit_cnt = ntohs(msg.hdr.arcount);
7327961SNatalie.Li@Sun.COM
7337961SNatalie.Li@Sun.COM if (smb_ads_skip_ques_sec(qcnt, &ptr, eom) != 0) {
7347961SNatalie.Li@Sun.COM res_ndestroy(&res_state);
7357961SNatalie.Li@Sun.COM return (NULL);
7367961SNatalie.Li@Sun.COM }
7377961SNatalie.Li@Sun.COM
7387961SNatalie.Li@Sun.COM hlist = smb_ads_hlist_alloc(ans_cnt);
7397961SNatalie.Li@Sun.COM if (hlist == NULL) {
7407961SNatalie.Li@Sun.COM res_ndestroy(&res_state);
7417961SNatalie.Li@Sun.COM return (NULL);
7427961SNatalie.Li@Sun.COM }
7437961SNatalie.Li@Sun.COM
7447961SNatalie.Li@Sun.COM /* walk through the answer section */
7457961SNatalie.Li@Sun.COM if (smb_ads_decode_host_ans_sec(ans_cnt, &ptr, eom, msg.buf,
7467961SNatalie.Li@Sun.COM hlist->ah_list) != 0) {
7477961SNatalie.Li@Sun.COM smb_ads_hlist_free(hlist);
7487961SNatalie.Li@Sun.COM res_ndestroy(&res_state);
7497961SNatalie.Li@Sun.COM return (NULL);
7507961SNatalie.Li@Sun.COM }
7517961SNatalie.Li@Sun.COM
7527961SNatalie.Li@Sun.COM /* check authority section */
7537961SNatalie.Li@Sun.COM if (ns_cnt > 0) {
7547961SNatalie.Li@Sun.COM if (smb_ads_skip_auth_sec(ns_cnt, &ptr, eom) != 0) {
7557961SNatalie.Li@Sun.COM smb_ads_hlist_free(hlist);
7567961SNatalie.Li@Sun.COM res_ndestroy(&res_state);
7577961SNatalie.Li@Sun.COM return (NULL);
7587961SNatalie.Li@Sun.COM }
7597961SNatalie.Li@Sun.COM }
7607961SNatalie.Li@Sun.COM
7617961SNatalie.Li@Sun.COM /*
7627961SNatalie.Li@Sun.COM * Check additional section to get IP address of ADS host.
7637961SNatalie.Li@Sun.COM */
7647961SNatalie.Li@Sun.COM if (addit_cnt > 0) {
7657961SNatalie.Li@Sun.COM if (smb_ads_decode_host_ip(addit_cnt, ans_cnt,
7667961SNatalie.Li@Sun.COM &ptr, eom, msg.buf, hlist->ah_list) != 0) {
7677961SNatalie.Li@Sun.COM smb_ads_hlist_free(hlist);
7687961SNatalie.Li@Sun.COM res_ndestroy(&res_state);
7697961SNatalie.Li@Sun.COM return (NULL);
7707961SNatalie.Li@Sun.COM }
7717961SNatalie.Li@Sun.COM }
7727961SNatalie.Li@Sun.COM
7737961SNatalie.Li@Sun.COM res_ndestroy(&res_state);
7747961SNatalie.Li@Sun.COM return (hlist);
7757961SNatalie.Li@Sun.COM }
7767961SNatalie.Li@Sun.COM
7777961SNatalie.Li@Sun.COM /*
7789021Samw@Sun.COM * smb_ads_get_site_service
7797961SNatalie.Li@Sun.COM *
7809021Samw@Sun.COM * Gets the msdcs SRV RR for the specified site.
7817961SNatalie.Li@Sun.COM */
7827961SNatalie.Li@Sun.COM static void
smb_ads_get_site_service(char * site_service,size_t len)7839021Samw@Sun.COM smb_ads_get_site_service(char *site_service, size_t len)
7847961SNatalie.Li@Sun.COM {
7859832Samw@Sun.COM (void) mutex_lock(&smb_ads_cfg.c_mtx);
7869832Samw@Sun.COM if (*smb_ads_cfg.c_site == '\0')
7877052Samw *site_service = '\0';
7887052Samw else
7899021Samw@Sun.COM (void) snprintf(site_service, len,
7909832Samw@Sun.COM SMB_ADS_MSDCS_SRV_SITE_RR, smb_ads_cfg.c_site);
7919832Samw@Sun.COM
7929832Samw@Sun.COM (void) mutex_unlock(&smb_ads_cfg.c_mtx);
7937961SNatalie.Li@Sun.COM }
7947961SNatalie.Li@Sun.COM
7957961SNatalie.Li@Sun.COM /*
7967961SNatalie.Li@Sun.COM * smb_ads_getipnodebyname
7977961SNatalie.Li@Sun.COM *
7987961SNatalie.Li@Sun.COM * This method gets the IP address by doing a host name lookup.
7997961SNatalie.Li@Sun.COM */
8007961SNatalie.Li@Sun.COM static int
smb_ads_getipnodebyname(smb_ads_host_info_t * hentry)8017961SNatalie.Li@Sun.COM smb_ads_getipnodebyname(smb_ads_host_info_t *hentry)
8027961SNatalie.Li@Sun.COM {
8037961SNatalie.Li@Sun.COM struct hostent *h;
8047961SNatalie.Li@Sun.COM int error;
8057961SNatalie.Li@Sun.COM
8068670SJose.Borrego@Sun.COM switch (hentry->ipaddr.a_family) {
8078670SJose.Borrego@Sun.COM case AF_INET6:
8088670SJose.Borrego@Sun.COM h = getipnodebyname(hentry->name, hentry->ipaddr.a_family,
8098670SJose.Borrego@Sun.COM AI_DEFAULT, &error);
8108670SJose.Borrego@Sun.COM if (h == NULL || h->h_length != IPV6_ADDR_LEN)
8118670SJose.Borrego@Sun.COM return (-1);
8128670SJose.Borrego@Sun.COM break;
8138670SJose.Borrego@Sun.COM
8148670SJose.Borrego@Sun.COM case AF_INET:
8158670SJose.Borrego@Sun.COM h = getipnodebyname(hentry->name, hentry->ipaddr.a_family,
8168670SJose.Borrego@Sun.COM 0, &error);
8178670SJose.Borrego@Sun.COM if (h == NULL || h->h_length != INADDRSZ)
8188670SJose.Borrego@Sun.COM return (-1);
8198670SJose.Borrego@Sun.COM break;
8208670SJose.Borrego@Sun.COM
8218670SJose.Borrego@Sun.COM default:
8227961SNatalie.Li@Sun.COM return (-1);
8238670SJose.Borrego@Sun.COM }
8248670SJose.Borrego@Sun.COM bcopy(*(h->h_addr_list), &hentry->ipaddr.a_ip, h->h_length);
8257961SNatalie.Li@Sun.COM freehostent(h);
8267961SNatalie.Li@Sun.COM return (0);
8277961SNatalie.Li@Sun.COM }
8287961SNatalie.Li@Sun.COM
8297961SNatalie.Li@Sun.COM /*
83011633SJoyce.McIntosh@Sun.COM * Checks the IP address to see if it is zero. If so, then do a host
83111633SJoyce.McIntosh@Sun.COM * lookup by hostname to get the IP address based on the IP family.
83211633SJoyce.McIntosh@Sun.COM *
83311633SJoyce.McIntosh@Sun.COM * If the family is unknown then do a lookup by hostame based on the
83411633SJoyce.McIntosh@Sun.COM * setting of the SMB_CI_IPV6_ENABLE property.
83511633SJoyce.McIntosh@Sun.COM */
83611633SJoyce.McIntosh@Sun.COM static int
smb_ads_set_ipaddr(smb_ads_host_info_t * hentry)83711633SJoyce.McIntosh@Sun.COM smb_ads_set_ipaddr(smb_ads_host_info_t *hentry)
83811633SJoyce.McIntosh@Sun.COM {
83911633SJoyce.McIntosh@Sun.COM if (smb_inet_iszero(&hentry->ipaddr)) {
84011633SJoyce.McIntosh@Sun.COM if (smb_ads_getipnodebyname(hentry) < 0)
84111633SJoyce.McIntosh@Sun.COM return (-1);
84211633SJoyce.McIntosh@Sun.COM } else if (SMB_ADS_AF_UNKNOWN(hentry)) {
84311633SJoyce.McIntosh@Sun.COM hentry->ipaddr.a_family =
84411633SJoyce.McIntosh@Sun.COM smb_config_getbool(SMB_CI_IPV6_ENABLE) ? AF_INET6 : AF_INET;
84511633SJoyce.McIntosh@Sun.COM
84611633SJoyce.McIntosh@Sun.COM if (smb_ads_getipnodebyname(hentry) < 0) {
84711633SJoyce.McIntosh@Sun.COM hentry->ipaddr.a_family = 0;
84811633SJoyce.McIntosh@Sun.COM return (-1);
84911633SJoyce.McIntosh@Sun.COM }
85011633SJoyce.McIntosh@Sun.COM }
85111633SJoyce.McIntosh@Sun.COM
85211633SJoyce.McIntosh@Sun.COM return (0);
85311633SJoyce.McIntosh@Sun.COM }
85411633SJoyce.McIntosh@Sun.COM
85511633SJoyce.McIntosh@Sun.COM /*
8567961SNatalie.Li@Sun.COM * smb_ads_find_host
8577961SNatalie.Li@Sun.COM *
8589832Samw@Sun.COM * Finds an ADS host in a given domain.
8599832Samw@Sun.COM *
8609832Samw@Sun.COM * If the cached host is valid, it will be used. Otherwise, a DC will
8619832Samw@Sun.COM * be selected based on the following criteria:
8629832Samw@Sun.COM *
8639832Samw@Sun.COM * 1) pdc (aka preferred DC) configuration
8649832Samw@Sun.COM * 2) AD site configuration - the scope of the DNS lookup will be
8659832Samw@Sun.COM * restricted to the specified site.
8669832Samw@Sun.COM * 3) DC on the same subnet
8679832Samw@Sun.COM * 4) DC with the lowest priority/highest weight
8689832Samw@Sun.COM *
8699832Samw@Sun.COM * The above items are listed in decreasing preference order. The selected
8709832Samw@Sun.COM * DC must be online.
8719832Samw@Sun.COM *
8729832Samw@Sun.COM * If this function is called during domain join, the specified kpasswd server
8739832Samw@Sun.COM * takes precedence over preferred DC, AD site, and so on.
8747961SNatalie.Li@Sun.COM *
8757961SNatalie.Li@Sun.COM * Parameters:
8769832Samw@Sun.COM * domain: fully-qualified domain name.
8779832Samw@Sun.COM * kpasswd_srv: fully-quailifed hostname of the kpasswd server.
8787961SNatalie.Li@Sun.COM *
8797961SNatalie.Li@Sun.COM * Returns:
8809832Samw@Sun.COM * A copy of the cached host info is returned. The caller is responsible
8819832Samw@Sun.COM * for deallocating the memory returned by this function.
8827961SNatalie.Li@Sun.COM */
8837961SNatalie.Li@Sun.COM /*ARGSUSED*/
8847961SNatalie.Li@Sun.COM smb_ads_host_info_t *
smb_ads_find_host(char * domain,char * kpasswd_srv)8859832Samw@Sun.COM smb_ads_find_host(char *domain, char *kpasswd_srv)
8867961SNatalie.Li@Sun.COM {
8877961SNatalie.Li@Sun.COM int i;
8887961SNatalie.Li@Sun.COM char site_service[MAXHOSTNAMELEN];
8899832Samw@Sun.COM smb_ads_host_list_t *hlist, *hlist2;
8909832Samw@Sun.COM smb_ads_host_info_t *hlistp = NULL, *host = NULL;
8919832Samw@Sun.COM smb_ads_host_info_t *found_kpasswd_srv = NULL;
8929832Samw@Sun.COM smb_ads_host_info_t *found_pdc = NULL;
8939832Samw@Sun.COM
8949832Samw@Sun.COM if ((kpasswd_srv) && (*kpasswd_srv == '\0'))
8959832Samw@Sun.COM kpasswd_srv = NULL;
8969832Samw@Sun.COM
8979832Samw@Sun.COM (void) mutex_lock(&smb_ads_cached_host_mtx);
8989832Samw@Sun.COM if (smb_ads_validate_cache_host(domain, kpasswd_srv)) {
8999832Samw@Sun.COM host = smb_ads_dup_host_info(smb_ads_cached_host_info);
9009832Samw@Sun.COM (void) mutex_unlock(&smb_ads_cached_host_mtx);
9019832Samw@Sun.COM return (host);
9027961SNatalie.Li@Sun.COM }
9037961SNatalie.Li@Sun.COM
9049832Samw@Sun.COM (void) mutex_unlock(&smb_ads_cached_host_mtx);
9059832Samw@Sun.COM smb_ads_free_cached_host();
9065331Samw
9077052Samw /*
9087052Samw * First look for ADS hosts in ADS site if configured. Then try
9097052Samw * without ADS site info.
9107052Samw */
9119021Samw@Sun.COM hlist = NULL;
9129021Samw@Sun.COM smb_ads_get_site_service(site_service, MAXHOSTNAMELEN);
9139832Samw@Sun.COM
9149832Samw@Sun.COM /*
9159832Samw@Sun.COM * If we're given an AD, the DNS SRV RR lookup should not be restricted
9169832Samw@Sun.COM * to the specified site since there is no guarantee that the specified
9179832Samw@Sun.COM * AD is in the specified site.
9189832Samw@Sun.COM */
9199832Samw@Sun.COM if (*site_service != '\0' && !kpasswd_srv &&
9209832Samw@Sun.COM !smb_ads_is_pdc_configured())
9219021Samw@Sun.COM hlist = smb_ads_query_dns_server(domain, site_service);
9229021Samw@Sun.COM
9239021Samw@Sun.COM if (!hlist)
9249021Samw@Sun.COM hlist = smb_ads_query_dns_server(domain,
9259021Samw@Sun.COM SMB_ADS_MSDCS_SRV_DC_RR);
9267961SNatalie.Li@Sun.COM
9277961SNatalie.Li@Sun.COM if ((hlist == NULL) || (hlist->ah_list == NULL) || (hlist->ah_cnt == 0))
9287961SNatalie.Li@Sun.COM return (NULL);
9299832Samw@Sun.COM
9309832Samw@Sun.COM for (i = 0, hlistp = hlist->ah_list; i < hlist->ah_cnt; i++) {
93111633SJoyce.McIntosh@Sun.COM if (smb_ads_set_ipaddr(&hlistp[i]) < 0)
93211633SJoyce.McIntosh@Sun.COM continue;
9335331Samw
9349832Samw@Sun.COM if (smb_ads_is_sought_host(&hlistp[i], kpasswd_srv))
9359832Samw@Sun.COM found_kpasswd_srv = &hlistp[i];
9369832Samw@Sun.COM
9379832Samw@Sun.COM if (smb_ads_match_pdc(&hlistp[i]))
9389832Samw@Sun.COM found_pdc = &hlistp[i];
9399832Samw@Sun.COM }
9409832Samw@Sun.COM
9419832Samw@Sun.COM if (found_kpasswd_srv && smb_ads_ldap_ping(found_kpasswd_srv) == 0) {
9429832Samw@Sun.COM host = found_kpasswd_srv;
9439832Samw@Sun.COM goto update_cache;
9449832Samw@Sun.COM }
9459832Samw@Sun.COM
9469832Samw@Sun.COM if (found_pdc && smb_ads_ldap_ping(found_pdc) == 0) {
9479832Samw@Sun.COM host = found_pdc;
9489832Samw@Sun.COM goto update_cache;
9499832Samw@Sun.COM }
9509832Samw@Sun.COM
9519832Samw@Sun.COM /*
9529832Samw@Sun.COM * If the specified DC (kpasswd_srv or pdc) is not found, fallback
9539832Samw@Sun.COM * to find a DC in the specified AD site.
9549832Samw@Sun.COM */
9559832Samw@Sun.COM if (*site_service != '\0' &&
9569832Samw@Sun.COM (kpasswd_srv || smb_ads_is_pdc_configured())) {
9579832Samw@Sun.COM hlist2 = smb_ads_query_dns_server(domain, site_service);
9589832Samw@Sun.COM if (hlist2 && hlist2->ah_list && hlist2->ah_cnt != 0) {
9597961SNatalie.Li@Sun.COM smb_ads_hlist_free(hlist);
9609832Samw@Sun.COM hlist = hlist2;
9619832Samw@Sun.COM hlistp = hlist->ah_list;
9629832Samw@Sun.COM
96311633SJoyce.McIntosh@Sun.COM for (i = 0; i < hlist->ah_cnt; i++)
96411633SJoyce.McIntosh@Sun.COM (void) smb_ads_set_ipaddr(&hlistp[i]);
9656849Sjb150015 }
9665331Samw }
9677961SNatalie.Li@Sun.COM
9687961SNatalie.Li@Sun.COM /* Select DC from DC list */
9699832Samw@Sun.COM host = smb_ads_select_dc(hlist);
9709832Samw@Sun.COM
9719832Samw@Sun.COM update_cache:
9729832Samw@Sun.COM if (host) {
9739832Samw@Sun.COM (void) mutex_lock(&smb_ads_cached_host_mtx);
9749832Samw@Sun.COM if (!smb_ads_cached_host_info)
9759832Samw@Sun.COM smb_ads_cached_host_info = smb_ads_dup_host_info(host);
9769832Samw@Sun.COM host = smb_ads_dup_host_info(smb_ads_cached_host_info);
9779832Samw@Sun.COM (void) mutex_unlock(&smb_ads_cached_host_mtx);
9787961SNatalie.Li@Sun.COM }
9797961SNatalie.Li@Sun.COM
9807961SNatalie.Li@Sun.COM smb_ads_hlist_free(hlist);
9819832Samw@Sun.COM return (host);
9825331Samw }
9835331Samw
9845331Samw /*
9857961SNatalie.Li@Sun.COM * Return the number of dots in a string.
9865331Samw */
9877961SNatalie.Li@Sun.COM static int
smb_ads_count_dots(const char * s)9887961SNatalie.Li@Sun.COM smb_ads_count_dots(const char *s)
9895331Samw {
9907961SNatalie.Li@Sun.COM int ndots = 0;
9917961SNatalie.Li@Sun.COM
9927961SNatalie.Li@Sun.COM while (*s) {
9937961SNatalie.Li@Sun.COM if (*s++ == '.')
9947961SNatalie.Li@Sun.COM ndots++;
9955331Samw }
9965331Samw
9977961SNatalie.Li@Sun.COM return (ndots);
9985331Samw }
9995331Samw
10005331Samw /*
10017961SNatalie.Li@Sun.COM * Convert a domain name in dot notation to distinguished name format,
10027961SNatalie.Li@Sun.COM * for example: sun.com -> dc=sun,dc=com.
10037961SNatalie.Li@Sun.COM *
10047961SNatalie.Li@Sun.COM * Returns a pointer to an allocated buffer containing the distinguished
10057961SNatalie.Li@Sun.COM * name.
10067961SNatalie.Li@Sun.COM */
10077961SNatalie.Li@Sun.COM static char *
smb_ads_convert_domain(const char * domain_name)10087961SNatalie.Li@Sun.COM smb_ads_convert_domain(const char *domain_name)
10097961SNatalie.Li@Sun.COM {
10107961SNatalie.Li@Sun.COM const char *s;
10117961SNatalie.Li@Sun.COM char *dn_name;
10127961SNatalie.Li@Sun.COM char buf[2];
10137961SNatalie.Li@Sun.COM int ndots;
10147961SNatalie.Li@Sun.COM int len;
10157961SNatalie.Li@Sun.COM
10167961SNatalie.Li@Sun.COM if (domain_name == NULL || *domain_name == 0)
10177961SNatalie.Li@Sun.COM return (NULL);
10187961SNatalie.Li@Sun.COM
10197961SNatalie.Li@Sun.COM ndots = smb_ads_count_dots(domain_name);
10207961SNatalie.Li@Sun.COM ++ndots;
10217961SNatalie.Li@Sun.COM len = strlen(domain_name) + (ndots * SMB_ADS_DN_PREFIX_LEN) + 1;
10227961SNatalie.Li@Sun.COM
10237961SNatalie.Li@Sun.COM if ((dn_name = malloc(len)) == NULL)
10247961SNatalie.Li@Sun.COM return (NULL);
10257961SNatalie.Li@Sun.COM
10267961SNatalie.Li@Sun.COM bzero(dn_name, len);
10277961SNatalie.Li@Sun.COM (void) strlcpy(dn_name, "dc=", len);
10287961SNatalie.Li@Sun.COM
10297961SNatalie.Li@Sun.COM buf[1] = '\0';
10307961SNatalie.Li@Sun.COM s = domain_name;
10317961SNatalie.Li@Sun.COM
10327961SNatalie.Li@Sun.COM while (*s) {
10337961SNatalie.Li@Sun.COM if (*s == '.') {
10347961SNatalie.Li@Sun.COM (void) strlcat(dn_name, ",dc=", len);
10357961SNatalie.Li@Sun.COM } else {
10367961SNatalie.Li@Sun.COM buf[0] = *s;
10377961SNatalie.Li@Sun.COM (void) strlcat(dn_name, buf, len);
10387961SNatalie.Li@Sun.COM }
10397961SNatalie.Li@Sun.COM ++s;
10407961SNatalie.Li@Sun.COM }
10417961SNatalie.Li@Sun.COM
10427961SNatalie.Li@Sun.COM return (dn_name);
10437961SNatalie.Li@Sun.COM }
10447961SNatalie.Li@Sun.COM
10457961SNatalie.Li@Sun.COM /*
10467961SNatalie.Li@Sun.COM * smb_ads_free_cached_host
10477961SNatalie.Li@Sun.COM *
10487961SNatalie.Li@Sun.COM * Free the memory use by the global smb_ads_cached_host_info & set it to NULL.
10495331Samw */
10505772Sas200622 static void
smb_ads_free_cached_host(void)10517961SNatalie.Li@Sun.COM smb_ads_free_cached_host(void)
10525331Samw {
10537961SNatalie.Li@Sun.COM (void) mutex_lock(&smb_ads_cached_host_mtx);
10547961SNatalie.Li@Sun.COM if (smb_ads_cached_host_info) {
10557961SNatalie.Li@Sun.COM free(smb_ads_cached_host_info);
10567961SNatalie.Li@Sun.COM smb_ads_cached_host_info = NULL;
10575331Samw }
10587961SNatalie.Li@Sun.COM (void) mutex_unlock(&smb_ads_cached_host_mtx);
10595331Samw }
10605331Samw
10615331Samw /*
10627052Samw * smb_ads_open
10635521Sas200622 * Open a LDAP connection to an ADS server if the system is in domain mode.
10645521Sas200622 * Acquire both Kerberos TGT and LDAP service tickets for the host principal.
10655521Sas200622 *
10665521Sas200622 * This function should only be called after the system is successfully joined
10675521Sas200622 * to a domain.
10685521Sas200622 */
10697052Samw smb_ads_handle_t *
smb_ads_open(void)10707052Samw smb_ads_open(void)
10715521Sas200622 {
10725772Sas200622 char domain[MAXHOSTNAMELEN];
10735521Sas200622
10745772Sas200622 if (smb_config_get_secmode() != SMB_SECMODE_DOMAIN)
10755521Sas200622 return (NULL);
10765521Sas200622
10775772Sas200622 if (smb_getfqdomainname(domain, MAXHOSTNAMELEN) != 0)
10785772Sas200622 return (NULL);
10795772Sas200622
10807052Samw return (smb_ads_open_main(domain, NULL, NULL));
10815521Sas200622 }
10825521Sas200622
108310717Samw@Sun.COM static int
smb_ads_saslcallback(LDAP * ld,unsigned flags,void * defaults,void * prompts)108410717Samw@Sun.COM smb_ads_saslcallback(LDAP *ld, unsigned flags, void *defaults, void *prompts)
108510717Samw@Sun.COM {
108610717Samw@Sun.COM NOTE(ARGUNUSED(ld, defaults));
108710717Samw@Sun.COM sasl_interact_t *interact;
108810717Samw@Sun.COM
108910717Samw@Sun.COM if (prompts == NULL || flags != LDAP_SASL_INTERACTIVE)
109010717Samw@Sun.COM return (LDAP_PARAM_ERROR);
109110717Samw@Sun.COM
109210717Samw@Sun.COM /* There should be no extra arguemnts for SASL/GSSAPI authentication */
109310717Samw@Sun.COM for (interact = prompts; interact->id != SASL_CB_LIST_END;
109410717Samw@Sun.COM interact++) {
109510717Samw@Sun.COM interact->result = NULL;
109610717Samw@Sun.COM interact->len = 0;
109710717Samw@Sun.COM }
109810717Samw@Sun.COM return (LDAP_SUCCESS);
109910717Samw@Sun.COM }
110010717Samw@Sun.COM
11015521Sas200622 /*
11027052Samw * smb_ads_open_main
11035331Samw * Open a LDAP connection to an ADS server.
11045521Sas200622 * If ADS is enabled and the administrative username, password, and
11055331Samw * ADS domain are defined then query DNS to find an ADS server if this is the
11065331Samw * very first call to this routine. After an ADS server is found then this
11075331Samw * server will be used everytime this routine is called until the system is
11085331Samw * rebooted or the ADS server becomes unavailable then an ADS server will
11097052Samw * be queried again. After the connection is made then an ADS handle
11105331Samw * is created to be returned.
11115331Samw *
11125331Samw * After the LDAP connection, the LDAP version will be set to 3 using
11135331Samw * ldap_set_option().
11145331Samw *
111510717Samw@Sun.COM * The LDAP connection is bound before the ADS handle is returned.
11165331Samw * Parameters:
11175772Sas200622 * domain - fully-qualified domain name
11185772Sas200622 * user - the user account for whom the Kerberos TGT ticket and ADS
11195772Sas200622 * service tickets are acquired.
11205772Sas200622 * password - password of the specified user
11215772Sas200622 *
11225331Samw * Returns:
11237052Samw * NULL : can't connect to ADS server or other errors
11247052Samw * smb_ads_handle_t* : handle to ADS server
11255331Samw */
11267052Samw static smb_ads_handle_t *
smb_ads_open_main(char * domain,char * user,char * password)11277052Samw smb_ads_open_main(char *domain, char *user, char *password)
11285331Samw {
11297052Samw smb_ads_handle_t *ah;
11305331Samw LDAP *ld;
11317961SNatalie.Li@Sun.COM int version = 3;
11327052Samw smb_ads_host_info_t *ads_host = NULL;
113310717Samw@Sun.COM int rc;
113410717Samw@Sun.COM
113510717Samw@Sun.COM if (user != NULL) {
113610717Samw@Sun.COM if (smb_kinit(user, password) == 0)
113710717Samw@Sun.COM return (NULL);
113810717Samw@Sun.COM user = NULL;
113910717Samw@Sun.COM password = NULL;
114010717Samw@Sun.COM }
11415331Samw
11427961SNatalie.Li@Sun.COM ads_host = smb_ads_find_host(domain, NULL);
11437961SNatalie.Li@Sun.COM if (ads_host == NULL)
11447961SNatalie.Li@Sun.COM return (NULL);
11457961SNatalie.Li@Sun.COM
11467052Samw ah = (smb_ads_handle_t *)malloc(sizeof (smb_ads_handle_t));
11479832Samw@Sun.COM if (ah == NULL) {
11489832Samw@Sun.COM free(ads_host);
11495331Samw return (NULL);
11509832Samw@Sun.COM }
11519832Samw@Sun.COM
11527052Samw (void) memset(ah, 0, sizeof (smb_ads_handle_t));
11535331Samw
11548670SJose.Borrego@Sun.COM if ((ld = ldap_init(ads_host->name, ads_host->port)) == NULL) {
11557961SNatalie.Li@Sun.COM smb_ads_free_cached_host();
11565331Samw free(ah);
11579832Samw@Sun.COM free(ads_host);
11585331Samw return (NULL);
11595331Samw }
11605331Samw
11615331Samw if (ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &version)
11625331Samw != LDAP_SUCCESS) {
11637961SNatalie.Li@Sun.COM smb_ads_free_cached_host();
11645331Samw free(ah);
11659832Samw@Sun.COM free(ads_host);
11665331Samw (void) ldap_unbind(ld);
11675331Samw return (NULL);
11685331Samw }
11695331Samw
11707348SJose.Borrego@Sun.COM (void) ldap_set_option(ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
11715331Samw ah->ld = ld;
11725331Samw ah->domain = strdup(domain);
11735331Samw
11745521Sas200622 if (ah->domain == NULL) {
11757052Samw smb_ads_close(ah);
11769832Samw@Sun.COM free(ads_host);
11775331Samw return (NULL);
11785331Samw }
11795331Samw
118011963SAfshin.Ardakani@Sun.COM /*
118111963SAfshin.Ardakani@Sun.COM * ah->domain is often used for generating service principal name.
118211963SAfshin.Ardakani@Sun.COM * Convert it to lower case for RFC 4120 section 6.2.1 conformance.
118311963SAfshin.Ardakani@Sun.COM */
118411963SAfshin.Ardakani@Sun.COM (void) smb_strlwr(ah->domain);
11857052Samw ah->domain_dn = smb_ads_convert_domain(domain);
11865331Samw if (ah->domain_dn == NULL) {
11877052Samw smb_ads_close(ah);
11889832Samw@Sun.COM free(ads_host);
11895331Samw return (NULL);
11905331Samw }
11915331Samw
11925331Samw ah->hostname = strdup(ads_host->name);
11935331Samw if (ah->hostname == NULL) {
11947052Samw smb_ads_close(ah);
11959832Samw@Sun.COM free(ads_host);
11965331Samw return (NULL);
11975331Samw }
11989832Samw@Sun.COM (void) mutex_lock(&smb_ads_cfg.c_mtx);
11999832Samw@Sun.COM if (*smb_ads_cfg.c_site != '\0') {
12009832Samw@Sun.COM if ((ah->site = strdup(smb_ads_cfg.c_site)) == NULL) {
12017052Samw smb_ads_close(ah);
12029832Samw@Sun.COM (void) mutex_unlock(&smb_ads_cfg.c_mtx);
12039832Samw@Sun.COM free(ads_host);
12045331Samw return (NULL);
12055331Samw }
12065331Samw } else {
12075331Samw ah->site = NULL;
12085331Samw }
12099832Samw@Sun.COM (void) mutex_unlock(&smb_ads_cfg.c_mtx);
12105331Samw
121110717Samw@Sun.COM rc = ldap_sasl_interactive_bind_s(ah->ld, "", "GSSAPI", NULL, NULL,
121210717Samw@Sun.COM LDAP_SASL_INTERACTIVE, &smb_ads_saslcallback, NULL);
121310717Samw@Sun.COM if (rc != LDAP_SUCCESS) {
121410717Samw@Sun.COM syslog(LOG_ERR, "ldal_sasl_interactive_bind_s failed (%s)",
121510717Samw@Sun.COM ldap_err2string(rc));
12167052Samw smb_ads_close(ah);
12179832Samw@Sun.COM free(ads_host);
12185331Samw return (NULL);
12195331Samw }
12205331Samw
12219832Samw@Sun.COM free(ads_host);
12225331Samw return (ah);
12235331Samw }
12245331Samw
12255331Samw /*
12267052Samw * smb_ads_close
12275331Samw * Close connection to ADS server and free memory allocated for ADS handle.
12285331Samw * LDAP unbind is called here.
12295331Samw * Parameters:
12305331Samw * ah: handle to ADS server
12315331Samw * Returns:
12325331Samw * void
12335331Samw */
12345331Samw void
smb_ads_close(smb_ads_handle_t * ah)12357052Samw smb_ads_close(smb_ads_handle_t *ah)
12365331Samw {
12375331Samw if (ah == NULL)
12385331Samw return;
12395331Samw /* close and free connection resources */
12405331Samw if (ah->ld)
12415331Samw (void) ldap_unbind(ah->ld);
12425331Samw
12435331Samw free(ah->domain);
12445331Samw free(ah->domain_dn);
12455331Samw free(ah->hostname);
12465331Samw free(ah->site);
12475331Samw free(ah);
12485331Samw }
12495331Samw
12505331Samw /*
12517052Samw * smb_ads_alloc_attr
12526432Sas200622 *
12536432Sas200622 * Since the attrs is a null-terminated array, all elements
12546432Sas200622 * in the array (except the last one) will point to allocated
12556432Sas200622 * memory.
12566432Sas200622 */
12576432Sas200622 static int
smb_ads_alloc_attr(LDAPMod * attrs[],int num)12587052Samw smb_ads_alloc_attr(LDAPMod *attrs[], int num)
12596432Sas200622 {
12606432Sas200622 int i;
12616432Sas200622
12626432Sas200622 bzero(attrs, num * sizeof (LDAPMod *));
12636432Sas200622 for (i = 0; i < (num - 1); i++) {
12646432Sas200622 attrs[i] = (LDAPMod *)malloc(sizeof (LDAPMod));
12656432Sas200622 if (attrs[i] == NULL) {
12667052Samw smb_ads_free_attr(attrs);
12676432Sas200622 return (-1);
12686432Sas200622 }
12696432Sas200622 }
12706432Sas200622
12716432Sas200622 return (0);
12726432Sas200622 }
12736432Sas200622
12746432Sas200622 /*
12757052Samw * smb_ads_free_attr
12765331Samw * Free memory allocated when publishing a share.
12775331Samw * Parameters:
12785521Sas200622 * attrs: an array of LDAPMod pointers
12795331Samw * Returns:
12805331Samw * None
12815331Samw */
12825331Samw static void
smb_ads_free_attr(LDAPMod * attrs[])12837052Samw smb_ads_free_attr(LDAPMod *attrs[])
12845331Samw {
12855331Samw int i;
12865521Sas200622 for (i = 0; attrs[i]; i++) {
12875521Sas200622 free(attrs[i]);
12885331Samw }
12895331Samw }
12905331Samw
12915331Samw /*
129211337SWilliam.Krier@Sun.COM * Returns share DN in an allocated buffer. The format of the DN is
129311337SWilliam.Krier@Sun.COM * cn=<sharename>,<container RDNs>,<domain DN>
129411337SWilliam.Krier@Sun.COM *
129511337SWilliam.Krier@Sun.COM * If the domain DN is not included in the container parameter,
129611337SWilliam.Krier@Sun.COM * then it will be appended to create the share DN.
129711337SWilliam.Krier@Sun.COM *
129811337SWilliam.Krier@Sun.COM * The caller must free the allocated buffer.
129911337SWilliam.Krier@Sun.COM */
130011337SWilliam.Krier@Sun.COM static char *
smb_ads_get_sharedn(const char * sharename,const char * container,const char * domain_dn)130111337SWilliam.Krier@Sun.COM smb_ads_get_sharedn(const char *sharename, const char *container,
130211337SWilliam.Krier@Sun.COM const char *domain_dn)
130311337SWilliam.Krier@Sun.COM {
130411337SWilliam.Krier@Sun.COM char *share_dn;
130511337SWilliam.Krier@Sun.COM int rc, offset, container_len, domain_len;
130611337SWilliam.Krier@Sun.COM boolean_t append_domain = B_TRUE;
130711337SWilliam.Krier@Sun.COM
130811337SWilliam.Krier@Sun.COM container_len = strlen(container);
130911337SWilliam.Krier@Sun.COM domain_len = strlen(domain_dn);
131011337SWilliam.Krier@Sun.COM
131111337SWilliam.Krier@Sun.COM if (container_len >= domain_len) {
131211337SWilliam.Krier@Sun.COM
131311337SWilliam.Krier@Sun.COM /* offset to last domain_len characters */
131411337SWilliam.Krier@Sun.COM offset = container_len - domain_len;
131511337SWilliam.Krier@Sun.COM
131611337SWilliam.Krier@Sun.COM if (smb_strcasecmp(container + offset,
131711337SWilliam.Krier@Sun.COM domain_dn, domain_len) == 0)
131811337SWilliam.Krier@Sun.COM append_domain = B_FALSE;
131911337SWilliam.Krier@Sun.COM }
132011337SWilliam.Krier@Sun.COM
132111337SWilliam.Krier@Sun.COM if (append_domain)
132211337SWilliam.Krier@Sun.COM rc = asprintf(&share_dn, "cn=%s,%s,%s", sharename,
132311337SWilliam.Krier@Sun.COM container, domain_dn);
132411337SWilliam.Krier@Sun.COM else
132511337SWilliam.Krier@Sun.COM rc = asprintf(&share_dn, "cn=%s,%s", sharename,
132611337SWilliam.Krier@Sun.COM container);
132711337SWilliam.Krier@Sun.COM
132811337SWilliam.Krier@Sun.COM return ((rc == -1) ? NULL : share_dn);
132911337SWilliam.Krier@Sun.COM }
133011337SWilliam.Krier@Sun.COM
133111337SWilliam.Krier@Sun.COM /*
13327052Samw * smb_ads_add_share
13337052Samw * Call by smb_ads_publish_share to create share object in ADS.
13345331Samw * This routine specifies the attributes of an ADS LDAP share object. The first
13355331Samw * attribute and values define the type of ADS object, the share object. The
13365331Samw * second attribute and value define the UNC of the share data for the share
13375331Samw * object. The LDAP synchronous add command is used to add the object into ADS.
13385331Samw * The container location to add the object needs to specified.
13395331Samw * Parameters:
13405331Samw * ah : handle to ADS server
13415331Samw * adsShareName: name of share object to be created in ADS
13425331Samw * shareUNC : share name on NetForce
13435331Samw * adsContainer: location in ADS to create share object
13445331Samw *
13455331Samw * Returns:
13465331Samw * -1 : error
13475331Samw * 0 : success
13485331Samw */
13495331Samw int
smb_ads_add_share(smb_ads_handle_t * ah,const char * adsShareName,const char * unc_name,const char * adsContainer)13507052Samw smb_ads_add_share(smb_ads_handle_t *ah, const char *adsShareName,
13515331Samw const char *unc_name, const char *adsContainer)
13525331Samw {
13537052Samw LDAPMod *attrs[SMB_ADS_SHARE_NUM_ATTR];
13545521Sas200622 int j = 0;
13555331Samw char *share_dn;
135611337SWilliam.Krier@Sun.COM int ret;
13578670SJose.Borrego@Sun.COM char *unc_names[] = {(char *)unc_name, NULL};
13585331Samw
135911337SWilliam.Krier@Sun.COM if ((share_dn = smb_ads_get_sharedn(adsShareName, adsContainer,
136011337SWilliam.Krier@Sun.COM ah->domain_dn)) == NULL)
13615331Samw return (-1);
13625331Samw
13637052Samw if (smb_ads_alloc_attr(attrs, SMB_ADS_SHARE_NUM_ATTR) != 0) {
13646432Sas200622 free(share_dn);
13656432Sas200622 return (-1);
13665521Sas200622 }
13675521Sas200622
13685521Sas200622 attrs[j]->mod_op = LDAP_MOD_ADD;
13695521Sas200622 attrs[j]->mod_type = "objectClass";
13708670SJose.Borrego@Sun.COM attrs[j]->mod_values = smb_ads_share_objcls;
13715331Samw
13725521Sas200622 attrs[++j]->mod_op = LDAP_MOD_ADD;
13735521Sas200622 attrs[j]->mod_type = "uNCName";
13748670SJose.Borrego@Sun.COM attrs[j]->mod_values = unc_names;
13755331Samw
13765521Sas200622 if ((ret = ldap_add_s(ah->ld, share_dn, attrs)) != LDAP_SUCCESS) {
137711963SAfshin.Ardakani@Sun.COM if (ret == LDAP_NO_SUCH_OBJECT) {
137811963SAfshin.Ardakani@Sun.COM syslog(LOG_ERR, "Failed to publish share %s in" \
137911963SAfshin.Ardakani@Sun.COM " AD. Container does not exist: %s.\n",
138011963SAfshin.Ardakani@Sun.COM adsShareName, share_dn);
138111963SAfshin.Ardakani@Sun.COM
138211963SAfshin.Ardakani@Sun.COM } else {
138311963SAfshin.Ardakani@Sun.COM syslog(LOG_ERR, "Failed to publish share %s in" \
138411963SAfshin.Ardakani@Sun.COM " AD: %s (%s).\n", adsShareName, share_dn,
138511963SAfshin.Ardakani@Sun.COM ldap_err2string(ret));
138611963SAfshin.Ardakani@Sun.COM }
13877052Samw smb_ads_free_attr(attrs);
13885331Samw free(share_dn);
13895331Samw return (ret);
13905331Samw }
13915331Samw free(share_dn);
13927052Samw smb_ads_free_attr(attrs);
13935331Samw
13945331Samw return (0);
13955331Samw }
13965331Samw
13975331Samw /*
13987052Samw * smb_ads_del_share
13997052Samw * Call by smb_ads_remove_share to remove share object from ADS. The container
14005331Samw * location to remove the object needs to specified. The LDAP synchronous
14015331Samw * delete command is used.
14025331Samw * Parameters:
14035331Samw * ah : handle to ADS server
14045331Samw * adsShareName: name of share object in ADS to be removed
14055331Samw * adsContainer: location of share object in ADS
14065331Samw * Returns:
14075331Samw * -1 : error
14085331Samw * 0 : success
14095331Samw */
14105331Samw static int
smb_ads_del_share(smb_ads_handle_t * ah,const char * adsShareName,const char * adsContainer)14117052Samw smb_ads_del_share(smb_ads_handle_t *ah, const char *adsShareName,
14125331Samw const char *adsContainer)
14135331Samw {
14147961SNatalie.Li@Sun.COM char *share_dn;
141511337SWilliam.Krier@Sun.COM int ret;
14165331Samw
141711337SWilliam.Krier@Sun.COM if ((share_dn = smb_ads_get_sharedn(adsShareName, adsContainer,
141811337SWilliam.Krier@Sun.COM ah->domain_dn)) == NULL)
14195331Samw return (-1);
14205331Samw
14215331Samw if ((ret = ldap_delete_s(ah->ld, share_dn)) != LDAP_SUCCESS) {
14229021Samw@Sun.COM smb_tracef("ldap_delete: %s", ldap_err2string(ret));
14235331Samw free(share_dn);
14245331Samw return (-1);
14255331Samw }
14265331Samw free(share_dn);
14275331Samw
14285331Samw return (0);
14295331Samw }
14305331Samw
14315331Samw
14325331Samw /*
14337052Samw * smb_ads_escape_search_filter_chars
14345331Samw *
14355331Samw * This routine will escape the special characters found in a string
14365331Samw * that will later be passed to the ldap search filter.
14375331Samw *
14385331Samw * RFC 1960 - A String Representation of LDAP Search Filters
14395331Samw * 3. String Search Filter Definition
14405331Samw * If a value must contain one of the characters '*' OR '(' OR ')',
14415331Samw * these characters
14425331Samw * should be escaped by preceding them with the backslash '\' character.
14435331Samw *
14445331Samw * RFC 2252 - LDAP Attribute Syntax Definitions
14455331Samw * a backslash quoting mechanism is used to escape
14465331Samw * the following separator symbol character (such as "'", "$" or "#") if
14475331Samw * it should occur in that string.
14485331Samw */
14495331Samw static int
smb_ads_escape_search_filter_chars(const char * src,char * dst)14507052Samw smb_ads_escape_search_filter_chars(const char *src, char *dst)
14515331Samw {
14527052Samw int avail = SMB_ADS_MAXBUFLEN - 1; /* reserve a space for NULL char */
14535331Samw
14545331Samw if (src == NULL || dst == NULL)
14555331Samw return (-1);
14565331Samw
14575331Samw while (*src) {
14585331Samw if (!avail) {
14595331Samw *dst = 0;
14605331Samw return (-1);
14615331Samw }
14625331Samw
14635331Samw switch (*src) {
14645331Samw case '\\':
14655331Samw case '\'':
14665331Samw case '$':
14675331Samw case '#':
14685331Samw case '*':
14695331Samw case '(':
14705331Samw case ')':
14715331Samw *dst++ = '\\';
14725331Samw avail--;
14735331Samw /* fall through */
14745331Samw
14755331Samw default:
14765331Samw *dst++ = *src++;
14775331Samw avail--;
14785331Samw }
14795331Samw }
14805331Samw
14815331Samw *dst = 0;
14825331Samw
14835331Samw return (0);
14845331Samw }
14855331Samw
14865331Samw /*
14877052Samw * smb_ads_lookup_share
14885331Samw * The search filter is set to search for a specific share name in the
14895331Samw * specified ADS container. The LDSAP synchronous search command is used.
14905331Samw * Parameters:
14915331Samw * ah : handle to ADS server
14925331Samw * adsShareName: name of share object in ADS to be searched
14935331Samw * adsContainer: location of share object in ADS
14945331Samw * Returns:
14955331Samw * -1 : error
14965331Samw * 0 : not found
14975331Samw * 1 : found
14985331Samw */
14995331Samw int
smb_ads_lookup_share(smb_ads_handle_t * ah,const char * adsShareName,const char * adsContainer,char * unc_name)15007052Samw smb_ads_lookup_share(smb_ads_handle_t *ah, const char *adsShareName,
15015331Samw const char *adsContainer, char *unc_name)
15025331Samw {
15037052Samw char *attrs[4], filter[SMB_ADS_MAXBUFLEN];
15045331Samw char *share_dn;
150511337SWilliam.Krier@Sun.COM int ret;
15065331Samw LDAPMessage *res;
15077052Samw char tmpbuf[SMB_ADS_MAXBUFLEN];
15085331Samw
15095331Samw if (adsShareName == NULL || adsContainer == NULL)
15105331Samw return (-1);
15115331Samw
151211337SWilliam.Krier@Sun.COM if ((share_dn = smb_ads_get_sharedn(adsShareName, adsContainer,
151311337SWilliam.Krier@Sun.COM ah->domain_dn)) == NULL)
15145331Samw return (-1);
15155331Samw
15165331Samw res = NULL;
15175331Samw attrs[0] = "cn";
15185331Samw attrs[1] = "objectClass";
15195331Samw attrs[2] = "uNCName";
15205331Samw attrs[3] = NULL;
15215331Samw
15227052Samw if (smb_ads_escape_search_filter_chars(unc_name, tmpbuf) != 0) {
15235331Samw free(share_dn);
15245331Samw return (-1);
15255331Samw }
15265331Samw
15275331Samw (void) snprintf(filter, sizeof (filter),
15285331Samw "(&(objectClass=volume)(uNCName=%s))", tmpbuf);
15295331Samw
15305331Samw if ((ret = ldap_search_s(ah->ld, share_dn,
15315331Samw LDAP_SCOPE_BASE, filter, attrs, 0, &res)) != LDAP_SUCCESS) {
15327961SNatalie.Li@Sun.COM if (ret != LDAP_NO_SUCH_OBJECT)
15339021Samw@Sun.COM smb_tracef("%s: ldap_search: %s", share_dn,
15349021Samw@Sun.COM ldap_err2string(ret));
15357961SNatalie.Li@Sun.COM
15365331Samw (void) ldap_msgfree(res);
15375331Samw free(share_dn);
15385331Samw return (0);
15395331Samw }
15405331Samw
15415331Samw (void) free(share_dn);
15425331Samw
15435331Samw /* no match is found */
15445331Samw if (ldap_count_entries(ah->ld, res) == 0) {
15455331Samw (void) ldap_msgfree(res);
15465331Samw return (0);
15475331Samw }
15485331Samw
15495331Samw /* free the search results */
15505331Samw (void) ldap_msgfree(res);
15515331Samw
15525331Samw return (1);
15535331Samw }
15545331Samw
15555331Samw /*
15567052Samw * smb_ads_publish_share
15575331Samw * Publish share into ADS. If a share name already exist in ADS in the same
15585331Samw * container then the existing share object is removed before adding the new
15595331Samw * share object.
15605331Samw * Parameters:
15617052Samw * ah : handle return from smb_ads_open
15625331Samw * adsShareName: name of share to be added to ADS directory
15635331Samw * shareUNC : name of share on client, can be NULL to use the same name
15645331Samw * as adsShareName
15655331Samw * adsContainer: location for share to be added in ADS directory, ie
15665331Samw * ou=share_folder
15675331Samw * uncType : use UNC_HOSTNAME to use hostname for UNC, use UNC_HOSTADDR
15685331Samw * to use host ip addr for UNC.
15695331Samw * Returns:
15705331Samw * -1 : error
15715331Samw * 0 : success
15725331Samw */
15735331Samw int
smb_ads_publish_share(smb_ads_handle_t * ah,const char * adsShareName,const char * shareUNC,const char * adsContainer,const char * hostname)15747052Samw smb_ads_publish_share(smb_ads_handle_t *ah, const char *adsShareName,
15755331Samw const char *shareUNC, const char *adsContainer, const char *hostname)
15765331Samw {
15775331Samw int ret;
15787052Samw char unc_name[SMB_ADS_MAXBUFLEN];
15795331Samw
15805331Samw if (adsShareName == NULL || adsContainer == NULL)
15815331Samw return (-1);
15825331Samw
15835331Samw if (shareUNC == 0 || *shareUNC == 0)
15845331Samw shareUNC = adsShareName;
15855331Samw
15867052Samw if (smb_ads_build_unc_name(unc_name, sizeof (unc_name),
15877961SNatalie.Li@Sun.COM hostname, shareUNC) < 0)
15885331Samw return (-1);
15895331Samw
15907052Samw ret = smb_ads_lookup_share(ah, adsShareName, adsContainer, unc_name);
15915331Samw
15925331Samw switch (ret) {
15935331Samw case 1:
15947052Samw (void) smb_ads_del_share(ah, adsShareName, adsContainer);
15957052Samw ret = smb_ads_add_share(ah, adsShareName, unc_name,
15967052Samw adsContainer);
15975331Samw break;
15985331Samw
15995331Samw case 0:
16007052Samw ret = smb_ads_add_share(ah, adsShareName, unc_name,
16017052Samw adsContainer);
16027961SNatalie.Li@Sun.COM if (ret == LDAP_ALREADY_EXISTS)
16035331Samw ret = -1;
16047961SNatalie.Li@Sun.COM
16055331Samw break;
16065331Samw
16075331Samw case -1:
16085331Samw default:
16095331Samw /* return with error code */
16105331Samw ret = -1;
16115331Samw }
16125331Samw
16135331Samw return (ret);
16145331Samw }
16155331Samw
16165331Samw /*
16177052Samw * smb_ads_remove_share
16185331Samw * Remove share from ADS. A search is done first before explicitly removing
16195331Samw * the share.
16205331Samw * Parameters:
16217052Samw * ah : handle return from smb_ads_open
16225331Samw * adsShareName: name of share to be removed from ADS directory
16235331Samw * adsContainer: location for share to be removed from ADS directory, ie
16245331Samw * ou=share_folder
16255331Samw * Returns:
16265331Samw * -1 : error
16275331Samw * 0 : success
16285331Samw */
16295331Samw int
smb_ads_remove_share(smb_ads_handle_t * ah,const char * adsShareName,const char * shareUNC,const char * adsContainer,const char * hostname)16307052Samw smb_ads_remove_share(smb_ads_handle_t *ah, const char *adsShareName,
16317052Samw const char *shareUNC, const char *adsContainer, const char *hostname)
16325331Samw {
16335331Samw int ret;
16347052Samw char unc_name[SMB_ADS_MAXBUFLEN];
16355331Samw
16365331Samw if (adsShareName == NULL || adsContainer == NULL)
16375331Samw return (-1);
16385331Samw if (shareUNC == 0 || *shareUNC == 0)
16395331Samw shareUNC = adsShareName;
16405331Samw
16417052Samw if (smb_ads_build_unc_name(unc_name, sizeof (unc_name),
16427961SNatalie.Li@Sun.COM hostname, shareUNC) < 0)
16435331Samw return (-1);
16445331Samw
16457052Samw ret = smb_ads_lookup_share(ah, adsShareName, adsContainer, unc_name);
16465331Samw if (ret == 0)
16475331Samw return (0);
16485331Samw if (ret == -1)
16495331Samw return (-1);
16505331Samw
16517052Samw return (smb_ads_del_share(ah, adsShareName, adsContainer));
16525331Samw }
16535331Samw
16545331Samw /*
16557961SNatalie.Li@Sun.COM * smb_ads_get_default_comp_container_dn
16565331Samw *
16577961SNatalie.Li@Sun.COM * Build the distinguished name for the default computer conatiner (i.e. the
16587961SNatalie.Li@Sun.COM * pre-defined Computers container).
16595331Samw */
16605331Samw static void
smb_ads_get_default_comp_container_dn(smb_ads_handle_t * ah,char * buf,size_t buflen)16617961SNatalie.Li@Sun.COM smb_ads_get_default_comp_container_dn(smb_ads_handle_t *ah, char *buf,
16627961SNatalie.Li@Sun.COM size_t buflen)
16635331Samw {
16647961SNatalie.Li@Sun.COM (void) snprintf(buf, buflen, "cn=%s,%s", SMB_ADS_COMPUTERS_CN,
16657961SNatalie.Li@Sun.COM ah->domain_dn);
16667961SNatalie.Li@Sun.COM }
16677961SNatalie.Li@Sun.COM
16687961SNatalie.Li@Sun.COM /*
16697961SNatalie.Li@Sun.COM * smb_ads_get_default_comp_dn
16707961SNatalie.Li@Sun.COM *
16717961SNatalie.Li@Sun.COM * Build the distinguished name for this system.
16727961SNatalie.Li@Sun.COM */
16737961SNatalie.Li@Sun.COM static void
smb_ads_get_default_comp_dn(smb_ads_handle_t * ah,char * buf,size_t buflen)16747961SNatalie.Li@Sun.COM smb_ads_get_default_comp_dn(smb_ads_handle_t *ah, char *buf, size_t buflen)
16757961SNatalie.Li@Sun.COM {
16767961SNatalie.Li@Sun.COM char nbname[NETBIOS_NAME_SZ];
16777961SNatalie.Li@Sun.COM char container_dn[SMB_ADS_DN_MAX];
16787961SNatalie.Li@Sun.COM
16797961SNatalie.Li@Sun.COM (void) smb_getnetbiosname(nbname, sizeof (nbname));
16807961SNatalie.Li@Sun.COM smb_ads_get_default_comp_container_dn(ah, container_dn, SMB_ADS_DN_MAX);
16817961SNatalie.Li@Sun.COM (void) snprintf(buf, buflen, "cn=%s,%s", nbname, container_dn);
16825331Samw }
16835331Samw
16845331Samw /*
16857052Samw * smb_ads_add_computer
16867052Samw *
16877052Samw * Returns 0 upon success. Otherwise, returns -1.
16887052Samw */
16897052Samw static int
smb_ads_add_computer(smb_ads_handle_t * ah,int dclevel,char * dn)16907348SJose.Borrego@Sun.COM smb_ads_add_computer(smb_ads_handle_t *ah, int dclevel, char *dn)
16917052Samw {
16927348SJose.Borrego@Sun.COM return (smb_ads_computer_op(ah, LDAP_MOD_ADD, dclevel, dn));
16937052Samw }
16947052Samw
16957052Samw /*
16967052Samw * smb_ads_modify_computer
16975331Samw *
16985331Samw * Returns 0 upon success. Otherwise, returns -1.
16995331Samw */
17005331Samw static int
smb_ads_modify_computer(smb_ads_handle_t * ah,int dclevel,char * dn)17017348SJose.Borrego@Sun.COM smb_ads_modify_computer(smb_ads_handle_t *ah, int dclevel, char *dn)
17025331Samw {
17037348SJose.Borrego@Sun.COM return (smb_ads_computer_op(ah, LDAP_MOD_REPLACE, dclevel, dn));
17045521Sas200622 }
17055521Sas200622
17065521Sas200622 /*
17077052Samw * smb_ads_get_dc_level
17085521Sas200622 *
17097052Samw * Returns the functional level of the DC upon success.
17107052Samw * Otherwise, -1 is returned.
17115521Sas200622 */
17125521Sas200622 static int
smb_ads_get_dc_level(smb_ads_handle_t * ah)17137052Samw smb_ads_get_dc_level(smb_ads_handle_t *ah)
17145521Sas200622 {
17157052Samw LDAPMessage *res, *entry;
17167052Samw char *attr[2];
17177052Samw char **vals;
17187052Samw int rc = -1;
17197052Samw
17207052Samw res = NULL;
17217052Samw attr[0] = SMB_ADS_ATTR_DCLEVEL;
17227052Samw attr[1] = NULL;
17237052Samw if (ldap_search_s(ah->ld, "", LDAP_SCOPE_BASE, NULL, attr,
17247052Samw 0, &res) != LDAP_SUCCESS) {
17257052Samw (void) ldap_msgfree(res);
17267052Samw return (-1);
17277052Samw }
17287052Samw
17297052Samw /* no match for the specified attribute is found */
17307052Samw if (ldap_count_entries(ah->ld, res) == 0) {
17317052Samw (void) ldap_msgfree(res);
17327052Samw return (-1);
17337052Samw }
17347052Samw
17357052Samw entry = ldap_first_entry(ah->ld, res);
17367052Samw if (entry) {
17377052Samw if ((vals = ldap_get_values(ah->ld, entry,
17387052Samw SMB_ADS_ATTR_DCLEVEL)) == NULL) {
17397052Samw /*
17407052Samw * Observed the values aren't populated
17417052Samw * by the Windows 2000 server.
17427052Samw */
17437052Samw (void) ldap_msgfree(res);
17447052Samw return (SMB_ADS_DCLEVEL_W2K);
17457052Samw }
17467052Samw
17477052Samw if (vals[0] != NULL)
17487052Samw rc = atoi(vals[0]);
17497052Samw
17507052Samw ldap_value_free(vals);
17517052Samw }
17527052Samw
17537052Samw (void) ldap_msgfree(res);
17547052Samw return (rc);
17555521Sas200622 }
17565521Sas200622
175711963SAfshin.Ardakani@Sun.COM /*
175811963SAfshin.Ardakani@Sun.COM * The fully-qualified hostname returned by this function is often used for
175911963SAfshin.Ardakani@Sun.COM * constructing service principal name. Return the fully-qualified hostname
176011963SAfshin.Ardakani@Sun.COM * in lower case for RFC 4120 section 6.2.1 conformance.
176111963SAfshin.Ardakani@Sun.COM */
17625521Sas200622 static int
smb_ads_getfqhostname(smb_ads_handle_t * ah,char * fqhost,int len)17637961SNatalie.Li@Sun.COM smb_ads_getfqhostname(smb_ads_handle_t *ah, char *fqhost, int len)
17647961SNatalie.Li@Sun.COM {
176511963SAfshin.Ardakani@Sun.COM if (smb_gethostname(fqhost, len, SMB_CASE_LOWER) != 0)
17667961SNatalie.Li@Sun.COM return (-1);
17677961SNatalie.Li@Sun.COM
17687961SNatalie.Li@Sun.COM (void) snprintf(fqhost, len, "%s.%s", fqhost,
17697961SNatalie.Li@Sun.COM ah->domain);
17707961SNatalie.Li@Sun.COM
17717961SNatalie.Li@Sun.COM return (0);
17727961SNatalie.Li@Sun.COM }
17737961SNatalie.Li@Sun.COM
17747961SNatalie.Li@Sun.COM static int
smb_ads_computer_op(smb_ads_handle_t * ah,int op,int dclevel,char * dn)17757348SJose.Borrego@Sun.COM smb_ads_computer_op(smb_ads_handle_t *ah, int op, int dclevel, char *dn)
17765521Sas200622 {
17777052Samw LDAPMod *attrs[SMB_ADS_COMPUTER_NUM_ATTR];
1778*12508Samw@Sun.COM char *sam_val[2];
1779*12508Samw@Sun.COM char *ctl_val[2], *fqh_val[2];
17807052Samw char *encrypt_val[2];
17816432Sas200622 int j = -1;
17825331Samw int ret, usrctl_flags = 0;
17837961SNatalie.Li@Sun.COM char sam_acct[SMB_SAMACCT_MAXLEN];
17845331Samw char fqhost[MAXHOSTNAMELEN];
17855331Samw char usrctl_buf[16];
17867052Samw char encrypt_buf[16];
17875521Sas200622 int max;
1788*12508Samw@Sun.COM smb_krb5_pn_set_t spn, upn;
17895331Samw
17907961SNatalie.Li@Sun.COM if (smb_getsamaccount(sam_acct, sizeof (sam_acct)) != 0)
17915331Samw return (-1);
17925331Samw
17937961SNatalie.Li@Sun.COM if (smb_ads_getfqhostname(ah, fqhost, MAXHOSTNAMELEN))
17947961SNatalie.Li@Sun.COM return (-1);
17955331Samw
1796*12508Samw@Sun.COM /* The SPN attribute is multi-valued and must be 1 or greater */
1797*12508Samw@Sun.COM if (smb_krb5_get_pn_set(&spn, SMB_PN_SPN_ATTR, ah->domain) == 0)
17986432Sas200622 return (-1);
17996432Sas200622
1800*12508Samw@Sun.COM /* The UPN attribute is single-valued and cannot be zero */
1801*12508Samw@Sun.COM if (smb_krb5_get_pn_set(&upn, SMB_PN_UPN_ATTR, ah->domain) != 1) {
1802*12508Samw@Sun.COM smb_krb5_free_pn_set(&spn);
1803*12508Samw@Sun.COM smb_krb5_free_pn_set(&upn);
18045331Samw return (-1);
18055331Samw }
18065331Samw
18077052Samw max = (SMB_ADS_COMPUTER_NUM_ATTR - ((op != LDAP_MOD_ADD) ? 1 : 0))
18089914Samw@Sun.COM - (dclevel >= SMB_ADS_DCLEVEL_W2K8 ? 0 : 1);
18097052Samw
18107052Samw if (smb_ads_alloc_attr(attrs, max) != 0) {
1811*12508Samw@Sun.COM smb_krb5_free_pn_set(&spn);
1812*12508Samw@Sun.COM smb_krb5_free_pn_set(&upn);
18136432Sas200622 return (-1);
18145521Sas200622 }
18155331Samw
18165521Sas200622 /* objectClass attribute is not modifiable. */
18175521Sas200622 if (op == LDAP_MOD_ADD) {
18185521Sas200622 attrs[++j]->mod_op = op;
18195521Sas200622 attrs[j]->mod_type = "objectClass";
18208670SJose.Borrego@Sun.COM attrs[j]->mod_values = smb_ads_computer_objcls;
18215521Sas200622 }
18225331Samw
18235521Sas200622 attrs[++j]->mod_op = op;
18247052Samw attrs[j]->mod_type = SMB_ADS_ATTR_SAMACCT;
18255331Samw sam_val[0] = sam_acct;
18265331Samw sam_val[1] = 0;
18275521Sas200622 attrs[j]->mod_values = sam_val;
18285331Samw
18295521Sas200622 attrs[++j]->mod_op = op;
18307052Samw attrs[j]->mod_type = SMB_ADS_ATTR_UPN;
1831*12508Samw@Sun.COM attrs[j]->mod_values = upn.s_pns;
18325331Samw
18335521Sas200622 attrs[++j]->mod_op = op;
18347052Samw attrs[j]->mod_type = SMB_ADS_ATTR_SPN;
1835*12508Samw@Sun.COM attrs[j]->mod_values = spn.s_pns;
18365331Samw
18375521Sas200622 attrs[++j]->mod_op = op;
18387052Samw attrs[j]->mod_type = SMB_ADS_ATTR_CTL;
18397052Samw usrctl_flags |= (SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT |
18407052Samw SMB_ADS_USER_ACCT_CTL_PASSWD_NOTREQD |
18417052Samw SMB_ADS_USER_ACCT_CTL_ACCOUNTDISABLE);
18425331Samw (void) snprintf(usrctl_buf, sizeof (usrctl_buf), "%d", usrctl_flags);
18435331Samw ctl_val[0] = usrctl_buf;
18445331Samw ctl_val[1] = 0;
18455521Sas200622 attrs[j]->mod_values = ctl_val;
18465331Samw
18475521Sas200622 attrs[++j]->mod_op = op;
18487052Samw attrs[j]->mod_type = SMB_ADS_ATTR_DNSHOST;
18495331Samw fqh_val[0] = fqhost;
18505331Samw fqh_val[1] = 0;
18515521Sas200622 attrs[j]->mod_values = fqh_val;
18525521Sas200622
18537052Samw /* enctypes support starting in Windows Server 2008 */
18547052Samw if (dclevel > SMB_ADS_DCLEVEL_W2K3) {
18557052Samw attrs[++j]->mod_op = op;
18567052Samw attrs[j]->mod_type = SMB_ADS_ATTR_ENCTYPES;
18577052Samw (void) snprintf(encrypt_buf, sizeof (encrypt_buf), "%d",
18587052Samw SMB_ADS_ENC_AES256 + SMB_ADS_ENC_AES128 + SMB_ADS_ENC_RC4 +
18597052Samw SMB_ADS_ENC_DES_MD5 + SMB_ADS_ENC_DES_CRC);
18607052Samw encrypt_val[0] = encrypt_buf;
18617052Samw encrypt_val[1] = 0;
18627052Samw attrs[j]->mod_values = encrypt_val;
18637052Samw }
18647052Samw
18655521Sas200622 switch (op) {
18665521Sas200622 case LDAP_MOD_ADD:
18675521Sas200622 if ((ret = ldap_add_s(ah->ld, dn, attrs)) != LDAP_SUCCESS) {
18689021Samw@Sun.COM syslog(LOG_NOTICE, "ldap_add: %s",
18695521Sas200622 ldap_err2string(ret));
18705521Sas200622 ret = -1;
18715521Sas200622 }
18725521Sas200622 break;
18735521Sas200622
18745521Sas200622 case LDAP_MOD_REPLACE:
18755521Sas200622 if ((ret = ldap_modify_s(ah->ld, dn, attrs)) != LDAP_SUCCESS) {
18769021Samw@Sun.COM syslog(LOG_NOTICE, "ldap_modify: %s",
18775521Sas200622 ldap_err2string(ret));
18785521Sas200622 ret = -1;
18795521Sas200622 }
18805521Sas200622 break;
18815521Sas200622
18825521Sas200622 default:
18835331Samw ret = -1;
18845521Sas200622
18855331Samw }
18865331Samw
18877052Samw smb_ads_free_attr(attrs);
1888*12508Samw@Sun.COM smb_krb5_free_pn_set(&spn);
1889*12508Samw@Sun.COM smb_krb5_free_pn_set(&upn);
18905331Samw
18915331Samw return (ret);
18925331Samw }
18935331Samw
18945331Samw /*
18955331Samw * Delete an ADS computer account.
18965331Samw */
18975331Samw static void
smb_ads_del_computer(smb_ads_handle_t * ah,char * dn)18987348SJose.Borrego@Sun.COM smb_ads_del_computer(smb_ads_handle_t *ah, char *dn)
18995331Samw {
19005331Samw int rc;
19015331Samw
19027052Samw if ((rc = ldap_delete_s(ah->ld, dn)) != LDAP_SUCCESS)
19039021Samw@Sun.COM smb_tracef("ldap_delete: %s", ldap_err2string(rc));
19047961SNatalie.Li@Sun.COM }
19057961SNatalie.Li@Sun.COM
19067961SNatalie.Li@Sun.COM /*
19077961SNatalie.Li@Sun.COM * Gets the value of the given attribute.
19087961SNatalie.Li@Sun.COM */
19097961SNatalie.Li@Sun.COM static smb_ads_qstat_t
smb_ads_getattr(LDAP * ld,LDAPMessage * entry,smb_ads_avpair_t * avpair)19107961SNatalie.Li@Sun.COM smb_ads_getattr(LDAP *ld, LDAPMessage *entry, smb_ads_avpair_t *avpair)
19117961SNatalie.Li@Sun.COM {
19127961SNatalie.Li@Sun.COM char **vals;
19137961SNatalie.Li@Sun.COM smb_ads_qstat_t rc = SMB_ADS_STAT_FOUND;
19147961SNatalie.Li@Sun.COM
19157961SNatalie.Li@Sun.COM assert(avpair);
19167961SNatalie.Li@Sun.COM avpair->avp_val = NULL;
19177961SNatalie.Li@Sun.COM vals = ldap_get_values(ld, entry, avpair->avp_attr);
19187961SNatalie.Li@Sun.COM if (!vals)
19197961SNatalie.Li@Sun.COM return (SMB_ADS_STAT_NOT_FOUND);
19207961SNatalie.Li@Sun.COM
19217961SNatalie.Li@Sun.COM if (!vals[0]) {
19227961SNatalie.Li@Sun.COM ldap_value_free(vals);
19237961SNatalie.Li@Sun.COM return (SMB_ADS_STAT_NOT_FOUND);
19247961SNatalie.Li@Sun.COM }
19257961SNatalie.Li@Sun.COM
19267961SNatalie.Li@Sun.COM avpair->avp_val = strdup(vals[0]);
19277961SNatalie.Li@Sun.COM if (!avpair->avp_val)
19287961SNatalie.Li@Sun.COM rc = SMB_ADS_STAT_ERR;
19297961SNatalie.Li@Sun.COM
19307961SNatalie.Li@Sun.COM ldap_value_free(vals);
19317961SNatalie.Li@Sun.COM return (rc);
19327961SNatalie.Li@Sun.COM }
19337961SNatalie.Li@Sun.COM
19347961SNatalie.Li@Sun.COM /*
19357961SNatalie.Li@Sun.COM * Process query's result.
19367961SNatalie.Li@Sun.COM */
19377961SNatalie.Li@Sun.COM static smb_ads_qstat_t
smb_ads_get_qstat(smb_ads_handle_t * ah,LDAPMessage * res,smb_ads_avpair_t * avpair)19387961SNatalie.Li@Sun.COM smb_ads_get_qstat(smb_ads_handle_t *ah, LDAPMessage *res,
19397961SNatalie.Li@Sun.COM smb_ads_avpair_t *avpair)
19407961SNatalie.Li@Sun.COM {
19417961SNatalie.Li@Sun.COM char fqhost[MAXHOSTNAMELEN];
19427961SNatalie.Li@Sun.COM smb_ads_avpair_t dnshost_avp;
19437961SNatalie.Li@Sun.COM smb_ads_qstat_t rc = SMB_ADS_STAT_FOUND;
19447961SNatalie.Li@Sun.COM LDAPMessage *entry;
19457961SNatalie.Li@Sun.COM
19467961SNatalie.Li@Sun.COM if (smb_ads_getfqhostname(ah, fqhost, MAXHOSTNAMELEN))
19477961SNatalie.Li@Sun.COM return (SMB_ADS_STAT_ERR);
19487961SNatalie.Li@Sun.COM
19497961SNatalie.Li@Sun.COM if (ldap_count_entries(ah->ld, res) == 0)
19507961SNatalie.Li@Sun.COM return (SMB_ADS_STAT_NOT_FOUND);
19517961SNatalie.Li@Sun.COM
19527961SNatalie.Li@Sun.COM if ((entry = ldap_first_entry(ah->ld, res)) == NULL)
19537961SNatalie.Li@Sun.COM return (SMB_ADS_STAT_ERR);
19547961SNatalie.Li@Sun.COM
19557961SNatalie.Li@Sun.COM dnshost_avp.avp_attr = SMB_ADS_ATTR_DNSHOST;
19567961SNatalie.Li@Sun.COM rc = smb_ads_getattr(ah->ld, entry, &dnshost_avp);
19577961SNatalie.Li@Sun.COM
19587961SNatalie.Li@Sun.COM switch (rc) {
19597961SNatalie.Li@Sun.COM case SMB_ADS_STAT_FOUND:
19607961SNatalie.Li@Sun.COM /*
19617961SNatalie.Li@Sun.COM * Returns SMB_ADS_STAT_DUP to avoid overwriting
19627961SNatalie.Li@Sun.COM * the computer account of another system whose
19637961SNatalie.Li@Sun.COM * NetBIOS name collides with that of the current
19647961SNatalie.Li@Sun.COM * system.
19657961SNatalie.Li@Sun.COM */
19667961SNatalie.Li@Sun.COM if (strcasecmp(dnshost_avp.avp_val, fqhost))
19677961SNatalie.Li@Sun.COM rc = SMB_ADS_STAT_DUP;
19687961SNatalie.Li@Sun.COM
19697961SNatalie.Li@Sun.COM free(dnshost_avp.avp_val);
19707961SNatalie.Li@Sun.COM break;
19717961SNatalie.Li@Sun.COM
19727961SNatalie.Li@Sun.COM case SMB_ADS_STAT_NOT_FOUND:
19737961SNatalie.Li@Sun.COM /*
19747961SNatalie.Li@Sun.COM * Pre-created computer account doesn't have
19757961SNatalie.Li@Sun.COM * the dNSHostname attribute. It's been observed
19767961SNatalie.Li@Sun.COM * that the dNSHostname attribute is only set after
19777961SNatalie.Li@Sun.COM * a successful domain join.
19787961SNatalie.Li@Sun.COM * Returns SMB_ADS_STAT_FOUND as the account is
19797961SNatalie.Li@Sun.COM * pre-created for the current system.
19807961SNatalie.Li@Sun.COM */
19817961SNatalie.Li@Sun.COM rc = SMB_ADS_STAT_FOUND;
19827961SNatalie.Li@Sun.COM break;
19837961SNatalie.Li@Sun.COM
19847961SNatalie.Li@Sun.COM default:
19857961SNatalie.Li@Sun.COM break;
19867961SNatalie.Li@Sun.COM }
19877961SNatalie.Li@Sun.COM
19887961SNatalie.Li@Sun.COM if (rc != SMB_ADS_STAT_FOUND)
19897961SNatalie.Li@Sun.COM return (rc);
19907961SNatalie.Li@Sun.COM
19917961SNatalie.Li@Sun.COM if (avpair)
19927961SNatalie.Li@Sun.COM rc = smb_ads_getattr(ah->ld, entry, avpair);
19937961SNatalie.Li@Sun.COM
19947961SNatalie.Li@Sun.COM return (rc);
19957961SNatalie.Li@Sun.COM
19965331Samw }
19975331Samw
19985331Samw /*
19997052Samw * smb_ads_lookup_computer_n_attr
20005331Samw *
20017961SNatalie.Li@Sun.COM * If avpair is NULL, checks the status of the specified computer account.
20027961SNatalie.Li@Sun.COM * Otherwise, looks up the value of the specified computer account's attribute.
20037961SNatalie.Li@Sun.COM * If found, the value field of the avpair will be allocated and set. The
20047961SNatalie.Li@Sun.COM * caller should free the allocated buffer.
20055331Samw *
20065331Samw * Return:
20077961SNatalie.Li@Sun.COM * SMB_ADS_STAT_FOUND - if both the computer and the specified attribute is
20087961SNatalie.Li@Sun.COM * found.
20097961SNatalie.Li@Sun.COM * SMB_ADS_STAT_NOT_FOUND - if either the computer or the specified attribute
20107961SNatalie.Li@Sun.COM * is not found.
20117961SNatalie.Li@Sun.COM * SMB_ADS_STAT_DUP - if the computer account is already used by other systems
20127961SNatalie.Li@Sun.COM * in the AD. This could happen if the hostname of multiple
20137961SNatalie.Li@Sun.COM * systems resolved to the same NetBIOS name.
20147961SNatalie.Li@Sun.COM * SMB_ADS_STAT_ERR - any failure.
20155331Samw */
20167961SNatalie.Li@Sun.COM 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)20177961SNatalie.Li@Sun.COM smb_ads_lookup_computer_n_attr(smb_ads_handle_t *ah, smb_ads_avpair_t *avpair,
20187348SJose.Borrego@Sun.COM int scope, char *dn)
20195331Samw {
20207961SNatalie.Li@Sun.COM char *attrs[3], filter[SMB_ADS_MAXBUFLEN];
20217961SNatalie.Li@Sun.COM LDAPMessage *res;
20227961SNatalie.Li@Sun.COM char sam_acct[SMB_SAMACCT_MAXLEN], sam_acct2[SMB_SAMACCT_MAXLEN];
20237961SNatalie.Li@Sun.COM smb_ads_qstat_t rc;
20247961SNatalie.Li@Sun.COM
20257961SNatalie.Li@Sun.COM if (smb_getsamaccount(sam_acct, sizeof (sam_acct)) != 0)
20267961SNatalie.Li@Sun.COM return (SMB_ADS_STAT_ERR);
20275331Samw
20285331Samw res = NULL;
20297961SNatalie.Li@Sun.COM attrs[0] = SMB_ADS_ATTR_DNSHOST;
20305331Samw attrs[1] = NULL;
20317961SNatalie.Li@Sun.COM attrs[2] = NULL;
20327961SNatalie.Li@Sun.COM
20337961SNatalie.Li@Sun.COM if (avpair) {
20347961SNatalie.Li@Sun.COM if (!avpair->avp_attr)
20357961SNatalie.Li@Sun.COM return (SMB_ADS_STAT_ERR);
20367961SNatalie.Li@Sun.COM
20377961SNatalie.Li@Sun.COM attrs[1] = avpair->avp_attr;
20387961SNatalie.Li@Sun.COM }
20397961SNatalie.Li@Sun.COM
20407961SNatalie.Li@Sun.COM if (smb_ads_escape_search_filter_chars(sam_acct, sam_acct2) != 0)
20417961SNatalie.Li@Sun.COM return (SMB_ADS_STAT_ERR);
20425331Samw
20437348SJose.Borrego@Sun.COM (void) snprintf(filter, sizeof (filter),
20447961SNatalie.Li@Sun.COM "(&(objectClass=computer)(%s=%s))", SMB_ADS_ATTR_SAMACCT,
20457961SNatalie.Li@Sun.COM sam_acct2);
20465331Samw
20477348SJose.Borrego@Sun.COM if (ldap_search_s(ah->ld, dn, scope, filter, attrs, 0,
20485331Samw &res) != LDAP_SUCCESS) {
20495331Samw (void) ldap_msgfree(res);
20507961SNatalie.Li@Sun.COM return (SMB_ADS_STAT_NOT_FOUND);
20515331Samw }
20525331Samw
20537961SNatalie.Li@Sun.COM rc = smb_ads_get_qstat(ah, res, avpair);
20545331Samw /* free the search results */
20555331Samw (void) ldap_msgfree(res);
20567961SNatalie.Li@Sun.COM return (rc);
20575331Samw }
20585331Samw
20595331Samw /*
20607052Samw * smb_ads_find_computer
20615331Samw *
20627348SJose.Borrego@Sun.COM * Starts by searching for the system's AD computer object in the default
20637348SJose.Borrego@Sun.COM * container (i.e. cn=Computers). If not found, searches the entire directory.
20647961SNatalie.Li@Sun.COM * If found, 'dn' will be set to the distinguished name of the system's AD
20657961SNatalie.Li@Sun.COM * computer object.
20665331Samw */
20677961SNatalie.Li@Sun.COM static smb_ads_qstat_t
smb_ads_find_computer(smb_ads_handle_t * ah,char * dn)20687348SJose.Borrego@Sun.COM smb_ads_find_computer(smb_ads_handle_t *ah, char *dn)
20695331Samw {
20707961SNatalie.Li@Sun.COM smb_ads_qstat_t stat;
20717961SNatalie.Li@Sun.COM smb_ads_avpair_t avpair;
20727961SNatalie.Li@Sun.COM
20737961SNatalie.Li@Sun.COM avpair.avp_attr = SMB_ADS_ATTR_DN;
20747961SNatalie.Li@Sun.COM smb_ads_get_default_comp_container_dn(ah, dn, SMB_ADS_DN_MAX);
20757961SNatalie.Li@Sun.COM stat = smb_ads_lookup_computer_n_attr(ah, &avpair, LDAP_SCOPE_ONELEVEL,
20767961SNatalie.Li@Sun.COM dn);
20777961SNatalie.Li@Sun.COM
20787961SNatalie.Li@Sun.COM if (stat == SMB_ADS_STAT_NOT_FOUND) {
20797348SJose.Borrego@Sun.COM (void) strlcpy(dn, ah->domain_dn, SMB_ADS_DN_MAX);
20807961SNatalie.Li@Sun.COM stat = smb_ads_lookup_computer_n_attr(ah, &avpair,
20817961SNatalie.Li@Sun.COM LDAP_SCOPE_SUBTREE, dn);
20827348SJose.Borrego@Sun.COM }
20837348SJose.Borrego@Sun.COM
20847961SNatalie.Li@Sun.COM if (stat == SMB_ADS_STAT_FOUND) {
20857961SNatalie.Li@Sun.COM (void) strlcpy(dn, avpair.avp_val, SMB_ADS_DN_MAX);
20867961SNatalie.Li@Sun.COM free(avpair.avp_val);
20877961SNatalie.Li@Sun.COM }
20887961SNatalie.Li@Sun.COM
20897961SNatalie.Li@Sun.COM return (stat);
20905331Samw }
20915331Samw
20925331Samw /*
20937052Samw * smb_ads_update_computer_cntrl_attr
20945331Samw *
20955331Samw * Modify the user account control attribute of an existing computer
20965331Samw * object on AD.
20975331Samw *
20988670SJose.Borrego@Sun.COM * Returns LDAP error code.
20995331Samw */
21005331Samw static int
smb_ads_update_computer_cntrl_attr(smb_ads_handle_t * ah,int flags,char * dn)21018670SJose.Borrego@Sun.COM smb_ads_update_computer_cntrl_attr(smb_ads_handle_t *ah, int flags, char *dn)
21025331Samw {
21036432Sas200622 LDAPMod *attrs[2];
21045331Samw char *ctl_val[2];
21058670SJose.Borrego@Sun.COM int ret = 0;
21065331Samw char usrctl_buf[16];
21075331Samw
21087052Samw if (smb_ads_alloc_attr(attrs, sizeof (attrs) / sizeof (LDAPMod *)) != 0)
21098670SJose.Borrego@Sun.COM return (LDAP_NO_MEMORY);
21106432Sas200622
21116432Sas200622 attrs[0]->mod_op = LDAP_MOD_REPLACE;
21127052Samw attrs[0]->mod_type = SMB_ADS_ATTR_CTL;
21135331Samw
21148670SJose.Borrego@Sun.COM (void) snprintf(usrctl_buf, sizeof (usrctl_buf), "%d", flags);
21155331Samw ctl_val[0] = usrctl_buf;
21165331Samw ctl_val[1] = 0;
21176432Sas200622 attrs[0]->mod_values = ctl_val;
21185331Samw if ((ret = ldap_modify_s(ah->ld, dn, attrs)) != LDAP_SUCCESS) {
21199021Samw@Sun.COM syslog(LOG_NOTICE, "ldap_modify: %s", ldap_err2string(ret));
21205331Samw }
21215331Samw
21227052Samw smb_ads_free_attr(attrs);
21235331Samw return (ret);
21245331Samw }
21255331Samw
21265331Samw /*
21277052Samw * smb_ads_lookup_computer_attr_kvno
21285331Samw *
21295331Samw * Lookup the value of the Kerberos version number attribute of the computer
21305331Samw * account.
21315331Samw */
21325331Samw static krb5_kvno
smb_ads_lookup_computer_attr_kvno(smb_ads_handle_t * ah,char * dn)21337348SJose.Borrego@Sun.COM smb_ads_lookup_computer_attr_kvno(smb_ads_handle_t *ah, char *dn)
21345331Samw {
21357961SNatalie.Li@Sun.COM smb_ads_avpair_t avpair;
21365331Samw int kvno = 1;
21375331Samw
21387961SNatalie.Li@Sun.COM avpair.avp_attr = SMB_ADS_ATTR_KVNO;
21397961SNatalie.Li@Sun.COM if (smb_ads_lookup_computer_n_attr(ah, &avpair,
21407961SNatalie.Li@Sun.COM LDAP_SCOPE_BASE, dn) == SMB_ADS_STAT_FOUND) {
21417961SNatalie.Li@Sun.COM kvno = atoi(avpair.avp_val);
21427961SNatalie.Li@Sun.COM free(avpair.avp_val);
21435331Samw }
21445331Samw
21455331Samw return (kvno);
21465331Samw }
21475331Samw
214811571SShawn.Emery@Sun.COM static int
smb_ads_gen_machine_passwd(char * machine_passwd,size_t bufsz)214911571SShawn.Emery@Sun.COM smb_ads_gen_machine_passwd(char *machine_passwd, size_t bufsz)
21505331Samw {
215111571SShawn.Emery@Sun.COM int i;
215211571SShawn.Emery@Sun.COM size_t pwdlen;
215311571SShawn.Emery@Sun.COM uint8_t *random_bytes;
21545331Samw
215511571SShawn.Emery@Sun.COM errno = 0;
215611571SShawn.Emery@Sun.COM if (machine_passwd == NULL || bufsz == 0) {
215711571SShawn.Emery@Sun.COM errno = EINVAL;
215811571SShawn.Emery@Sun.COM return (-1);
21595331Samw }
21605331Samw
216111571SShawn.Emery@Sun.COM pwdlen = bufsz - 1;
216211571SShawn.Emery@Sun.COM random_bytes = calloc(1, pwdlen);
216311571SShawn.Emery@Sun.COM if (random_bytes == NULL)
216411571SShawn.Emery@Sun.COM return (-1);
216511571SShawn.Emery@Sun.COM
216611571SShawn.Emery@Sun.COM if (pkcs11_get_random(random_bytes, pwdlen) != 0) {
216711571SShawn.Emery@Sun.COM free(random_bytes);
216811571SShawn.Emery@Sun.COM return (-1);
216911571SShawn.Emery@Sun.COM }
217011571SShawn.Emery@Sun.COM
217111571SShawn.Emery@Sun.COM for (i = 0; i < pwdlen; i++)
217211571SShawn.Emery@Sun.COM machine_passwd[i] = (random_bytes[i] % SMB_ADS_PWD_CHAR_NUM) +
217311571SShawn.Emery@Sun.COM SMB_ADS_PWD_CHAR_START;
217411571SShawn.Emery@Sun.COM
217511571SShawn.Emery@Sun.COM machine_passwd[pwdlen] = 0;
217611571SShawn.Emery@Sun.COM bzero(random_bytes, pwdlen);
217711571SShawn.Emery@Sun.COM free(random_bytes);
217811571SShawn.Emery@Sun.COM return (0);
21795331Samw }
21805331Samw
21815331Samw /*
21827052Samw * smb_ads_join
21835331Samw *
21845331Samw * Besides the NT-4 style domain join (using MS-RPC), CIFS server also
21855331Samw * provides the domain join using Kerberos Authentication, Keberos
21865521Sas200622 * Change & Set password, and LDAP protocols. Basically, AD join
21875331Samw * operation would require the following tickets to be acquired for the
21885331Samw * the user account that is provided for the domain join.
21895331Samw *
21905331Samw * 1) a Keberos TGT ticket,
21915331Samw * 2) a ldap service ticket, and
21925331Samw * 3) kadmin/changpw service ticket
21935331Samw *
21945331Samw * The ADS client first sends a ldap search request to find out whether
21955331Samw * or not the workstation trust account already exists in the Active Directory.
21965331Samw * The existing computer object for this workstation will be removed and
21975331Samw * a new one will be added. The machine account password is randomly
21987052Samw * generated and set for the newly created computer object using KPASSWD
21995331Samw * protocol (See RFC 3244). Once the password is set, our ADS client
22005331Samw * finalizes the machine account by modifying the user acount control
22015331Samw * attribute of the computer object. Kerberos keys derived from the machine
22025331Samw * account password will be stored locally in /etc/krb5/krb5.keytab file.
22035331Samw * That would be needed while acquiring Kerberos TGT ticket for the host
22045331Samw * principal after the domain join operation.
22055331Samw */
22067052Samw smb_adjoin_status_t
smb_ads_join(char * domain,char * user,char * usr_passwd,char * machine_passwd,size_t len)22077052Samw smb_ads_join(char *domain, char *user, char *usr_passwd, char *machine_passwd,
220811571SShawn.Emery@Sun.COM size_t len)
22095331Samw {
22107052Samw smb_ads_handle_t *ah = NULL;
22115331Samw krb5_context ctx = NULL;
2212*12508Samw@Sun.COM krb5_principal *krb5princs = NULL;
22135331Samw krb5_kvno kvno;
22145967Scp160787 boolean_t des_only, delete = B_TRUE;
22157052Samw smb_adjoin_status_t rc = SMB_ADJOIN_SUCCESS;
22165521Sas200622 boolean_t new_acct;
22178670SJose.Borrego@Sun.COM int dclevel, num, usrctl_flags = 0;
22187961SNatalie.Li@Sun.COM smb_ads_qstat_t qstat;
22197348SJose.Borrego@Sun.COM char dn[SMB_ADS_DN_MAX];
22208334SJose.Borrego@Sun.COM char *tmpfile;
2221*12508Samw@Sun.COM int cnt;
2222*12508Samw@Sun.COM smb_krb5_pn_set_t spns;
22237052Samw
22247052Samw krb5_enctype *encptr;
22257052Samw
22267052Samw if ((ah = smb_ads_open_main(domain, user, usr_passwd)) == NULL) {
22276139Sjb150015 smb_ccache_remove(SMB_CCACHE_PATH);
22287052Samw return (SMB_ADJOIN_ERR_GET_HANDLE);
22295521Sas200622 }
22305521Sas200622
223111571SShawn.Emery@Sun.COM if (smb_ads_gen_machine_passwd(machine_passwd, len) != 0) {
223211571SShawn.Emery@Sun.COM syslog(LOG_NOTICE, "machine password generation: %m");
223311571SShawn.Emery@Sun.COM smb_ads_close(ah);
223411571SShawn.Emery@Sun.COM smb_ccache_remove(SMB_CCACHE_PATH);
223511571SShawn.Emery@Sun.COM return (SMB_ADJOIN_ERR_GEN_PWD);
223611571SShawn.Emery@Sun.COM }
22375331Samw
22387052Samw if ((dclevel = smb_ads_get_dc_level(ah)) == -1) {
22397052Samw smb_ads_close(ah);
22407052Samw smb_ccache_remove(SMB_CCACHE_PATH);
22417052Samw return (SMB_ADJOIN_ERR_GET_DCLEVEL);
22427052Samw }
22437052Samw
22447961SNatalie.Li@Sun.COM qstat = smb_ads_find_computer(ah, dn);
22457961SNatalie.Li@Sun.COM switch (qstat) {
22467961SNatalie.Li@Sun.COM case SMB_ADS_STAT_FOUND:
22475521Sas200622 new_acct = B_FALSE;
22487348SJose.Borrego@Sun.COM if (smb_ads_modify_computer(ah, dclevel, dn) != 0) {
22497052Samw smb_ads_close(ah);
22506139Sjb150015 smb_ccache_remove(SMB_CCACHE_PATH);
22517052Samw return (SMB_ADJOIN_ERR_MOD_TRUST_ACCT);
22525521Sas200622 }
22537961SNatalie.Li@Sun.COM break;
22547961SNatalie.Li@Sun.COM
22557961SNatalie.Li@Sun.COM case SMB_ADS_STAT_NOT_FOUND:
22565521Sas200622 new_acct = B_TRUE;
22577961SNatalie.Li@Sun.COM smb_ads_get_default_comp_dn(ah, dn, SMB_ADS_DN_MAX);
22587348SJose.Borrego@Sun.COM if (smb_ads_add_computer(ah, dclevel, dn) != 0) {
22597052Samw smb_ads_close(ah);
22606139Sjb150015 smb_ccache_remove(SMB_CCACHE_PATH);
22617052Samw return (SMB_ADJOIN_ERR_ADD_TRUST_ACCT);
22625521Sas200622 }
22637961SNatalie.Li@Sun.COM break;
22647961SNatalie.Li@Sun.COM
22657961SNatalie.Li@Sun.COM default:
22667961SNatalie.Li@Sun.COM if (qstat == SMB_ADS_STAT_DUP)
22677961SNatalie.Li@Sun.COM rc = SMB_ADJOIN_ERR_DUP_TRUST_ACCT;
22687961SNatalie.Li@Sun.COM else
22697961SNatalie.Li@Sun.COM rc = SMB_ADJOIN_ERR_TRUST_ACCT;
22707961SNatalie.Li@Sun.COM smb_ads_close(ah);
22717961SNatalie.Li@Sun.COM smb_ccache_remove(SMB_CCACHE_PATH);
22727961SNatalie.Li@Sun.COM return (rc);
22735521Sas200622 }
22745521Sas200622
22755521Sas200622 des_only = B_FALSE;
22765331Samw
22775331Samw if (smb_krb5_ctx_init(&ctx) != 0) {
22787052Samw rc = SMB_ADJOIN_ERR_INIT_KRB_CTX;
22795331Samw goto adjoin_cleanup;
22805331Samw }
22815331Samw
2282*12508Samw@Sun.COM if (smb_krb5_get_pn_set(&spns, SMB_PN_KEYTAB_ENTRY, ah->domain) == 0) {
22837052Samw rc = SMB_ADJOIN_ERR_GET_SPNS;
22845331Samw goto adjoin_cleanup;
22855331Samw }
22865331Samw
2287*12508Samw@Sun.COM if (smb_krb5_get_kprincs(ctx, spns.s_pns, spns.s_cnt, &krb5princs)
2288*12508Samw@Sun.COM != 0) {
2289*12508Samw@Sun.COM smb_krb5_free_pn_set(&spns);
2290*12508Samw@Sun.COM rc = SMB_ADJOIN_ERR_GET_SPNS;
2291*12508Samw@Sun.COM goto adjoin_cleanup;
2292*12508Samw@Sun.COM }
2293*12508Samw@Sun.COM
2294*12508Samw@Sun.COM cnt = spns.s_cnt;
2295*12508Samw@Sun.COM smb_krb5_free_pn_set(&spns);
2296*12508Samw@Sun.COM
2297*12508Samw@Sun.COM if (smb_krb5_setpwd(ctx, ah->domain, machine_passwd) != 0) {
22987052Samw rc = SMB_ADJOIN_ERR_KSETPWD;
22997052Samw goto adjoin_cleanup;
23007052Samw }
23017052Samw
23027348SJose.Borrego@Sun.COM kvno = smb_ads_lookup_computer_attr_kvno(ah, dn);
23037052Samw
23048670SJose.Borrego@Sun.COM /*
23058670SJose.Borrego@Sun.COM * Only members of Domain Admins and Enterprise Admins can set
23068670SJose.Borrego@Sun.COM * the TRUSTED_FOR_DELEGATION userAccountControl flag.
23078670SJose.Borrego@Sun.COM */
23088670SJose.Borrego@Sun.COM if (smb_ads_update_computer_cntrl_attr(ah,
230910001SJoyce.McIntosh@Sun.COM SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT |
23108670SJose.Borrego@Sun.COM SMB_ADS_USER_ACCT_CTL_TRUSTED_FOR_DELEGATION, dn)
23118670SJose.Borrego@Sun.COM == LDAP_INSUFFICIENT_ACCESS) {
23128670SJose.Borrego@Sun.COM usrctl_flags |= (SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT |
23138670SJose.Borrego@Sun.COM SMB_ADS_USER_ACCT_CTL_DONT_EXPIRE_PASSWD);
23148670SJose.Borrego@Sun.COM
23159021Samw@Sun.COM syslog(LOG_NOTICE, "Unable to set the "
23168670SJose.Borrego@Sun.COM "TRUSTED_FOR_DELEGATION userAccountControl flag on "
23178670SJose.Borrego@Sun.COM "the machine account in Active Directory. Please refer "
23188670SJose.Borrego@Sun.COM "to the Troubleshooting guide for more information.");
23198670SJose.Borrego@Sun.COM
23208670SJose.Borrego@Sun.COM } else {
23218670SJose.Borrego@Sun.COM usrctl_flags |= (SMB_ADS_USER_ACCT_CTL_WKSTATION_TRUST_ACCT |
23228670SJose.Borrego@Sun.COM SMB_ADS_USER_ACCT_CTL_TRUSTED_FOR_DELEGATION |
23238670SJose.Borrego@Sun.COM SMB_ADS_USER_ACCT_CTL_DONT_EXPIRE_PASSWD);
23248670SJose.Borrego@Sun.COM }
23258670SJose.Borrego@Sun.COM
23268670SJose.Borrego@Sun.COM if (des_only)
23278670SJose.Borrego@Sun.COM usrctl_flags |= SMB_ADS_USER_ACCT_CTL_USE_DES_KEY_ONLY;
23288670SJose.Borrego@Sun.COM
23298670SJose.Borrego@Sun.COM if (smb_ads_update_computer_cntrl_attr(ah, usrctl_flags, dn)
23307348SJose.Borrego@Sun.COM != 0) {
23317052Samw rc = SMB_ADJOIN_ERR_UPDATE_CNTRL_ATTR;
23325331Samw goto adjoin_cleanup;
23335331Samw }
23345331Samw
23358334SJose.Borrego@Sun.COM tmpfile = mktemp(SMBNS_KRB5_KEYTAB_TMP);
23368334SJose.Borrego@Sun.COM if (tmpfile == NULL)
23378334SJose.Borrego@Sun.COM tmpfile = SMBNS_KRB5_KEYTAB_TMP;
23388334SJose.Borrego@Sun.COM
2339*12508Samw@Sun.COM encptr = smb_ads_get_enctypes(dclevel, &num);
2340*12508Samw@Sun.COM if (smb_krb5_kt_populate(ctx, ah->domain, krb5princs, cnt,
2341*12508Samw@Sun.COM tmpfile, kvno, machine_passwd, encptr, num) != 0) {
23427052Samw rc = SMB_ADJOIN_ERR_WRITE_KEYTAB;
23435331Samw goto adjoin_cleanup;
23445331Samw }
23455331Samw
23465521Sas200622 delete = B_FALSE;
23475331Samw adjoin_cleanup:
23485521Sas200622 if (new_acct && delete)
23497348SJose.Borrego@Sun.COM smb_ads_del_computer(ah, dn);
23505331Samw
23517052Samw if (rc != SMB_ADJOIN_ERR_INIT_KRB_CTX) {
23527052Samw if (rc != SMB_ADJOIN_ERR_GET_SPNS)
2353*12508Samw@Sun.COM smb_krb5_free_kprincs(ctx, krb5princs, cnt);
23545331Samw smb_krb5_ctx_fini(ctx);
23555967Scp160787 }
23565331Samw
23578334SJose.Borrego@Sun.COM /* commit keytab file */
23588334SJose.Borrego@Sun.COM if (rc == SMB_ADJOIN_SUCCESS) {
23598334SJose.Borrego@Sun.COM if (rename(tmpfile, SMBNS_KRB5_KEYTAB) != 0) {
23608334SJose.Borrego@Sun.COM (void) unlink(tmpfile);
23618334SJose.Borrego@Sun.COM rc = SMB_ADJOIN_ERR_COMMIT_KEYTAB;
23628334SJose.Borrego@Sun.COM } else {
23638334SJose.Borrego@Sun.COM /* Set IDMAP config */
23648334SJose.Borrego@Sun.COM if (smb_config_set_idmap_domain(ah->domain) != 0) {
23658334SJose.Borrego@Sun.COM rc = SMB_ADJOIN_ERR_IDMAP_SET_DOMAIN;
23668334SJose.Borrego@Sun.COM } else {
23678334SJose.Borrego@Sun.COM
23688334SJose.Borrego@Sun.COM /* Refresh IDMAP service */
23698334SJose.Borrego@Sun.COM if (smb_config_refresh_idmap() != 0)
23708334SJose.Borrego@Sun.COM rc = SMB_ADJOIN_ERR_IDMAP_REFRESH;
23718334SJose.Borrego@Sun.COM }
23728334SJose.Borrego@Sun.COM }
23738334SJose.Borrego@Sun.COM } else {
23748334SJose.Borrego@Sun.COM (void) unlink(tmpfile);
23758334SJose.Borrego@Sun.COM }
23768334SJose.Borrego@Sun.COM
23777052Samw smb_ads_close(ah);
23786139Sjb150015 smb_ccache_remove(SMB_CCACHE_PATH);
23795331Samw return (rc);
23805331Samw }
23815331Samw
23825331Samw /*
23839021Samw@Sun.COM * smb_ads_join_errmsg
23845331Samw *
23855331Samw * Display error message for the specific adjoin error code.
23865331Samw */
23879021Samw@Sun.COM void
smb_ads_join_errmsg(smb_adjoin_status_t status)23889021Samw@Sun.COM smb_ads_join_errmsg(smb_adjoin_status_t status)
23895331Samw {
23909021Samw@Sun.COM int i;
23919021Samw@Sun.COM struct xlate_table {
23929021Samw@Sun.COM smb_adjoin_status_t status;
23939021Samw@Sun.COM char *msg;
23949021Samw@Sun.COM } adjoin_table[] = {
23959021Samw@Sun.COM { SMB_ADJOIN_ERR_GET_HANDLE, "Failed to connect to an "
23969021Samw@Sun.COM "Active Directory server." },
239711571SShawn.Emery@Sun.COM { SMB_ADJOIN_ERR_GEN_PWD, "Failed to generate machine "
239811571SShawn.Emery@Sun.COM "password." },
23999021Samw@Sun.COM { SMB_ADJOIN_ERR_GET_DCLEVEL, "Unknown functional level of "
24009021Samw@Sun.COM "the domain controller. The rootDSE attribute named "
24019021Samw@Sun.COM "\"domainControllerFunctionality\" is missing from the "
24029021Samw@Sun.COM "Active Directory." },
24039021Samw@Sun.COM { SMB_ADJOIN_ERR_ADD_TRUST_ACCT, "Failed to create the "
24049021Samw@Sun.COM "workstation trust account." },
24059021Samw@Sun.COM { SMB_ADJOIN_ERR_MOD_TRUST_ACCT, "Failed to modify the "
24069021Samw@Sun.COM "workstation trust account." },
24079021Samw@Sun.COM { SMB_ADJOIN_ERR_DUP_TRUST_ACCT, "Failed to create the "
24089021Samw@Sun.COM "workstation trust account because its name is already "
24099021Samw@Sun.COM "in use." },
24109021Samw@Sun.COM { SMB_ADJOIN_ERR_TRUST_ACCT, "Error in querying the "
24119021Samw@Sun.COM "workstation trust account" },
24129021Samw@Sun.COM { SMB_ADJOIN_ERR_INIT_KRB_CTX, "Failed to initialize Kerberos "
24139021Samw@Sun.COM "context." },
24149021Samw@Sun.COM { SMB_ADJOIN_ERR_GET_SPNS, "Failed to get Kerberos "
24159021Samw@Sun.COM "principals." },
24169021Samw@Sun.COM { SMB_ADJOIN_ERR_KSETPWD, "Failed to set machine password." },
24179021Samw@Sun.COM { SMB_ADJOIN_ERR_UPDATE_CNTRL_ATTR, "Failed to modify "
24189021Samw@Sun.COM "userAccountControl attribute of the workstation trust "
24199021Samw@Sun.COM "account." },
24209021Samw@Sun.COM { SMB_ADJOIN_ERR_WRITE_KEYTAB, "Error in writing to local "
24219021Samw@Sun.COM "keytab file (i.e /etc/krb5/krb5.keytab)." },
24229021Samw@Sun.COM { SMB_ADJOIN_ERR_IDMAP_SET_DOMAIN, "Failed to update idmap "
24239021Samw@Sun.COM "configuration." },
24249021Samw@Sun.COM { SMB_ADJOIN_ERR_IDMAP_REFRESH, "Failed to refresh idmap "
24259021Samw@Sun.COM "service." },
24269021Samw@Sun.COM { SMB_ADJOIN_ERR_COMMIT_KEYTAB, "Failed to commit changes to "
24279021Samw@Sun.COM "local keytab file (i.e. /etc/krb5/krb5.keytab)." }
24289021Samw@Sun.COM };
24299021Samw@Sun.COM
24309021Samw@Sun.COM for (i = 0; i < sizeof (adjoin_table) / sizeof (adjoin_table[0]); i++) {
24319021Samw@Sun.COM if (adjoin_table[i].status == status)
24329021Samw@Sun.COM syslog(LOG_NOTICE, "%s", adjoin_table[i].msg);
24339021Samw@Sun.COM }
24345331Samw }
24357348SJose.Borrego@Sun.COM
24367348SJose.Borrego@Sun.COM /*
24379832Samw@Sun.COM * smb_ads_match_pdc
24387961SNatalie.Li@Sun.COM *
24399832Samw@Sun.COM * Returns B_TRUE if the given host's IP address matches the preferred DC's
24409832Samw@Sun.COM * IP address. Otherwise, returns B_FALSE.
24417961SNatalie.Li@Sun.COM */
24429832Samw@Sun.COM static boolean_t
smb_ads_match_pdc(smb_ads_host_info_t * host)24439832Samw@Sun.COM smb_ads_match_pdc(smb_ads_host_info_t *host)
24447961SNatalie.Li@Sun.COM {
24459832Samw@Sun.COM boolean_t match = B_FALSE;
24469832Samw@Sun.COM
24479832Samw@Sun.COM if (!host)
24489832Samw@Sun.COM return (match);
24499832Samw@Sun.COM
24509832Samw@Sun.COM (void) mutex_lock(&smb_ads_cfg.c_mtx);
24519832Samw@Sun.COM if (smb_inet_equal(&host->ipaddr, &smb_ads_cfg.c_pdc))
24529832Samw@Sun.COM match = B_TRUE;
24539832Samw@Sun.COM (void) mutex_unlock(&smb_ads_cfg.c_mtx);
24549832Samw@Sun.COM
24559832Samw@Sun.COM return (match);
24567961SNatalie.Li@Sun.COM }
24577961SNatalie.Li@Sun.COM
24587961SNatalie.Li@Sun.COM /*
24597961SNatalie.Li@Sun.COM * smb_ads_select_dcfromsubnet
24607961SNatalie.Li@Sun.COM *
24617961SNatalie.Li@Sun.COM * This method walks the list of DCs and returns the first DC record that
24627961SNatalie.Li@Sun.COM * responds to ldap ping and is in the same subnet as the host.
24637961SNatalie.Li@Sun.COM *
24647961SNatalie.Li@Sun.COM * Returns a pointer to the found DC record.
24657961SNatalie.Li@Sun.COM * Returns NULL, on error or if no DC record is found.
24667961SNatalie.Li@Sun.COM */
24677961SNatalie.Li@Sun.COM static smb_ads_host_info_t *
smb_ads_select_dcfromsubnet(smb_ads_host_list_t * hlist)24687961SNatalie.Li@Sun.COM smb_ads_select_dcfromsubnet(smb_ads_host_list_t *hlist)
24697961SNatalie.Li@Sun.COM {
24707961SNatalie.Li@Sun.COM smb_ads_host_info_t *hentry;
24717961SNatalie.Li@Sun.COM smb_nic_t *lnic;
24727961SNatalie.Li@Sun.COM smb_niciter_t ni;
24737961SNatalie.Li@Sun.COM size_t cnt;
24747961SNatalie.Li@Sun.COM int i;
24757961SNatalie.Li@Sun.COM
247611963SAfshin.Ardakani@Sun.COM if (smb_nic_getfirst(&ni) != SMB_NIC_SUCCESS)
24777961SNatalie.Li@Sun.COM return (NULL);
24787961SNatalie.Li@Sun.COM do {
24797961SNatalie.Li@Sun.COM lnic = &ni.ni_nic;
24807961SNatalie.Li@Sun.COM cnt = hlist->ah_cnt;
24817961SNatalie.Li@Sun.COM
24827961SNatalie.Li@Sun.COM for (i = 0; i < cnt; i++) {
24837961SNatalie.Li@Sun.COM hentry = &hlist->ah_list[i];
24848670SJose.Borrego@Sun.COM if ((hentry->ipaddr.a_family == AF_INET) &&
24858670SJose.Borrego@Sun.COM (lnic->nic_ip.a_family == AF_INET)) {
24868670SJose.Borrego@Sun.COM if ((hentry->ipaddr.a_ipv4 &
24878670SJose.Borrego@Sun.COM lnic->nic_mask) ==
24888670SJose.Borrego@Sun.COM (lnic->nic_ip.a_ipv4 &
24898670SJose.Borrego@Sun.COM lnic->nic_mask))
24908670SJose.Borrego@Sun.COM if (smb_ads_ldap_ping(hentry) == 0)
24918670SJose.Borrego@Sun.COM return (hentry);
24928670SJose.Borrego@Sun.COM }
24937961SNatalie.Li@Sun.COM }
249411963SAfshin.Ardakani@Sun.COM } while (smb_nic_getnext(&ni) == SMB_NIC_SUCCESS);
24957961SNatalie.Li@Sun.COM
24967961SNatalie.Li@Sun.COM return (NULL);
24977961SNatalie.Li@Sun.COM }
24987961SNatalie.Li@Sun.COM
24997961SNatalie.Li@Sun.COM /*
25007961SNatalie.Li@Sun.COM * smb_ads_select_dcfromlist
25017961SNatalie.Li@Sun.COM *
25027961SNatalie.Li@Sun.COM * This method walks the list of DCs and returns the first DC that
25037961SNatalie.Li@Sun.COM * responds to ldap ping.
25047961SNatalie.Li@Sun.COM *
25057961SNatalie.Li@Sun.COM * Returns a pointer to the found DC record.
25067961SNatalie.Li@Sun.COM * Returns NULL if no DC record is found.
25077961SNatalie.Li@Sun.COM */
25087961SNatalie.Li@Sun.COM static smb_ads_host_info_t *
smb_ads_select_dcfromlist(smb_ads_host_list_t * hlist)25097961SNatalie.Li@Sun.COM smb_ads_select_dcfromlist(smb_ads_host_list_t *hlist)
25107961SNatalie.Li@Sun.COM {
25117961SNatalie.Li@Sun.COM smb_ads_host_info_t *hentry;
25127961SNatalie.Li@Sun.COM size_t cnt;
25137961SNatalie.Li@Sun.COM int i;
25147961SNatalie.Li@Sun.COM
25157961SNatalie.Li@Sun.COM cnt = hlist->ah_cnt;
25167961SNatalie.Li@Sun.COM for (i = 0; i < cnt; i++) {
25177961SNatalie.Li@Sun.COM hentry = &hlist->ah_list[i];
25187961SNatalie.Li@Sun.COM if (smb_ads_ldap_ping(hentry) == 0)
25197961SNatalie.Li@Sun.COM return (hentry);
25207961SNatalie.Li@Sun.COM }
25217961SNatalie.Li@Sun.COM
25227961SNatalie.Li@Sun.COM return (NULL);
25237961SNatalie.Li@Sun.COM }
25247961SNatalie.Li@Sun.COM
25257961SNatalie.Li@Sun.COM /*
25267348SJose.Borrego@Sun.COM * smb_ads_dc_compare
25277348SJose.Borrego@Sun.COM *
25287348SJose.Borrego@Sun.COM * Comparision function for sorting host entries (SRV records of DC) via qsort.
25297961SNatalie.Li@Sun.COM * RFC 2052/2782 are taken as reference, while implementing this algorithm.
25307961SNatalie.Li@Sun.COM *
25317961SNatalie.Li@Sun.COM * Domain Controllers(DCs) with lowest priority in their SRV DNS records
25327961SNatalie.Li@Sun.COM * are selected first. If they have equal priorities, then DC with highest
25337961SNatalie.Li@Sun.COM * weight in its SRV DNS record is selected. If the priority and weight are
25347961SNatalie.Li@Sun.COM * both equal, then the DC at the top of the list is selected.
25357348SJose.Borrego@Sun.COM */
25367348SJose.Borrego@Sun.COM static int
smb_ads_dc_compare(const void * p,const void * q)25377348SJose.Borrego@Sun.COM smb_ads_dc_compare(const void *p, const void *q)
25387348SJose.Borrego@Sun.COM {
25397348SJose.Borrego@Sun.COM smb_ads_host_info_t *h1 = (smb_ads_host_info_t *)p;
25407348SJose.Borrego@Sun.COM smb_ads_host_info_t *h2 = (smb_ads_host_info_t *)q;
25417348SJose.Borrego@Sun.COM
25427348SJose.Borrego@Sun.COM if (h1->priority < h2->priority)
25437348SJose.Borrego@Sun.COM return (-1);
25447348SJose.Borrego@Sun.COM if (h1->priority > h2->priority)
25457348SJose.Borrego@Sun.COM return (1);
25467348SJose.Borrego@Sun.COM
25477348SJose.Borrego@Sun.COM /* Priorities are equal */
25487348SJose.Borrego@Sun.COM if (h1->weight < h2->weight)
25497348SJose.Borrego@Sun.COM return (1);
25507348SJose.Borrego@Sun.COM if (h1->weight > h2->weight)
25517348SJose.Borrego@Sun.COM return (-1);
25527348SJose.Borrego@Sun.COM
25537348SJose.Borrego@Sun.COM return (0);
25547348SJose.Borrego@Sun.COM }
25557348SJose.Borrego@Sun.COM
25567348SJose.Borrego@Sun.COM /*
25577348SJose.Borrego@Sun.COM * smb_ads_select_dc
25587348SJose.Borrego@Sun.COM *
25597961SNatalie.Li@Sun.COM * The list of ADS hosts returned by ADS lookup, is sorted by lowest priority
25607961SNatalie.Li@Sun.COM * and highest weight. On this sorted list, following additional rules are
25617961SNatalie.Li@Sun.COM * applied, to select a DC.
25627348SJose.Borrego@Sun.COM *
25637961SNatalie.Li@Sun.COM * - If there is a DC in the same subnet, then return the DC,
25647961SNatalie.Li@Sun.COM * if it responds to ldap ping.
25657961SNatalie.Li@Sun.COM * - Else, return first DC that responds to ldap ping.
25667961SNatalie.Li@Sun.COM *
25677961SNatalie.Li@Sun.COM * A reference to the host entry from input host list is returned.
25687348SJose.Borrego@Sun.COM *
25697348SJose.Borrego@Sun.COM * Returns NULL on error.
25707348SJose.Borrego@Sun.COM */
25717348SJose.Borrego@Sun.COM static smb_ads_host_info_t *
smb_ads_select_dc(smb_ads_host_list_t * hlist)25727348SJose.Borrego@Sun.COM smb_ads_select_dc(smb_ads_host_list_t *hlist)
25737348SJose.Borrego@Sun.COM {
25747961SNatalie.Li@Sun.COM smb_ads_host_info_t *hentry = NULL;
25757961SNatalie.Li@Sun.COM
25767961SNatalie.Li@Sun.COM if (hlist->ah_cnt == 0)
25777348SJose.Borrego@Sun.COM return (NULL);
25787348SJose.Borrego@Sun.COM
25797961SNatalie.Li@Sun.COM if (hlist->ah_cnt == 1) {
25807961SNatalie.Li@Sun.COM hentry = hlist->ah_list;
25817961SNatalie.Li@Sun.COM if (smb_ads_ldap_ping(hentry) == 0)
25827961SNatalie.Li@Sun.COM return (hentry);
25837348SJose.Borrego@Sun.COM }
25847348SJose.Borrego@Sun.COM
25857961SNatalie.Li@Sun.COM /* Sort the list by priority and weight */
25867961SNatalie.Li@Sun.COM qsort(hlist->ah_list, hlist->ah_cnt,
25877961SNatalie.Li@Sun.COM sizeof (smb_ads_host_info_t), smb_ads_dc_compare);
25887961SNatalie.Li@Sun.COM
25897961SNatalie.Li@Sun.COM if ((hentry = smb_ads_select_dcfromsubnet(hlist)) != NULL)
25907961SNatalie.Li@Sun.COM return (hentry);
25917961SNatalie.Li@Sun.COM
25927961SNatalie.Li@Sun.COM if ((hentry = smb_ads_select_dcfromlist(hlist)) != NULL)
25937961SNatalie.Li@Sun.COM return (hentry);
25947961SNatalie.Li@Sun.COM
25957348SJose.Borrego@Sun.COM return (NULL);
25967348SJose.Borrego@Sun.COM }
25978334SJose.Borrego@Sun.COM
25988334SJose.Borrego@Sun.COM /*
25998334SJose.Borrego@Sun.COM * smb_ads_lookup_msdcs
26008334SJose.Borrego@Sun.COM *
26018334SJose.Borrego@Sun.COM * If server argument is set, try to locate the specified DC.
26028334SJose.Borrego@Sun.COM * If it is set to empty string, locate any DCs in the specified domain.
26038334SJose.Borrego@Sun.COM * Returns the discovered DC via buf.
26048334SJose.Borrego@Sun.COM *
26058334SJose.Borrego@Sun.COM * fqdn - fully-qualified domain name
26068334SJose.Borrego@Sun.COM * server - fully-qualifed hostname of a DC
26078334SJose.Borrego@Sun.COM * buf - the hostname of the discovered DC
26088334SJose.Borrego@Sun.COM */
26098334SJose.Borrego@Sun.COM boolean_t
smb_ads_lookup_msdcs(char * fqdn,char * server,char * buf,uint32_t buflen)26108334SJose.Borrego@Sun.COM smb_ads_lookup_msdcs(char *fqdn, char *server, char *buf, uint32_t buflen)
26118334SJose.Borrego@Sun.COM {
26128334SJose.Borrego@Sun.COM smb_ads_host_info_t *hinfo = NULL;
26138334SJose.Borrego@Sun.COM char *p;
26148334SJose.Borrego@Sun.COM char *sought_host;
26158670SJose.Borrego@Sun.COM char ipstr[INET6_ADDRSTRLEN];
26168334SJose.Borrego@Sun.COM
26178334SJose.Borrego@Sun.COM if (!fqdn || !buf)
26188334SJose.Borrego@Sun.COM return (B_FALSE);
26198334SJose.Borrego@Sun.COM
26209252SChristopher.Parker@Sun.COM ipstr[0] = '\0';
26218334SJose.Borrego@Sun.COM *buf = '\0';
26228334SJose.Borrego@Sun.COM sought_host = (*server == 0 ? NULL : server);
26238334SJose.Borrego@Sun.COM if ((hinfo = smb_ads_find_host(fqdn, sought_host)) == NULL)
26248334SJose.Borrego@Sun.COM return (B_FALSE);
26258334SJose.Borrego@Sun.COM
26269252SChristopher.Parker@Sun.COM (void) smb_inet_ntop(&hinfo->ipaddr, ipstr,
26279252SChristopher.Parker@Sun.COM SMB_IPSTRLEN(hinfo->ipaddr.a_family));
26289252SChristopher.Parker@Sun.COM smb_tracef("msdcsLookupADS: %s [%s]", hinfo->name, ipstr);
26298334SJose.Borrego@Sun.COM
26308334SJose.Borrego@Sun.COM (void) strlcpy(buf, hinfo->name, buflen);
26318334SJose.Borrego@Sun.COM /*
26328334SJose.Borrego@Sun.COM * Remove the domain extension
26338334SJose.Borrego@Sun.COM */
26348334SJose.Borrego@Sun.COM if ((p = strchr(buf, '.')) != 0)
26358334SJose.Borrego@Sun.COM *p = '\0';
26368334SJose.Borrego@Sun.COM
26379832Samw@Sun.COM free(hinfo);
26388334SJose.Borrego@Sun.COM return (B_TRUE);
26398334SJose.Borrego@Sun.COM }
2640*12508Samw@Sun.COM
2641*12508Samw@Sun.COM static krb5_enctype *
smb_ads_get_enctypes(int dclevel,int * num)2642*12508Samw@Sun.COM smb_ads_get_enctypes(int dclevel, int *num)
2643*12508Samw@Sun.COM {
2644*12508Samw@Sun.COM krb5_enctype *encptr;
2645*12508Samw@Sun.COM
2646*12508Samw@Sun.COM if (dclevel >= SMB_ADS_DCLEVEL_W2K8) {
2647*12508Samw@Sun.COM *num = sizeof (w2k8enctypes) / sizeof (krb5_enctype);
2648*12508Samw@Sun.COM encptr = w2k8enctypes;
2649*12508Samw@Sun.COM } else {
2650*12508Samw@Sun.COM *num = sizeof (pre_w2k8enctypes) / sizeof (krb5_enctype);
2651*12508Samw@Sun.COM encptr = pre_w2k8enctypes;
2652*12508Samw@Sun.COM }
2653*12508Samw@Sun.COM
2654*12508Samw@Sun.COM return (encptr);
2655*12508Samw@Sun.COM }
2656