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; }
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; }
void cli_nt_pipes_close(struct cli_state *cli) { struct rpc_pipe_client *cp, *next; for (cp = cli->pipe_list; cp; cp = next) { next = cp->next; cli_rpc_pipe_close(cp); } }
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 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; }
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; } } }