summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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);