Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : User credentials handling (as regards on-disk files)
5 :
6 : Copyright (C) Jelmer Vernooij 2005
7 : Copyright (C) Tim Potter 2001
8 : Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
9 :
10 : This program is free software; you can redistribute it and/or modify
11 : it under the terms of the GNU General Public License as published by
12 : the Free Software Foundation; either version 3 of the License, or
13 : (at your option) any later version.
14 :
15 : This program is distributed in the hope that it will be useful,
16 : but WITHOUT ANY WARRANTY; without even the implied warranty of
17 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 : GNU General Public License for more details.
19 :
20 : You should have received a copy of the GNU General Public License
21 : along with this program. If not, see <http://www.gnu.org/licenses/>.
22 : */
23 :
24 : #include "includes.h"
25 : #include "lib/events/events.h"
26 : #include <ldb.h>
27 : #include "librpc/gen_ndr/samr.h" /* for struct samrPassword */
28 : #include "param/secrets.h"
29 : #include "system/filesys.h"
30 : #include "auth/credentials/credentials.h"
31 : #include "auth/credentials/credentials_internal.h"
32 : #include "auth/credentials/credentials_krb5.h"
33 : #include "auth/kerberos/kerberos_util.h"
34 : #include "param/param.h"
35 : #include "lib/events/events.h"
36 : #include "dsdb/samdb/samdb.h"
37 : #include "source3/include/secrets.h"
38 : #include "dbwrap/dbwrap.h"
39 : #include "dbwrap/dbwrap_open.h"
40 : #include "lib/util/util_tdb.h"
41 : #include "libds/common/roles.h"
42 :
43 : #undef DBGC_CLASS
44 : #define DBGC_CLASS DBGC_AUTH
45 :
46 : /**
47 : * Fill in credentials for the machine trust account, from the secrets database.
48 : *
49 : * @param cred Credentials structure to fill in
50 : * @retval NTSTATUS error detailing any failure
51 : */
52 41522 : static NTSTATUS cli_credentials_set_secrets_lct(struct cli_credentials *cred,
53 : struct loadparm_context *lp_ctx,
54 : struct ldb_context *ldb,
55 : const char *base,
56 : const char *filter,
57 : time_t secrets_tdb_last_change_time,
58 : const char *secrets_tdb_password,
59 : char **error_string)
60 : {
61 : TALLOC_CTX *mem_ctx;
62 :
63 : int ldb_ret;
64 : struct ldb_message *msg;
65 :
66 : const char *machine_account;
67 : const char *password;
68 : const char *domain;
69 : const char *realm;
70 : enum netr_SchannelType sct;
71 : const char *salt_principal;
72 : char *keytab;
73 : const struct ldb_val *whenChanged;
74 : time_t lct;
75 :
76 : /* ok, we are going to get it now, don't recurse back here */
77 41522 : cred->machine_account_pending = false;
78 :
79 : /* some other parts of the system will key off this */
80 41522 : cred->machine_account = true;
81 :
82 41522 : mem_ctx = talloc_named(cred, 0, "cli_credentials_set_secrets from ldb");
83 :
84 41522 : if (!ldb) {
85 : /* Local secrets are stored in secrets.ldb */
86 41522 : ldb = secrets_db_connect(mem_ctx, lp_ctx);
87 41522 : if (!ldb) {
88 613 : *error_string = talloc_strdup(cred, "Could not open secrets.ldb");
89 613 : talloc_free(mem_ctx);
90 613 : return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
91 : }
92 : }
93 :
94 40909 : ldb_ret = dsdb_search_one(ldb, mem_ctx, &msg,
95 : ldb_dn_new(mem_ctx, ldb, base),
96 : LDB_SCOPE_SUBTREE,
97 : NULL, 0, "%s", filter);
98 :
99 40909 : if (ldb_ret != LDB_SUCCESS) {
100 18 : *error_string = talloc_asprintf(cred, "Could not find entry to match filter: '%s' base: '%s': %s: %s",
101 : filter, base ? base : "",
102 : ldb_strerror(ldb_ret), ldb_errstring(ldb));
103 18 : talloc_free(mem_ctx);
104 18 : return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
105 : }
106 :
107 40891 : password = ldb_msg_find_attr_as_string(msg, "secret", NULL);
108 :
109 40891 : whenChanged = ldb_msg_find_ldb_val(msg, "whenChanged");
110 40891 : if (!whenChanged || ldb_val_to_time(whenChanged, &lct) != LDB_SUCCESS) {
111 : /* This attribute is mandatory */
112 0 : talloc_free(mem_ctx);
113 0 : return NT_STATUS_NOT_FOUND;
114 : }
115 :
116 : /* Don't set secrets.ldb info if the secrets.tdb entry was more recent */
117 40891 : if (lct < secrets_tdb_last_change_time) {
118 0 : talloc_free(mem_ctx);
119 0 : return NT_STATUS_NOT_FOUND;
120 : }
121 :
122 40891 : if ((lct == secrets_tdb_last_change_time) &&
123 40885 : (secrets_tdb_password != NULL) &&
124 40885 : (password != NULL) &&
125 40885 : (strcmp(password, secrets_tdb_password) != 0)) {
126 0 : talloc_free(mem_ctx);
127 0 : return NT_STATUS_NOT_FOUND;
128 : }
129 :
130 40891 : cli_credentials_set_password_last_changed_time(cred, lct);
131 :
132 40891 : machine_account = ldb_msg_find_attr_as_string(msg, "samAccountName", NULL);
133 :
134 40891 : if (!machine_account) {
135 0 : machine_account = ldb_msg_find_attr_as_string(msg, "servicePrincipalName", NULL);
136 :
137 0 : if (!machine_account) {
138 0 : const char *ldap_bind_dn = ldb_msg_find_attr_as_string(msg, "ldapBindDn", NULL);
139 0 : if (!ldap_bind_dn) {
140 0 : *error_string = talloc_asprintf(cred,
141 : "Could not find 'samAccountName', "
142 : "'servicePrincipalName' or "
143 : "'ldapBindDn' in secrets record: %s",
144 0 : ldb_dn_get_linearized(msg->dn));
145 0 : talloc_free(mem_ctx);
146 0 : return NT_STATUS_CANT_ACCESS_DOMAIN_INFO;
147 : } else {
148 : /* store bind dn in credentials */
149 0 : cli_credentials_set_bind_dn(cred, ldap_bind_dn);
150 : }
151 : }
152 : }
153 :
154 40891 : salt_principal = ldb_msg_find_attr_as_string(msg, "saltPrincipal", NULL);
155 40891 : cli_credentials_set_salt_principal(cred, salt_principal);
156 :
157 40891 : sct = ldb_msg_find_attr_as_int(msg, "secureChannelType", 0);
158 40891 : if (sct) {
159 40889 : cli_credentials_set_secure_channel_type(cred, sct);
160 : }
161 :
162 40891 : if (!password) {
163 0 : const struct ldb_val *nt_password_hash = ldb_msg_find_ldb_val(msg, "unicodePwd");
164 : struct samr_Password hash;
165 0 : ZERO_STRUCT(hash);
166 0 : if (nt_password_hash) {
167 0 : memcpy(hash.hash, nt_password_hash->data,
168 0 : MIN(nt_password_hash->length, sizeof(hash.hash)));
169 :
170 0 : cli_credentials_set_nt_hash(cred, &hash, CRED_SPECIFIED);
171 : } else {
172 0 : cli_credentials_set_password(cred, NULL, CRED_SPECIFIED);
173 : }
174 : } else {
175 40891 : cli_credentials_set_password(cred, password, CRED_SPECIFIED);
176 : }
177 :
178 40891 : domain = ldb_msg_find_attr_as_string(msg, "flatname", NULL);
179 40891 : if (domain) {
180 40889 : cli_credentials_set_domain(cred, domain, CRED_SPECIFIED);
181 : }
182 :
183 40891 : realm = ldb_msg_find_attr_as_string(msg, "realm", NULL);
184 40891 : if (realm) {
185 40891 : cli_credentials_set_realm(cred, realm, CRED_SPECIFIED);
186 : }
187 :
188 40891 : if (machine_account) {
189 40891 : cli_credentials_set_username(cred, machine_account, CRED_SPECIFIED);
190 : }
191 :
192 40891 : cli_credentials_set_kvno(cred, ldb_msg_find_attr_as_int(msg, "msDS-KeyVersionNumber", 0));
193 :
194 : /* If there was an external keytab specified by reference in
195 : * the LDB, then use this. Otherwise we will make one up
196 : * (chewing CPU time) from the password */
197 40891 : keytab = keytab_name_from_msg(cred, ldb, msg);
198 40891 : if (keytab) {
199 40891 : cli_credentials_set_keytab_name(cred, lp_ctx, keytab, CRED_SPECIFIED);
200 40891 : talloc_free(keytab);
201 : }
202 40891 : talloc_free(mem_ctx);
203 :
204 40891 : return NT_STATUS_OK;
205 : }
206 :
207 :
208 : /**
209 : * Fill in credentials for the machine trust account, from the secrets database.
210 : *
211 : * @param cred Credentials structure to fill in
212 : * @retval NTSTATUS error detailing any failure
213 : */
214 0 : _PUBLIC_ NTSTATUS cli_credentials_set_secrets(struct cli_credentials *cred,
215 : struct loadparm_context *lp_ctx,
216 : struct ldb_context *ldb,
217 : const char *base,
218 : const char *filter,
219 : char **error_string)
220 : {
221 0 : NTSTATUS status = cli_credentials_set_secrets_lct(cred, lp_ctx, ldb, base, filter, 0, NULL, error_string);
222 0 : if (!NT_STATUS_IS_OK(status)) {
223 : /* set anonymous as the fallback, if the machine account won't work */
224 0 : cli_credentials_set_anonymous(cred);
225 : }
226 0 : return status;
227 : }
228 :
229 : /**
230 : * Fill in credentials for the machine trust account, from the secrets database.
231 : *
232 : * @param cred Credentials structure to fill in
233 : * @retval NTSTATUS error detailing any failure
234 : */
235 41402 : _PUBLIC_ NTSTATUS cli_credentials_set_machine_account(struct cli_credentials *cred,
236 : struct loadparm_context *lp_ctx)
237 : {
238 : struct db_context *db_ctx;
239 : char *secrets_tdb_path;
240 : int hash_size, tdb_flags;
241 :
242 41402 : secrets_tdb_path = lpcfg_private_db_path(cred, lp_ctx, "secrets");
243 41402 : if (secrets_tdb_path == NULL) {
244 0 : return NT_STATUS_NO_MEMORY;
245 : }
246 :
247 41402 : hash_size = lpcfg_tdb_hash_size(lp_ctx, secrets_tdb_path);
248 41402 : tdb_flags = lpcfg_tdb_flags(lp_ctx, TDB_DEFAULT);
249 :
250 41402 : db_ctx = dbwrap_local_open(
251 : cred,
252 : secrets_tdb_path,
253 : hash_size,
254 : tdb_flags,
255 : O_RDWR,
256 : 0600,
257 : DBWRAP_LOCK_ORDER_1,
258 : DBWRAP_FLAG_NONE);
259 41402 : TALLOC_FREE(secrets_tdb_path);
260 :
261 : /*
262 : * We do not check for errors here, we might not have a
263 : * secrets.tdb at all, and so we just need to check the
264 : * secrets.ldb
265 : */
266 41402 : return cli_credentials_set_machine_account_db_ctx(cred, lp_ctx, db_ctx);
267 : }
268 :
269 : /**
270 : * Fill in credentials for the machine trust account, from the
271 : * secrets.ldb or passed in handle to secrets.tdb (perhaps in CTDB).
272 : *
273 : * This version is used in parts of the code that can link in the
274 : * CTDB dbwrap backend, by passing down the already open handle.
275 : *
276 : * @param cred Credentials structure to fill in
277 : * @param db_ctx dbwrap context for secrets.tdb
278 : * @retval NTSTATUS error detailing any failure
279 : */
280 41520 : _PUBLIC_ NTSTATUS cli_credentials_set_machine_account_db_ctx(struct cli_credentials *cred,
281 : struct loadparm_context *lp_ctx,
282 : struct db_context *db_ctx)
283 : {
284 : NTSTATUS status;
285 : char *filter;
286 41520 : char *error_string = NULL;
287 : const char *domain;
288 : bool secrets_tdb_password_more_recent;
289 41520 : time_t secrets_tdb_lct = 0;
290 41520 : char *secrets_tdb_password = NULL;
291 41520 : char *secrets_tdb_old_password = NULL;
292 41520 : uint32_t secrets_tdb_secure_channel_type = SEC_CHAN_NULL;
293 41520 : int server_role = lpcfg_server_role(lp_ctx);
294 41520 : int security = lpcfg_security(lp_ctx);
295 : char *keystr;
296 41520 : char *keystr_upper = NULL;
297 41520 : TALLOC_CTX *tmp_ctx = talloc_named(cred, 0, "cli_credentials_set_secrets from ldb");
298 41520 : if (!tmp_ctx) {
299 0 : return NT_STATUS_NO_MEMORY;
300 : }
301 :
302 : /* Bleh, nasty recursion issues: We are setting a machine
303 : * account here, so we don't want the 'pending' flag around
304 : * any more */
305 41520 : cred->machine_account_pending = false;
306 :
307 : /* We have to do this, as the fallback in
308 : * cli_credentials_set_secrets is to run as anonymous, so the domain is wiped */
309 41520 : domain = cli_credentials_get_domain(cred);
310 :
311 41520 : if (db_ctx) {
312 : TDB_DATA dbuf;
313 40997 : keystr = talloc_asprintf(tmp_ctx, "%s/%s",
314 : SECRETS_MACHINE_LAST_CHANGE_TIME,
315 : domain);
316 40997 : keystr_upper = strupper_talloc(tmp_ctx, keystr);
317 40997 : status = dbwrap_fetch(db_ctx, tmp_ctx, string_tdb_data(keystr_upper),
318 : &dbuf);
319 40997 : if (NT_STATUS_IS_OK(status) && dbuf.dsize == 4) {
320 40978 : secrets_tdb_lct = IVAL(dbuf.dptr,0);
321 : }
322 :
323 40997 : keystr = talloc_asprintf(tmp_ctx, "%s/%s",
324 : SECRETS_MACHINE_PASSWORD,
325 : domain);
326 40997 : keystr_upper = strupper_talloc(tmp_ctx, keystr);
327 40997 : status = dbwrap_fetch(db_ctx, tmp_ctx, string_tdb_data(keystr_upper),
328 : &dbuf);
329 40997 : if (NT_STATUS_IS_OK(status)) {
330 40978 : secrets_tdb_password = (char *)dbuf.dptr;
331 : }
332 :
333 40997 : keystr = talloc_asprintf(tmp_ctx, "%s/%s",
334 : SECRETS_MACHINE_PASSWORD_PREV,
335 : domain);
336 40997 : keystr_upper = strupper_talloc(tmp_ctx, keystr);
337 40997 : status = dbwrap_fetch(db_ctx, tmp_ctx, string_tdb_data(keystr_upper),
338 : &dbuf);
339 40997 : if (NT_STATUS_IS_OK(status)) {
340 1824 : secrets_tdb_old_password = (char *)dbuf.dptr;
341 : }
342 :
343 40997 : keystr = talloc_asprintf(tmp_ctx, "%s/%s",
344 : SECRETS_MACHINE_SEC_CHANNEL_TYPE,
345 : domain);
346 40997 : keystr_upper = strupper_talloc(tmp_ctx, keystr);
347 40997 : status = dbwrap_fetch(db_ctx, tmp_ctx, string_tdb_data(keystr_upper),
348 : &dbuf);
349 40997 : if (NT_STATUS_IS_OK(status) && dbuf.dsize == 4) {
350 40978 : secrets_tdb_secure_channel_type = IVAL(dbuf.dptr,0);
351 : }
352 : }
353 :
354 41520 : filter = talloc_asprintf(cred, SECRETS_PRIMARY_DOMAIN_FILTER,
355 : domain);
356 41520 : status = cli_credentials_set_secrets_lct(cred, lp_ctx, NULL,
357 : SECRETS_PRIMARY_DOMAIN_DN,
358 : filter, secrets_tdb_lct, secrets_tdb_password, &error_string);
359 41520 : if (secrets_tdb_password == NULL) {
360 542 : secrets_tdb_password_more_recent = false;
361 40978 : } else if (NT_STATUS_EQUAL(NT_STATUS_CANT_ACCESS_DOMAIN_INFO, status)
362 40885 : || NT_STATUS_EQUAL(NT_STATUS_NOT_FOUND, status)) {
363 93 : secrets_tdb_password_more_recent = true;
364 40885 : } else if (secrets_tdb_lct > cli_credentials_get_password_last_changed_time(cred)) {
365 0 : secrets_tdb_password_more_recent = true;
366 40885 : } else if (secrets_tdb_lct == cli_credentials_get_password_last_changed_time(cred)) {
367 40885 : secrets_tdb_password_more_recent = strcmp(secrets_tdb_password, cli_credentials_get_password(cred)) != 0;
368 : } else {
369 0 : secrets_tdb_password_more_recent = false;
370 : }
371 :
372 41520 : if (secrets_tdb_password_more_recent) {
373 93 : enum credentials_use_kerberos use_kerberos =
374 : CRED_USE_KERBEROS_DISABLED;
375 93 : char *machine_account = talloc_asprintf(tmp_ctx, "%s$", lpcfg_netbios_name(lp_ctx));
376 93 : cli_credentials_set_password(cred, secrets_tdb_password, CRED_SPECIFIED);
377 93 : cli_credentials_set_old_password(cred, secrets_tdb_old_password, CRED_SPECIFIED);
378 93 : cli_credentials_set_domain(cred, domain, CRED_SPECIFIED);
379 93 : if (strequal(domain, lpcfg_workgroup(lp_ctx))) {
380 93 : cli_credentials_set_realm(cred, lpcfg_realm(lp_ctx), CRED_SPECIFIED);
381 :
382 93 : switch (server_role) {
383 93 : case ROLE_DOMAIN_MEMBER:
384 93 : if (security != SEC_ADS) {
385 3 : break;
386 : }
387 :
388 : FALL_THROUGH;
389 : case ROLE_ACTIVE_DIRECTORY_DC:
390 90 : use_kerberos = CRED_USE_KERBEROS_DESIRED;
391 90 : break;
392 : }
393 : }
394 93 : cli_credentials_set_kerberos_state(cred,
395 : use_kerberos,
396 : CRED_SPECIFIED);
397 93 : cli_credentials_set_username(cred, machine_account, CRED_SPECIFIED);
398 93 : cli_credentials_set_password_last_changed_time(cred, secrets_tdb_lct);
399 93 : cli_credentials_set_secure_channel_type(cred, secrets_tdb_secure_channel_type);
400 93 : status = NT_STATUS_OK;
401 41427 : } else if (!NT_STATUS_IS_OK(status)) {
402 538 : if (db_ctx) {
403 : error_string
404 36 : = talloc_asprintf(cred,
405 : "Failed to fetch machine account password for %s from both "
406 : "secrets.ldb (%s) and from %s",
407 : domain,
408 18 : error_string == NULL ? "error" : error_string,
409 : dbwrap_name(db_ctx));
410 : } else {
411 : char *secrets_tdb_path;
412 :
413 520 : secrets_tdb_path = lpcfg_private_db_path(tmp_ctx,
414 : lp_ctx,
415 : "secrets");
416 520 : if (secrets_tdb_path == NULL) {
417 0 : return NT_STATUS_NO_MEMORY;
418 : }
419 :
420 520 : error_string = talloc_asprintf(cred,
421 : "Failed to fetch machine account password from "
422 : "secrets.ldb: %s and failed to open %s",
423 520 : error_string == NULL ? "error" : error_string,
424 : secrets_tdb_path);
425 : }
426 538 : DEBUG(1, ("Could not find machine account in secrets database: %s: %s\n",
427 : error_string == NULL ? "error" : error_string,
428 : nt_errstr(status)));
429 : /* set anonymous as the fallback, if the machine account won't work */
430 538 : cli_credentials_set_anonymous(cred);
431 : }
432 :
433 41520 : TALLOC_FREE(tmp_ctx);
434 41520 : return status;
435 : }
436 :
437 : /**
438 : * Fill in credentials for a particular principal, from the secrets database.
439 : *
440 : * @param cred Credentials structure to fill in
441 : * @retval NTSTATUS error detailing any failure
442 : */
443 2 : _PUBLIC_ NTSTATUS cli_credentials_set_stored_principal(struct cli_credentials *cred,
444 : struct loadparm_context *lp_ctx,
445 : const char *serviceprincipal)
446 : {
447 : NTSTATUS status;
448 : char *filter;
449 2 : char *error_string = NULL;
450 : /* Bleh, nasty recursion issues: We are setting a machine
451 : * account here, so we don't want the 'pending' flag around
452 : * any more */
453 2 : cred->machine_account_pending = false;
454 2 : filter = talloc_asprintf(cred, SECRETS_PRINCIPAL_SEARCH,
455 : cli_credentials_get_realm(cred),
456 : cli_credentials_get_domain(cred),
457 : serviceprincipal);
458 2 : status = cli_credentials_set_secrets_lct(cred, lp_ctx, NULL,
459 : SECRETS_PRINCIPALS_DN, filter,
460 : 0, NULL, &error_string);
461 2 : if (!NT_STATUS_IS_OK(status)) {
462 0 : DEBUG(1, ("Could not find %s principal in secrets database: %s: %s\n",
463 : serviceprincipal, nt_errstr(status),
464 : error_string ? error_string : "<no error>"));
465 : }
466 2 : return status;
467 : }
468 :
469 : /**
470 : * Ask that when required, the credentials system will be filled with
471 : * machine trust account, from the secrets database.
472 : *
473 : * @param cred Credentials structure to fill in
474 : * @note This function is used to call the above function after, rather
475 : * than during, popt processing.
476 : *
477 : */
478 4010 : _PUBLIC_ void cli_credentials_set_machine_account_pending(struct cli_credentials *cred,
479 : struct loadparm_context *lp_ctx)
480 : {
481 4010 : cred->machine_account_pending = true;
482 4010 : cred->machine_account_pending_lp_ctx = lp_ctx;
483 4010 : }
484 :
485 :
|