such as the local SID and machine trust password */
#include "includes.h"
+#include "lib/tdb/include/tdbutil.h"
+#include "secrets.h"
+#include "param/param.h"
+#include "system/filesys.h"
+#include "db_wrap.h"
+#include "lib/ldb/include/ldb.h"
+#include "dsdb/samdb/samdb.h"
-#undef DBGC_CLASS
-#define DBGC_CLASS DBGC_PASSDB
+static struct tdb_wrap *tdb;
-static TDB_CONTEXT *tdb;
-
-/* open up the secrets database */
-BOOL secrets_init(void)
-{
- pstring fname;
-
- if (tdb)
- return True;
-
- pstrcpy(fname, lp_private_dir());
- pstrcat(fname,"/secrets.tdb");
-
- tdb = tdb_open_log(fname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
-
- if (!tdb) {
- DEBUG(0,("Failed to open %s\n", fname));
- return False;
- }
- return True;
-}
-
-/* read a entry from the secrets database - the caller must free the result
- if size is non-null then the size of the entry is put in there
- */
-void *secrets_fetch(const char *key, size_t *size)
-{
- TDB_DATA kbuf, dbuf;
- secrets_init();
- if (!tdb)
- return NULL;
- kbuf.dptr = strdup(key);
- kbuf.dsize = strlen(key);
- dbuf = tdb_fetch(tdb, kbuf);
- if (size)
- *size = dbuf.dsize;
- free(kbuf.dptr);
- return dbuf.dptr;
-}
-
-/* store a secrets entry
- */
-BOOL secrets_store(const char *key, const void *data, size_t size)
-{
- TDB_DATA kbuf, dbuf;
- int ret;
-
- secrets_init();
- if (!tdb)
- return False;
- kbuf.dptr = strdup(key);
- kbuf.dsize = strlen(key);
- dbuf.dptr = memdup(data, size);
- dbuf.dsize = size;
-
- ret = tdb_store(tdb, kbuf, dbuf, TDB_REPLACE) == 0;
-
- free(kbuf.dptr);
- free(dbuf.dptr);
-
- return ret == 0;
-}
-
-
-/* delete a secets database entry
+/**
+ * Use a TDB to store an incrementing random seed.
+ *
+ * Initialised to the current pid, the very first time Samba starts,
+ * and incremented by one each time it is needed.
+ *
+ * @note Not called by systems with a working /dev/urandom.
*/
-BOOL secrets_delete(const char *key)
+static void get_rand_seed(int *new_seed)
{
- TDB_DATA kbuf;
- int ret;
-
- secrets_init();
- if (!tdb)
- return False;
- kbuf.dptr = strdup(key);
- kbuf.dsize = strlen(key);
- ret = tdb_delete(tdb, kbuf);
- free(kbuf.dptr);
- return ret == 0;
-}
-
-BOOL secrets_store_domain_sid(const char *domain, const DOM_SID *sid)
-{
- fstring key;
-
- slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_DOMAIN_SID, domain);
- strupper(key);
- return secrets_store(key, sid, sizeof(DOM_SID));
-}
-
-BOOL secrets_fetch_domain_sid(const char *domain, DOM_SID *sid)
-{
- DOM_SID *dyn_sid;
- fstring key;
- size_t size;
-
- slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_DOMAIN_SID, domain);
- strupper(key);
- dyn_sid = (DOM_SID *)secrets_fetch(key, &size);
-
- if (dyn_sid == NULL)
- return False;
-
- if (size != sizeof(DOM_SID))
- {
- SAFE_FREE(dyn_sid);
- return False;
+ *new_seed = getpid();
+ if (tdb) {
+ tdb_change_int32_atomic(tdb->tdb, "INFO/random_seed", new_seed, 1);
}
-
- *sid = *dyn_sid;
- SAFE_FREE(dyn_sid);
- return True;
}
-BOOL secrets_store_domain_guid(const char *domain, GUID *guid)
+/* close the secrets database */
+void secrets_shutdown(void)
{
- fstring key;
-
- slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_DOMAIN_GUID, domain);
- strupper(key);
- return secrets_store(key, guid, sizeof(GUID));
+ talloc_free(tdb);
}
-BOOL secrets_fetch_domain_guid(const char *domain, GUID *guid)
+/* open up the secrets database */
+BOOL secrets_init(void)
{
- GUID *dyn_guid;
- fstring key;
- size_t size;
- GUID new_guid;
+ char *fname;
+ uint8_t dummy;
- slprintf(key, sizeof(key)-1, "%s/%s", SECRETS_DOMAIN_GUID, domain);
- strupper(key);
- dyn_guid = (GUID *)secrets_fetch(key, &size);
+ if (tdb)
+ return True;
- DEBUG(6,("key is %s, size is %d\n", key, (int)size));
+ asprintf(&fname, "%s/secrets.tdb", lp_private_dir());
- if ((NULL == dyn_guid) && (ROLE_DOMAIN_PDC == lp_server_role())) {
- uuid_generate_random(&new_guid);
- if (!secrets_store_domain_guid(domain, &new_guid))
- return False;
- dyn_guid = (GUID *)secrets_fetch(key, &size);
- if (dyn_guid == NULL)
- return False;
- }
+ tdb = tdb_wrap_open(talloc_autofree_context(), fname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600);
- if (size != sizeof(GUID))
- {
- SAFE_FREE(dyn_guid);
+ if (!tdb) {
+ DEBUG(0,("Failed to open %s\n", fname));
+ SAFE_FREE(fname);
return False;
}
+ SAFE_FREE(fname);
- *guid = *dyn_guid;
- SAFE_FREE(dyn_guid);
- return True;
-}
-
-/**
- * Form a key for fetching the machine trust account password
- *
- * @param domain domain name
- *
- * @return stored password's key
- **/
-const char *trust_keystr(const char *domain)
-{
- static fstring keystr;
-
- slprintf(keystr,sizeof(keystr)-1,"%s/%s",
- SECRETS_MACHINE_ACCT_PASS, domain);
- strupper(keystr);
-
- return keystr;
-}
-
-/**
- * Form a key for fetching a trusted domain password
- *
- * @param domain trusted domain name
- *
- * @return stored password's key
- **/
-char *trustdom_keystr(const char *domain)
-{
- static char* keystr;
-
- asprintf(&keystr, "%s/%s", SECRETS_DOMTRUST_ACCT_PASS, domain);
- strupper(keystr);
-
- return keystr;
-}
-
-/************************************************************************
- Lock the trust password entry.
-************************************************************************/
+ /**
+ * Set a reseed function for the crypto random generator
+ *
+ * This avoids a problem where systems without /dev/urandom
+ * could send the same challenge to multiple clients
+ */
+ set_rand_reseed_callback(get_rand_seed);
-BOOL secrets_lock_trust_account_password(const char *domain, BOOL dolock)
-{
- if (!tdb)
- return False;
+ /* Ensure that the reseed is done now, while we are root, etc */
+ generate_random_buffer(&dummy, sizeof(dummy));
- if (dolock)
- return (tdb_lock_bystring(tdb, trust_keystr(domain),0) == 0);
- else
- tdb_unlock_bystring(tdb, trust_keystr(domain));
return True;
}
-/************************************************************************
- Routine to get the trust account password for a domain.
- The user of this function must have locked the trust password file using
- the above call.
-************************************************************************/
-
-BOOL secrets_fetch_trust_account_password(const char *domain, uint8 ret_pwd[16],
- time_t *pass_last_set_time)
-{
- struct machine_acct_pass *pass;
- char *plaintext;
- size_t size;
-
- plaintext = secrets_fetch_machine_password();
- if (plaintext) {
- /* we have an ADS password - use that */
- DEBUG(4,("Using ADS machine password\n"));
- E_md4hash(plaintext, ret_pwd);
- SAFE_FREE(plaintext);
- pass_last_set_time = 0;
- return True;
- }
-
- if (!(pass = secrets_fetch(trust_keystr(domain), &size))) {
- DEBUG(5, ("secrets_fetch failed!\n"));
- return False;
+/*
+ connect to the schannel ldb
+*/
+struct ldb_context *secrets_db_connect(TALLOC_CTX *mem_ctx)
+{
+ char *path;
+ struct ldb_context *ldb;
+ BOOL existed;
+ const char *init_ldif =
+ "dn: @ATTRIBUTES\n" \
+ "computerName: CASE_INSENSITIVE\n" \
+ "flatname: CASE_INSENSITIVE\n";
+
+ path = private_path(mem_ctx, "secrets.ldb");
+ if (!path) {
+ return NULL;
}
- if (size != sizeof(*pass)) {
- DEBUG(0, ("secrets were of incorrect size!\n"));
- return False;
- }
-
- if (pass_last_set_time) *pass_last_set_time = pass->mod_time;
- memcpy(ret_pwd, pass->hash, 16);
- SAFE_FREE(pass);
- return True;
-}
-
-/************************************************************************
- Routine to get account password to trusted domain
-************************************************************************/
-
-BOOL secrets_fetch_trusted_domain_password(const char *domain, char** pwd,
- DOM_SID *sid, time_t *pass_last_set_time)
-{
- struct trusted_dom_pass *pass;
- size_t size;
-
- /* fetching trusted domain password structure */
- if (!(pass = secrets_fetch(trustdom_keystr(domain), &size))) {
- DEBUG(5, ("secrets_fetch failed!\n"));
- return False;
- }
-
- if (size != sizeof(*pass)) {
- DEBUG(0, ("secrets were of incorrect size!\n"));
- return False;
- }
+ existed = file_exist(path);
- /* the trust's password */
- if (pwd) {
- *pwd = strdup(pass->pass);
- if (!*pwd) {
- return False;
- }
+ /* Secrets.ldb *must* always be local. If we call for a
+ * system_session() we will recurse */
+ ldb = ldb_wrap_connect(mem_ctx, path, NULL, NULL, 0, NULL);
+ talloc_free(path);
+ if (!ldb) {
+ return NULL;
}
-
- /* last change time */
- if (pass_last_set_time) *pass_last_set_time = pass->mod_time;
-
- /* domain sid */
- memcpy(&sid, &(pass->domain_sid), sizeof(sid));
-
- SAFE_FREE(pass);
-
- return True;
-}
-
-/************************************************************************
- Routine to set the trust account password for a domain.
-************************************************************************/
-
-BOOL secrets_store_trust_account_password(const char *domain, uint8 new_pwd[16])
-{
- struct machine_acct_pass pass;
-
- pass.mod_time = time(NULL);
- memcpy(pass.hash, new_pwd, 16);
-
- return secrets_store(trust_keystr(domain), (void *)&pass, sizeof(pass));
-}
-
-/**
- * Routine to set the password for trusted domain
- *
- * @param domain remote domain name
- * @param pwd plain text password of trust relationship
- * @param sid remote domain sid
- *
- * @return true if succeeded
- **/
-
-BOOL secrets_store_trusted_domain_password(const char* domain, smb_ucs2_t *uni_dom_name,
- size_t uni_name_len, const char* pwd,
- DOM_SID sid)
-{
- struct trusted_dom_pass pass;
- ZERO_STRUCT(pass);
-
- /* unicode domain name and its length */
- if (!uni_dom_name)
- return False;
-
- strncpy_w(pass.uni_name, uni_dom_name, sizeof(pass.uni_name) - 1);
- pass.uni_name_len = uni_name_len;
-
- /* last change time */
- pass.mod_time = time(NULL);
-
- /* password of the trust */
- pass.pass_len = strlen(pwd);
- fstrcpy(pass.pass, pwd);
-
- /* domain sid */
- memcpy(&(pass.domain_sid), &sid, sizeof(sid));
-
- return secrets_store(trustdom_keystr(domain), (void *)&pass, sizeof(pass));
-}
-
-/************************************************************************
- Routine to set the plaintext machine account password for a realm
-the password is assumed to be a null terminated ascii string
-************************************************************************/
-
-BOOL secrets_store_machine_password(const char *pass)
-{
- char *key;
- BOOL ret;
- asprintf(&key, "%s/%s", SECRETS_MACHINE_PASSWORD, lp_workgroup());
- strupper(key);
- ret = secrets_store(key, pass, strlen(pass)+1);
- free(key);
- return ret;
-}
-
-
-/************************************************************************
- Routine to fetch the plaintext machine account password for a realm
-the password is assumed to be a null terminated ascii string
-************************************************************************/
-char *secrets_fetch_machine_password(void)
-{
- char *key;
- char *ret;
- asprintf(&key, "%s/%s", SECRETS_MACHINE_PASSWORD, lp_workgroup());
- strupper(key);
- ret = (char *)secrets_fetch(key, NULL);
- free(key);
- return ret;
-}
-
-
-
-/************************************************************************
- Routine to delete the machine trust account password file for a domain.
-************************************************************************/
-
-BOOL trust_password_delete(const char *domain)
-{
- return secrets_delete(trust_keystr(domain));
-}
-
-/************************************************************************
- Routine to delete the password for trusted domain
-************************************************************************/
-
-BOOL trusted_domain_password_delete(const char *domain)
-{
- return secrets_delete(trustdom_keystr(domain));
-}
-
-
-BOOL secrets_store_ldap_pw(const char* dn, char* pw)
-{
- char *key = NULL;
- BOOL ret;
- if (asprintf(&key, "%s/%s", SECRETS_LDAP_BIND_PW, dn) < 0) {
- DEBUG(0, ("secrets_store_ldap_pw: asprintf failed!\n"));
- return False;
+ if (!existed) {
+ gendb_add_ldif(ldb, init_ldif);
}
-
- ret = secrets_store(key, pw, strlen(pw)+1);
-
- SAFE_FREE(key);
- return ret;
-}
-
-/**
- * Get trusted domains info from secrets.tdb.
- *
- * The linked list is allocated on the supplied talloc context, caller gets to destroy
- * when done.
- *
- * @param ctx Allocation context
- * @param enum_ctx Starting index, eg. we can start fetching at third
- * or sixth trusted domain entry. Zero is the first index.
- * Value it is set to is the enum context for the next enumeration.
- * @param num_domains Number of domain entries to fetch at one call
- * @param domains Pointer to array of trusted domain structs to be filled up
- *
- * @return nt status code of rpc response
- **/
+ return ldb;
+}
-NTSTATUS secrets_get_trusted_domains(TALLOC_CTX* ctx, int* enum_ctx, unsigned int max_num_domains, int *num_domains, TRUSTDOM ***domains)
+struct dom_sid *secrets_get_domain_sid(TALLOC_CTX *mem_ctx,
+ const char *domain)
{
- TDB_LIST_NODE *keys, *k;
- TRUSTDOM *dom = NULL;
- char *pattern;
- unsigned int start_idx;
- uint32 idx = 0;
- size_t size;
- fstring dom_name;
- struct trusted_dom_pass *pass;
- NTSTATUS status;
-
- if (!secrets_init()) return NT_STATUS_ACCESS_DENIED;
-
- *num_domains = 0;
- start_idx = *enum_ctx;
-
- /* generate searching pattern */
- if (!(pattern = talloc_asprintf(ctx, "%s/*", SECRETS_DOMTRUST_ACCT_PASS))) {
- DEBUG(0, ("secrets_get_trusted_domains: talloc_asprintf() failed!\n"));
- return NT_STATUS_NO_MEMORY;
- }
-
- DEBUG(5, ("secrets_get_trusted_domains: looking for %d domains, starting at index %d\n",
- max_num_domains, *enum_ctx));
-
- *domains = talloc_zero(ctx, sizeof(**domains)*max_num_domains);
-
- /* fetching trusted domains' data and collecting them in a list */
- keys = tdb_search_keys(tdb, pattern);
-
- /*
- * if there's no keys returned ie. no trusted domain,
- * return "no more entries" code
- */
- status = NT_STATUS_NO_MORE_ENTRIES;
+ struct ldb_context *ldb;
+ struct ldb_message **msgs;
+ int ldb_ret;
+ const char *attrs[] = { "objectSid", NULL };
+ struct dom_sid *result = NULL;
- /* searching for keys in sectrets db -- way to go ... */
- for (k = keys; k; k = k->next) {
- char *secrets_key;
-
- /* important: ensure null-termination of the key string */
- secrets_key = strndup(k->node_key.dptr, k->node_key.dsize);
- if (!secrets_key) {
- DEBUG(0, ("strndup failed!\n"));
- return NT_STATUS_NO_MEMORY;
- }
-
- pass = secrets_fetch(secrets_key, &size);
-
- if (size != sizeof(*pass)) {
- DEBUG(2, ("Secrets record %s is invalid!\n", secrets_key));
- SAFE_FREE(pass);
- continue;
- }
-
- pull_ucs2_fstring(dom_name, pass->uni_name);
- DEBUG(18, ("Fetched secret record num %d.\nDomain name: %s, SID: %s\n",
- idx, dom_name, sid_string_talloc(ctx, &pass->domain_sid)));
-
- SAFE_FREE(secrets_key);
-
- if (idx >= start_idx && idx < start_idx + max_num_domains) {
- dom = talloc_zero(ctx, sizeof(*dom));
- if (!dom) {
- /* free returned tdb record */
- SAFE_FREE(pass);
-
- return NT_STATUS_NO_MEMORY;
- }
-
- /* copy domain sid */
- SMB_ASSERT(sizeof(dom->sid) == sizeof(pass->domain_sid));
- memcpy(&(dom->sid), &(pass->domain_sid), sizeof(dom->sid));
-
- /* copy unicode domain name */
- dom->name = talloc_strdup_w(ctx, pass->uni_name);
-
- (*domains)[idx - start_idx] = dom;
-
- DEBUG(18, ("Secret record is in required range.\n \
- start_idx = %d, max_num_domains = %d. Added to returned array.\n",
- start_idx, max_num_domains));
-
- *enum_ctx = idx + 1;
- (*num_domains)++;
-
- /* set proper status code to return */
- if (k->next) {
- /* there are yet some entries to enumerate */
- status = STATUS_MORE_ENTRIES;
- } else {
- /* this is the last entry in the whole enumeration */
- status = NT_STATUS_OK;
- }
- } else {
- DEBUG(18, ("Secret is outside the required range.\n \
- start_idx = %d, max_num_domains = %d. Not added to returned array\n",
- start_idx, max_num_domains));
- }
-
- idx++;
-
- /* free returned tdb record */
- SAFE_FREE(pass);
+ ldb = secrets_db_connect(mem_ctx);
+ if (ldb == NULL) {
+ DEBUG(5, ("secrets_db_connect failed\n"));
+ goto done;
}
-
- DEBUG(5, ("secrets_get_trusted_domains: got %d domains\n", *num_domains));
-
- /* free the results of searching the keys */
- tdb_search_list_free(keys);
- return status;
-}
+ ldb_ret = gendb_search(ldb, ldb,
+ ldb_dn_explode(mem_ctx, SECRETS_PRIMARY_DOMAIN_DN),
+ &msgs, attrs,
+ SECRETS_PRIMARY_DOMAIN_FILTER, domain);
-/*******************************************************************************
- Lock the secrets tdb based on a string - this is used as a primitive form of mutex
- between smbd instances.
-*******************************************************************************/
-
-BOOL secrets_named_mutex(const char *name, unsigned int timeout, size_t *p_ref_count)
-{
- size_t ref_count = *p_ref_count;
- int ret = 0;
-
- if (!message_init())
- return False;
-
- if (ref_count == 0) {
- ret = tdb_lock_bystring(tdb, name, timeout);
- if (ret == 0)
- DEBUG(10,("secrets_named_mutex: got mutex for %s\n", name ));
+ if (ldb_ret == 0) {
+ DEBUG(5, ("Did not find domain record for %s\n", domain));
+ goto done;
}
- if (ret == 0) {
- *p_ref_count = ++ref_count;
- DEBUG(10,("secrets_named_mutex: ref_count for mutex %s = %u\n", name, (unsigned int)ref_count ));
+ if (ldb_ret > 1) {
+ DEBUG(5, ("Found more than one (%d) domain records for %s\n",
+ ldb_ret, domain));
+ goto done;
}
- return (ret == 0);
-}
-/*******************************************************************************
- Unlock a named mutex.
-*******************************************************************************/
-
-void secrets_named_mutex_release(const char *name, size_t *p_ref_count)
-{
- size_t ref_count = *p_ref_count;
-
- SMB_ASSERT(ref_count != 0);
-
- if (ref_count == 1) {
- tdb_unlock_bystring(tdb, name);
- DEBUG(10,("secrets_named_mutex: released mutex for %s\n", name ));
+ result = samdb_result_dom_sid(mem_ctx, msgs[0], "objectSid");
+ if (result == NULL) {
+ DEBUG(0, ("Domain object for %s does not contain a SID!\n",
+ domain));
+ goto done;
}
- *p_ref_count = --ref_count;
- DEBUG(10,("secrets_named_mutex_release: ref_count for mutex %s = %u\n", name, (unsigned int)ref_count ));
+ done:
+ talloc_free(ldb);
+ return result;
}
-