1da6c28aaSamw /*
2da6c28aaSamw * CDDL HEADER START
3da6c28aaSamw *
4da6c28aaSamw * The contents of this file are subject to the terms of the
5da6c28aaSamw * Common Development and Distribution License (the "License").
6da6c28aaSamw * You may not use this file except in compliance with the License.
7da6c28aaSamw *
8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw * See the License for the specific language governing permissions
11da6c28aaSamw * and limitations under the License.
12da6c28aaSamw *
13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw *
19da6c28aaSamw * CDDL HEADER END
20da6c28aaSamw */
21da6c28aaSamw /*
221fdeec65Sjoyce mcintosh * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
231ed6b69aSGordon Ross * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
24da6c28aaSamw */
25da6c28aaSamw
26da6c28aaSamw /*
27da6c28aaSamw * Utility functions to support the RPC interface library.
28da6c28aaSamw */
29da6c28aaSamw
30da6c28aaSamw #include <stdio.h>
31da6c28aaSamw #include <stdarg.h>
32da6c28aaSamw #include <strings.h>
33da6c28aaSamw #include <unistd.h>
34da6c28aaSamw #include <netdb.h>
35da6c28aaSamw #include <stdlib.h>
36da6c28aaSamw #include <sys/time.h>
37da6c28aaSamw #include <sys/systm.h>
38*b819cea2SGordon Ross #include <note.h>
39fc724630SAlan Wright #include <syslog.h>
40da6c28aaSamw
41da6c28aaSamw #include <smbsrv/libsmb.h>
42da6c28aaSamw #include <smbsrv/libsmbns.h>
43da6c28aaSamw #include <smbsrv/libmlsvc.h>
441ed6b69aSGordon Ross #include <smbsrv/ntaccess.h>
45da6c28aaSamw #include <smbsrv/smbinfo.h>
46ed9aabc7SGordon Ross #include <libsmbrdr.h>
478d7e4166Sjose borrego #include <lsalib.h>
488d7e4166Sjose borrego #include <samlib.h>
498d7e4166Sjose borrego #include <smbsrv/netrauth.h>
50da6c28aaSamw
51da6c28aaSamw extern int netr_open(char *, char *, mlsvc_handle_t *);
52da6c28aaSamw extern int netr_close(mlsvc_handle_t *);
53da6c28aaSamw extern DWORD netlogon_auth(char *, mlsvc_handle_t *, DWORD);
54da6c28aaSamw
551ed6b69aSGordon Ross static DWORD
561ed6b69aSGordon Ross mlsvc_join_rpc(smb_domainex_t *dxi,
571ed6b69aSGordon Ross char *admin_user, char *admin_pw,
581ed6b69aSGordon Ross char *machine_name, char *machine_pw);
591ed6b69aSGordon Ross static DWORD
601ed6b69aSGordon Ross mlsvc_join_noauth(smb_domainex_t *dxi,
611ed6b69aSGordon Ross char *machine_name, char *machine_pw);
621ed6b69aSGordon Ross
631ed6b69aSGordon Ross
64faa1795aSjb150015 DWORD
mlsvc_netlogon(char * server,char * domain)65faa1795aSjb150015 mlsvc_netlogon(char *server, char *domain)
66faa1795aSjb150015 {
67faa1795aSjb150015 mlsvc_handle_t netr_handle;
68faa1795aSjb150015 DWORD status;
69faa1795aSjb150015
70faa1795aSjb150015 if (netr_open(server, domain, &netr_handle) == 0) {
71fc724630SAlan Wright if ((status = netlogon_auth(server, &netr_handle,
72fc724630SAlan Wright NETR_FLG_INIT)) != NT_STATUS_SUCCESS)
73fc724630SAlan Wright syslog(LOG_NOTICE, "Failed to establish NETLOGON "
74fc724630SAlan Wright "credential chain");
75faa1795aSjb150015 (void) netr_close(&netr_handle);
76faa1795aSjb150015 } else {
771ed6b69aSGordon Ross syslog(LOG_NOTICE, "Failed to connect to %s "
781ed6b69aSGordon Ross "for domain %s", server, domain);
791ed6b69aSGordon Ross status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
80faa1795aSjb150015 }
81faa1795aSjb150015
82faa1795aSjb150015 return (status);
83faa1795aSjb150015 }
84faa1795aSjb150015
85da6c28aaSamw /*
861ed6b69aSGordon Ross * Join the specified domain. The method varies depending on whether
871ed6b69aSGordon Ross * we're using "secure join" (using an administrative account to join)
881ed6b69aSGordon Ross * or "unsecure join" (using a pre-created machine account). In the
891ed6b69aSGordon Ross * latter case, the machine account is created "by hand" before this
901ed6b69aSGordon Ross * machine attempts to join, and we just change the password from the
911ed6b69aSGordon Ross * (weak) default password for a new machine account to a random one.
92eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States *
931ed6b69aSGordon Ross * Note that the caller has already done "DC discovery" and passes the
941ed6b69aSGordon Ross * domain info. in the first arg.
95da6c28aaSamw *
96da6c28aaSamw * Returns NT status codes.
97da6c28aaSamw */
98da6c28aaSamw DWORD
mlsvc_join(smb_domainex_t * dxi,char * admin_user,char * admin_pw)991ed6b69aSGordon Ross mlsvc_join(smb_domainex_t *dxi, char *admin_user, char *admin_pw)
100da6c28aaSamw {
1011ed6b69aSGordon Ross char machine_name[SMB_SAMACCT_MAXLEN];
1021ed6b69aSGordon Ross char machine_pw[NETR_MACHINE_ACCT_PASSWD_MAX];
1031ed6b69aSGordon Ross unsigned char passwd_hash[SMBAUTH_HASH_SZ];
1041ed6b69aSGordon Ross smb_domain_t *di = &dxi->d_primary;
105da6c28aaSamw DWORD status;
1061ed6b69aSGordon Ross int rc;
107da6c28aaSamw
1081ed6b69aSGordon Ross /*
1091ed6b69aSGordon Ross * Domain join support: AD (Kerberos+LDAP) or MS-RPC?
1101ed6b69aSGordon Ross * Leave the AD code path disabled until it can be
1111ed6b69aSGordon Ross * fixed up so that the SMB server is in complete
1121ed6b69aSGordon Ross * control of which AD server we talk to. See:
1131ed6b69aSGordon Ross * NX 12427 (Re-enable Kerberos+LDAP with...)
1141ed6b69aSGordon Ross */
1151ed6b69aSGordon Ross boolean_t ads_enabled = smb_config_get_ads_enable();
116da6c28aaSamw
1171ed6b69aSGordon Ross if (smb_getsamaccount(machine_name, sizeof (machine_name)) != 0)
1181ed6b69aSGordon Ross return (NT_STATUS_INTERNAL_ERROR);
119da6c28aaSamw
1201ed6b69aSGordon Ross (void) smb_gen_random_passwd(machine_pw, sizeof (machine_pw));
121eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States
1221ed6b69aSGordon Ross /*
1231ed6b69aSGordon Ross * A non-null user means we do "secure join".
1241ed6b69aSGordon Ross */
1251ed6b69aSGordon Ross if (admin_user != NULL && admin_user[0] != '\0') {
1261ed6b69aSGordon Ross /*
1271ed6b69aSGordon Ross * Doing "secure join", so authenticate as the
1281ed6b69aSGordon Ross * specified user (with admin. rights).
1291ed6b69aSGordon Ross */
1301ed6b69aSGordon Ross (void) smb_auth_ntlm_hash(admin_pw, passwd_hash);
1311ed6b69aSGordon Ross smb_ipc_set(admin_user, passwd_hash);
132da6c28aaSamw
1331ed6b69aSGordon Ross /*
1341ed6b69aSGordon Ross * If enabled, try to join using AD Services.
1351ed6b69aSGordon Ross * The ADS code needs work. Not enabled yet.
1361ed6b69aSGordon Ross */
137da6c28aaSamw status = NT_STATUS_UNSUCCESSFUL;
1381ed6b69aSGordon Ross if (ads_enabled) {
1391ed6b69aSGordon Ross smb_adjoin_status_t err;
1401ed6b69aSGordon Ross err = smb_ads_join(di->di_fqname,
1411ed6b69aSGordon Ross admin_user, admin_pw, machine_pw);
1421ed6b69aSGordon Ross if (err != SMB_ADJOIN_SUCCESS) {
1431ed6b69aSGordon Ross smb_ads_join_errmsg(err);
144da6c28aaSamw } else {
1451ed6b69aSGordon Ross status = NT_STATUS_SUCCESS;
146da6c28aaSamw }
147da6c28aaSamw }
148da6c28aaSamw
1491ed6b69aSGordon Ross /*
1501ed6b69aSGordon Ross * If ADS was disabled or gave an error,
1511ed6b69aSGordon Ross * fall-back and try to join using RPC.
1521ed6b69aSGordon Ross */
1531ed6b69aSGordon Ross if (status != NT_STATUS_SUCCESS) {
1541ed6b69aSGordon Ross status = mlsvc_join_rpc(dxi,
1551ed6b69aSGordon Ross admin_user, admin_pw,
1561ed6b69aSGordon Ross machine_name, machine_pw);
1571ed6b69aSGordon Ross }
1581ed6b69aSGordon Ross
1591ed6b69aSGordon Ross } else {
1601ed6b69aSGordon Ross /*
1611ed6b69aSGordon Ross * Doing "Unsecure join" (pre-created account)
1621ed6b69aSGordon Ross */
1631ed6b69aSGordon Ross bzero(passwd_hash, sizeof (passwd_hash));
1641ed6b69aSGordon Ross smb_ipc_set(MLSVC_ANON_USER, passwd_hash);
1651ed6b69aSGordon Ross
1661ed6b69aSGordon Ross status = mlsvc_join_noauth(dxi, machine_name, machine_pw);
1671ed6b69aSGordon Ross }
1681ed6b69aSGordon Ross
1691ed6b69aSGordon Ross if (status != NT_STATUS_SUCCESS)
1701ed6b69aSGordon Ross goto out;
1711ed6b69aSGordon Ross
1721ed6b69aSGordon Ross /*
1731ed6b69aSGordon Ross * Make sure we can authenticate using the
1741ed6b69aSGordon Ross * (new, or updated) machine account.
1751ed6b69aSGordon Ross */
1761ed6b69aSGordon Ross (void) smb_auth_ntlm_hash(machine_pw, passwd_hash);
1771ed6b69aSGordon Ross smb_ipc_set(machine_name, passwd_hash);
1781ed6b69aSGordon Ross rc = smbrdr_logon(dxi->d_dc, di->di_nbname, machine_name);
1791ed6b69aSGordon Ross if (rc != 0) {
1801ed6b69aSGordon Ross syslog(LOG_NOTICE, "Authenticate with "
1811ed6b69aSGordon Ross "new/updated machine account: %s",
1821ed6b69aSGordon Ross strerror(rc));
1831ed6b69aSGordon Ross status = NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
1841ed6b69aSGordon Ross goto out;
1851ed6b69aSGordon Ross }
1861ed6b69aSGordon Ross
1871ed6b69aSGordon Ross /*
1881ed6b69aSGordon Ross * Store the new machine account password.
1891ed6b69aSGordon Ross */
1901ed6b69aSGordon Ross rc = smb_setdomainprops(NULL, dxi->d_dc, machine_pw);
1911ed6b69aSGordon Ross if (rc != 0) {
1929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States syslog(LOG_NOTICE,
1931ed6b69aSGordon Ross "Failed to save machine account password");
1941ed6b69aSGordon Ross status = NT_STATUS_INTERNAL_DB_ERROR;
1951ed6b69aSGordon Ross goto out;
196fc724630SAlan Wright }
197da6c28aaSamw
1981ed6b69aSGordon Ross /*
1991ed6b69aSGordon Ross * Update idmap config
2001ed6b69aSGordon Ross */
2011ed6b69aSGordon Ross if (smb_config_set_idmap_domain(di->di_fqname) != 0)
2021ed6b69aSGordon Ross syslog(LOG_NOTICE, "Failed to set idmap domain name");
2031ed6b69aSGordon Ross if (smb_config_refresh_idmap() != 0)
2041ed6b69aSGordon Ross syslog(LOG_NOTICE, "Failed to refresh idmap service");
2051ed6b69aSGordon Ross
2061ed6b69aSGordon Ross /*
2071ed6b69aSGordon Ross * Note: The caller (smbd) saves the "secmode" and
2081ed6b69aSGordon Ross * domain info (via smb_config_setdomaininfo) and
2091ed6b69aSGordon Ross * and does smb_ipc_commit (or rollback).
2101ed6b69aSGordon Ross */
2111ed6b69aSGordon Ross status = 0;
2121ed6b69aSGordon Ross
2131ed6b69aSGordon Ross out:
2141ed6b69aSGordon Ross /* Avoid leaving cleartext passwords around. */
2151ed6b69aSGordon Ross bzero(machine_pw, sizeof (machine_pw));
2161ed6b69aSGordon Ross bzero(passwd_hash, sizeof (passwd_hash));
2171ed6b69aSGordon Ross
2181ed6b69aSGordon Ross return (status);
219da6c28aaSamw }
220da6c28aaSamw
2211ed6b69aSGordon Ross static DWORD
mlsvc_join_rpc(smb_domainex_t * dxi,char * admin_user,char * admin_pw,char * machine_name,char * machine_pw)2221ed6b69aSGordon Ross mlsvc_join_rpc(smb_domainex_t *dxi,
2231ed6b69aSGordon Ross char *admin_user, char *admin_pw,
2241ed6b69aSGordon Ross char *machine_name, char *machine_pw)
2251ed6b69aSGordon Ross {
2261ed6b69aSGordon Ross mlsvc_handle_t samr_handle;
2271ed6b69aSGordon Ross mlsvc_handle_t domain_handle;
2281ed6b69aSGordon Ross mlsvc_handle_t user_handle;
2291ed6b69aSGordon Ross smb_account_t ainfo;
2301ed6b69aSGordon Ross char *server = dxi->d_dc;
2311ed6b69aSGordon Ross smb_domain_t *di = &dxi->d_primary;
2321ed6b69aSGordon Ross DWORD account_flags;
2331ed6b69aSGordon Ross DWORD rid;
2341ed6b69aSGordon Ross DWORD status;
2351ed6b69aSGordon Ross int rc;
2361ed6b69aSGordon Ross
2371ed6b69aSGordon Ross /* Caller did smb_ipc_set() so we don't need the pw for now. */
2381ed6b69aSGordon Ross _NOTE(ARGUNUSED(admin_pw));
2391ed6b69aSGordon Ross
2401ed6b69aSGordon Ross rc = samr_open(server, di->di_nbname, admin_user,
2411ed6b69aSGordon Ross MAXIMUM_ALLOWED, &samr_handle);
2421ed6b69aSGordon Ross if (rc != 0) {
2431ed6b69aSGordon Ross syslog(LOG_NOTICE, "sam_connect to server %s failed", server);
2441ed6b69aSGordon Ross return (RPC_NT_SERVER_UNAVAILABLE);
2451ed6b69aSGordon Ross }
2461ed6b69aSGordon Ross /* have samr_handle */
2471ed6b69aSGordon Ross
2481ed6b69aSGordon Ross status = samr_open_domain(&samr_handle, MAXIMUM_ALLOWED,
2491ed6b69aSGordon Ross (struct samr_sid *)di->di_binsid, &domain_handle);
2501ed6b69aSGordon Ross if (status != NT_STATUS_SUCCESS)
2511ed6b69aSGordon Ross goto out_samr_handle;
2521ed6b69aSGordon Ross /* have domain_handle */
2531ed6b69aSGordon Ross
2541ed6b69aSGordon Ross account_flags = SAMR_AF_WORKSTATION_TRUST_ACCOUNT;
2551ed6b69aSGordon Ross status = samr_create_user(&domain_handle, machine_name,
2561ed6b69aSGordon Ross account_flags, &rid, &user_handle);
2571ed6b69aSGordon Ross if (status == NT_STATUS_USER_EXISTS) {
2581ed6b69aSGordon Ross status = samr_lookup_domain_names(&domain_handle,
2591ed6b69aSGordon Ross machine_name, &ainfo);
2601ed6b69aSGordon Ross if (status != NT_STATUS_SUCCESS)
2611ed6b69aSGordon Ross goto out_domain_handle;
2621ed6b69aSGordon Ross status = samr_open_user(&domain_handle, MAXIMUM_ALLOWED,
2631ed6b69aSGordon Ross ainfo.a_rid, &user_handle);
2641ed6b69aSGordon Ross }
2651ed6b69aSGordon Ross if (status != NT_STATUS_SUCCESS) {
2661ed6b69aSGordon Ross syslog(LOG_NOTICE,
2671ed6b69aSGordon Ross "Create or open machine account: %s",
2681ed6b69aSGordon Ross xlate_nt_status(status));
2691ed6b69aSGordon Ross goto out_domain_handle;
2701ed6b69aSGordon Ross }
2711ed6b69aSGordon Ross
2721ed6b69aSGordon Ross /*
2731ed6b69aSGordon Ross * The account exists, and we have user_handle open
2741ed6b69aSGordon Ross * on that account. Set the password and flags.
2751ed6b69aSGordon Ross */
2761ed6b69aSGordon Ross
2771ed6b69aSGordon Ross status = netr_set_user_password(&user_handle, machine_pw);
2781ed6b69aSGordon Ross if (status != NT_STATUS_SUCCESS) {
2791ed6b69aSGordon Ross syslog(LOG_NOTICE,
2801ed6b69aSGordon Ross "Set machine account password: %s",
2811ed6b69aSGordon Ross xlate_nt_status(status));
2821ed6b69aSGordon Ross goto out_user_handle;
2831ed6b69aSGordon Ross }
2841ed6b69aSGordon Ross
2851ed6b69aSGordon Ross account_flags |= SAMR_AF_DONT_EXPIRE_PASSWD;
2861ed6b69aSGordon Ross status = netr_set_user_control(&user_handle, account_flags);
2871ed6b69aSGordon Ross if (status != NT_STATUS_SUCCESS) {
2881ed6b69aSGordon Ross syslog(LOG_NOTICE,
2891ed6b69aSGordon Ross "Set machine account control flags: %s",
2901ed6b69aSGordon Ross xlate_nt_status(status));
2911ed6b69aSGordon Ross goto out_user_handle;
2921ed6b69aSGordon Ross }
2931ed6b69aSGordon Ross
2941ed6b69aSGordon Ross out_user_handle:
2951ed6b69aSGordon Ross (void) samr_close_handle(&user_handle);
2961ed6b69aSGordon Ross out_domain_handle:
2971ed6b69aSGordon Ross (void) samr_close_handle(&domain_handle);
2981ed6b69aSGordon Ross out_samr_handle:
2991ed6b69aSGordon Ross (void) samr_close_handle(&samr_handle);
3001ed6b69aSGordon Ross
3011ed6b69aSGordon Ross return (status);
3021ed6b69aSGordon Ross }
3031ed6b69aSGordon Ross
3041ed6b69aSGordon Ross /*
3051ed6b69aSGordon Ross * Doing "Unsecure join" (using a pre-created machine account).
3061ed6b69aSGordon Ross * All we need to do is change the password from the default
3071ed6b69aSGordon Ross * to a random string.
3081ed6b69aSGordon Ross *
3091ed6b69aSGordon Ross * Note: this is a work in progres. Nexenta issue 11960
3101ed6b69aSGordon Ross * (allow joining an AD domain using a pre-created computer account)
3111ed6b69aSGordon Ross * It turns out that to change the machine account password,
3121ed6b69aSGordon Ross * we need to use a different RPC call, performed over the
3131ed6b69aSGordon Ross * NetLogon secure channel. (See netr_server_password_set2)
3141ed6b69aSGordon Ross */
3151ed6b69aSGordon Ross static DWORD
mlsvc_join_noauth(smb_domainex_t * dxi,char * machine_name,char * machine_pw)3161ed6b69aSGordon Ross mlsvc_join_noauth(smb_domainex_t *dxi,
3171ed6b69aSGordon Ross char *machine_name, char *machine_pw)
3181ed6b69aSGordon Ross {
3191ed6b69aSGordon Ross char old_pw[SMB_SAMACCT_MAXLEN];
3201ed6b69aSGordon Ross DWORD status;
3211ed6b69aSGordon Ross
3221ed6b69aSGordon Ross /*
3231ed6b69aSGordon Ross * Compose the current (default) password for the
3241ed6b69aSGordon Ross * pre-created machine account, which is just the
3251ed6b69aSGordon Ross * account name in lower case, truncated to 14
3261ed6b69aSGordon Ross * characters.
3271ed6b69aSGordon Ross */
3281ed6b69aSGordon Ross if (smb_gethostname(old_pw, sizeof (old_pw), SMB_CASE_LOWER) != 0)
3291ed6b69aSGordon Ross return (NT_STATUS_INTERNAL_ERROR);
3301ed6b69aSGordon Ross old_pw[14] = '\0';
3311ed6b69aSGordon Ross
3321ed6b69aSGordon Ross status = netr_change_password(dxi->d_dc, machine_name,
3331ed6b69aSGordon Ross old_pw, machine_pw);
3341ed6b69aSGordon Ross if (status != NT_STATUS_SUCCESS) {
3351ed6b69aSGordon Ross syslog(LOG_NOTICE,
3361ed6b69aSGordon Ross "Change machine account password: %s",
3371ed6b69aSGordon Ross xlate_nt_status(status));
3381ed6b69aSGordon Ross }
339da6c28aaSamw return (status);
340da6c28aaSamw }
341a0aa776eSAlan Wright
342a0aa776eSAlan Wright void
mlsvc_disconnect(const char * server)343a0aa776eSAlan Wright mlsvc_disconnect(const char *server)
344a0aa776eSAlan Wright {
345a0aa776eSAlan Wright smbrdr_disconnect(server);
346a0aa776eSAlan Wright }
347