static BOOL cli_open_policy_hnd(void) { /* Initialise cli LSA connection */ if (!cli_ipc) { NTSTATUS ret; cli_ipc = connect_one("IPC$"); global_pipe_hnd = cli_rpc_pipe_open_noauth(cli_ipc, PI_LSARPC, &ret); if (!global_pipe_hnd) { return False; } } /* Open policy handle */ if (!got_policy_hnd) { /* Some systems don't support SEC_RIGHTS_MAXIMUM_ALLOWED, but NT sends 0x2000000 so we might as well do it too. */ if (!NT_STATUS_IS_OK(rpccli_lsa_open_policy(global_pipe_hnd, cli_ipc->mem_ctx, True, GENERIC_EXECUTE_ACCESS, &pol))) { return False; } got_policy_hnd = True; } return True; }
static bool cli_open_policy_hnd(void) { /* Initialise cli LSA connection */ if (!cli_ipc) { NTSTATUS ret; cli_ipc = connect_one("IPC$"); ret = cli_rpc_pipe_open_noauth(cli_ipc, &ndr_table_lsarpc, &global_pipe_hnd); if (!NT_STATUS_IS_OK(ret)) { return False; } } /* Open policy handle */ if (!got_policy_hnd) { /* Some systems don't support SEC_FLAG_MAXIMUM_ALLOWED, but NT sends 0x2000000 so we might as well do it too. */ if (!NT_STATUS_IS_OK(rpccli_lsa_open_policy(global_pipe_hnd, talloc_tos(), True, GENERIC_EXECUTE_ACCESS, &pol))) { return False; } got_policy_hnd = True; } return True; }
NTSTATUS netdom_get_domain_sid( TALLOC_CTX *mem_ctx, struct cli_state *cli, char **domain, DOM_SID **sid ) { struct rpc_pipe_client *pipe_hnd = NULL; POLICY_HND lsa_pol; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; 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; }
static NTSTATUS net_sh_run(struct net_context *c, struct rpc_sh_ctx *ctx, struct rpc_sh_cmd *cmd, int argc, const char **argv) { TALLOC_CTX *mem_ctx; struct rpc_pipe_client *pipe_hnd = NULL; NTSTATUS status; mem_ctx = talloc_new(ctx); if (mem_ctx == NULL) { d_fprintf(stderr, _("talloc_new failed\n")); return NT_STATUS_NO_MEMORY; } status = cli_rpc_pipe_open_noauth(ctx->cli, &cmd->table->syntax_id, &pipe_hnd); if (!NT_STATUS_IS_OK(status)) { d_fprintf(stderr, _("Could not open pipe: %s\n"), nt_errstr(status)); return status; } status = cmd->fn(c, mem_ctx, ctx, pipe_hnd, argc, argv); TALLOC_FREE(pipe_hnd); talloc_destroy(mem_ctx); return status; }
NTSTATUS net_rpc_lookup_name(struct net_context *c, TALLOC_CTX *mem_ctx, struct cli_state *cli, const char *name, const char **ret_domain, const char **ret_name, DOM_SID *ret_sid, enum lsa_SidType *ret_type) { struct rpc_pipe_client *lsa_pipe; POLICY_HND pol; NTSTATUS result = NT_STATUS_OK; const char **dom_names; DOM_SID *sids; enum lsa_SidType *types; ZERO_STRUCT(pol); result = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id, &lsa_pipe); if (!NT_STATUS_IS_OK(result)) { d_fprintf(stderr, "Could not initialise lsa pipe\n"); return result; } result = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, false, SEC_RIGHTS_MAXIMUM_ALLOWED, &pol); if (!NT_STATUS_IS_OK(result)) { d_fprintf(stderr, "open_policy failed: %s\n", nt_errstr(result)); return result; } result = rpccli_lsa_lookup_names(lsa_pipe, mem_ctx, &pol, 1, &name, &dom_names, 1, &sids, &types); if (!NT_STATUS_IS_OK(result)) { /* This can happen easily, don't log an error */ goto done; } if (ret_domain != NULL) { *ret_domain = dom_names[0]; } if (ret_name != NULL) { *ret_name = talloc_strdup(mem_ctx, name); } if (ret_sid != NULL) { sid_copy(ret_sid, &sids[0]); } if (ret_type != NULL) { *ret_type = types[0]; } done: if (is_valid_policy_hnd(&pol)) { rpccli_lsa_Close(lsa_pipe, mem_ctx, &pol); } TALLOC_FREE(lsa_pipe); return result; }
static NTSTATUS pipe_cm_connect(TALLOC_CTX *mem_ctx, struct cli_state *cli, const struct ndr_syntax_id *interface, struct rpc_pipe_client **presult) { struct client_pipe_connection *p; NTSTATUS status; p = TALLOC_ZERO_ARRAY(mem_ctx, struct client_pipe_connection, 1); if (!p) { return NT_STATUS_NO_MEMORY; } status = cli_rpc_pipe_open_noauth(cli, interface, &p->pipe); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(p); return status; } p->cli = cli; DLIST_ADD(pipe_connections, p); *presult = p->pipe; return NT_STATUS_OK; }
static bool get_rpc_shares(struct cli_state *cli, void (*fn)(const char *, uint32, const char *, void *), void *state) { NTSTATUS status; struct rpc_pipe_client *pipe_hnd; TALLOC_CTX *mem_ctx; WERROR werr; struct srvsvc_NetShareInfoCtr info_ctr; struct srvsvc_NetShareCtr1 ctr1; int i; uint32_t resume_handle = 0; uint32_t total_entries = 0; mem_ctx = talloc_new(NULL); if (mem_ctx == NULL) { DEBUG(0, ("talloc_new failed\n")); return False; } pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SRVSVC, &status); if (pipe_hnd == NULL) { DEBUG(10, ("Could not connect to srvsvc pipe: %s\n", nt_errstr(status))); TALLOC_FREE(mem_ctx); return False; } ZERO_STRUCT(info_ctr); ZERO_STRUCT(ctr1); info_ctr.level = 1; info_ctr.ctr.ctr1 = &ctr1; status = rpccli_srvsvc_NetShareEnumAll(pipe_hnd, mem_ctx, pipe_hnd->cli->desthost, &info_ctr, 0xffffffff, &total_entries, &resume_handle, &werr); if (!NT_STATUS_IS_OK(status) || !W_ERROR_IS_OK(werr)) { TALLOC_FREE(mem_ctx); cli_rpc_pipe_close(pipe_hnd); return False; } for (i=0; i<total_entries; i++) { struct srvsvc_NetShareInfo1 info = info_ctr.ctr.ctr1->array[i]; fn(info.name, info.type, info.comment, state); } TALLOC_FREE(mem_ctx); cli_rpc_pipe_close(pipe_hnd); return True; }
static NTSTATUS connect_and_get_info(TALLOC_CTX *mem_ctx, struct net_context *net_ctx, struct cli_state **cli, struct rpc_pipe_client **pipe_hnd, struct policy_handle *pol_hnd, struct dom_data *dom_data) { NTSTATUS status; NTSTATUS result; status = net_make_ipc_connection_ex(net_ctx, NULL, NULL, NULL, NET_FLAGS_PDC, cli); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to connect to [%s] with error [%s]\n", net_ctx->opt_host, nt_errstr(status))); return status; } status = cli_rpc_pipe_open_noauth(*cli, &ndr_table_lsarpc.syntax_id, pipe_hnd); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to initialise lsa pipe with error [%s]\n", nt_errstr(status))); return status; } status = dcerpc_lsa_open_policy2((*pipe_hnd)->binding_handle, mem_ctx, (*pipe_hnd)->srv_name_slash, false, (LSA_POLICY_VIEW_LOCAL_INFORMATION | LSA_POLICY_TRUST_ADMIN | LSA_POLICY_CREATE_SECRET), pol_hnd, &result); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Failed to open policy handle with error [%s]\n", nt_errstr(status))); return status; } if (!NT_STATUS_IS_OK(result)) { DEBUG(0, ("lsa_open_policy2 with error [%s]\n", nt_errstr(result))); return result; } status = get_domain_info(mem_ctx, (*pipe_hnd)->binding_handle, pol_hnd, dom_data); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("get_domain_info failed with error [%s].\n", nt_errstr(status))); return status; } return NT_STATUS_OK; }
static NTSTATUS cmd_testme(struct rpc_pipe_client *cli, TALLOC_CTX *mem_ctx, int argc, const char **argv) { struct rpc_pipe_client *lsa_pipe = NULL, *samr_pipe = NULL; NTSTATUS status = NT_STATUS_UNSUCCESSFUL; struct policy_handle pol; d_printf("testme\n"); status = cli_rpc_pipe_open_noauth(rpc_pipe_np_smb_conn(cli), &ndr_table_lsarpc.syntax_id, &lsa_pipe); if (!NT_STATUS_IS_OK(status)) { goto done; } status = cli_rpc_pipe_open_noauth(rpc_pipe_np_smb_conn(cli), &ndr_table_samr.syntax_id, &samr_pipe); if (!NT_STATUS_IS_OK(status)) { goto done; } status = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, False, KEY_QUERY_VALUE, &pol); if (!NT_STATUS_IS_OK(status)) goto done; status = rpccli_lsa_Close(lsa_pipe, mem_ctx, &pol); if (!NT_STATUS_IS_OK(status)) goto done; done: TALLOC_FREE(lsa_pipe); TALLOC_FREE(samr_pipe); return status; }
NTSTATUS net_scan_dc(struct net_context *c, struct cli_state *cli, struct net_dc_info *dc_info) { TALLOC_CTX *mem_ctx = talloc_tos(); struct rpc_pipe_client *dssetup_pipe = NULL; struct dcerpc_binding_handle *dssetup_handle = NULL; union dssetup_DsRoleInfo info; NTSTATUS status; WERROR werr; ZERO_STRUCTP(dc_info); status = cli_rpc_pipe_open_noauth(cli, &ndr_table_dssetup.syntax_id, &dssetup_pipe); if (!NT_STATUS_IS_OK(status)) { DEBUG(10,("net_scan_dc: failed to open dssetup pipe with %s, " "retrying with lsa pipe\n", nt_errstr(status))); return net_scan_dc_noad(c, cli, dc_info); } dssetup_handle = dssetup_pipe->binding_handle; status = dcerpc_dssetup_DsRoleGetPrimaryDomainInformation(dssetup_handle, mem_ctx, DS_ROLE_BASIC_INFORMATION, &info, &werr); TALLOC_FREE(dssetup_pipe); if (NT_STATUS_IS_OK(status)) { status = werror_to_ntstatus(werr); } if (!NT_STATUS_IS_OK(status)) { return status; } dc_info->is_dc = (info.basic.role & (DS_ROLE_PRIMARY_DC|DS_ROLE_BACKUP_DC)); dc_info->is_pdc = (info.basic.role & DS_ROLE_PRIMARY_DC); dc_info->is_ad = (info.basic.flags & DS_ROLE_PRIMARY_DS_RUNNING); dc_info->is_mixed_mode = (info.basic.flags & DS_ROLE_PRIMARY_DS_MIXED_MODE); dc_info->netbios_domain_name = talloc_strdup(mem_ctx, info.basic.domain); dc_info->dns_domain_name = talloc_strdup(mem_ctx, info.basic.dns_domain); dc_info->forest_name = talloc_strdup(mem_ctx, info.basic.forest); return NT_STATUS_OK; }
/** * Connect a server and open a given pipe * * @param cli_dst A cli_state * @param pipe The pipe to open * @param got_pipe boolean that stores if we got a pipe * * @return Normal NTSTATUS return. **/ NTSTATUS connect_dst_pipe(struct net_context *c, struct cli_state **cli_dst, struct rpc_pipe_client **pp_pipe_hnd, const struct ndr_syntax_id *interface) { NTSTATUS nt_status; char *server_name = SMB_STRDUP("127.0.0.1"); struct cli_state *cli_tmp = NULL; struct rpc_pipe_client *pipe_hnd = NULL; if (server_name == NULL) { return NT_STATUS_NO_MEMORY; } if (c->opt_destination) { SAFE_FREE(server_name); if ((server_name = SMB_STRDUP(c->opt_destination)) == NULL) { return NT_STATUS_NO_MEMORY; } } /* make a connection to a named pipe */ nt_status = connect_to_ipc(c, &cli_tmp, NULL, server_name); if (!NT_STATUS_IS_OK(nt_status)) { SAFE_FREE(server_name); return nt_status; } nt_status = cli_rpc_pipe_open_noauth(cli_tmp, interface, &pipe_hnd); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0, ("couldn't not initialize pipe\n")); cli_shutdown(cli_tmp); SAFE_FREE(server_name); return nt_status; } *cli_dst = cli_tmp; *pp_pipe_hnd = pipe_hnd; SAFE_FREE(server_name); return nt_status; }
/** * Connect a server and open a given pipe * * @param cli_dst A cli_state * @param pipe The pipe to open * @param got_pipe boolean that stores if we got a pipe * * @return Normal NTSTATUS return. **/ NTSTATUS connect_dst_pipe(struct cli_state **cli_dst, struct rpc_pipe_client **pp_pipe_hnd, int pipe_num) { NTSTATUS nt_status; char *server_name = SMB_STRDUP("127.0.0.1"); struct cli_state *cli_tmp = NULL; struct rpc_pipe_client *pipe_hnd = NULL; if (server_name == NULL) { return NT_STATUS_NO_MEMORY; } if (opt_destination) { SAFE_FREE(server_name); if ((server_name = SMB_STRDUP(opt_destination)) == NULL) { return NT_STATUS_NO_MEMORY; } } /* make a connection to a named pipe */ nt_status = connect_to_ipc(&cli_tmp, NULL, server_name); if (!NT_STATUS_IS_OK(nt_status)) { SAFE_FREE(server_name); return nt_status; } pipe_hnd = cli_rpc_pipe_open_noauth(cli_tmp, pipe_num, &nt_status); if (!pipe_hnd) { DEBUG(1, ("couldn't not initialize pipe\n")); cli_shutdown(cli_tmp); SAFE_FREE(server_name); return nt_status; } *cli_dst = cli_tmp; *pp_pipe_hnd = pipe_hnd; SAFE_FREE(server_name); return nt_status; }
NTSTATUS net_scan_dc(struct net_context *c, struct cli_state *cli, struct net_dc_info *dc_info) { TALLOC_CTX *mem_ctx = talloc_tos(); struct rpc_pipe_client *dssetup_pipe = NULL; union dssetup_DsRoleInfo info; NTSTATUS status; ZERO_STRUCTP(dc_info); status = cli_rpc_pipe_open_noauth(cli, &ndr_table_dssetup.syntax_id, &dssetup_pipe); if (!NT_STATUS_IS_OK(status)) { return status; } status = rpccli_dssetup_DsRoleGetPrimaryDomainInformation(dssetup_pipe, mem_ctx, DS_ROLE_BASIC_INFORMATION, &info, NULL); TALLOC_FREE(dssetup_pipe); if (!NT_STATUS_IS_OK(status)) { return status; } dc_info->is_dc = (info.basic.role & (DS_ROLE_PRIMARY_DC|DS_ROLE_BACKUP_DC)); dc_info->is_pdc = (info.basic.role & DS_ROLE_PRIMARY_DC); dc_info->is_ad = (info.basic.flags & DS_ROLE_PRIMARY_DS_RUNNING); dc_info->is_mixed_mode = (info.basic.flags & DS_ROLE_PRIMARY_DS_MIXED_MODE); dc_info->netbios_domain_name = talloc_strdup(mem_ctx, info.basic.domain); dc_info->dns_domain_name = talloc_strdup(mem_ctx, info.basic.dns_domain); dc_info->forest_name = talloc_strdup(mem_ctx, info.basic.forest); return NT_STATUS_OK; }
static NTSTATUS pipe_cm_connect(TALLOC_CTX *mem_ctx, struct client_ipc_connection *ipc, const struct ndr_syntax_id *interface, struct rpc_pipe_client **presult) { struct client_pipe_connection *p; NTSTATUS status; p = talloc_zero_array(mem_ctx, struct client_pipe_connection, 1); if (!p) { return NT_STATUS_NO_MEMORY; } status = cli_rpc_pipe_open_noauth(ipc->cli, interface, &p->pipe); if (!NT_STATUS_IS_OK(status)) { TALLOC_FREE(p); return status; } DLIST_ADD(ipc->pipe_connections, p); *presult = p->pipe; return NT_STATUS_OK; }
static NTSTATUS connect_to_domain_password_server(struct cli_state **cli, const char *domain, const char *dc_name, const struct sockaddr_storage *dc_ss, struct rpc_pipe_client **pipe_ret) { NTSTATUS result; struct rpc_pipe_client *netlogon_pipe = NULL; *cli = NULL; *pipe_ret = NULL; /* TODO: Send a SAMLOGON request to determine whether this is a valid logonserver. We can avoid a 30-second timeout if the DC is down if the SAMLOGON request fails as it is only over UDP. */ /* we use a mutex to prevent two connections at once - when a Win2k PDC get two connections where one hasn't completed a session setup yet it will send a TCP reset to the first connection (tridge) */ /* * With NT4.x DC's *all* authentication must be serialized to avoid * ACCESS_DENIED errors if 2 auths are done from the same machine. JRA. */ mutex = grab_named_mutex(NULL, dc_name, 10); if (mutex == NULL) { return NT_STATUS_NO_LOGON_SERVERS; } /* Attempt connection */ result = cli_full_connection(cli, lp_netbios_name(), dc_name, dc_ss, 0, "IPC$", "IPC", "", "", "", 0, SMB_SIGNING_DEFAULT); if (!NT_STATUS_IS_OK(result)) { /* map to something more useful */ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) { result = NT_STATUS_NO_LOGON_SERVERS; } if (*cli) { cli_shutdown(*cli); *cli = NULL; } TALLOC_FREE(mutex); return result; } /* * We now have an anonymous connection to IPC$ on the domain password server. */ /* * Even if the connect succeeds we need to setup the netlogon * pipe here. We do this as we may just have changed the domain * account password on the PDC and yet we may be talking to * a BDC that doesn't have this replicated yet. In this case * a successful connect to a DC needs to take the netlogon connect * into account also. This patch from "Bjart Kvarme" <*****@*****.**>. */ /* open the netlogon pipe. */ if (lp_client_schannel()) { /* We also setup the creds chain in the open_schannel call. */ result = cli_rpc_pipe_open_schannel( *cli, &ndr_table_netlogon, NCACN_NP, DCERPC_AUTH_LEVEL_PRIVACY, domain, &netlogon_pipe); } else { result = cli_rpc_pipe_open_noauth( *cli, &ndr_table_netlogon, &netlogon_pipe); } if (!NT_STATUS_IS_OK(result)) { DEBUG(0,("connect_to_domain_password_server: unable to open the domain client session to \ machine %s. Error was : %s.\n", dc_name, nt_errstr(result))); cli_shutdown(*cli); *cli = NULL; TALLOC_FREE(mutex); return result; }
static NTSTATUS net_scan_dc_noad(struct net_context *c, struct cli_state *cli, struct net_dc_info *dc_info) { TALLOC_CTX *mem_ctx = talloc_tos(); struct rpc_pipe_client *pipe_hnd = NULL; struct dcerpc_binding_handle *b; NTSTATUS status, result; struct policy_handle pol; union lsa_PolicyInformation *info; ZERO_STRUCTP(dc_info); ZERO_STRUCT(pol); status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id, &pipe_hnd); if (!NT_STATUS_IS_OK(status)) { return status; } b = pipe_hnd->binding_handle; status = dcerpc_lsa_open_policy(b, mem_ctx, false, SEC_FLAG_MAXIMUM_ALLOWED, &pol, &result); if (!NT_STATUS_IS_OK(status)) { goto done; } if (!NT_STATUS_IS_OK(result)) { status = result; goto done; } status = dcerpc_lsa_QueryInfoPolicy(b, mem_ctx, &pol, LSA_POLICY_INFO_ACCOUNT_DOMAIN, &info, &result); if (!NT_STATUS_IS_OK(status)) { goto done; } if (!NT_STATUS_IS_OK(result)) { status = result; goto done; } dc_info->netbios_domain_name = talloc_strdup(mem_ctx, info->account_domain.name.string); if (dc_info->netbios_domain_name == NULL) { status = NT_STATUS_NO_MEMORY; goto done; } done: if (is_valid_policy_hnd(&pol)) { dcerpc_lsa_Close(b, mem_ctx, &pol, &result); } TALLOC_FREE(pipe_hnd); return status; }
static NTSTATUS connect_to_domain_password_server(struct cli_state **cli_ret, const char *domain, const char *dc_name, const struct sockaddr_storage *dc_ss, struct rpc_pipe_client **pipe_ret, TALLOC_CTX *mem_ctx, struct netlogon_creds_cli_context **creds_ret) { TALLOC_CTX *frame = talloc_stackframe(); struct messaging_context *msg_ctx = server_messaging_context(); NTSTATUS result; struct cli_state *cli = NULL; struct rpc_pipe_client *netlogon_pipe = NULL; struct netlogon_creds_cli_context *netlogon_creds = NULL; struct netlogon_creds_CredentialState *creds = NULL; uint32_t netlogon_flags = 0; enum netr_SchannelType sec_chan_type = 0; const char *_account_name = NULL; const char *account_name = NULL; struct samr_Password current_nt_hash; struct samr_Password *previous_nt_hash = NULL; bool ok; *cli_ret = NULL; *pipe_ret = NULL; *creds_ret = NULL; /* TODO: Send a SAMLOGON request to determine whether this is a valid logonserver. We can avoid a 30-second timeout if the DC is down if the SAMLOGON request fails as it is only over UDP. */ /* we use a mutex to prevent two connections at once - when a Win2k PDC get two connections where one hasn't completed a session setup yet it will send a TCP reset to the first connection (tridge) */ /* * With NT4.x DC's *all* authentication must be serialized to avoid * ACCESS_DENIED errors if 2 auths are done from the same machine. JRA. */ mutex = grab_named_mutex(NULL, dc_name, 10); if (mutex == NULL) { TALLOC_FREE(frame); return NT_STATUS_NO_LOGON_SERVERS; } /* Attempt connection */ result = cli_full_connection(&cli, lp_netbios_name(), dc_name, dc_ss, 0, "IPC$", "IPC", "", "", "", 0, SMB_SIGNING_DEFAULT); if (!NT_STATUS_IS_OK(result)) { /* map to something more useful */ if (NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL)) { result = NT_STATUS_NO_LOGON_SERVERS; } TALLOC_FREE(mutex); TALLOC_FREE(frame); return result; } /* * We now have an anonymous connection to IPC$ on the domain password server. */ ok = get_trust_pw_hash(domain, current_nt_hash.hash, &_account_name, &sec_chan_type); if (!ok) { cli_shutdown(cli); TALLOC_FREE(mutex); TALLOC_FREE(frame); return NT_STATUS_CANT_ACCESS_DOMAIN_INFO; } account_name = talloc_asprintf(talloc_tos(), "%s$", _account_name); if (account_name == NULL) { cli_shutdown(cli); TALLOC_FREE(mutex); TALLOC_FREE(frame); return NT_STATUS_NO_MEMORY; } result = rpccli_create_netlogon_creds(dc_name, domain, account_name, sec_chan_type, msg_ctx, talloc_tos(), &netlogon_creds); if (!NT_STATUS_IS_OK(result)) { cli_shutdown(cli); TALLOC_FREE(mutex); TALLOC_FREE(frame); SAFE_FREE(previous_nt_hash); return result; } result = rpccli_setup_netlogon_creds(cli, netlogon_creds, false, /* force_reauth */ current_nt_hash, previous_nt_hash); SAFE_FREE(previous_nt_hash); if (!NT_STATUS_IS_OK(result)) { cli_shutdown(cli); TALLOC_FREE(mutex); TALLOC_FREE(frame); return result; } result = netlogon_creds_cli_get(netlogon_creds, talloc_tos(), &creds); if (!NT_STATUS_IS_OK(result)) { cli_shutdown(cli); TALLOC_FREE(mutex); TALLOC_FREE(frame); return result; } netlogon_flags = creds->negotiate_flags; TALLOC_FREE(creds); if (netlogon_flags & NETLOGON_NEG_AUTHENTICATED_RPC) { result = cli_rpc_pipe_open_schannel_with_key( cli, &ndr_table_netlogon, NCACN_NP, domain, netlogon_creds, &netlogon_pipe); } else { result = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon, &netlogon_pipe); } if (!NT_STATUS_IS_OK(result)) { DEBUG(0,("connect_to_domain_password_server: " "unable to open the domain client session to " "machine %s. Flags[0x%08X] Error was : %s.\n", dc_name, (unsigned)netlogon_flags, nt_errstr(result))); cli_shutdown(cli); TALLOC_FREE(mutex); TALLOC_FREE(frame); return result; } if(!netlogon_pipe) { DEBUG(0, ("connect_to_domain_password_server: unable to open " "the domain client session to machine %s. Error " "was : %s.\n", dc_name, nt_errstr(result))); cli_shutdown(cli); TALLOC_FREE(mutex); TALLOC_FREE(frame); return NT_STATUS_NO_LOGON_SERVERS; } /* We exit here with the mutex *locked*. JRA */ *cli_ret = cli; *pipe_ret = netlogon_pipe; *creds_ret = talloc_move(mem_ctx, &netlogon_creds); TALLOC_FREE(frame); return NT_STATUS_OK; }
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; }
NTSTATUS net_rpc_lookup_name(struct net_context *c, TALLOC_CTX *mem_ctx, struct cli_state *cli, const char *name, const char **ret_domain, const char **ret_name, struct dom_sid *ret_sid, enum lsa_SidType *ret_type) { struct rpc_pipe_client *lsa_pipe = NULL; struct policy_handle pol; NTSTATUS status, result; const char **dom_names; struct dom_sid *sids; enum lsa_SidType *types; struct dcerpc_binding_handle *b; ZERO_STRUCT(pol); status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id, &lsa_pipe); if (!NT_STATUS_IS_OK(status)) { d_fprintf(stderr, _("Could not initialise lsa pipe\n")); return status; } b = lsa_pipe->binding_handle; status = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, false, SEC_FLAG_MAXIMUM_ALLOWED, &pol); if (!NT_STATUS_IS_OK(status)) { d_fprintf(stderr, "open_policy %s: %s\n", _("failed"), nt_errstr(status)); return status; } status = rpccli_lsa_lookup_names(lsa_pipe, mem_ctx, &pol, 1, &name, &dom_names, 1, &sids, &types); if (!NT_STATUS_IS_OK(status)) { /* This can happen easily, don't log an error */ goto done; } if (ret_domain != NULL) { *ret_domain = dom_names[0]; } if (ret_name != NULL) { *ret_name = talloc_strdup(mem_ctx, name); } if (ret_sid != NULL) { sid_copy(ret_sid, &sids[0]); } if (ret_type != NULL) { *ret_type = types[0]; } done: if (is_valid_policy_hnd(&pol)) { dcerpc_lsa_Close(b, mem_ctx, &pol, &result); } TALLOC_FREE(lsa_pipe); return status; }
/* * Connect to a server for getting/setting attributes, possibly on an existing * connection. This works similarly to SMBC_server(). */ SMBCSRV * SMBC_attr_server(TALLOC_CTX *ctx, SMBCCTX *context, const char *server, uint16_t port, const char *share, char **pp_workgroup, char **pp_username, char **pp_password) { int flags; struct cli_state *ipc_cli = NULL; struct rpc_pipe_client *pipe_hnd = NULL; NTSTATUS nt_status; SMBCSRV *srv=NULL; SMBCSRV *ipc_srv=NULL; /* * Use srv->cli->desthost and srv->cli->share instead of * server and share below to connect to the actual share, * i.e., a normal share or a referred share from * 'msdfs proxy' share. */ srv = SMBC_server(ctx, context, true, server, port, share, pp_workgroup, pp_username, pp_password); if (!srv) { return NULL; } server = smbXcli_conn_remote_name(srv->cli->conn); share = srv->cli->share; /* * See if we've already created this special connection. Reference * our "special" share name '*IPC$', which is an impossible real share * name due to the leading asterisk. */ ipc_srv = SMBC_find_server(ctx, context, server, "*IPC$", pp_workgroup, pp_username, pp_password); if (!ipc_srv) { int signing_state = SMB_SIGNING_DEFAULT; /* We didn't find a cached connection. Get the password */ if (!*pp_password || (*pp_password)[0] == '\0') { /* ... then retrieve it now. */ SMBC_call_auth_fn(ctx, context, server, share, pp_workgroup, pp_username, pp_password); if (!*pp_workgroup || !*pp_username || !*pp_password) { errno = ENOMEM; return NULL; } } flags = 0; if (smbc_getOptionUseKerberos(context)) { flags |= CLI_FULL_CONNECTION_USE_KERBEROS; } if (smbc_getOptionUseCCache(context)) { flags |= CLI_FULL_CONNECTION_USE_CCACHE; } if (context->internal->smb_encryption_level != SMBC_ENCRYPTLEVEL_NONE) { signing_state = SMB_SIGNING_REQUIRED; } nt_status = cli_full_connection(&ipc_cli, lp_netbios_name(), server, NULL, 0, "IPC$", "?????", *pp_username, *pp_workgroup, *pp_password, flags, signing_state); if (! NT_STATUS_IS_OK(nt_status)) { DEBUG(1,("cli_full_connection failed! (%s)\n", nt_errstr(nt_status))); errno = ENOTSUP; return NULL; } if (context->internal->smb_encryption_level) { /* Attempt UNIX smb encryption. */ if (!NT_STATUS_IS_OK(cli_force_encryption(ipc_cli, *pp_username, *pp_password, *pp_workgroup))) { /* * context->smb_encryption_level == * 1 means don't fail if encryption can't be * negotiated, == 2 means fail if encryption * can't be negotiated. */ DEBUG(4,(" SMB encrypt failed on IPC$\n")); if (context->internal->smb_encryption_level == 2) { cli_shutdown(ipc_cli); errno = EPERM; return NULL; } } DEBUG(4,(" SMB encrypt ok on IPC$\n")); } ipc_srv = SMB_MALLOC_P(SMBCSRV); if (!ipc_srv) { errno = ENOMEM; cli_shutdown(ipc_cli); return NULL; } ZERO_STRUCTP(ipc_srv); DLIST_ADD(ipc_srv->cli, ipc_cli); nt_status = cli_rpc_pipe_open_noauth( ipc_srv->cli, &ndr_table_lsarpc, &pipe_hnd); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("cli_nt_session_open fail!\n")); errno = ENOTSUP; cli_shutdown(ipc_srv->cli); free(ipc_srv); return NULL; } /* * Some systems don't support * SEC_FLAG_MAXIMUM_ALLOWED, but NT sends 0x2000000 * so we might as well do it too. */ nt_status = rpccli_lsa_open_policy( pipe_hnd, talloc_tos(), True, GENERIC_EXECUTE_ACCESS, &ipc_srv->pol); if (!NT_STATUS_IS_OK(nt_status)) { errno = SMBC_errno(context, ipc_srv->cli); cli_shutdown(ipc_srv->cli); free(ipc_srv); return NULL; } /* now add it to the cache (internal or external) */ errno = 0; /* let cache function set errno if it likes */ if (smbc_getFunctionAddCachedServer(context)(context, ipc_srv, server, "*IPC$", *pp_workgroup, *pp_username)) { DEBUG(3, (" Failed to add server to cache\n")); if (errno == 0) { errno = ENOMEM; } cli_shutdown(ipc_srv->cli); free(ipc_srv); return NULL; } DLIST_ADD(context->internal->servers, ipc_srv); } return ipc_srv; }
NTSTATUS remote_password_change(const char *remote_machine, const char *user_name, const char *old_passwd, const char *new_passwd, char **err_str) { struct nmb_name calling, called; struct cli_state *cli; struct rpc_pipe_client *pipe_hnd; struct sockaddr_storage ss; NTSTATUS result; bool pass_must_change = False; *err_str = NULL; if(!resolve_name( remote_machine, &ss, 0x20)) { asprintf(err_str, "Unable to find an IP address for machine " "%s.\n", remote_machine); return NT_STATUS_UNSUCCESSFUL; } cli = cli_initialise(); if (!cli) { return NT_STATUS_NO_MEMORY; } result = cli_connect(cli, remote_machine, &ss); if (!NT_STATUS_IS_OK(result)) { asprintf(err_str, "Unable to connect to SMB server on " "machine %s. Error was : %s.\n", remote_machine, nt_errstr(result)); cli_shutdown(cli); return result; } make_nmb_name(&calling, global_myname() , 0x0); make_nmb_name(&called , remote_machine, 0x20); if (!cli_session_request(cli, &calling, &called)) { asprintf(err_str, "machine %s rejected the session setup. " "Error was : %s.\n", remote_machine, cli_errstr(cli) ); result = cli_nt_error(cli); cli_shutdown(cli); return result; } cli->protocol = PROTOCOL_NT1; if (!cli_negprot(cli)) { asprintf(err_str, "machine %s rejected the negotiate " "protocol. Error was : %s.\n", remote_machine, cli_errstr(cli) ); result = cli_nt_error(cli); cli_shutdown(cli); return result; } /* Given things like SMB signing, restrict anonymous and the like, try an authenticated connection first */ result = cli_session_setup(cli, user_name, old_passwd, strlen(old_passwd)+1, old_passwd, strlen(old_passwd)+1, ""); if (!NT_STATUS_IS_OK(result)) { /* Password must change or Password expired are the only valid * error conditions here from where we can proceed, the rest like * account locked out or logon failure will lead to errors later * anyway */ if (!NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) && !NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED)) { asprintf(err_str, "Could not connect to machine %s: " "%s\n", remote_machine, cli_errstr(cli)); cli_shutdown(cli); return result; } pass_must_change = True; /* * We should connect as the anonymous user here, in case * the server has "must change password" checked... * Thanks to <*****@*****.**> for this fix. */ result = cli_session_setup(cli, "", "", 0, "", 0, ""); if (!NT_STATUS_IS_OK(result)) { asprintf(err_str, "machine %s rejected the session " "setup. Error was : %s.\n", remote_machine, cli_errstr(cli) ); cli_shutdown(cli); return result; } cli_init_creds(cli, "", "", NULL); } else { cli_init_creds(cli, user_name, "", old_passwd); } if (!cli_send_tconX(cli, "IPC$", "IPC", "", 1)) { asprintf(err_str, "machine %s rejected the tconX on the IPC$ " "share. Error was : %s.\n", remote_machine, cli_errstr(cli) ); result = cli_nt_error(cli); cli_shutdown(cli); return result; } /* Try not to give the password away too easily */ if (!pass_must_change) { pipe_hnd = cli_rpc_pipe_open_ntlmssp(cli, PI_SAMR, PIPE_AUTH_LEVEL_PRIVACY, "", /* what domain... ? */ user_name, old_passwd, &result); } else { /* * If the user password must be changed the ntlmssp bind will * fail the same way as the session setup above did. The * difference ist that with a pipe bind we don't get a good * error message, the result will be that the rpc call below * will just fail. So we do it anonymously, there's no other * way. */ pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &result); } if (!pipe_hnd) { if (lp_client_lanman_auth()) { /* Use the old RAP method. */ if (!cli_oem_change_password(cli, user_name, new_passwd, old_passwd)) { asprintf(err_str, "machine %s rejected the " "password change: Error was : %s.\n", remote_machine, cli_errstr(cli) ); result = cli_nt_error(cli); cli_shutdown(cli); return result; } } else { asprintf(err_str, "SAMR connection to machine %s " "failed. Error was %s, but LANMAN password " "changed are disabled\n", nt_errstr(result), remote_machine); result = cli_nt_error(cli); cli_shutdown(cli); return result; } } if (NT_STATUS_IS_OK(result = rpccli_samr_chgpasswd_user(pipe_hnd, pipe_hnd->mem_ctx, user_name, new_passwd, old_passwd))) { /* Great - it all worked! */ cli_shutdown(cli); return NT_STATUS_OK; } else if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) { /* it failed, but for reasons such as wrong password, too short etc ... */ asprintf(err_str, "machine %s rejected the password change: " "Error was : %s.\n", remote_machine, get_friendly_nt_error_msg(result)); cli_shutdown(cli); return result; } /* OK, that failed, so try again... */ cli_rpc_pipe_close(pipe_hnd); /* Try anonymous NTLMSSP... */ cli_init_creds(cli, "", "", NULL); result = NT_STATUS_UNSUCCESSFUL; /* OK, this is ugly, but... try an anonymous pipe. */ pipe_hnd = cli_rpc_pipe_open_noauth(cli, PI_SAMR, &result); if ( pipe_hnd && (NT_STATUS_IS_OK(result = rpccli_samr_chgpasswd_user(pipe_hnd, pipe_hnd->mem_ctx, user_name, new_passwd, old_passwd)))) { /* Great - it all worked! */ cli_shutdown(cli); return NT_STATUS_OK; } else { if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) { /* it failed, but again it was due to things like new password too short */ asprintf(err_str, "machine %s rejected the " "(anonymous) password change: Error was : " "%s.\n", remote_machine, get_friendly_nt_error_msg(result)); cli_shutdown(cli); return result; } /* We have failed to change the user's password, and we think the server just might not support SAMR password changes, so fall back */ if (lp_client_lanman_auth()) { /* Use the old RAP method. */ if (cli_oem_change_password(cli, user_name, new_passwd, old_passwd)) { /* SAMR failed, but the old LanMan protocol worked! */ cli_shutdown(cli); return NT_STATUS_OK; } asprintf(err_str, "machine %s rejected the password " "change: Error was : %s.\n", remote_machine, cli_errstr(cli) ); result = cli_nt_error(cli); cli_shutdown(cli); return result; } else { asprintf(err_str, "SAMR connection to machine %s " "failed. Error was %s, but LANMAN password " "changed are disabled\n", nt_errstr(result), remote_machine); cli_shutdown(cli); return NT_STATUS_UNSUCCESSFUL; } } }
/* * Connect to a server for getting/setting attributes, possibly on an existing * connection. This works similarly to SMBC_server(). */ SMBCSRV * SMBC_attr_server(TALLOC_CTX *ctx, SMBCCTX *context, const char *server, const char *share, char **pp_workgroup, char **pp_username, char **pp_password) { int flags; struct sockaddr_storage ss; struct cli_state *ipc_cli; struct rpc_pipe_client *pipe_hnd; NTSTATUS nt_status; SMBCSRV *ipc_srv=NULL; /* * See if we've already created this special connection. Reference * our "special" share name '*IPC$', which is an impossible real share * name due to the leading asterisk. */ ipc_srv = SMBC_find_server(ctx, context, server, "*IPC$", pp_workgroup, pp_username, pp_password); if (!ipc_srv) { /* We didn't find a cached connection. Get the password */ if (!*pp_password || (*pp_password)[0] == '\0') { /* ... then retrieve it now. */ SMBC_call_auth_fn(ctx, context, server, share, pp_workgroup, pp_username, pp_password); if (!*pp_workgroup || !*pp_username || !*pp_password) { errno = ENOMEM; return NULL; } } flags = 0; if (smbc_getOptionUseKerberos(context)) { flags |= CLI_FULL_CONNECTION_USE_KERBEROS; } zero_sockaddr(&ss); nt_status = cli_full_connection(&ipc_cli, global_myname(), server, &ss, 0, "IPC$", "?????", *pp_username, *pp_workgroup, *pp_password, flags, Undefined, NULL); if (! NT_STATUS_IS_OK(nt_status)) { DEBUG(1,("cli_full_connection failed! (%s)\n", nt_errstr(nt_status))); errno = ENOTSUP; return NULL; } if (context->internal->smb_encryption_level) { /* Attempt UNIX smb encryption. */ if (!NT_STATUS_IS_OK(cli_force_encryption(ipc_cli, *pp_username, *pp_password, *pp_workgroup))) { /* * context->smb_encryption_level == * 1 means don't fail if encryption can't be * negotiated, == 2 means fail if encryption * can't be negotiated. */ DEBUG(4,(" SMB encrypt failed on IPC$\n")); if (context->internal->smb_encryption_level == 2) { cli_shutdown(ipc_cli); errno = EPERM; return NULL; } } DEBUG(4,(" SMB encrypt ok on IPC$\n")); } ipc_srv = SMB_MALLOC_P(SMBCSRV); if (!ipc_srv) { errno = ENOMEM; cli_shutdown(ipc_cli); return NULL; } ZERO_STRUCTP(ipc_srv); ipc_srv->cli = ipc_cli; nt_status = cli_rpc_pipe_open_noauth( ipc_srv->cli, &ndr_table_lsarpc.syntax_id, &pipe_hnd); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(1, ("cli_nt_session_open fail!\n")); errno = ENOTSUP; cli_shutdown(ipc_srv->cli); free(ipc_srv); return NULL; } /* * Some systems don't support * SEC_RIGHTS_MAXIMUM_ALLOWED, but NT sends 0x2000000 * so we might as well do it too. */ nt_status = rpccli_lsa_open_policy( pipe_hnd, talloc_tos(), True, GENERIC_EXECUTE_ACCESS, &ipc_srv->pol); if (!NT_STATUS_IS_OK(nt_status)) { errno = SMBC_errno(context, ipc_srv->cli); cli_shutdown(ipc_srv->cli); return NULL; } /* now add it to the cache (internal or external) */ errno = 0; /* let cache function set errno if it likes */ if (smbc_getFunctionAddCachedServer(context)(context, ipc_srv, server, "*IPC$", *pp_workgroup, *pp_username)) { DEBUG(3, (" Failed to add server to cache\n")); if (errno == 0) { errno = ENOMEM; } cli_shutdown(ipc_srv->cli); free(ipc_srv); return NULL; } DLIST_ADD(context->internal->servers, ipc_srv); } return ipc_srv; }
bool enumerate_domain_trusts( TALLOC_CTX *mem_ctx, const char *domain, char ***domain_names, uint32 *num_domains, DOM_SID **sids ) { struct policy_handle pol; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; fstring dc_name; struct sockaddr_storage dc_ss; uint32 enum_ctx = 0; struct cli_state *cli = NULL; struct rpc_pipe_client *lsa_pipe; bool retry; struct lsa_DomainList dom_list; int i; *domain_names = NULL; *num_domains = 0; *sids = NULL; /* lookup a DC first */ if ( !get_dc_name(domain, NULL, dc_name, &dc_ss) ) { DEBUG(3,("enumerate_domain_trusts: can't locate a DC for domain %s\n", domain)); return False; } /* setup the anonymous connection */ result = cli_full_connection( &cli, global_myname(), dc_name, &dc_ss, 0, "IPC$", "IPC", "", "", "", 0, Undefined, &retry); if ( !NT_STATUS_IS_OK(result) ) goto done; /* open the LSARPC_PIPE */ result = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id, &lsa_pipe); if (!NT_STATUS_IS_OK(result)) { goto done; } /* get a handle */ result = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, True, LSA_POLICY_VIEW_LOCAL_INFORMATION, &pol); if ( !NT_STATUS_IS_OK(result) ) goto done; /* Lookup list of trusted domains */ result = rpccli_lsa_EnumTrustDom(lsa_pipe, mem_ctx, &pol, &enum_ctx, &dom_list, (uint32_t)-1); if ( !NT_STATUS_IS_OK(result) ) goto done; *num_domains = dom_list.count; *domain_names = TALLOC_ZERO_ARRAY(mem_ctx, char *, *num_domains); if (!*domain_names) { result = NT_STATUS_NO_MEMORY; goto done; } *sids = TALLOC_ZERO_ARRAY(mem_ctx, DOM_SID, *num_domains); if (!*sids) { result = NT_STATUS_NO_MEMORY; goto done; } for (i=0; i< *num_domains; i++) { (*domain_names)[i] = CONST_DISCARD(char *, dom_list.domains[i].name.string); (*sids)[i] = *dom_list.domains[i].sid; } done: /* cleanup */ if (cli) { DEBUG(10,("enumerate_domain_trusts: shutting down connection...\n")); cli_shutdown( cli ); } return NT_STATUS_IS_OK(result); }
static struct con_struct *create_cs(struct net_context *c, TALLOC_CTX *ctx, NTSTATUS *perr) { NTSTATUS nt_status; struct sockaddr_storage loopback_ss; *perr = NT_STATUS_OK; if (!interpret_string_addr(&loopback_ss, "127.0.0.1", AI_NUMERICHOST)) { *perr = NT_STATUS_INVALID_PARAMETER; return NULL; } if (cs) { if (cs->failed_connect) { *perr = cs->err; return NULL; } return cs; } cs = talloc(ctx, struct con_struct); if (!cs) { *perr = NT_STATUS_NO_MEMORY; return NULL; } ZERO_STRUCTP(cs); talloc_set_destructor(cs, cs_destructor); /* Connect to localhost with given username/password. */ /* JRA. Pretty sure we can just do this anonymously.... */ #if 0 if (!opt_password && !opt_machine_pass) { char *pass = getpass("Password:"******"IPC$", "IPC", #if 0 c->opt_user_name, c->opt_workgroup, c->opt_password, #else "", c->opt_workgroup, "", #endif 0, SMB_SIGNING_DEFAULT); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(2,("create_cs: Connect failed. Error was %s\n", nt_errstr(nt_status))); cs->failed_connect = true; cs->err = nt_status; *perr = nt_status; return NULL; } nt_status = cli_rpc_pipe_open_noauth(cs->cli, &ndr_table_lsarpc.syntax_id, &cs->lsapipe); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(2,("create_cs: open LSA pipe failed. Error was %s\n", nt_errstr(nt_status))); cs->failed_connect = true; cs->err = nt_status; *perr = nt_status; return NULL; } nt_status = rpccli_lsa_open_policy(cs->lsapipe, ctx, true, SEC_FLAG_MAXIMUM_ALLOWED, &cs->pol); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(2,("create_cs: rpccli_lsa_open_policy failed. Error was %s\n", nt_errstr(nt_status))); cs->failed_connect = true; cs->err = nt_status; *perr = nt_status; return NULL; } return cs; }
NTSTATUS remote_password_change(const char *remote_machine, const char *user_name, const char *old_passwd, const char *new_passwd, char **err_str) { struct cli_state *cli = NULL; struct rpc_pipe_client *pipe_hnd = NULL; char *user, *domain, *p; NTSTATUS result; bool pass_must_change = False; user = talloc_strdup(talloc_tos(), user_name); SMB_ASSERT(user != NULL); domain = talloc_strdup(talloc_tos(), ""); SMB_ASSERT(domain != NULL); /* allow usernames of the form domain\\user or domain/user */ if ((p = strchr_m(user,'\\')) || (p = strchr_m(user,'/')) || (p = strchr_m(user,*lp_winbind_separator()))) { *p = 0; domain = user; user = p+1; } *err_str = NULL; result = cli_connect_nb(remote_machine, NULL, 0, 0x20, NULL, SMB_SIGNING_DEFAULT, 0, &cli); if (!NT_STATUS_IS_OK(result)) { if (asprintf(err_str, "Unable to connect to SMB server on " "machine %s. Error was : %s.\n", remote_machine, nt_errstr(result))==-1) { *err_str = NULL; } return result; } result = cli_negprot(cli, PROTOCOL_NT1); if (!NT_STATUS_IS_OK(result)) { if (asprintf(err_str, "machine %s rejected the negotiate " "protocol. Error was : %s.\n", remote_machine, nt_errstr(result)) == -1) { *err_str = NULL; } cli_shutdown(cli); return result; } /* Given things like SMB signing, restrict anonymous and the like, try an authenticated connection first */ result = cli_session_setup(cli, user_name, old_passwd, strlen(old_passwd)+1, old_passwd, strlen(old_passwd)+1, ""); if (!NT_STATUS_IS_OK(result)) { /* Password must change or Password expired are the only valid * error conditions here from where we can proceed, the rest like * account locked out or logon failure will lead to errors later * anyway */ if (!NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_MUST_CHANGE) && !NT_STATUS_EQUAL(result, NT_STATUS_PASSWORD_EXPIRED)) { if (asprintf(err_str, "Could not connect to machine %s: " "%s\n", remote_machine, nt_errstr(result)) == -1) { *err_str = NULL; } cli_shutdown(cli); return result; } pass_must_change = True; /* * We should connect as the anonymous user here, in case * the server has "must change password" checked... * Thanks to <*****@*****.**> for this fix. */ result = cli_session_setup(cli, "", "", 0, "", 0, ""); if (!NT_STATUS_IS_OK(result)) { if (asprintf(err_str, "machine %s rejected the session " "setup. Error was : %s.\n", remote_machine, nt_errstr(result)) == -1) { *err_str = NULL; } cli_shutdown(cli); return result; } result = cli_init_creds(cli, "", "", NULL); if (!NT_STATUS_IS_OK(result)) { cli_shutdown(cli); return result; } } else { result = cli_init_creds(cli, user, domain, old_passwd); if (!NT_STATUS_IS_OK(result)) { cli_shutdown(cli); return result; } } result = cli_tree_connect(cli, "IPC$", "IPC", "", 1); if (!NT_STATUS_IS_OK(result)) { if (asprintf(err_str, "machine %s rejected the tconX on the " "IPC$ share. Error was : %s.\n", remote_machine, nt_errstr(result))) { *err_str = NULL; } cli_shutdown(cli); return result; } /* Try not to give the password away too easily */ if (!pass_must_change) { result = cli_rpc_pipe_open_ntlmssp(cli, &ndr_table_samr.syntax_id, NCACN_NP, DCERPC_AUTH_LEVEL_PRIVACY, domain, user, old_passwd, &pipe_hnd); } else { /* * If the user password must be changed the ntlmssp bind will * fail the same way as the session setup above did. The * difference ist that with a pipe bind we don't get a good * error message, the result will be that the rpc call below * will just fail. So we do it anonymously, there's no other * way. */ result = cli_rpc_pipe_open_noauth( cli, &ndr_table_samr.syntax_id, &pipe_hnd); } if (!NT_STATUS_IS_OK(result)) { if (lp_client_lanman_auth()) { /* Use the old RAP method. */ if (!cli_oem_change_password(cli, user_name, new_passwd, old_passwd)) { result = cli_nt_error(cli); if (asprintf(err_str, "machine %s rejected the " "password change: Error was : %s.\n", remote_machine, nt_errstr(result)) == -1) { *err_str = NULL; } cli_shutdown(cli); return result; } } else { if (asprintf(err_str, "SAMR connection to machine %s " "failed. Error was %s, but LANMAN password " "changes are disabled\n", remote_machine, nt_errstr(result)) == -1) { *err_str = NULL; } cli_shutdown(cli); return result; } } result = rpccli_samr_chgpasswd_user2(pipe_hnd, talloc_tos(), user_name, new_passwd, old_passwd); if (NT_STATUS_IS_OK(result)) { /* Great - it all worked! */ cli_shutdown(cli); return NT_STATUS_OK; } else if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) { /* it failed, but for reasons such as wrong password, too short etc ... */ if (asprintf(err_str, "machine %s rejected the password change: " "Error was : %s.\n", remote_machine, get_friendly_nt_error_msg(result)) == -1) { *err_str = NULL; } cli_shutdown(cli); return result; } /* OK, that failed, so try again... */ TALLOC_FREE(pipe_hnd); /* Try anonymous NTLMSSP... */ result = cli_init_creds(cli, "", "", NULL); if (!NT_STATUS_IS_OK(result)) { cli_shutdown(cli); return result; } result = NT_STATUS_UNSUCCESSFUL; /* OK, this is ugly, but... try an anonymous pipe. */ result = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id, &pipe_hnd); if ( NT_STATUS_IS_OK(result) && (NT_STATUS_IS_OK(result = rpccli_samr_chgpasswd_user2( pipe_hnd, talloc_tos(), user_name, new_passwd, old_passwd)))) { /* Great - it all worked! */ cli_shutdown(cli); return NT_STATUS_OK; } else { if (!(NT_STATUS_EQUAL(result, NT_STATUS_ACCESS_DENIED) || NT_STATUS_EQUAL(result, NT_STATUS_UNSUCCESSFUL))) { /* it failed, but again it was due to things like new password too short */ if (asprintf(err_str, "machine %s rejected the " "(anonymous) password change: Error was : " "%s.\n", remote_machine, get_friendly_nt_error_msg(result)) == -1) { *err_str = NULL; } cli_shutdown(cli); return result; } /* We have failed to change the user's password, and we think the server just might not support SAMR password changes, so fall back */ if (lp_client_lanman_auth()) { /* Use the old RAP method. */ if (cli_oem_change_password(cli, user_name, new_passwd, old_passwd)) { /* SAMR failed, but the old LanMan protocol worked! */ cli_shutdown(cli); return NT_STATUS_OK; } result = cli_nt_error(cli); if (asprintf(err_str, "machine %s rejected the password " "change: Error was : %s.\n", remote_machine, nt_errstr(result)) == -1) { *err_str = NULL; } cli_shutdown(cli); return result; } else { if (asprintf(err_str, "SAMR connection to machine %s " "failed. Error was %s, but LANMAN password " "changes are disabled\n", nt_errstr(result), remote_machine) == -1) { *err_str = NULL; } cli_shutdown(cli); return NT_STATUS_UNSUCCESSFUL; } } }
static bool enumerate_domain_trusts( TALLOC_CTX *mem_ctx, const char *domain, char ***domain_names, uint32 *num_domains, struct dom_sid **sids ) { struct policy_handle pol; NTSTATUS status, result; fstring dc_name; struct sockaddr_storage dc_ss; uint32 enum_ctx = 0; struct cli_state *cli = NULL; struct rpc_pipe_client *lsa_pipe = NULL; struct lsa_DomainList dom_list; int i; struct dcerpc_binding_handle *b = NULL; *domain_names = NULL; *num_domains = 0; *sids = NULL; /* lookup a DC first */ if ( !get_dc_name(domain, NULL, dc_name, &dc_ss) ) { DEBUG(3,("enumerate_domain_trusts: can't locate a DC for domain %s\n", domain)); return False; } /* setup the anonymous connection */ status = cli_full_connection( &cli, lp_netbios_name(), dc_name, &dc_ss, 0, "IPC$", "IPC", "", "", "", 0, Undefined); if ( !NT_STATUS_IS_OK(status) ) goto done; /* open the LSARPC_PIPE */ status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id, &lsa_pipe); if (!NT_STATUS_IS_OK(status)) { goto done; } b = lsa_pipe->binding_handle; /* get a handle */ status = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, True, LSA_POLICY_VIEW_LOCAL_INFORMATION, &pol); if ( !NT_STATUS_IS_OK(status) ) goto done; /* Lookup list of trusted domains */ status = dcerpc_lsa_EnumTrustDom(b, mem_ctx, &pol, &enum_ctx, &dom_list, (uint32_t)-1, &result); if ( !NT_STATUS_IS_OK(status) ) goto done; if (!NT_STATUS_IS_OK(result)) { status = result; goto done; } *num_domains = dom_list.count; *domain_names = talloc_zero_array(mem_ctx, char *, *num_domains); if (!*domain_names) { status = NT_STATUS_NO_MEMORY; goto done; } *sids = talloc_zero_array(mem_ctx, struct dom_sid, *num_domains); if (!*sids) { status = NT_STATUS_NO_MEMORY; goto done; } for (i=0; i< *num_domains; i++) { (*domain_names)[i] = discard_const_p(char, dom_list.domains[i].name.string); (*sids)[i] = *dom_list.domains[i].sid; } done: /* cleanup */ if (cli) { DEBUG(10,("enumerate_domain_trusts: shutting down connection...\n")); cli_shutdown( cli ); } return NT_STATUS_IS_OK(status); }
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; uint32 acct_flags=0; uint32 fields_present; uchar pwbuf[532]; SAM_USERINFO_CTR ctr; SAM_USER_INFO_25 p25; const int infolevel = 25; struct MD5Context md5ctx; uchar md5buffer[16]; DATA_BLOB digested_session_key; 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 */ acct_flags = SAMR_GENERIC_READ | SAMR_GENERIC_WRITE | SAMR_GENERIC_EXECUTE | SAMR_STANDARD_WRITEDAC | SAMR_STANDARD_DELETE | SAMR_USER_SETPASS | SAMR_USER_GETATTR | SAMR_USER_SETATTR; DEBUG(10, ("Creating account with flags: %d\n",acct_flags)); status = rpccli_samr_create_dom_user(pipe_hnd, mem_ctx, &domain_pol, acct_name, acb_info, acct_flags, &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); if (!NT_STATUS_IS_OK(status)) { return status; } /* Create a random machine account password and generate the hash */ E_md4hash(clear_pw, md4_trust_password); encode_pw_buffer(pwbuf, clear_pw, STR_UNICODE); generate_random_buffer((uint8*)md5buffer, sizeof(md5buffer)); digested_session_key = data_blob_talloc(mem_ctx, 0, 16); MD5Init(&md5ctx); MD5Update(&md5ctx, md5buffer, sizeof(md5buffer)); MD5Update(&md5ctx, cli->user_session_key.data, cli->user_session_key.length); MD5Final(digested_session_key.data, &md5ctx); SamOEMhashBlob(pwbuf, sizeof(pwbuf), &digested_session_key); memcpy(&pwbuf[516], md5buffer, sizeof(md5buffer)); /* 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 ;; } /* Set password and account flags on machine account */ ZERO_STRUCT(ctr); ZERO_STRUCT(p25); fields_present = ACCT_NT_PWD_SET | ACCT_LM_PWD_SET | ACCT_FLAGS; init_sam_user_info25P(&p25, fields_present, acb_info, (char *)pwbuf); ctr.switch_value = infolevel; ctr.info.id25 = &p25; status = rpccli_samr_set_userinfo2(pipe_hnd, mem_ctx, &user_pol, infolevel, &cli->user_session_key, &ctr); if ( !NT_STATUS_IS_OK(status) ) { d_fprintf( stderr, "Failed to set password for machine account (%s)\n", nt_errstr(status)); return status; } rpccli_samr_close(pipe_hnd, mem_ctx, &user_pol); cli_rpc_pipe_close(pipe_hnd); /* Done with this pipe */ return status; }
BOOL enumerate_domain_trusts( TALLOC_CTX *mem_ctx, const char *domain, char ***domain_names, uint32 *num_domains, DOM_SID **sids ) { POLICY_HND pol; NTSTATUS result = NT_STATUS_UNSUCCESSFUL; fstring dc_name; struct in_addr dc_ip; uint32 enum_ctx = 0; struct cli_state *cli = NULL; struct rpc_pipe_client *lsa_pipe; BOOL retry; *domain_names = NULL; *num_domains = 0; *sids = NULL; /* lookup a DC first */ if ( !get_dc_name(domain, NULL, dc_name, &dc_ip) ) { DEBUG(3,("enumerate_domain_trusts: can't locate a DC for domain %s\n", domain)); return False; } /* setup the anonymous connection */ result = cli_full_connection( &cli, global_myname(), dc_name, &dc_ip, 0, "IPC$", "IPC", "", "", "", 0, Undefined, &retry); if ( !NT_STATUS_IS_OK(result) ) goto done; /* open the LSARPC_PIPE */ lsa_pipe = cli_rpc_pipe_open_noauth( cli, PI_LSARPC, &result ); if ( !lsa_pipe) { goto done; } /* get a handle */ result = rpccli_lsa_open_policy(lsa_pipe, mem_ctx, True, POLICY_VIEW_LOCAL_INFORMATION, &pol); if ( !NT_STATUS_IS_OK(result) ) goto done; /* Lookup list of trusted domains */ result = rpccli_lsa_enum_trust_dom(lsa_pipe, mem_ctx, &pol, &enum_ctx, num_domains, domain_names, sids); if ( !NT_STATUS_IS_OK(result) ) goto done; done: /* cleanup */ if (cli) { DEBUG(10,("enumerate_domain_trusts: shutting down connection...\n")); cli_shutdown( cli ); } return NT_STATUS_IS_OK(result); }
int net_rpc_join_newstyle(struct net_context *c, int argc, const char **argv) { /* libsmb variables */ struct cli_state *cli; TALLOC_CTX *mem_ctx; uint32 acb_info = ACB_WSTRUST; uint32_t neg_flags = NETLOGON_NEG_AUTH2_ADS_FLAGS; enum netr_SchannelType sec_channel_type; struct rpc_pipe_client *pipe_hnd = NULL; struct dcerpc_binding_handle *b = NULL; /* rpc variables */ struct policy_handle lsa_pol, sam_pol, domain_pol, user_pol; struct dom_sid *domain_sid; uint32 user_rid; /* Password stuff */ char *clear_trust_password = NULL; struct samr_CryptPassword crypt_pwd; uchar md4_trust_password[16]; union samr_UserInfo set_info; /* Misc */ NTSTATUS status, result; int retval = 1; const char *domain = NULL; char *acct_name; struct lsa_String lsa_acct_name; uint32 acct_flags=0; uint32_t access_granted = 0; union lsa_PolicyInformation *info = NULL; struct samr_Ids user_rids; struct samr_Ids name_types; /* check what type of join */ if (argc >= 0) { sec_channel_type = get_sec_channel_type(argv[0]); } else { sec_channel_type = get_sec_channel_type(NULL); } switch (sec_channel_type) { case SEC_CHAN_WKSTA: acb_info = ACB_WSTRUST; break; case SEC_CHAN_BDC: acb_info = ACB_SVRTRUST; break; #if 0 case SEC_CHAN_DOMAIN: acb_info = ACB_DOMTRUST; break; #endif default: DEBUG(0,("secure channel type %d not yet supported\n", sec_channel_type)); break; } /* Make authenticated connection to remote machine */ status = net_make_ipc_connection(c, NET_FLAGS_PDC, &cli); if (!NT_STATUS_IS_OK(status)) { return 1; } if (!(mem_ctx = talloc_init("net_rpc_join_newstyle"))) { DEBUG(0, ("Could not initialise talloc context\n")); goto done; } /* Fetch domain sid */ status = cli_rpc_pipe_open_noauth(cli, &ndr_table_lsarpc.syntax_id, &pipe_hnd); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Error connecting to LSA pipe. Error was %s\n", nt_errstr(status) )); goto done; } b = pipe_hnd->binding_handle; CHECK_RPC_ERR(rpccli_lsa_open_policy(pipe_hnd, mem_ctx, true, SEC_FLAG_MAXIMUM_ALLOWED, &lsa_pol), "error opening lsa policy handle"); CHECK_DCERPC_ERR(dcerpc_lsa_QueryInfoPolicy(b, mem_ctx, &lsa_pol, LSA_POLICY_INFO_ACCOUNT_DOMAIN, &info, &result), "error querying info policy"); domain = info->account_domain.name.string; domain_sid = info->account_domain.sid; dcerpc_lsa_Close(b, mem_ctx, &lsa_pol, &result); TALLOC_FREE(pipe_hnd); /* Done with this pipe */ /* Bail out if domain didn't get set. */ if (!domain) { DEBUG(0, ("Could not get domain name.\n")); goto done; } /* Create domain user */ status = cli_rpc_pipe_open_noauth(cli, &ndr_table_samr.syntax_id, &pipe_hnd); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Error connecting to SAM pipe. Error was %s\n", nt_errstr(status) )); goto done; } b = pipe_hnd->binding_handle; CHECK_DCERPC_ERR(dcerpc_samr_Connect2(b, mem_ctx, pipe_hnd->desthost, SAMR_ACCESS_ENUM_DOMAINS | SAMR_ACCESS_LOOKUP_DOMAIN, &sam_pol, &result), "could not connect to SAM database"); CHECK_DCERPC_ERR(dcerpc_samr_OpenDomain(b, mem_ctx, &sam_pol, SAMR_DOMAIN_ACCESS_LOOKUP_INFO_1 | SAMR_DOMAIN_ACCESS_CREATE_USER | SAMR_DOMAIN_ACCESS_OPEN_ACCOUNT, domain_sid, &domain_pol, &result), "could not open domain"); /* Create domain user */ if ((acct_name = talloc_asprintf(mem_ctx, "%s$", global_myname())) == NULL) { status = NT_STATUS_NO_MEMORY; goto done; } strlower_m(acct_name); init_lsa_String(&lsa_acct_name, acct_name); acct_flags = SEC_GENERIC_READ | SEC_GENERIC_WRITE | SEC_GENERIC_EXECUTE | SEC_STD_WRITE_DAC | SEC_STD_DELETE | SAMR_USER_ACCESS_SET_PASSWORD | SAMR_USER_ACCESS_GET_ATTRIBUTES | SAMR_USER_ACCESS_SET_ATTRIBUTES; DEBUG(10, ("Creating account with flags: %d\n",acct_flags)); status = dcerpc_samr_CreateUser2(b, mem_ctx, &domain_pol, &lsa_acct_name, acb_info, acct_flags, &user_pol, &access_granted, &user_rid, &result); if (!NT_STATUS_IS_OK(status)) { goto done; } if (!NT_STATUS_IS_OK(result) && !NT_STATUS_EQUAL(result, NT_STATUS_USER_EXISTS)) { status = result; 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(result) == NT_STATUS_V(NT_STATUS_ACCESS_DENIED)) d_fprintf(stderr, _("User specified does not have " "administrator privileges\n")); goto done; } /* We *must* do this.... don't ask... */ if (NT_STATUS_IS_OK(result)) { dcerpc_samr_Close(b, mem_ctx, &user_pol, &result); } CHECK_DCERPC_ERR_DEBUG(dcerpc_samr_LookupNames(b, mem_ctx, &domain_pol, 1, &lsa_acct_name, &user_rids, &name_types, &result), ("error looking up rid for user %s: %s/%s\n", acct_name, nt_errstr(status), nt_errstr(result))); if (user_rids.count != 1) { status = NT_STATUS_INVALID_NETWORK_RESPONSE; goto done; } if (name_types.count != 1) { status = NT_STATUS_INVALID_NETWORK_RESPONSE; goto done; } if (name_types.ids[0] != SID_NAME_USER) { DEBUG(0, ("%s is not a user account (type=%d)\n", acct_name, name_types.ids[0])); goto done; } user_rid = user_rids.ids[0]; /* Open handle on user */ CHECK_DCERPC_ERR_DEBUG( dcerpc_samr_OpenUser(b, mem_ctx, &domain_pol, SEC_FLAG_MAXIMUM_ALLOWED, user_rid, &user_pol, &result), ("could not re-open existing user %s: %s/%s\n", acct_name, nt_errstr(status), nt_errstr(result))); /* Create a random machine account password */ clear_trust_password = generate_random_str(talloc_tos(), DEFAULT_TRUST_ACCOUNT_PASSWORD_LENGTH); E_md4hash(clear_trust_password, md4_trust_password); /* Set password on machine account */ init_samr_CryptPassword(clear_trust_password, &cli->user_session_key, &crypt_pwd); set_info.info24.password = crypt_pwd; set_info.info24.password_expired = PASS_DONT_CHANGE_AT_NEXT_LOGON; CHECK_DCERPC_ERR(dcerpc_samr_SetUserInfo2(b, mem_ctx, &user_pol, 24, &set_info, &result), "error setting trust account password"); /* 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 */ set_info.info16.acct_flags = acb_info; /* Ignoring the return value is necessary for joining a domain as a normal user with "Add workstation to domain" privilege. */ status = dcerpc_samr_SetUserInfo(b, mem_ctx, &user_pol, 16, &set_info, &result); dcerpc_samr_Close(b, mem_ctx, &user_pol, &result); TALLOC_FREE(pipe_hnd); /* Done with this pipe */ /* Now check the whole process from top-to-bottom */ status = cli_rpc_pipe_open_noauth(cli, &ndr_table_netlogon.syntax_id, &pipe_hnd); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Error connecting to NETLOGON pipe. Error was %s\n", nt_errstr(status) )); goto done; } status = rpccli_netlogon_setup_creds(pipe_hnd, cli->desthost, /* server name */ domain, /* domain */ global_myname(), /* client name */ global_myname(), /* machine account name */ md4_trust_password, sec_channel_type, &neg_flags); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Error in domain join verification (credential setup failed): %s\n\n", nt_errstr(status))); if ( NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) && (sec_channel_type == SEC_CHAN_BDC) ) { d_fprintf(stderr, _("Please make sure that no computer " "account\nnamed like this machine " "(%s) exists in the domain\n"), global_myname()); } goto done; } /* We can only check the schannel connection if the client is allowed to do this and the server supports it. If not, just assume success (after all the rpccli_netlogon_setup_creds() succeeded, and we'll do the same again (setup creds) in net_rpc_join_ok(). JRA. */ if (lp_client_schannel() && (neg_flags & NETLOGON_NEG_SCHANNEL)) { struct rpc_pipe_client *netlogon_schannel_pipe; status = cli_rpc_pipe_open_schannel_with_key( cli, &ndr_table_netlogon.syntax_id, NCACN_NP, DCERPC_AUTH_LEVEL_PRIVACY, domain, &pipe_hnd->dc, &netlogon_schannel_pipe); if (!NT_STATUS_IS_OK(status)) { DEBUG(0, ("Error in domain join verification (schannel setup failed): %s\n\n", nt_errstr(status))); if ( NT_STATUS_EQUAL(status, NT_STATUS_ACCESS_DENIED) && (sec_channel_type == SEC_CHAN_BDC) ) { d_fprintf(stderr, _("Please make sure that no " "computer account\nnamed " "like this machine (%s) " "exists in the domain\n"), global_myname()); } goto done; } TALLOC_FREE(netlogon_schannel_pipe); } TALLOC_FREE(pipe_hnd); /* Now store the secret in the secrets database */ strupper_m(CONST_DISCARD(char *, domain)); if (!secrets_store_domain_sid(domain, domain_sid)) { DEBUG(0, ("error storing domain sid for %s\n", domain)); goto done; } if (!secrets_store_machine_password(clear_trust_password, domain, sec_channel_type)) { DEBUG(0, ("error storing plaintext domain secrets for %s\n", domain)); } /* double-check, connection from scratch */ status = net_rpc_join_ok(c, domain, cli->desthost, &cli->dest_ss); retval = NT_STATUS_IS_OK(status) ? 0 : -1; done: /* Display success or failure */ if (domain) { if (retval != 0) { fprintf(stderr,_("Unable to join domain %s.\n"),domain); } else { printf(_("Joined domain %s.\n"),domain); } } cli_shutdown(cli); TALLOC_FREE(clear_trust_password); return retval; }
NTSTATUS change_trust_account_password( const char *domain, const char *remote_machine) { NTSTATUS nt_status = NT_STATUS_UNSUCCESSFUL; struct sockaddr_storage pdc_ss; fstring dc_name; struct cli_state *cli = NULL; struct rpc_pipe_client *netlogon_pipe = NULL; DEBUG(5,("change_trust_account_password: Attempting to change trust account password in domain %s....\n", domain)); if (remote_machine == NULL || !strcmp(remote_machine, "*")) { /* Use the PDC *only* for this */ if ( !get_pdc_ip(domain, &pdc_ss) ) { DEBUG(0,("Can't get IP for PDC for domain %s\n", domain)); goto failed; } if ( !name_status_find( domain, 0x1b, 0x20, &pdc_ss, dc_name) ) goto failed; } else { /* supoport old deprecated "smbpasswd -j DOMAIN -r MACHINE" behavior */ fstrcpy( dc_name, remote_machine ); } /* if this next call fails, then give up. We can't do password changes on BDC's --jerry */ if (!NT_STATUS_IS_OK(cli_full_connection(&cli, global_myname(), dc_name, NULL, 0, "IPC$", "IPC", "", "", "", 0, Undefined, NULL))) { DEBUG(0,("modify_trust_password: Connection to %s failed!\n", dc_name)); nt_status = NT_STATUS_UNSUCCESSFUL; goto failed; } /* * Ok - we have an anonymous connection to the IPC$ share. * Now start the NT Domain stuff :-). */ /* Shouldn't we open this with schannel ? JRA. */ nt_status = cli_rpc_pipe_open_noauth( cli, &ndr_table_netlogon.syntax_id, &netlogon_pipe); if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0,("modify_trust_password: unable to open the domain client session to machine %s. Error was : %s.\n", dc_name, nt_errstr(nt_status))); cli_shutdown(cli); cli = NULL; goto failed; } nt_status = trust_pw_find_change_and_store_it( netlogon_pipe, netlogon_pipe, domain); cli_shutdown(cli); cli = NULL; failed: if (!NT_STATUS_IS_OK(nt_status)) { DEBUG(0,("%s : change_trust_account_password: Failed to change password for domain %s.\n", current_timestring(talloc_tos(), False), domain)); } else DEBUG(5,("change_trust_account_password: sucess!\n")); return nt_status; }