r4682: A LDB-based secrets implementation in Samba4.
authorAndrew Bartlett <abartlet@samba.org>
Tue, 11 Jan 2005 14:04:58 +0000 (14:04 +0000)
committerGerald (Jerry) Carter <jerry@samba.org>
Wed, 10 Oct 2007 18:08:42 +0000 (13:08 -0500)
This uses LDB (a local secrets.ldb and the global samdb) to fill out
the secrets from an LSA perspective.

Some small changes to come, but the bulk of the work is now done.

A re-provision is required after this change.

Andrew Bartlett
(This used to be commit ded33033521a6a1c7ea80758c5c5aeeebb182a51)

source4/lib/util.c
source4/libcli/auth/session.c
source4/librpc/idl/lsa.idl
source4/passdb/secrets.c
source4/provision.ldif
source4/rpc_server/lsa/dcesrv_lsa.c
source4/script/provision.pl
source4/secrets.ldif [new file with mode: 0644]
source4/torture/rpc/lsa.c
source4/torture/rpc/samsync.c

index ac5124840e8c7cc5f0c952c1690a3b7753869dea..9341a011af36ead28a2ed6555b47485bc0e14cf5 100644 (file)
@@ -712,6 +712,21 @@ char *lib_path(TALLOC_CTX* mem_ctx, const char *name)
        return fname;
 }
 
+/**
+ * @brief Returns an absolute path to a file in the Samba private directory.
+ *
+ * @param name File to find, relative to PRIVATEDIR.
+ *
+ * @retval Pointer to a talloc'ed string containing the full path.
+ **/
+
+char *private_path(TALLOC_CTX* mem_ctx, const char *name)
+{
+       char *fname;
+       fname = talloc_asprintf(mem_ctx, "%s/%s", lp_private_dir(), name);
+       return fname;
+}
+
 /*
   return a path in the smbd.tmp directory, where all temporary file
   for smbd go. If NULL is passed for name then return the directory 
index 91eee9ce81860d5415772edc224e8ac76265bc95..9b4132a4905db5edc498787f8dfa4ab91cb22653 100644 (file)
@@ -113,18 +113,18 @@ char *sess_decrypt_string(DATA_BLOB *blob, const DATA_BLOB *session_key)
 
        sess_crypt_blob(&out, blob, session_key, False);
 
-       slen = IVAL(out.data, 0);
-       if (slen > blob->length - 8) {
-               DEBUG(0,("Invalid crypt length %d\n", slen));
-               return NULL;
-       }
-
        if (IVAL(out.data, 4) != 1) {
                DEBUG(0,("Unexpected revision number %d in session crypted string\n",
                         IVAL(out.data, 4)));
                return NULL;
        }
 
+       slen = IVAL(out.data, 0);
+       if (slen > blob->length - 8) {
+               DEBUG(0,("Invalid crypt length %d\n", slen));
+               return NULL;
+       }
+
        ret = strndup((const char *)(out.data+8), slen);
 
        data_blob_free(&out);
@@ -169,42 +169,43 @@ DATA_BLOB sess_encrypt_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob_in, const DATA_
 }
 
 /*
-  a convenient wrapper around sess_crypt_blob() for strings, using the LSA convention
-
-  caller should free the returned string
+  Decrypt a DATA_BLOB using the LSA convention
 */
-DATA_BLOB sess_decrypt_blob(TALLOC_CTX *mem_ctx, DATA_BLOB *blob, const DATA_BLOB *session_key)
+NTSTATUS sess_decrypt_blob(TALLOC_CTX *mem_ctx, const DATA_BLOB *blob, const DATA_BLOB *session_key, 
+                          DATA_BLOB *ret)
 {
        DATA_BLOB out;
        int slen;
-       DATA_BLOB ret;
 
        if (blob->length < 8) {
-               return data_blob(NULL, 0);
+               return NT_STATUS_INVALID_PARAMETER;
        }
        
        out = data_blob_talloc(mem_ctx, NULL, blob->length);
        if (!out.data) {
-               return data_blob(NULL, 0);
+               return NT_STATUS_NO_MEMORY;
        }
 
        sess_crypt_blob(&out, blob, session_key, False);
 
+       if (IVAL(out.data, 4) != 1) {
+               DEBUG(0,("Unexpected revision number %d in session crypted string\n",
+                        IVAL(out.data, 4)));
+               return NT_STATUS_UNKNOWN_REVISION;
+       }
+               
        slen = IVAL(out.data, 0);
        if (slen > blob->length - 8) {
                DEBUG(0,("Invalid crypt length %d\n", slen));
-               return data_blob(NULL, 0);
+               return NT_STATUS_WRONG_PASSWORD;
        }
 
-       if (IVAL(out.data, 4) != 1) {
-               DEBUG(0,("Unexpected revision number %d in session crypted string\n",
-                        IVAL(out.data, 4)));
-               return data_blob(NULL, 0);
+       *ret = data_blob_talloc(mem_ctx, out.data+8, slen);
+       if (!ret->data) {
+               return NT_STATUS_NO_MEMORY;
        }
-               
-       ret = data_blob_talloc(mem_ctx, out.data+8, slen);
 
        data_blob_free(&out);
 
-       return ret;
+       return NT_STATUS_OK;
 }
index 850acdcd05062080ba64d6aab52c474f41d6ae87..4906947adaf52602afba4f7463345e45bd2dbad1 100644 (file)
 
        /* Function:          0x1c */
        NTSTATUS lsa_OpenSecret(
-               [in,ref]     policy_handle *handle,
-               [in]         lsa_String       name,
-               [in]         uint32         access_mask,
-               [out,ref]    policy_handle *sec_handle
+               [in,ref]     policy_handle    *handle,
+               [in]         lsa_String        name,
+               [in]         uint32            access_mask,
+               [out,ref]    policy_handle    *sec_handle
                );
 
        /* Function:           0x1d */
 
        NTSTATUS lsa_SetSecret(
-               [in,ref]     policy_handle *handle,
+               [in,ref]     policy_handle    *sec_handle,
                [in]         lsa_DATA_BUF     *new_val,
                [in]         lsa_DATA_BUF     *old_val
                );
 
        /* Function:         0x1e */
        NTSTATUS lsa_QuerySecret (
-               [in,ref]     policy_handle *handle,
+               [in,ref]     policy_handle     *sec_handle,
                [in,out]     lsa_DATA_BUF_PTR  *new_val,
                [in,out]     NTTIME_hyper      *new_mtime,
                [in,out]     lsa_DATA_BUF_PTR  *old_val,
index 389db30f8ca18801e2afec1a2a165b404493c538..7045cf6af7da8f802257c17e6eaedb3541818e5c 100644 (file)
@@ -170,3 +170,25 @@ void secrets_named_mutex_release(const char *name, size_t *p_ref_count)
        DEBUG(10,("secrets_named_mutex_release: ref_count for mutex %s = %u\n", name, (uint_t)ref_count ));
 }
 
+/*
+  connect to the schannel ldb
+*/
+struct ldb_wrap *secrets_db_connect(TALLOC_CTX *mem_ctx)
+{
+       char *path;
+       struct ldb_wrap *ldb;
+
+       path = private_path(mem_ctx, "secrets.ldb");
+       if (!path) {
+               return NULL;
+       }
+       
+       ldb = ldb_wrap_connect(mem_ctx, path, 0, NULL);
+       talloc_free(path);
+       if (!ldb) {
+               return NULL;
+       }
+
+       return ldb;
+}
+
index 8ebf6a9c408c50094a2228bfe8c7794c905eb641..c160972b5d451acb028da3e94b967e83bbc52a1d 100644 (file)
@@ -140,6 +140,23 @@ systemFlags: 0x8c000000
 objectCategory: CN=Container,CN=Schema,CN=Configuration,${BASEDN}
 isCriticalSystemObject: TRUE
 
+dn: CN=System,${BASEDN}
+objectClass: top
+objectClass: container
+cn: System
+description: Builtin system settings
+instanceType: 4
+whenCreated: ${LDAPTIME}
+whenChanged: ${LDAPTIME}
+uSNCreated: 1
+uSNChanged: 1
+showInAdvancedViewOnly: TRUE
+name: System
+objectGUID: ${NEWGUID}
+systemFlags: 0x8c000000
+objectCategory: CN=Container,CN=Schema,CN=Configuration,${BASEDN}
+isCriticalSystemObject: TRUE
+
 dn: CN=Builtin,${BASEDN}
 objectClass: top
 objectClass: builtinDomain
index 752795b65b4cd5c3a9442d88a17a08ac1cfb83d4..d6e0854968efa8f8df786a032fdd245b01714ef4 100644 (file)
@@ -4,6 +4,7 @@
    endpoint server for the lsarpc pipe
 
    Copyright (C) Andrew Tridgell 2004
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -27,6 +28,7 @@
 #include "rpc_server/common/common.h"
 #include "lib/ldb/include/ldb.h"
 #include "auth/auth.h"
+#include "system/time.h"
 
 /*
   this type allows us to distinguish handle types
@@ -42,11 +44,12 @@ enum lsa_handle {
 */
 struct lsa_policy_state {
        struct dcesrv_handle *handle;
-       void *sam_ctx;
+       struct ldb_wrap *sam_ctx;
        struct sidmap_context *sidmap;
        uint32_t access_mask;
        const char *domain_dn;
        const char *builtin_dn;
+       const char *system_dn;
        const char *domain_name;
        struct dom_sid *domain_sid;
        struct dom_sid *builtin_sid;
@@ -65,6 +68,16 @@ struct lsa_account_state {
 };
 
 
+/*
+  state associated with a lsa_OpenSecret() operation
+*/
+struct lsa_secret_state {
+       struct lsa_policy_state *policy;
+       uint32_t access_mask;
+       const char *secret_dn;
+       struct ldb_wrap *sam_ctx;
+};
+
 /* 
   lsa_Close 
 */
@@ -209,6 +222,15 @@ static NTSTATUS lsa_get_policy_state(struct dcesrv_call_state *dce_call, TALLOC_
                return NT_STATUS_NO_SUCH_DOMAIN;                
        }
 
+       /* work out the system_dn - useful for so many calls its worth
+          fetching here */
+       state->system_dn = samdb_search_string(state->sam_ctx, state, state->domain_dn,
+                                              "dn", "(&(objectClass=container)(cn=System))");
+       if (!state->system_dn) {
+               talloc_free(state);
+               return NT_STATUS_NO_SUCH_DOMAIN;                
+       }
+
        sid_str = samdb_search_string(state->sam_ctx, state, NULL,
                                      "objectSid", "dn=%s", state->domain_dn);
        if (!sid_str) {
@@ -780,16 +802,6 @@ static NTSTATUS lsa_LookupSids(struct dcesrv_call_state *dce_call, TALLOC_CTX *m
 }
 
 
-/* 
-  lsa_CreateSecret 
-*/
-static NTSTATUS lsa_CreateSecret(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct lsa_CreateSecret *r)
-{
-       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
-}
-
-
 /* 
   lsa_OpenAccount 
 */
@@ -1223,13 +1235,218 @@ static NTSTATUS lsa_SetInformationTrustedDomain(struct dcesrv_call_state *dce_ca
 }
 
 
+/* 
+  lsa_CreateSecret 
+*/
+static NTSTATUS lsa_CreateSecret(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
+                                struct lsa_CreateSecret *r)
+{
+       struct dcesrv_handle *policy_handle;
+       struct lsa_policy_state *policy_state;
+       struct lsa_secret_state *secret_state;
+       struct dcesrv_handle *handle;
+       struct ldb_message **msgs, *msg;
+       const char *attrs[] = {
+               NULL
+       };
+
+       const char *name;
+
+       int ret;
+
+       DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);
+       ZERO_STRUCTP(r->out.sec_handle);
+       
+       policy_state = policy_handle->data;
+
+       if (!r->in.name.string) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+       
+       secret_state = talloc(mem_ctx, struct lsa_secret_state);
+       if (!secret_state) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       msg = ldb_msg_new(mem_ctx);
+       if (msg == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if (strncmp("G$", r->in.name.string, 2) == 0) {
+               const char *name2;
+               name = &r->in.name.string[2];
+               secret_state->sam_ctx = talloc_reference(secret_state, policy_state->sam_ctx);
+
+               if (strlen(name) < 1) {
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+
+               name2 = talloc_asprintf(mem_ctx, "%s Secret", name);
+               /* search for the secret record */
+               ret = samdb_search(secret_state->sam_ctx,
+                                  mem_ctx, policy_state->system_dn, &msgs, attrs,
+                                  "(&(cn=%s)(objectclass=secret))", 
+                                  name2);
+               if (ret > 0) {
+                       return NT_STATUS_OBJECT_NAME_COLLISION;
+               }
+               
+               if (ret < 0 || ret > 1) {
+                       DEBUG(0,("Found %d records matching DN %s\n", ret, policy_state->system_dn));
+                       return NT_STATUS_INTERNAL_DB_CORRUPTION;
+               }
+
+               msg->dn = talloc_asprintf(mem_ctx, "cn=%s,%s", name2, policy_state->system_dn);
+               if (!name2 || !msg->dn) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               
+               samdb_msg_add_string(secret_state->sam_ctx, mem_ctx, msg, "cn", name2);
+       
+       } else {
+               name = r->in.name.string;
+               if (strlen(name) < 1) {
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+
+               secret_state->sam_ctx = talloc_reference(secret_state, secrets_db_connect(mem_ctx));
+               /* search for the secret record */
+               ret = samdb_search(secret_state->sam_ctx,
+                                  mem_ctx, "cn=LSA Secrets", &msgs, attrs,
+                                  "(&(cn=%s)(objectclass=secret))", 
+                                  name);
+               if (ret > 0) {
+                       return NT_STATUS_OBJECT_NAME_COLLISION;
+               }
+               
+               if (ret < 0 || ret > 1) {
+                       DEBUG(0,("Found %d records matching DN %s\n", ret, policy_state->system_dn));
+                       return NT_STATUS_INTERNAL_DB_CORRUPTION;
+               }
+
+               msg->dn = talloc_asprintf(mem_ctx, "cn=%s,cn=LSA Secrets", name);
+               samdb_msg_add_string(secret_state->sam_ctx, mem_ctx, msg, "cn", name);
+       } 
+       samdb_msg_add_string(secret_state->sam_ctx, mem_ctx, msg, "objectClass", "secret");
+       
+       secret_state->secret_dn = talloc_reference(secret_state, msg->dn);
+
+       /* create the secret */
+       ret = samdb_add(secret_state->sam_ctx, mem_ctx, msg);
+       if (ret != 0) {
+               DEBUG(0,("Failed to create secret record %s\n", msg->dn));
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+
+       handle = dcesrv_handle_new(dce_call->context, LSA_HANDLE_SECRET);
+       if (!handle) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       
+       handle->data = talloc_steal(handle, secret_state);
+       
+       secret_state->access_mask = r->in.access_mask;
+       secret_state->policy = talloc_reference(secret_state, policy_state);
+       
+       *r->out.sec_handle = handle->wire_handle;
+       
+       return NT_STATUS_OK;
+}
+
+
 /* 
   lsa_OpenSecret 
 */
 static NTSTATUS lsa_OpenSecret(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct lsa_OpenSecret *r)
+                              struct lsa_OpenSecret *r)
 {
-       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+       struct dcesrv_handle *policy_handle;
+       
+       struct lsa_policy_state *policy_state;
+       struct lsa_secret_state *secret_state;
+       struct dcesrv_handle *handle;
+       struct ldb_message **msgs;
+       const char *attrs[] = {
+               NULL
+       };
+
+       const char *name;
+
+       int ret;
+
+       DCESRV_PULL_HANDLE(policy_handle, r->in.handle, LSA_HANDLE_POLICY);
+       ZERO_STRUCTP(r->out.sec_handle);
+       policy_state = policy_handle->data;
+
+       if (!r->in.name.string) {
+               return NT_STATUS_INVALID_PARAMETER;
+       }
+       
+       secret_state = talloc(mem_ctx, struct lsa_secret_state);
+       if (!secret_state) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       if (strncmp("G$", r->in.name.string, 2) == 0) {
+               name = &r->in.name.string[2];
+               secret_state->sam_ctx = talloc_reference(secret_state, policy_state->sam_ctx);
+
+               if (strlen(name) < 1) {
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+
+               /* search for the secret record */
+               ret = samdb_search(secret_state->sam_ctx,
+                                  mem_ctx, policy_state->system_dn, &msgs, attrs,
+                                  "(&(cn=%s Secret)(objectclass=secret))", 
+                                  name);
+               if (ret == 0) {
+                       return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+               }
+               
+               if (ret != 1) {
+                       DEBUG(0,("Found %d records matching DN %s\n", ret, policy_state->system_dn));
+                       return NT_STATUS_INTERNAL_DB_CORRUPTION;
+               }
+       
+       } else {
+               name = r->in.name.string;
+               if (strlen(name) < 1) {
+                       return NT_STATUS_INVALID_PARAMETER;
+               }
+
+               secret_state->sam_ctx = talloc_reference(secret_state, secrets_db_connect(mem_ctx));
+               /* search for the secret record */
+               ret = samdb_search(secret_state->sam_ctx,
+                                  mem_ctx, "cn=LSA Secrets", &msgs, attrs,
+                                  "(&(cn=%s)(objectclass=secret))", 
+                                  name);
+               if (ret == 0) {
+                       return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+               }
+               
+               if (ret != 1) {
+                       DEBUG(0,("Found %d records matching DN %s\n", ret, policy_state->system_dn));
+                       return NT_STATUS_INTERNAL_DB_CORRUPTION;
+               }
+       } 
+
+       secret_state->secret_dn = talloc_reference(secret_state, msgs[0]->dn);
+       
+       handle = dcesrv_handle_new(dce_call->context, LSA_HANDLE_SECRET);
+       if (!handle) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       
+       handle->data = talloc_steal(handle, secret_state);
+       
+       secret_state->access_mask = r->in.access_mask;
+       secret_state->policy = talloc_reference(secret_state, policy_state);
+       
+       *r->out.sec_handle = handle->wire_handle;
+       
+       return NT_STATUS_OK;
 }
 
 
@@ -1237,9 +1454,145 @@ static NTSTATUS lsa_OpenSecret(struct dcesrv_call_state *dce_call, TALLOC_CTX *m
   lsa_SetSecret 
 */
 static NTSTATUS lsa_SetSecret(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct lsa_SetSecret *r)
+                             struct lsa_SetSecret *r)
 {
-       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+
+       struct dcesrv_handle *h;
+       struct lsa_secret_state *secret_state;
+       struct ldb_message *msg;
+       DATA_BLOB session_key;
+       DATA_BLOB crypt_secret, secret;
+       struct ldb_val val;
+       int ret;
+       NTSTATUS status = NT_STATUS_OK;
+
+       struct timeval now = timeval_current();
+       NTTIME nt_now = timeval_to_nttime(&now);
+
+       DCESRV_PULL_HANDLE(h, r->in.sec_handle, LSA_HANDLE_SECRET);
+
+       secret_state = h->data;
+
+       msg = ldb_msg_new(mem_ctx);
+       if (msg == NULL) {
+               return NT_STATUS_NO_MEMORY;
+       }
+
+       msg->dn = talloc_reference(mem_ctx, secret_state->secret_dn);
+       if (!msg->dn) {
+               return NT_STATUS_NO_MEMORY;
+       }
+       status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
+       if (!NT_STATUS_IS_OK(status)) {
+               return status;
+       }
+
+       if (r->in.old_val) {
+               /* Decrypt */
+               crypt_secret.data = r->in.old_val->data;
+               crypt_secret.length = r->in.old_val->size;
+               
+               status = sess_decrypt_blob(mem_ctx, &crypt_secret, &session_key, &secret);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+               
+               val.data = secret.data;
+               val.length = secret.length;
+               
+               /* set value */
+               if (samdb_msg_add_value(secret_state->sam_ctx, 
+                                       mem_ctx, msg, "priorSecret", &val) != 0) {
+                       return NT_STATUS_NO_MEMORY; 
+               }
+               
+               /* set old value mtime */
+               if (samdb_msg_add_uint64(secret_state->sam_ctx, 
+                                        mem_ctx, msg, "priorSetTime", nt_now) != 0) { 
+                       return NT_STATUS_NO_MEMORY; 
+               }
+       }
+
+       if (r->in.new_val) {
+               /* Decrypt */
+               crypt_secret.data = r->in.new_val->data;
+               crypt_secret.length = r->in.new_val->size;
+               
+               status = sess_decrypt_blob(mem_ctx, &crypt_secret, &session_key, &secret);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return status;
+               }
+               
+               val.data = secret.data;
+               val.length = secret.length;
+               
+               /* set value */
+               if (samdb_msg_add_value(secret_state->sam_ctx, 
+                                       mem_ctx, msg, "secret", &val) != 0) {
+                       return NT_STATUS_NO_MEMORY; 
+               }
+               
+               /* set new value mtime */
+               if (samdb_msg_add_uint64(secret_state->sam_ctx, 
+                                        mem_ctx, msg, "lastSetTime", nt_now) != 0) { 
+                       return NT_STATUS_NO_MEMORY; 
+               }
+               
+               /* If the old value is not set, then migrate the
+                * current value to the old value */
+               if (!r->in.old_val) {
+                       const struct ldb_val *new_val;
+                       NTTIME last_set_time;
+                       struct ldb_message **res;
+                       const char *attrs[] = {
+                               "secret",
+                               "lastSetTime",
+                               NULL
+                       };
+                       
+                       /* search for the secret record */
+                       ret = samdb_search(secret_state->sam_ctx,
+                                          mem_ctx, NULL, &res, attrs,
+                                          "(dn=%s)", secret_state->secret_dn);
+                       if (ret == 0) {
+                               return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+                       }
+                       
+                       if (ret != 1) {
+                               DEBUG(0,("Found %d records matching dn=%s\n", ret, secret_state->secret_dn));
+                               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+                       }
+
+                       new_val = ldb_msg_find_ldb_val(res[0], "secret");
+                       last_set_time = ldb_msg_find_uint64(res[0], "lastSetTime", 0);
+                       
+                       if (new_val) {
+                               /* set value */
+                               if (samdb_msg_add_value(secret_state->sam_ctx, 
+                                                       mem_ctx, msg, "priorSecret", 
+                                                       new_val) != 0) {
+                                       return NT_STATUS_NO_MEMORY; 
+                               }
+                       }
+                       
+                       /* set new value mtime */
+                       if (ldb_msg_find_ldb_val(res[0], "lastSetTime")) {
+                               if (samdb_msg_add_uint64(secret_state->sam_ctx, 
+                                                        mem_ctx, msg, "priorSetTime", last_set_time) != 0) { 
+                                       return NT_STATUS_NO_MEMORY; 
+                               }
+                       }
+               }
+       }
+
+       /* modify the samdb record */
+       ret = samdb_replace(secret_state->sam_ctx, mem_ctx, msg);
+       if (ret != 0) {
+               /* we really need samdb.c to return NTSTATUS */
+               return NT_STATUS_UNSUCCESSFUL;
+       }
+
+       return NT_STATUS_OK;
 }
 
 
@@ -1247,9 +1600,105 @@ static NTSTATUS lsa_SetSecret(struct dcesrv_call_state *dce_call, TALLOC_CTX *me
   lsa_QuerySecret 
 */
 static NTSTATUS lsa_QuerySecret(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
-                      struct lsa_QuerySecret *r)
+                               struct lsa_QuerySecret *r)
 {
-       DCESRV_FAULT(DCERPC_FAULT_OP_RNG_ERROR);
+       struct dcesrv_handle *h;
+       struct lsa_secret_state *secret_state;
+       struct ldb_message *msg;
+       DATA_BLOB session_key;
+       DATA_BLOB crypt_secret, secret;
+       int ret;
+       struct ldb_message **res;
+       const char *attrs[] = {
+               "secret",
+               "priorSecret",
+               "lastSetTime",
+               "priorSetTime", 
+               NULL
+       };
+
+       NTSTATUS nt_status;
+
+       time_t now = time(NULL);
+       NTTIME now_nt;
+       unix_to_nt_time(&now_nt, now);
+
+       DCESRV_PULL_HANDLE(h, r->in.sec_handle, LSA_HANDLE_SECRET);
+
+       secret_state = h->data;
+
+       /* pull all the user attributes */
+       ret = samdb_search(secret_state->sam_ctx, mem_ctx, NULL, &res, attrs,
+                          "dn=%s", secret_state->secret_dn);
+       if (ret != 1) {
+               return NT_STATUS_INTERNAL_DB_CORRUPTION;
+       }
+       msg = res[0];
+       
+       nt_status = dcesrv_fetch_session_key(dce_call->conn, &session_key);
+       if (!NT_STATUS_IS_OK(nt_status)) {
+               return nt_status;
+       }
+       
+       if (r->in.old_val) {
+               const struct ldb_val *prior_val;
+               /* Decrypt */
+               prior_val = ldb_msg_find_ldb_val(res[0], "priorSecret");
+               
+               if (prior_val && prior_val->length) {
+                       secret.data = prior_val->data;
+                       secret.length = prior_val->length;
+               
+                       crypt_secret = sess_encrypt_blob(mem_ctx, &secret, &session_key);
+                       if (!crypt_secret.length) {
+                               return NT_STATUS_NO_MEMORY;
+                       }
+                       r->out.old_val = talloc(mem_ctx, struct lsa_DATA_BUF_PTR);
+                       r->out.old_val->buf = talloc(mem_ctx, struct lsa_DATA_BUF);
+                       r->out.old_val->buf->size = crypt_secret.length;
+                       r->out.old_val->buf->length = crypt_secret.length;
+                       r->out.old_val->buf->data = crypt_secret.data;
+               }
+       }
+       
+       if (r->in.old_mtime) {
+               r->out.old_mtime = talloc(mem_ctx, NTTIME_hyper);
+               if (!r->out.old_mtime) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               *r->out.old_mtime = ldb_msg_find_uint64(res[0], "priorSetTime", 0);
+       }
+       
+       if (r->in.new_val) {
+               const struct ldb_val *new_val;
+               /* Decrypt */
+               new_val = ldb_msg_find_ldb_val(res[0], "secret");
+               
+               if (new_val && new_val->length) {
+                       secret.data = new_val->data;
+                       secret.length = new_val->length;
+               
+                       crypt_secret = sess_encrypt_blob(mem_ctx, &secret, &session_key);
+                       if (!crypt_secret.length) {
+                               return NT_STATUS_NO_MEMORY;
+                       }
+                       r->out.new_val = talloc(mem_ctx, struct lsa_DATA_BUF_PTR);
+                       r->out.new_val->buf = talloc(mem_ctx, struct lsa_DATA_BUF);
+                       r->out.new_val->buf->length = crypt_secret.length;
+                       r->out.new_val->buf->size = crypt_secret.length;
+                       r->out.new_val->buf->data = crypt_secret.data;
+               }
+       }
+       
+       if (r->in.new_mtime) {
+               r->out.new_mtime = talloc(mem_ctx, NTTIME_hyper);
+               if (!r->out.new_mtime) {
+                       return NT_STATUS_NO_MEMORY;
+               }
+               *r->out.new_mtime = ldb_msg_find_uint64(res[0], "lastSetTime", 0);
+       }
+       
+       return NT_STATUS_OK;
 }
 
 
index 2dd37bed12149f7357ff991450e6806bf31beb3d..cc6e1adf21db16ecec7b2866d73b4bb489afa7d2 100755 (executable)
@@ -389,6 +389,31 @@ system("ldbadd -H newrootdse.ldb newrootdse.ldif");
 
 print "done\n";
 
+$data = FileLoad("secrets.ldif") || die "Unable to load secrets.ldif\n";
+
+$res = "";
+
+print "applying substitutions ...\n";
+
+while ($data =~ /(.*?)\$\{(\w*)\}(.*)/s) {
+       my $sub = substitute($2);
+       $res .= "$1$sub";
+       $data = $3;
+}
+$res .= $data;
+
+print "saving ldif to newsecrets.ldif ...\n";
+
+FileSave("newsecrets.ldif", $res);
+
+unlink("newsecrets.ldb");
+
+print "creating newsecrets.ldb ...\n";
+
+system("ldbadd -H newsecrets.ldb newsecrets.ldif");
+
+print "done\n";
+
 print "generating dns zone file ...\n";
 
 $data = FileLoad("provision.zone") || die "Unable to load provision.zone\n";
@@ -425,6 +450,8 @@ Installation:
   Samba4 installation
 - Please move newrootdse.ldb to rootdse.ldb in the private/ directory
   of your Samba4 installation
+- Please move newsecrets.ldb to secrets.ldb in the private/ directory
+  of your Samba4 installation
 - Please move newhklm.ldb to hklm.ldb in the private/ directory
   of your Samba4 installation
 - Please use $dnsdomain.zone to in BIND dns server
diff --git a/source4/secrets.ldif b/source4/secrets.ldif
new file mode 100644 (file)
index 0000000..63ce7f2
--- /dev/null
@@ -0,0 +1,9 @@
+dn: @INDEXLIST
+@IDXATTR: name
+@IDXATTR: cn
+
+
+dn: CN=LSA Secrets
+objectClass: top
+objectClass: container
+cn: LSA Secrets
index f1a5b760402dab8e24013d3fc62b177b9f2cfea4..c9f730cd27d824c70932edad0c58b38da316328f 100644 (file)
@@ -3,6 +3,7 @@
    test suite for lsa rpc operations
 
    Copyright (C) Andrew Tridgell 2003
+   Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-2005
    
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
@@ -682,7 +683,7 @@ static BOOL test_CreateSecret(struct dcerpc_pipe *p,
        struct lsa_QuerySecret r6;
        struct lsa_SetSecret r7;
        struct lsa_QuerySecret r8;
-       struct policy_handle sec_handle, sec_handle2;
+       struct policy_handle sec_handle, sec_handle2, sec_handle3;
        struct lsa_Delete d;
        struct lsa_DATA_BUF buf1;
        struct lsa_DATA_BUF_PTR bufp1;
@@ -721,6 +722,16 @@ static BOOL test_CreateSecret(struct dcerpc_pipe *p,
                        return False;
                }
                
+               r.in.handle = handle;
+               r.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
+               r.out.sec_handle = &sec_handle3;
+               
+               status = dcerpc_lsa_CreateSecret(p, mem_ctx, &r);
+               if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_COLLISION)) {
+                       printf("CreateSecret should have failed OBJECT_NAME_COLLISION - %s\n", nt_errstr(status));
+                       return False;
+               }
+               
                r2.in.handle = handle;
                r2.in.access_mask = SEC_FLAG_MAXIMUM_ALLOWED;
                r2.in.name = r.in.name;
@@ -742,7 +753,7 @@ static BOOL test_CreateSecret(struct dcerpc_pipe *p,
                
                enc_key = sess_encrypt_string(secret1, &session_key);
                
-               r3.in.handle = &sec_handle;
+               r3.in.sec_handle = &sec_handle;
                r3.in.new_val = &buf1;
                r3.in.old_val = NULL;
                r3.in.new_val->data = enc_key.data;
@@ -757,13 +768,31 @@ static BOOL test_CreateSecret(struct dcerpc_pipe *p,
                        ret = False;
                }
                
+               r3.in.sec_handle = &sec_handle;
+               r3.in.new_val = &buf1;
+               r3.in.old_val = NULL;
+               r3.in.new_val->data = enc_key.data;
+               r3.in.new_val->length = enc_key.length;
+               r3.in.new_val->size = enc_key.length;
+               
+               /* break the encrypted data */
+               enc_key.data[0]++;
+
+               printf("Testing SetSecret with broken key\n");
+               
+               status = dcerpc_lsa_SetSecret(p, mem_ctx, &r3);
+               if (!NT_STATUS_EQUAL(status, NT_STATUS_UNKNOWN_REVISION)) {
+                       printf("SetSecret should have failed UNKNOWN_REVISION - %s\n", nt_errstr(status));
+                       ret = False;
+               }
+               
                data_blob_free(&enc_key);
                
                ZERO_STRUCT(new_mtime);
                ZERO_STRUCT(old_mtime);
                
                /* fetch the secret back again */
-               r4.in.handle = &sec_handle;
+               r4.in.sec_handle = &sec_handle;
                r4.in.new_val = &bufp1;
                r4.in.new_mtime = &new_mtime;
                r4.in.old_val = NULL;
@@ -771,17 +800,18 @@ static BOOL test_CreateSecret(struct dcerpc_pipe *p,
                
                bufp1.buf = NULL;
                
+               printf("Testing QuerySecret\n");
                status = dcerpc_lsa_QuerySecret(p, mem_ctx, &r4);
                if (!NT_STATUS_IS_OK(status)) {
                        printf("QuerySecret failed - %s\n", nt_errstr(status));
                        ret = False;
                } else {
-                       if (r4.out.new_val->buf == NULL) {
+                       if (r4.out.new_val == NULL || r4.out.new_val->buf == NULL) {
                                printf("No secret buffer returned\n");
                                ret = False;
                        } else {
                                blob1.data = r4.out.new_val->buf->data;
-                               blob1.length = r4.out.new_val->buf->length;
+                               blob1.length = r4.out.new_val->buf->size;
                                
                                blob2 = data_blob_talloc(mem_ctx, NULL, blob1.length);
                                
@@ -797,7 +827,7 @@ static BOOL test_CreateSecret(struct dcerpc_pipe *p,
                
                enc_key = sess_encrypt_string(secret3, &session_key);
                
-               r5.in.handle = &sec_handle;
+               r5.in.sec_handle = &sec_handle;
                r5.in.new_val = &buf1;
                r5.in.old_val = NULL;
                r5.in.new_val->data = enc_key.data;
@@ -818,7 +848,7 @@ static BOOL test_CreateSecret(struct dcerpc_pipe *p,
                ZERO_STRUCT(old_mtime);
                
                /* fetch the secret back again */
-               r6.in.handle = &sec_handle;
+               r6.in.sec_handle = &sec_handle;
                r6.in.new_val = &bufp1;
                r6.in.new_mtime = &new_mtime;
                r6.in.old_val = &bufp2;
@@ -839,7 +869,7 @@ static BOOL test_CreateSecret(struct dcerpc_pipe *p,
                                ret = False;
                        } else {
                                blob1.data = r6.out.new_val->buf->data;
-                               blob1.length = r6.out.new_val->buf->length;
+                               blob1.length = r6.out.new_val->buf->size;
                                
                                blob2 = data_blob_talloc(mem_ctx, NULL, blob1.length);
                                
@@ -873,7 +903,7 @@ static BOOL test_CreateSecret(struct dcerpc_pipe *p,
 
                enc_key = sess_encrypt_string(secret5, &session_key);
                
-               r7.in.handle = &sec_handle;
+               r7.in.sec_handle = &sec_handle;
                r7.in.old_val = &buf1;
                r7.in.old_val->data = enc_key.data;
                r7.in.old_val->length = enc_key.length;
@@ -891,7 +921,7 @@ static BOOL test_CreateSecret(struct dcerpc_pipe *p,
                data_blob_free(&enc_key);
                
                /* fetch the secret back again */
-               r8.in.handle = &sec_handle;
+               r8.in.sec_handle = &sec_handle;
                r8.in.new_val = &bufp1;
                r8.in.new_mtime = &new_mtime;
                r8.in.old_val = &bufp2;
@@ -931,7 +961,7 @@ static BOOL test_CreateSecret(struct dcerpc_pipe *p,
                                }
 
                                blob1.data = r8.out.old_val->buf->data;
-                               blob1.length = r8.out.old_val->buf->length;
+                               blob1.length = r8.out.old_val->buf->size;
                                
                                blob2 = data_blob_talloc(mem_ctx, NULL, blob1.length);
                                
@@ -968,14 +998,15 @@ static BOOL test_CreateSecret(struct dcerpc_pipe *p,
                if (!NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
                        printf("Second delete expected INVALID_HANDLE - %s\n", nt_errstr(status));
                        ret = False;
-               }
+               } else {
 
-               printf("Testing OpenSecret of just-deleted secret\n");
-               
-               status = dcerpc_lsa_OpenSecret(p, mem_ctx, &r2);
-               if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
-                       printf("OpenSecret expected OBJECT_NAME_NOT_FOUND - %s\n", nt_errstr(status));
-                       ret = False;
+                       printf("Testing OpenSecret of just-deleted secret\n");
+                       
+                       status = dcerpc_lsa_OpenSecret(p, mem_ctx, &r2);
+                       if (!NT_STATUS_EQUAL(status, NT_STATUS_OBJECT_NAME_NOT_FOUND)) {
+                               printf("OpenSecret expected OBJECT_NAME_NOT_FOUND - %s\n", nt_errstr(status));
+                               ret = False;
+                       }
                }
                
        }
index e393cd40fe7e67df27e3faaea8d92b8ed305a3e3..8c85787fe2bbdb7336ecc38727e3f686e9d62561 100644 (file)
@@ -778,8 +778,11 @@ static BOOL samsync_handle_secret(TALLOC_CTX *mem_ctx, struct samsync_state *sam
                lsa_blob1.data = q.out.old_val->buf->data;
                lsa_blob1.length = q.out.old_val->buf->length;
 
-               lsa_blob_out = sess_decrypt_blob(mem_ctx, &lsa_blob1, &session_key);
-               
+               status = sess_decrypt_blob(mem_ctx, &lsa_blob1, &session_key, &lsa_blob_out);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return False;
+               }
+
                if (!q.out.old_mtime) {
                        printf("OLD mtime not available on LSA for secret %s\n", old->name);
                        ret = False;
@@ -814,7 +817,10 @@ static BOOL samsync_handle_secret(TALLOC_CTX *mem_ctx, struct samsync_state *sam
                lsa_blob1.data = q.out.new_val->buf->data;
                lsa_blob1.length = q.out.new_val->buf->length;
 
-               lsa_blob_out = sess_decrypt_blob(mem_ctx, &lsa_blob1, &session_key);
+               status = sess_decrypt_blob(mem_ctx, &lsa_blob1, &session_key, &lsa_blob_out);
+               if (!NT_STATUS_IS_OK(status)) {
+                       return False;
+               }
                
                if (!q.out.new_mtime) {
                        printf("NEW mtime not available on LSA for secret %s\n", new->name);