summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2005-01-11 14:04:58 +0000
committerGerald (Jerry) Carter <jerry@samba.org>2007-10-10 13:08:42 -0500
commita249198d539685be5cb97e179e85ae00dbba8c83 (patch)
tree1e0ae58592cc6a4d7a09934a1fabca03e53871b6 /source4
parent7ab7debcf17d833ac15512604f73b551c27534c2 (diff)
downloadsamba-a249198d539685be5cb97e179e85ae00dbba8c83.tar.gz
samba-a249198d539685be5cb97e179e85ae00dbba8c83.tar.bz2
samba-a249198d539685be5cb97e179e85ae00dbba8c83.zip
r4682: A LDB-based secrets implementation in Samba4.
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)
Diffstat (limited to 'source4')
-rw-r--r--source4/lib/util.c15
-rw-r--r--source4/libcli/auth/session.c43
-rw-r--r--source4/librpc/idl/lsa.idl12
-rw-r--r--source4/passdb/secrets.c22
-rw-r--r--source4/provision.ldif17
-rw-r--r--source4/rpc_server/lsa/dcesrv_lsa.c483
-rwxr-xr-xsource4/script/provision.pl27
-rw-r--r--source4/secrets.ldif9
-rw-r--r--source4/torture/rpc/lsa.c67
-rw-r--r--source4/torture/rpc/samsync.c12
10 files changed, 642 insertions, 65 deletions
diff --git a/source4/lib/util.c b/source4/lib/util.c
index ac5124840e..9341a011af 100644
--- a/source4/lib/util.c
+++ b/source4/lib/util.c
@@ -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
diff --git a/source4/libcli/auth/session.c b/source4/libcli/auth/session.c
index 91eee9ce81..9b4132a490 100644
--- a/source4/libcli/auth/session.c
+++ b/source4/libcli/auth/session.c
@@ -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;
}
diff --git a/source4/librpc/idl/lsa.idl b/source4/librpc/idl/lsa.idl
index 850acdcd05..4906947ada 100644
--- a/source4/librpc/idl/lsa.idl
+++ b/source4/librpc/idl/lsa.idl
@@ -535,16 +535,16 @@
/* 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
);
@@ -555,7 +555,7 @@
/* 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,
diff --git a/source4/passdb/secrets.c b/source4/passdb/secrets.c
index 389db30f8c..7045cf6af7 100644
--- a/source4/passdb/secrets.c
+++ b/source4/passdb/secrets.c
@@ -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;
+}
+
diff --git a/source4/provision.ldif b/source4/provision.ldif
index 8ebf6a9c40..c160972b5d 100644
--- a/source4/provision.ldif
+++ b/source4/provision.ldif
@@ -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
diff --git a/source4/rpc_server/lsa/dcesrv_lsa.c b/source4/rpc_server/lsa/dcesrv_lsa.c
index 752795b65b..d6e0854968 100644
--- a/source4/rpc_server/lsa/dcesrv_lsa.c
+++ b/source4/rpc_server/lsa/dcesrv_lsa.c
@@ -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) {
@@ -781,16 +803,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
*/
static NTSTATUS lsa_OpenAccount(struct dcesrv_call_state *dce_call, TALLOC_CTX *mem_ctx,
@@ -1224,12 +1236,217 @@ 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;
}
diff --git a/source4/script/provision.pl b/source4/script/provision.pl
index 2dd37bed12..cc6e1adf21 100755
--- a/source4/script/provision.pl
+++ b/source4/script/provision.pl
@@ -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
index 0000000000..63ce7f2afb
--- /dev/null
+++ b/source4/secrets.ldif
@@ -0,0 +1,9 @@
+dn: @INDEXLIST
+@IDXATTR: name
+@IDXATTR: cn
+
+
+dn: CN=LSA Secrets
+objectClass: top
+objectClass: container
+cn: LSA Secrets
diff --git a/source4/torture/rpc/lsa.c b/source4/torture/rpc/lsa.c
index f1a5b76040..c9f730cd27 100644
--- a/source4/torture/rpc/lsa.c
+++ b/source4/torture/rpc/lsa.c
@@ -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;
+ }
}
}
diff --git a/source4/torture/rpc/samsync.c b/source4/torture/rpc/samsync.c
index e393cd40fe..8c85787fe2 100644
--- a/source4/torture/rpc/samsync.c
+++ b/source4/torture/rpc/samsync.c
@@ -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);