diff options
author | Gerald Carter <jerry@samba.org> | 2006-05-18 20:12:45 +0000 |
---|---|---|
committer | Gerald (Jerry) Carter <jerry@samba.org> | 2007-10-10 11:17:08 -0500 |
commit | 463e7c11711e0c511d81c892e4be621ea3bfe8b1 (patch) | |
tree | f12bbe77073176ea53a4c3784e61f119858cc823 /source3 | |
parent | 0648638fef56a65f9389c8a98f66c57663e8c401 (diff) | |
download | samba-463e7c11711e0c511d81c892e4be621ea3bfe8b1.tar.gz samba-463e7c11711e0c511d81c892e4be621ea3bfe8b1.tar.bz2 samba-463e7c11711e0c511d81c892e4be621ea3bfe8b1.zip |
r15701: change 'net ads leave' to disable the machine account in the domain (since removal implies greater permissions that Windows clients require)
(This used to be commit ad1f947625612ef16adb69fc2cfeffc68a9a2e02)
Diffstat (limited to 'source3')
-rw-r--r-- | source3/Makefile.in | 2 | ||||
-rw-r--r-- | source3/libads/ldap.c | 184 | ||||
-rw-r--r-- | source3/utils/net.h | 2 | ||||
-rw-r--r-- | source3/utils/net_ads.c | 267 | ||||
-rw-r--r-- | source3/utils/net_domain.c | 338 |
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; +} + |