summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source3/Makefile.in2
-rw-r--r--source3/libads/ldap.c184
-rw-r--r--source3/utils/net.h2
-rw-r--r--source3/utils/net_ads.c267
-rw-r--r--source3/utils/net_domain.c338
5 files changed, 396 insertions, 397 deletions
diff --git a/source3/Makefile.in b/source3/Makefile.in
index 25927be3ef..effd438def 100644
--- a/source3/Makefile.in
+++ b/source3/Makefile.in
@@ -570,7 +570,7 @@ TOOL_OBJ = client/smbctool.o client/clitar.o $(PARAM_OBJ) $(LIBSMB_OBJ) \
$(LIB_NONSMBD_OBJ) $(KRBCLIENT_OBJ) \
$(READLINE_OBJ) $(POPT_LIB_OBJ) $(SECRETS_OBJ)
-NET_OBJ1 = utils/net.o utils/net_ads.o utils/net_help.o \
+NET_OBJ1 = utils/net.o utils/net_ads.o utils/net_domain.o utils/net_help.o \
utils/net_rap.o utils/net_rpc.o utils/net_rpc_samsync.o \
utils/net_rpc_join.o utils/net_time.o utils/net_lookup.o \
utils/net_cache.o utils/net_groupmap.o utils/net_idmap.o \
diff --git a/source3/libads/ldap.c b/source3/libads/ldap.c
index 293163c05e..3307ad83fe 100644
--- a/source3/libads/ldap.c
+++ b/source3/libads/ldap.c
@@ -1753,190 +1753,6 @@ int ads_count_replies(ADS_STRUCT *ads, void *res)
}
/**
- * Delete a machine from the realm
- * @param ads connection to ads server
- * @param hostname Machine to remove
- * @return status of delete
- **/
-ADS_STATUS ads_leave_realm(ADS_STRUCT *ads, const char *hostname)
-{
- ADS_STATUS status;
- void *res, *msg;
- char *hostnameDN, *host;
- int rc;
- LDAPControl ldap_control;
- LDAPControl * pldap_control[2] = {NULL, NULL};
-
- pldap_control[0] = &ldap_control;
- memset(&ldap_control, 0, sizeof(LDAPControl));
- ldap_control.ldctl_oid = (char *)LDAP_SERVER_TREE_DELETE_OID;
-
- /* hostname must be lowercase */
- host = SMB_STRDUP(hostname);
- strlower_m(host);
-
- status = ads_find_machine_acct(ads, &res, host);
- if (!ADS_ERR_OK(status)) {
- DEBUG(0, ("Host account for %s does not exist.\n", host));
- return status;
- }
-
- msg = ads_first_entry(ads, res);
- if (!msg) {
- return ADS_ERROR_SYSTEM(ENOENT);
- }
-
- hostnameDN = ads_get_dn(ads, (LDAPMessage *)msg);
-
-
- rc = ldap_delete_ext_s(ads->ld, hostnameDN, pldap_control, NULL);
- if (rc) {
- DEBUG(3,("ldap_delete_ext_s failed with error code %d\n", rc));
- }else {
- DEBUG(3,("ldap_delete_ext_s succeeded with error code %d\n", rc));
- }
-
- ads_memfree(ads, hostnameDN);
- if (rc != LDAP_SUCCESS) {
- return ADS_ERROR(rc);
- }
-
- status = ads_find_machine_acct(ads, &res, host);
- if (ADS_ERR_OK(status) && ads_count_replies(ads, res) == 1) {
- DEBUG(0, ("Failed to remove host account.\n"));
- return status;
- }
-
- free(host);
-
- return status;
-}
-
-#if 0
-/**
- * add machine account to existing security descriptor
- * @param ads connection to ads server
- * @param hostname machine to add
- * @param dn DN of security descriptor
- * @return status
- **/
-static ADS_STATUS ads_set_machine_sd(ADS_STRUCT *ads, const char *hostname, char *dn)
-{
- const char *attrs[] = {"nTSecurityDescriptor", "objectSid", 0};
- char *expr = 0;
- size_t sd_size = 0;
- struct berval bval = {0, NULL};
- prs_struct ps_wire;
- char *escaped_hostname = escape_ldap_string_alloc(hostname);
-
- LDAPMessage *res = 0;
- LDAPMessage *msg = 0;
- ADS_MODLIST mods = 0;
-
- NTSTATUS status;
- ADS_STATUS ret;
- DOM_SID sid;
- SEC_DESC *psd = NULL;
- TALLOC_CTX *ctx = NULL;
-
- /* Avoid segmentation fault in prs_mem_free if
- * we have to bail out before prs_init */
- ps_wire.is_dynamic = False;
-
- if (!ads) {
- SAFE_FREE(escaped_hostname);
- return ADS_ERROR(LDAP_SERVER_DOWN);
- }
-
- ret = ADS_ERROR(LDAP_SUCCESS);
-
- if (!escaped_hostname) {
- return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
- }
-
- if (asprintf(&expr, "(samAccountName=%s$)", escaped_hostname) == -1) {
- DEBUG(1, ("ads_set_machine_sd: asprintf failed!\n"));
- SAFE_FREE(escaped_hostname);
- return ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
- }
-
- SAFE_FREE(escaped_hostname);
-
- ret = ads_search(ads, (void *) &res, expr, attrs);
-
- SAFE_FREE(expr);
-
- if (!ADS_ERR_OK(ret)) return ret;
-
- if ( !(msg = ads_first_entry(ads, res) )) {
- ret = ADS_ERROR(LDAP_NO_RESULTS_RETURNED);
- goto ads_set_sd_error;
- }
-
- if (!ads_pull_sid(ads, msg, attrs[1], &sid)) {
- ret = ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
- goto ads_set_sd_error;
- }
-
- if (!(ctx = talloc_init("sec_io_desc"))) {
- ret = ADS_ERROR(LDAP_NO_MEMORY);
- goto ads_set_sd_error;
- }
-
- if (!ads_pull_sd(ads, ctx, msg, attrs[0], &psd)) {
- ret = ADS_ERROR_NT(NT_STATUS_INVALID_PARAMETER);
- goto ads_set_sd_error;
- }
-
- status = sec_desc_add_sid(ctx, &psd, &sid, SEC_RIGHTS_FULL_CTRL, &sd_size);
-
- if (!NT_STATUS_IS_OK(status)) {
- ret = ADS_ERROR_NT(status);
- goto ads_set_sd_error;
- }
-
- if (!prs_init(&ps_wire, sd_size, ctx, MARSHALL)) {
- ret = ADS_ERROR_NT(NT_STATUS_NO_MEMORY);
- }
-
- if (!sec_io_desc("sd_wire", &psd, &ps_wire, 1)) {
- ret = ADS_ERROR(LDAP_NO_MEMORY);
- goto ads_set_sd_error;
- }
-
-#if 0
- file_save("/tmp/sec_desc.new", ps_wire.data_p, sd_size);
-#endif
- if (!(mods = ads_init_mods(ctx))) return ADS_ERROR(LDAP_NO_MEMORY);
-
- bval.bv_len = prs_offset(&ps_wire);
- bval.bv_val = TALLOC(ctx, bval.bv_len);
- if (!bval.bv_val) {
- ret = ADS_ERROR(LDAP_NO_MEMORY);
- goto ads_set_sd_error;
- }
-
- prs_set_offset(&ps_wire, 0);
-
- if (!prs_copy_data_out(bval.bv_val, &ps_wire, bval.bv_len)) {
- ret = ADS_ERROR(LDAP_NO_MEMORY);
- goto ads_set_sd_error;
- }
-
- ret = ads_mod_ber(ctx, &mods, attrs[0], &bval);
- if (ADS_ERR_OK(ret)) {
- ret = ads_gen_mod(ads, dn, mods);
- }
-
-ads_set_sd_error:
- ads_msgfree(ads, res);
- prs_mem_free(&ps_wire);
- talloc_destroy(ctx);
- return ret;
-}
-#endif
-
-/**
* pull the first entry from a ADS result
* @param ads connection to ads server
* @param res Results of search
diff --git a/source3/utils/net.h b/source3/utils/net.h
index b1af230a65..d037871f82 100644
--- a/source3/utils/net.h
+++ b/source3/utils/net.h
@@ -62,6 +62,8 @@ struct rpc_sh_cmd {
const char *help;
};
+enum netdom_domain_t { ND_TYPE_NT4, ND_TYPE_AD };
+
/* INCLUDE FILES */
#include "utils/net_proto.h"
diff --git a/source3/utils/net_ads.c b/source3/utils/net_ads.c
index fc62558320..10831c878b 100644
--- a/source3/utils/net_ads.c
+++ b/source3/utils/net_ads.c
@@ -26,6 +26,7 @@
/* Macro for checking RPC error codes to make things more readable */
+#if 0
#define CHECK_RPC_ERR(rpc, msg) \
if (!NT_STATUS_IS_OK(result = rpc)) { \
DEBUG(0, (msg ": %s\n", nt_errstr(result))); \
@@ -38,6 +39,7 @@
goto done; \
}
+#endif
#ifdef HAVE_ADS
int net_ads_usage(int argc, const char **argv)
@@ -746,35 +748,70 @@ static int net_ads_status(int argc, const char **argv)
return 0;
}
+/*******************************************************************
+ Leave an AD domain. Windows XP disables the machine account.
+ We'll try the same. The old code would do an LDAP delete.
+ That only worked using the machine creds because added the machine
+ with full control to the computer object's ACL.
+*******************************************************************/
static int net_ads_leave(int argc, const char **argv)
{
ADS_STRUCT *ads = NULL;
- ADS_STATUS rc;
+ int ret = -1;
+ struct cli_state *cli = NULL;
+ TALLOC_CTX *ctx;
+ DOM_SID *dom_sid = NULL;
if (!secrets_init()) {
DEBUG(1,("Failed to initialise secrets database\n"));
return -1;
}
- if (!opt_password) {
- net_use_machine_password();
+ if (!(ctx = talloc_init("net_ads_leave"))) {
+ DEBUG(0, ("Could not initialise talloc context\n"));
+ return -1;
}
+ /* The finds a DC and takes care of getting the
+ user creds if necessary */
+
if (!(ads = ads_startup())) {
return -1;
}
- rc = ads_leave_realm(ads, global_myname());
- if (!ADS_ERR_OK(rc)) {
- d_fprintf(stderr, "Failed to delete host '%s' from the '%s' realm.\n",
+ /* make RPC calls here */
+
+ if ( !NT_STATUS_IS_OK(connect_to_ipc_krb5(&cli, &ads->ldap_ip,
+ ads->config.ldap_server_name)) )
+ {
+ goto done;
+ }
+
+ saf_store( cli->server_domain, cli->desthost );
+
+ if ( !NT_STATUS_IS_OK(netdom_get_domain_sid( ctx, cli, &dom_sid )) ) {
+ goto done;
+ }
+
+ if ( !NT_STATUS_IS_OK(netdom_leave_domain( ctx, cli, dom_sid )) ) {
+ d_printf(stderr, "Failed to disable machine account for '%s' in realm '%s'\n",
global_myname(), ads->config.realm);
- ads_destroy(&ads);
- return -1;
+ goto done;
}
+
+ d_printf("Disabled account for '%s' in realm '%s'\n",
+ global_myname(), ads->config.realm);
+
+ ret = 0;
+
+done:
+ if ( cli )
+ cli_shutdown(cli);
- d_printf("Removed '%s' from realm '%s'\n", global_myname(), ads->config.realm);
ads_destroy(&ads);
- return 0;
+ TALLOC_FREE( ctx );
+
+ return ret;
}
static int net_ads_join_ok(void)
@@ -846,203 +883,6 @@ static int check_ads_config( void )
}
/*******************************************************************
- Store the machine password and domain SID
- ********************************************************************/
-
-static int store_domain_account( const char *domain, DOM_SID *sid, const char *pw )
-{
- if (!secrets_store_domain_sid(domain, sid)) {
- DEBUG(1,("Failed to save domain sid\n"));
- return -1;
- }
-
- if (!secrets_store_machine_password(pw, domain, SEC_CHAN_WKSTA)) {
- DEBUG(1,("Failed to save machine password\n"));
- return -1;
- }
-
- return 0;
-}
-
-/*******************************************************************
- ********************************************************************/
-
-static NTSTATUS join_fetch_domain_sid( TALLOC_CTX *mem_ctx, struct cli_state *cli, DOM_SID **sid )
-{
- struct rpc_pipe_client *pipe_hnd = NULL;
- POLICY_HND lsa_pol;
- NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
- char *domain = NULL;
-
- if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &status)) == NULL ) {
- DEBUG(0, ("Error connecting to LSA pipe. Error was %s\n",
- nt_errstr(status) ));
- return status;
- }
-
- status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, True,
- SEC_RIGHTS_MAXIMUM_ALLOWED, &lsa_pol);
- if ( !NT_STATUS_IS_OK(status) )
- return status;
-
- status = rpccli_lsa_query_info_policy(pipe_hnd, mem_ctx,
- &lsa_pol, 5, &domain, sid);
- if ( !NT_STATUS_IS_OK(status) )
- return status;
-
- rpccli_lsa_close(pipe_hnd, mem_ctx, &lsa_pol);
- cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
-
- /* Bail out if domain didn't get set. */
- if (!domain) {
- DEBUG(0, ("Could not get domain name.\n"));
- return NT_STATUS_UNSUCCESSFUL;
- }
-
- return NT_STATUS_OK;
-}
-
-/*******************************************************************
- Do the domain join
- ********************************************************************/
-
-static NTSTATUS join_create_machine( TALLOC_CTX *mem_ctx, struct cli_state *cli,
- DOM_SID *dom_sid, const char *clear_pw )
-{
- struct rpc_pipe_client *pipe_hnd = NULL;
- POLICY_HND sam_pol, domain_pol, user_pol;
- NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
- char *acct_name;
- const char *const_acct_name;
- uint32 user_rid;
- uint32 num_rids, *name_types, *user_rids;
- uint32 flags = 0x3e8;
- uint32 acb_info = ACB_WSTRUST;
- uchar pwbuf[516];
- SAM_USERINFO_CTR ctr;
- SAM_USER_INFO_24 p24;
- SAM_USER_INFO_16 p16;
- uchar md4_trust_password[16];
-
- /* Open the domain */
-
- if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
- DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
- nt_errstr(status) ));
- return status;
- }
-
- status = rpccli_samr_connect(pipe_hnd, mem_ctx,
- SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
- if ( !NT_STATUS_IS_OK(status) )
- return status;
-
-
- status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
- SEC_RIGHTS_MAXIMUM_ALLOWED, dom_sid, &domain_pol);
- if ( !NT_STATUS_IS_OK(status) )
- return status;
-
- /* Create domain user */
-
- acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname());
- strlower_m(acct_name);
- const_acct_name = acct_name;
-
- /* Don't try to set any acb_info flags other than ACB_WSTRUST */
-
- status = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx, &domain_pol,
- acct_name, acb_info, 0xe005000b, &user_pol, &user_rid);
-
- if ( !NT_STATUS_IS_OK(status)
- && !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS))
- {
- d_fprintf(stderr, "Creation of workstation account failed\n");
-
- /* If NT_STATUS_ACCESS_DENIED then we have a valid
- username/password combo but the user does not have
- administrator access. */
-
- if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
- d_fprintf(stderr, "User specified does not have administrator privileges\n");
-
- return status;
- }
-
- /* We *must* do this.... don't ask... */
-
- if (NT_STATUS_IS_OK(status)) {
- rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
- }
-
- status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
- &domain_pol, flags, 1, &const_acct_name,
- &num_rids, &user_rids, &name_types);
- if ( !NT_STATUS_IS_OK(status) )
- return status;
-
- if ( name_types[0] != SID_NAME_USER) {
- DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
- return NT_STATUS_INVALID_WORKSTATION;
- }
-
- user_rid = user_rids[0];
-
- /* Open handle on user */
-
- status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
- SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
-
- /* Create a random machine account password */
-
- E_md4hash( clear_pw, md4_trust_password);
- encode_pw_buffer(pwbuf, clear_pw, STR_UNICODE);
-
- /* Set password on machine account */
-
- ZERO_STRUCT(ctr);
- ZERO_STRUCT(p24);
-
- init_sam_user_info24(&p24, (char *)pwbuf,24);
-
- ctr.switch_value = 24;
- ctr.info.id24 = &p24;
-
- status = rpccli_samr_set_userinfo(pipe_hnd, mem_ctx, &user_pol,
- 24, &cli->user_session_key, &ctr);
-
- /* Why do we have to try to (re-)set the ACB to be the same as what
- we passed in the samr_create_dom_user() call? When a NT
- workstation is joined to a domain by an administrator the
- acb_info is set to 0x80. For a normal user with "Add
- workstations to the domain" rights the acb_info is 0x84. I'm
- not sure whether it is supposed to make a difference or not. NT
- seems to cope with either value so don't bomb out if the set
- userinfo2 level 0x10 fails. -tpot */
-
- ZERO_STRUCT(ctr);
- ctr.switch_value = 16;
- ctr.info.id16 = &p16;
-
- /* Fill in the additional account flags now */
-
- acb_info |= ACB_PWNOEXP;
-#ifndef ENCTYPE_ARCFOUR_HMAC
- acb_info |= ACB_USE_DES_KEY_ONLY;
-#endif
-
- init_sam_user_info16(&p16, acb_info);
-
- status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16,
- &cli->user_session_key, &ctr);
-
- rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
- cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
-
- return status;
-}
-
-/*******************************************************************
Do the domain join
********************************************************************/
@@ -1057,12 +897,15 @@ static int net_join_domain( TALLOC_CTX *ctx, const char *servername,
saf_store( cli->server_domain, cli->desthost );
- if ( !NT_STATUS_IS_OK(join_fetch_domain_sid( ctx, cli, dom_sid )) )
+ if ( !NT_STATUS_IS_OK(netdom_get_domain_sid( ctx, cli, dom_sid )) )
goto done;
- if ( !NT_STATUS_IS_OK(join_create_machine( ctx, cli, *dom_sid, password )) )
+ if ( !NT_STATUS_IS_OK(netdom_join_domain( ctx, cli, *dom_sid,
+ password, ND_TYPE_AD )) )
+ {
goto done;
-
+ }
+
ret = 0;
done:
@@ -1270,8 +1113,8 @@ int net_ads_join(int argc, const char **argv)
neede to bootstrap winbindd's first connection to the DC to get the real
short domain name --jerry */
- if ( (store_domain_account( lp_workgroup(), domain_sid, password ) == -1)
- || (store_domain_account( short_domain_name, domain_sid, password ) == -1) )
+ if ( (netdom_store_machine_account( lp_workgroup(), domain_sid, password ) == -1)
+ || (netdom_store_machine_account( short_domain_name, domain_sid, password ) == -1) )
{
ads_destroy(&ads);
return -1;
diff --git a/source3/utils/net_domain.c b/source3/utils/net_domain.c
new file mode 100644
index 0000000000..ae8d6b6c55
--- /dev/null
+++ b/source3/utils/net_domain.c
@@ -0,0 +1,338 @@
+/*
+ Samba Unix/Linux SMB client library
+ net ads commands
+ Copyright (C) 2001 Andrew Tridgell (tridge@samba.org)
+ Copyright (C) 2001 Remus Koos (remuskoos@yahoo.com)
+ Copyright (C) 2002 Jim McDonough (jmcd@us.ibm.com)
+ Copyright (C) 2006 Gerald (Jerry) Carter (jerry@samba.org)
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+#include "utils/net.h"
+
+/* Macro for checking RPC error codes to make things more readable */
+
+#define CHECK_RPC_ERR(rpc, msg) \
+ if (!NT_STATUS_IS_OK(result = rpc)) { \
+ DEBUG(0, (msg ": %s\n", nt_errstr(result))); \
+ goto done; \
+ }
+
+#define CHECK_RPC_ERR_DEBUG(rpc, debug_args) \
+ if (!NT_STATUS_IS_OK(result = rpc)) { \
+ DEBUG(0, debug_args); \
+ goto done; \
+ }
+
+/*******************************************************************
+ Leave an AD domain. Windows XP disables the machine account.
+ We'll try the same. The old code would do an LDAP delete.
+ That only worked using the machine creds because added the machine
+ with full control to the computer object's ACL.
+*******************************************************************/
+
+NTSTATUS netdom_leave_domain( TALLOC_CTX *mem_ctx, struct cli_state *cli,
+ DOM_SID *dom_sid )
+{
+ struct rpc_pipe_client *pipe_hnd = NULL;
+ POLICY_HND sam_pol, domain_pol, user_pol;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ char *acct_name;
+ uint32 flags = 0x3e8;
+ const char *const_acct_name;
+ uint32 user_rid;
+ uint32 num_rids, *name_types, *user_rids;
+ SAM_USERINFO_CTR ctr, *qctr = NULL;
+ SAM_USER_INFO_16 p16;
+
+ /* Open the domain */
+
+ if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
+ DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
+ nt_errstr(status) ));
+ return status;
+ }
+
+ status = rpccli_samr_connect(pipe_hnd, mem_ctx,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
+ if ( !NT_STATUS_IS_OK(status) )
+ return status;
+
+
+ status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, dom_sid, &domain_pol);
+ if ( !NT_STATUS_IS_OK(status) )
+ return status;
+
+ /* Create domain user */
+
+ acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname());
+ strlower_m(acct_name);
+ const_acct_name = acct_name;
+
+ status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
+ &domain_pol, flags, 1, &const_acct_name,
+ &num_rids, &user_rids, &name_types);
+ if ( !NT_STATUS_IS_OK(status) )
+ return status;
+
+ if ( name_types[0] != SID_NAME_USER) {
+ DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
+ return NT_STATUS_INVALID_WORKSTATION;
+ }
+
+ user_rid = user_rids[0];
+
+ /* Open handle on user */
+
+ status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
+ if ( !NT_STATUS_IS_OK(status) ) {
+ goto done;
+ }
+
+ /* Get user info */
+
+ status = rpccli_samr_query_userinfo(pipe_hnd, mem_ctx, &user_pol, 16, &qctr);
+ if ( !NT_STATUS_IS_OK(status) ) {
+ rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
+ goto done;
+ }
+
+ /* now disable and setuser info */
+
+ ZERO_STRUCT(ctr);
+ ctr.switch_value = 16;
+ ctr.info.id16 = &p16;
+
+ p16.acb_info = qctr->info.id16->acb_info | ACB_DISABLED;
+
+ status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16,
+ &cli->user_session_key, &ctr);
+
+ rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
+
+done:
+ rpccli_samr_close(pipe_hnd, mem_ctx, &domain_pol);
+ rpccli_samr_close(pipe_hnd, mem_ctx, &sam_pol);
+
+ cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
+
+ return status;
+}
+
+/*******************************************************************
+ Store the machine password and domain SID
+ ********************************************************************/
+
+int netdom_store_machine_account( const char *domain, DOM_SID *sid, const char *pw )
+{
+ if (!secrets_store_domain_sid(domain, sid)) {
+ DEBUG(1,("Failed to save domain sid\n"));
+ return -1;
+ }
+
+ if (!secrets_store_machine_password(pw, domain, SEC_CHAN_WKSTA)) {
+ DEBUG(1,("Failed to save machine password\n"));
+ return -1;
+ }
+
+ return 0;
+}
+
+/*******************************************************************
+ ********************************************************************/
+
+NTSTATUS netdom_get_domain_sid( TALLOC_CTX *mem_ctx, struct cli_state *cli, DOM_SID **sid )
+{
+ struct rpc_pipe_client *pipe_hnd = NULL;
+ POLICY_HND lsa_pol;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ char *domain = NULL;
+
+ if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_LSARPC, &status)) == NULL ) {
+ DEBUG(0, ("Error connecting to LSA pipe. Error was %s\n",
+ nt_errstr(status) ));
+ return status;
+ }
+
+ status = rpccli_lsa_open_policy(pipe_hnd, mem_ctx, True,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, &lsa_pol);
+ if ( !NT_STATUS_IS_OK(status) )
+ return status;
+
+ status = rpccli_lsa_query_info_policy(pipe_hnd, mem_ctx,
+ &lsa_pol, 5, &domain, sid);
+ if ( !NT_STATUS_IS_OK(status) )
+ return status;
+
+ rpccli_lsa_close(pipe_hnd, mem_ctx, &lsa_pol);
+ cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
+
+ /* Bail out if domain didn't get set. */
+ if (!domain) {
+ DEBUG(0, ("Could not get domain name.\n"));
+ return NT_STATUS_UNSUCCESSFUL;
+ }
+
+ return NT_STATUS_OK;
+}
+
+/*******************************************************************
+ Do the domain join
+ ********************************************************************/
+
+NTSTATUS netdom_join_domain( TALLOC_CTX *mem_ctx, struct cli_state *cli,
+ DOM_SID *dom_sid, const char *clear_pw,
+ enum netdom_domain_t dom_type )
+{
+ struct rpc_pipe_client *pipe_hnd = NULL;
+ POLICY_HND sam_pol, domain_pol, user_pol;
+ NTSTATUS status = NT_STATUS_UNSUCCESSFUL;
+ char *acct_name;
+ const char *const_acct_name;
+ uint32 user_rid;
+ uint32 num_rids, *name_types, *user_rids;
+ uint32 flags = 0x3e8;
+ uint32 acb_info = ACB_WSTRUST;
+ uchar pwbuf[516];
+ SAM_USERINFO_CTR ctr;
+ SAM_USER_INFO_24 p24;
+ SAM_USER_INFO_16 p16;
+ uchar md4_trust_password[16];
+
+ /* Open the domain */
+
+ if ( (pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &status)) == NULL ) {
+ DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n",
+ nt_errstr(status) ));
+ return status;
+ }
+
+ status = rpccli_samr_connect(pipe_hnd, mem_ctx,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, &sam_pol);
+ if ( !NT_STATUS_IS_OK(status) )
+ return status;
+
+
+ status = rpccli_samr_open_domain(pipe_hnd, mem_ctx, &sam_pol,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, dom_sid, &domain_pol);
+ if ( !NT_STATUS_IS_OK(status) )
+ return status;
+
+ /* Create domain user */
+
+ acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname());
+ strlower_m(acct_name);
+ const_acct_name = acct_name;
+
+ /* Don't try to set any acb_info flags other than ACB_WSTRUST */
+
+ status = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx, &domain_pol,
+ acct_name, acb_info, 0xe005000b, &user_pol, &user_rid);
+
+ if ( !NT_STATUS_IS_OK(status)
+ && !NT_STATUS_EQUAL(status, NT_STATUS_USER_EXISTS))
+ {
+ d_fprintf(stderr, "Creation of workstation account failed\n");
+
+ /* If NT_STATUS_ACCESS_DENIED then we have a valid
+ username/password combo but the user does not have
+ administrator access. */
+
+ if (NT_STATUS_V(status) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED))
+ d_fprintf(stderr, "User specified does not have administrator privileges\n");
+
+ return status;
+ }
+
+ /* We *must* do this.... don't ask... */
+
+ if (NT_STATUS_IS_OK(status)) {
+ rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
+ }
+
+ status = rpccli_samr_lookup_names(pipe_hnd, mem_ctx,
+ &domain_pol, flags, 1, &const_acct_name,
+ &num_rids, &user_rids, &name_types);
+ if ( !NT_STATUS_IS_OK(status) )
+ return status;
+
+ if ( name_types[0] != SID_NAME_USER) {
+ DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types[0]));
+ return NT_STATUS_INVALID_WORKSTATION;
+ }
+
+ user_rid = user_rids[0];
+
+ /* Open handle on user */
+
+ status = rpccli_samr_open_user(pipe_hnd, mem_ctx, &domain_pol,
+ SEC_RIGHTS_MAXIMUM_ALLOWED, user_rid, &user_pol);
+
+ /* Create a random machine account password */
+
+ E_md4hash( clear_pw, md4_trust_password);
+ encode_pw_buffer(pwbuf, clear_pw, STR_UNICODE);
+
+ /* Set password on machine account */
+
+ ZERO_STRUCT(ctr);
+ ZERO_STRUCT(p24);
+
+ init_sam_user_info24(&p24, (char *)pwbuf,24);
+
+ ctr.switch_value = 24;
+ ctr.info.id24 = &p24;
+
+ status = rpccli_samr_set_userinfo(pipe_hnd, mem_ctx, &user_pol,
+ 24, &cli->user_session_key, &ctr);
+
+ /* Why do we have to try to (re-)set the ACB to be the same as what
+ we passed in the samr_create_dom_user() call? When a NT
+ workstation is joined to a domain by an administrator the
+ acb_info is set to 0x80. For a normal user with "Add
+ workstations to the domain" rights the acb_info is 0x84. I'm
+ not sure whether it is supposed to make a difference or not. NT
+ seems to cope with either value so don't bomb out if the set
+ userinfo2 level 0x10 fails. -tpot */
+
+ ZERO_STRUCT(ctr);
+ ctr.switch_value = 16;
+ ctr.info.id16 = &p16;
+
+ /* Fill in the additional account flags now */
+
+ acb_info |= ACB_PWNOEXP;
+ if ( dom_type == ND_TYPE_AD ) {
+#if !defined(ENCTYPE_ARCFOUR_HMAC)
+ acb_info |= ACB_USE_DES_KEY_ONLY;
+#endif
+ ;;
+ }
+
+ init_sam_user_info16(&p16, acb_info);
+
+ status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, 16,
+ &cli->user_session_key, &ctr);
+
+ rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol);
+ cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */
+
+ return status;
+}
+