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
#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
*/
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;
};
+/*
+ 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
*/
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) {
}
-/*
- 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
*/
}
+/*
+ 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;
}
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;
}
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;
}
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
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;
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;
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;
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;
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);
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;
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;
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);
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;
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;
}
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);
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;
+ }
}
}