r4702: implment idl, torture test and server code for netr_ServerPasswordSet2()
authorStefan Metzmacher <metze@samba.org>
Wed, 12 Jan 2005 07:22:34 +0000 (07:22 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:08:45 +0000 (13:08 -0500)
metze
(This used to be commit 7d8ba92da2b8babe7165f105591fd3e5738b2319)

source4/librpc/idl/netlogon.idl
source4/librpc/idl/samr.idl
source4/rpc_server/netlogon/dcerpc_netlogon.c
source4/torture/rpc/netlogon.c

index 3b4f299d7cb3402987f7a76f37feaee72f5a711a..82519699827915cc20d31a120cd1fe66e98baa69 100644 (file)
@@ -1004,9 +1004,17 @@ interface netlogon
                [out,switch_is(level)] netr_DomainInfo info
                );
 
-       /****************/
+       /*****************/
        /* Function 0x1e */
-       WERROR netr_NETRSERVERPASSWORDSET2();
+       NTSTATUS netr_ServerPasswordSet2(
+               [in]  unistr *server_name,
+               [in]  unistr account_name,
+               [in]  netr_SchannelType secure_channel_type,
+               [in]  unistr computer_name,
+               [in]  netr_Authenticator credential,
+               [in]  samr_CryptPassword new_password,
+               [out] netr_Authenticator return_authenticator
+               );
 
        /****************/
        /* Function 0x1f */
index 56387936c7a91b066c2784cd37d689122acd5973..84aaa2a10aeee7983877b5eda3268e195f3c8b92 100644 (file)
                uint8  unknown4;
        } samr_UserInfo21;
 
-       typedef [flag(NDR_PAHEX)] struct {
+       typedef [public, flag(NDR_PAHEX)] struct {
                uint8 data[516];
        } samr_CryptPassword;
 
index 731905e2a60c96ca29c61929fa5fac40e7af2f8f..9eed9eb1f345e94bc28b2148309ac57d8506e768 100644 (file)
@@ -364,7 +364,7 @@ static NTSTATUS netr_ServerPasswordSet(struct dcesrv_call_state *dce_call, TALLO
        }
 
        if (num_records_domain == 0) {
-               DEBUG(3,("check_sam_security: Couldn't find domain [%s] in passdb file.\n", 
+               DEBUG(3,("Couldn't find domain [%s] in samdb.\n", 
                         domain_sid));
                return NT_STATUS_NO_SUCH_USER;
        }
@@ -1000,12 +1000,115 @@ static NTSTATUS netr_LogonGetDomainInfo(struct dcesrv_call_state *dce_call, TALL
 
 
 /* 
-  netr_NETRSERVERPASSWORDSET
+  netr_ServerPasswordSet
 */
-static WERROR netr_NETRSERVERPASSWORDSET2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct netr_NETRSERVERPASSWORDSET2 *r)
+static NTSTATUS netr_ServerPasswordSet2(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                                      struct netr_ServerPasswordSet2 *r)
 {
-       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+       struct server_pipe_state *pipe_state = dce_call->context->private;
+
+       void *sam_ctx;
+       int num_records;
+       int num_records_domain;
+       int ret;
+       struct ldb_message **msgs;
+       struct ldb_message **msgs_domain;
+       NTSTATUS nt_status;
+       struct ldb_message *mod;
+       const char *domain_sid;
+       char new_pass[512];
+       uint32_t new_pass_len;
+
+       const char *attrs[] = {"objectSid", NULL };
+
+       const char **domain_attrs = attrs;
+
+       nt_status = netr_creds_server_step_check(pipe_state, &r->in.credential, &r->out.return_authenticator);
+       NT_STATUS_NOT_OK_RETURN(nt_status);
+
+       sam_ctx = samdb_connect(mem_ctx);
+       if (sam_ctx == NULL) {
+               return NT_STATUS_INVALID_SYSTEM_SERVICE;
+       }
+       /* pull the user attributes */
+       num_records = samdb_search(sam_ctx, mem_ctx, NULL, &msgs, attrs,
+                                  "(&(sAMAccountName=%s)(objectclass=user))", 
+                                  pipe_state->creds->account_name);
+       if (num_records == -1) {
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+
+       if (num_records == 0) {
+               DEBUG(3,("Couldn't find user [%s] in samdb.\n", 
+                        pipe_state->creds->account_name));
+               return NT_STATUS_NO_SUCH_USER;
+       }
+
+       if (num_records > 1) {
+               DEBUG(0,("Found %d records matching user [%s]\n", num_records, 
+                        pipe_state->creds->account_name));
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+
+       domain_sid = samdb_result_sid_prefix(mem_ctx, msgs[0], "objectSid");
+       if (!domain_sid) {
+               DEBUG(0,("no objectSid in user record\n"));
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+
+       /* find the domain's DN */
+       num_records_domain = samdb_search(sam_ctx, mem_ctx, NULL, 
+                                         &msgs_domain, domain_attrs,
+                                         "(&(objectSid=%s)(objectclass=domain))", 
+                                         domain_sid);
+       if (num_records_domain == -1) {
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+
+       if (num_records_domain == 0) {
+               DEBUG(3,("Couldn't find domain [%s] in samdb.\n", 
+                        domain_sid));
+               return NT_STATUS_NO_SUCH_USER;
+       }
+
+       if (num_records_domain > 1) {
+               DEBUG(0,("Found %d records matching domain [%s]\n", 
+                        num_records_domain, domain_sid));
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+
+       mod = talloc_zero(mem_ctx, struct ldb_message);
+       NT_STATUS_HAVE_NO_MEMORY(mod);
+       mod->dn = talloc_reference(mod, msgs[0]->dn);
+    
+       creds_arcfour_crypt(pipe_state->creds, r->in.new_password.data, 516);
+
+       ret = decode_pw_buffer(r->in.new_password.data, new_pass, sizeof(new_pass),
+                             &new_pass_len, STR_UNICODE);
+       if (!ret) {
+               DEBUG(3,("netr_ServerPasswordSet2: failed to decode password buffer\n"));
+               return NT_STATUS_ACCESS_DENIED;
+       }
+
+       /* set the password - samdb needs to know both the domain and user DNs,
+          so the domain password policy can be used */
+       nt_status = samdb_set_password(sam_ctx, mod,
+                                      msgs[0]->dn,
+                                      msgs_domain[0]->dn,
+                                      mod, new_pass, /* we have plaintext */
+                                      NULL, NULL,
+                                      False /* This is not considered a password change */,
+                                      NULL);
+       ZERO_ARRAY(new_pass);
+       NT_STATUS_NOT_OK_RETURN(nt_status);
+
+       ret = samdb_replace(sam_ctx, mem_ctx, mod);
+       if (ret != 0) {
+               /* we really need samdb.c to return NTSTATUS */
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       return NT_STATUS_OK;
 }
 
 
index 67e0bc9393e5336983306c6e617f9bb3b78ede58..00a12b361bb1fec15b2da0741c4be2c2c2937889 100644 (file)
@@ -317,6 +317,74 @@ static BOOL test_SetPassword(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
        return True;
 }
 
+/*
+  try a change password for our machine account
+*/
+static BOOL test_SetPassword2(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
+{
+       NTSTATUS status;
+       struct netr_ServerPasswordSet2 r;
+       const char *password;
+       struct creds_CredentialState creds;
+
+       if (!test_SetupCredentials(p, mem_ctx, TEST_MACHINE_NAME,
+                                  machine_password, &creds)) {
+               return False;
+       }
+
+       r.in.server_name = talloc_asprintf(mem_ctx, "\\\\%s", dcerpc_server_name(p));
+       r.in.account_name = talloc_asprintf(mem_ctx, "%s$", TEST_MACHINE_NAME);
+       r.in.secure_channel_type = SEC_CHAN_BDC;
+       r.in.computer_name = TEST_MACHINE_NAME;
+
+       password = generate_random_str(mem_ctx, 8);
+       encode_pw_buffer(r.in.new_password.data, password, STR_UNICODE);
+       creds_arcfour_crypt(&creds, r.in.new_password.data, 516);
+
+       printf("Testing ServerPasswordSet2 on machine account\n");
+       printf("Changing machine account password to '%s'\n", password);
+
+       creds_client_authenticator(&creds, &r.in.credential);
+
+       status = dcerpc_netr_ServerPasswordSet2(p, mem_ctx, &r);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("ServerPasswordSet2 - %s\n", nt_errstr(status));
+               return False;
+       }
+
+       if (!creds_client_check(&creds, &r.out.return_authenticator.cred)) {
+               printf("Credential chaining failed\n");
+       }
+
+       /* by changing the machine password twice we test the
+          credentials chaining fully, and we verify that the server
+          allows the password to be set to the same value twice in a
+          row (match win2k3) */
+       printf("Testing a second ServerPasswordSet2 on machine account\n");
+       printf("Changing machine account password to '%s' (same as previous run)\n", password);
+
+       creds_client_authenticator(&creds, &r.in.credential);
+
+       status = dcerpc_netr_ServerPasswordSet2(p, mem_ctx, &r);
+       if (!NT_STATUS_IS_OK(status)) {
+               printf("ServerPasswordSet (2) - %s\n", nt_errstr(status));
+               return False;
+       }
+
+       if (!creds_client_check(&creds, &r.out.return_authenticator.cred)) {
+               printf("Credential chaining failed\n");
+       }
+
+       machine_password = password;
+
+       if (!test_SetupCredentials(p, mem_ctx, TEST_MACHINE_NAME, machine_password, &creds)) {
+               printf("ServerPasswordSet failed to actually change the password\n");
+               return False;
+       }
+
+       return True;
+}
+
 /*
   try a netlogon SamLogon
 */
@@ -398,8 +466,6 @@ static BOOL test_SamLogon(struct dcerpc_pipe *p, TALLOC_CTX *mem_ctx)
        return ret;
 }
 
-
-
 /* we remember the sequence numbers so we can easily do a DatabaseDelta */
 static uint64_t sequence_nums[3];
 
@@ -1216,6 +1282,7 @@ BOOL torture_rpc_netlogon(void)
        ret &= test_LogonUasLogoff(p, mem_ctx);
        ret &= test_SamLogon(p, mem_ctx);
        ret &= test_SetPassword(p, mem_ctx);
+       ret &= test_SetPassword2(p, mem_ctx);
        ret &= test_GetDomainInfo(p, mem_ctx);
        ret &= test_DatabaseSync(p, mem_ctx);
        ret &= test_DatabaseDeltas(p, mem_ctx);