diff options
-rw-r--r-- | source4/lib/util.c | 15 | ||||
-rw-r--r-- | source4/libcli/auth/session.c | 43 | ||||
-rw-r--r-- | source4/librpc/idl/lsa.idl | 12 | ||||
-rw-r--r-- | source4/passdb/secrets.c | 22 | ||||
-rw-r--r-- | source4/provision.ldif | 17 | ||||
-rw-r--r-- | source4/rpc_server/lsa/dcesrv_lsa.c | 483 | ||||
-rwxr-xr-x | source4/script/provision.pl | 27 | ||||
-rw-r--r-- | source4/secrets.ldif | 9 | ||||
-rw-r--r-- | source4/torture/rpc/lsa.c | 67 | ||||
-rw-r--r-- | source4/torture/rpc/samsync.c | 12 |
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); |