1/* 2 Unix SMB/CIFS implementation. 3 Copyright (C) Andrew Tridgell 1992-2001 4 Copyright (C) Andrew Bartlett 2002 5 Copyright (C) Rafal Szczesniak 2002 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 3 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program. If not, see <http://www.gnu.org/licenses/>. 19*/ 20 21/* the Samba secrets database stores any generated, private information 22 such as the local SID and machine trust password */ 23 24#include "includes.h" 25#include "secrets.h" 26#include "param/param.h" 27#include "system/filesys.h" 28#include "tdb_wrap.h" 29#include "lib/ldb/include/ldb.h" 30#include "../tdb/include/tdb.h" 31#include "../lib/util/util_tdb.h" 32#include "../lib/util/util_ldb.h" 33#include "librpc/gen_ndr/ndr_security.h" 34 35/** 36 * Use a TDB to store an incrementing random seed. 37 * 38 * Initialised to the current pid, the very first time Samba starts, 39 * and incremented by one each time it is needed. 40 * 41 * @note Not called by systems with a working /dev/urandom. 42 */ 43static void get_rand_seed(struct tdb_wrap *secretsdb, int *new_seed) 44{ 45 *new_seed = getpid(); 46 if (secretsdb != NULL) { 47 tdb_change_int32_atomic(secretsdb->tdb, "INFO/random_seed", new_seed, 1); 48 } 49} 50 51/** 52 * open up the secrets database 53 */ 54struct tdb_wrap *secrets_init(TALLOC_CTX *mem_ctx, struct loadparm_context *lp_ctx) 55{ 56 char *fname; 57 uint8_t dummy; 58 struct tdb_wrap *tdb; 59 60 fname = private_path(mem_ctx, lp_ctx, "secrets.tdb"); 61 62 tdb = tdb_wrap_open(mem_ctx, fname, 0, TDB_DEFAULT, O_RDWR|O_CREAT, 0600); 63 64 if (!tdb) { 65 DEBUG(0,("Failed to open %s\n", fname)); 66 talloc_free(fname); 67 return NULL; 68 } 69 talloc_free(fname); 70 71 /** 72 * Set a reseed function for the crypto random generator 73 * 74 * This avoids a problem where systems without /dev/urandom 75 * could send the same challenge to multiple clients 76 */ 77 set_rand_reseed_callback((void (*) (void *, int *))get_rand_seed, tdb); 78 79 /* Ensure that the reseed is done now, while we are root, etc */ 80 generate_random_buffer(&dummy, sizeof(dummy)); 81 82 return tdb; 83} 84 85/** 86 connect to the secrets ldb 87*/ 88struct ldb_context *secrets_db_connect(TALLOC_CTX *mem_ctx, 89 struct tevent_context *ev_ctx, 90 struct loadparm_context *lp_ctx) 91{ 92 char *path; 93 const char *url; 94 struct ldb_context *ldb; 95 96 url = lp_secrets_url(lp_ctx); 97 if (!url || !url[0]) { 98 return NULL; 99 } 100 101 path = private_path(mem_ctx, lp_ctx, url); 102 if (!path) { 103 return NULL; 104 } 105 106 /* Secrets.ldb *must* always be local. If we call for a 107 * system_session() we will recurse */ 108 ldb = ldb_init(mem_ctx, ev_ctx); 109 if (!ldb) { 110 talloc_free(path); 111 return NULL; 112 } 113 114 ldb_set_modules_dir(ldb, 115 talloc_asprintf(ldb, "%s/ldb", lp_modulesdir(lp_ctx))); 116 117 if (ldb_connect(ldb, path, 0, NULL) != 0) { 118 talloc_free(path); 119 return NULL; 120 } 121 122 /* the update_keytab module relies on this being setup */ 123 if (ldb_set_opaque(ldb, "loadparm", lp_ctx) != LDB_SUCCESS) { 124 talloc_free(path); 125 talloc_free(ldb); 126 return NULL; 127 } 128 129 talloc_free(path); 130 131 return ldb; 132} 133 134/** 135 * Retrieve the domain SID from the secrets database. 136 * @return pointer to a SID object if the SID could be obtained, NULL otherwise 137 */ 138struct dom_sid *secrets_get_domain_sid(TALLOC_CTX *mem_ctx, 139 struct tevent_context *ev_ctx, 140 struct loadparm_context *lp_ctx, 141 const char *domain) 142{ 143 struct ldb_context *ldb; 144 struct ldb_message **msgs; 145 int ldb_ret; 146 const char *attrs[] = { "objectSid", NULL }; 147 struct dom_sid *result = NULL; 148 const struct ldb_val *v; 149 enum ndr_err_code ndr_err; 150 151 ldb = secrets_db_connect(mem_ctx, ev_ctx, lp_ctx); 152 if (ldb == NULL) { 153 DEBUG(5, ("secrets_db_connect failed\n")); 154 return NULL; 155 } 156 157 ldb_ret = gendb_search(ldb, ldb, 158 ldb_dn_new(mem_ctx, ldb, SECRETS_PRIMARY_DOMAIN_DN), 159 &msgs, attrs, 160 SECRETS_PRIMARY_DOMAIN_FILTER, domain); 161 162 if (ldb_ret == -1) { 163 DEBUG(5, ("Error searching for domain SID for %s: %s", 164 domain, ldb_errstring(ldb))); 165 talloc_free(ldb); 166 return NULL; 167 } 168 169 if (ldb_ret == 0) { 170 DEBUG(5, ("Did not find domain record for %s\n", domain)); 171 talloc_free(ldb); 172 return NULL; 173 } 174 175 if (ldb_ret > 1) { 176 DEBUG(5, ("Found more than one (%d) domain records for %s\n", 177 ldb_ret, domain)); 178 talloc_free(ldb); 179 return NULL; 180 } 181 182 v = ldb_msg_find_ldb_val(msgs[0], "objectSid"); 183 if (v == NULL) { 184 DEBUG(0, ("Domain object for %s does not contain a SID!\n", 185 domain)); 186 return NULL; 187 } 188 result = talloc(mem_ctx, struct dom_sid); 189 if (result == NULL) { 190 talloc_free(ldb); 191 return NULL; 192 } 193 194 ndr_err = ndr_pull_struct_blob(v, result, NULL, result, 195 (ndr_pull_flags_fn_t)ndr_pull_dom_sid); 196 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) { 197 talloc_free(result); 198 talloc_free(ldb); 199 return NULL; 200 } 201 202 return result; 203} 204