Line data Source code
1 : /*
2 : Unix SMB/CIFS implementation.
3 :
4 : Copyright (C) Guenther Deschner <gd@samba.org> 2008
5 : Copyright (C) Michael Adam 2008
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 : #include "includes.h"
22 : #include "smb_krb5.h"
23 : #include "libnet/libnet_dssync.h"
24 : #include "libnet/libnet_keytab.h"
25 : #include "librpc/gen_ndr/ndr_drsblobs.h"
26 : #include "lib/crypto/md4.h"
27 :
28 : #if defined(HAVE_ADS)
29 :
30 0 : static NTSTATUS keytab_startup(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
31 : struct replUpToDateVectorBlob **pold_utdv)
32 : {
33 0 : krb5_error_code ret = 0;
34 0 : struct libnet_keytab_context *keytab_ctx;
35 0 : struct libnet_keytab_entry *entry;
36 0 : struct replUpToDateVectorBlob *old_utdv = NULL;
37 0 : char *principal;
38 :
39 0 : ret = libnet_keytab_init(mem_ctx, ctx->output_filename, &keytab_ctx);
40 0 : if (ret) {
41 0 : return krb5_to_nt_status(ret);
42 : }
43 :
44 0 : keytab_ctx->dns_domain_name = ctx->dns_domain_name;
45 0 : keytab_ctx->clean_old_entries = ctx->clean_old_entries;
46 0 : ctx->private_data = keytab_ctx;
47 :
48 0 : principal = talloc_asprintf(mem_ctx, "UTDV/%s@%s",
49 : ctx->nc_dn, ctx->dns_domain_name);
50 0 : NT_STATUS_HAVE_NO_MEMORY(principal);
51 :
52 0 : entry = libnet_keytab_search(keytab_ctx, principal, 0, ENCTYPE_NULL,
53 : mem_ctx);
54 0 : if (entry) {
55 0 : enum ndr_err_code ndr_err;
56 0 : old_utdv = talloc(mem_ctx, struct replUpToDateVectorBlob);
57 :
58 0 : ndr_err = ndr_pull_struct_blob(&entry->password, old_utdv, old_utdv,
59 : (ndr_pull_flags_fn_t)ndr_pull_replUpToDateVectorBlob);
60 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
61 0 : NTSTATUS status = ndr_map_error2ntstatus(ndr_err);
62 0 : ctx->error_message = talloc_asprintf(ctx,
63 : "Failed to pull UpToDateVector: %s",
64 : nt_errstr(status));
65 0 : return status;
66 : }
67 :
68 0 : if (DEBUGLEVEL >= 10) {
69 0 : NDR_PRINT_DEBUG(replUpToDateVectorBlob, old_utdv);
70 : }
71 : }
72 :
73 0 : if (pold_utdv) {
74 0 : *pold_utdv = old_utdv;
75 : }
76 :
77 0 : return NT_STATUS_OK;
78 : }
79 :
80 0 : static NTSTATUS keytab_finish(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
81 : struct replUpToDateVectorBlob *new_utdv)
82 : {
83 0 : NTSTATUS status = NT_STATUS_OK;
84 0 : krb5_error_code ret = 0;
85 0 : struct libnet_keytab_context *keytab_ctx =
86 : (struct libnet_keytab_context *)ctx->private_data;
87 :
88 0 : if (new_utdv) {
89 0 : enum ndr_err_code ndr_err;
90 0 : DATA_BLOB blob;
91 :
92 0 : if (DEBUGLEVEL >= 10) {
93 0 : NDR_PRINT_DEBUG(replUpToDateVectorBlob, new_utdv);
94 : }
95 :
96 0 : ndr_err = ndr_push_struct_blob(&blob, mem_ctx, new_utdv,
97 : (ndr_push_flags_fn_t)ndr_push_replUpToDateVectorBlob);
98 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
99 0 : status = ndr_map_error2ntstatus(ndr_err);
100 0 : ctx->error_message = talloc_asprintf(ctx,
101 : "Failed to push UpToDateVector: %s",
102 : nt_errstr(status));
103 0 : goto done;
104 : }
105 :
106 0 : status = libnet_keytab_add_to_keytab_entries(mem_ctx, keytab_ctx, 0,
107 : ctx->nc_dn, "UTDV",
108 : ENCTYPE_NULL,
109 : blob);
110 0 : if (!NT_STATUS_IS_OK(status)) {
111 0 : goto done;
112 : }
113 : }
114 :
115 0 : ret = libnet_keytab_add(keytab_ctx);
116 0 : if (ret) {
117 0 : status = krb5_to_nt_status(ret);
118 0 : ctx->error_message = talloc_asprintf(ctx,
119 : "Failed to add entries to keytab %s: %s",
120 : keytab_ctx->keytab_name, error_message(ret));
121 0 : goto done;
122 : }
123 :
124 0 : ctx->result_message = talloc_asprintf(ctx,
125 : "Vampired %d accounts to keytab %s",
126 : keytab_ctx->count,
127 : keytab_ctx->keytab_name);
128 :
129 0 : done:
130 0 : TALLOC_FREE(keytab_ctx);
131 0 : return status;
132 : }
133 :
134 : /****************************************************************
135 : ****************************************************************/
136 :
137 0 : static NTSTATUS parse_supplemental_credentials(TALLOC_CTX *mem_ctx,
138 : const DATA_BLOB *blob,
139 : struct package_PrimaryKerberosCtr3 **pkb3,
140 : struct package_PrimaryKerberosCtr4 **pkb4)
141 : {
142 0 : NTSTATUS status;
143 0 : enum ndr_err_code ndr_err;
144 0 : struct supplementalCredentialsBlob scb;
145 0 : struct supplementalCredentialsPackage *scpk = NULL;
146 0 : DATA_BLOB scpk_blob;
147 0 : struct package_PrimaryKerberosBlob *pkb;
148 0 : bool newer_keys = false;
149 0 : uint32_t j;
150 :
151 0 : ndr_err = ndr_pull_struct_blob_all(blob, mem_ctx, &scb,
152 : (ndr_pull_flags_fn_t)ndr_pull_supplementalCredentialsBlob);
153 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
154 0 : status = ndr_map_error2ntstatus(ndr_err);
155 0 : goto done;
156 : }
157 0 : if ((scb.sub.signature != SUPPLEMENTAL_CREDENTIALS_SIGNATURE)
158 0 : && (scb.sub.num_packages != 0))
159 : {
160 0 : if (DEBUGLEVEL >= 10) {
161 0 : NDR_PRINT_DEBUG(supplementalCredentialsBlob, &scb);
162 : }
163 0 : status = NT_STATUS_INVALID_PARAMETER;
164 0 : goto done;
165 : }
166 0 : for (j=0; j < scb.sub.num_packages; j++) {
167 0 : if (strcmp("Primary:Kerberos-Newer-Keys",
168 0 : scb.sub.packages[j].name) == 0)
169 : {
170 0 : scpk = &scb.sub.packages[j];
171 0 : if (!scpk->data || !scpk->data[0]) {
172 0 : scpk = NULL;
173 0 : continue;
174 : }
175 0 : newer_keys = true;
176 0 : break;
177 0 : } else if (strcmp("Primary:Kerberos",
178 0 : scb.sub.packages[j].name) == 0)
179 : {
180 : /*
181 : * grab this but don't break here:
182 : * there might still be newer-keys ...
183 : */
184 0 : scpk = &scb.sub.packages[j];
185 0 : if (!scpk->data || !scpk->data[0]) {
186 0 : scpk = NULL;
187 : }
188 : }
189 : }
190 :
191 0 : if (!scpk) {
192 : /* no data */
193 0 : status = NT_STATUS_OK;
194 0 : goto done;
195 : }
196 :
197 0 : scpk_blob = strhex_to_data_blob(mem_ctx, scpk->data);
198 0 : if (!scpk_blob.data) {
199 0 : status = NT_STATUS_NO_MEMORY;
200 0 : goto done;
201 : }
202 :
203 0 : pkb = talloc_zero(mem_ctx, struct package_PrimaryKerberosBlob);
204 0 : if (!pkb) {
205 0 : status = NT_STATUS_NO_MEMORY;
206 0 : goto done;
207 : }
208 0 : ndr_err = ndr_pull_struct_blob(&scpk_blob, mem_ctx, pkb,
209 : (ndr_pull_flags_fn_t)ndr_pull_package_PrimaryKerberosBlob);
210 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
211 0 : status = ndr_map_error2ntstatus(ndr_err);
212 0 : goto done;
213 : }
214 :
215 0 : if (!newer_keys && pkb->version != 3) {
216 0 : status = NT_STATUS_INVALID_PARAMETER;
217 0 : goto done;
218 : }
219 :
220 0 : if (newer_keys && pkb->version != 4) {
221 0 : status = NT_STATUS_INVALID_PARAMETER;
222 0 : goto done;
223 : }
224 :
225 0 : if (pkb->version == 4 && pkb4) {
226 0 : *pkb4 = &pkb->ctr.ctr4;
227 0 : } else if (pkb->version == 3 && pkb3) {
228 0 : *pkb3 = &pkb->ctr.ctr3;
229 : }
230 :
231 0 : status = NT_STATUS_OK;
232 :
233 0 : done:
234 0 : return status;
235 : }
236 :
237 0 : static NTSTATUS store_or_fetch_attribute(TALLOC_CTX *mem_ctx,
238 : struct libnet_keytab_context *ctx,
239 : const char *object_dn,
240 : const char *attr,
241 : char **value)
242 : {
243 0 : DATA_BLOB blob = { .length = 0, };
244 0 : NTSTATUS status;
245 :
246 0 : if (*value == NULL) {
247 : /* look into keytab ... */
248 0 : struct libnet_keytab_entry *entry = NULL;
249 0 : char *principal = NULL;
250 :
251 0 : D_DEBUG("looking for %s/%s@%s in keytayb...\n",
252 : attr, object_dn, ctx->dns_domain_name);
253 :
254 0 : principal = talloc_asprintf(mem_ctx,
255 : "%s/%s@%s",
256 : attr,
257 : object_dn,
258 : ctx->dns_domain_name);
259 0 : if (principal == NULL) {
260 0 : return NT_STATUS_NO_MEMORY;
261 : }
262 0 : entry = libnet_keytab_search(ctx,
263 : principal,
264 : 0,
265 : ENCTYPE_NULL,
266 : mem_ctx);
267 0 : if (entry != NULL) {
268 0 : *value = talloc_strndup(mem_ctx,
269 0 : (char *)entry->password.data,
270 : entry->password.length);
271 0 : if (*value == NULL) {
272 0 : return NT_STATUS_NO_MEMORY;
273 : }
274 0 : D_DEBUG("found %s: %s\n", attr, *value);
275 0 : TALLOC_FREE(entry);
276 : } else {
277 0 : *value = NULL;
278 0 : D_DEBUG("entry not found\n");
279 : }
280 0 : TALLOC_FREE(principal);
281 0 : return NT_STATUS_OK;
282 : }
283 :
284 0 : blob = data_blob_string_const_null(*value);
285 0 : blob = data_blob_dup_talloc(mem_ctx, blob);
286 0 : if (blob.data == NULL) {
287 0 : return NT_STATUS_NO_MEMORY;
288 : }
289 :
290 0 : status = libnet_keytab_add_to_keytab_entries(mem_ctx,
291 : ctx,
292 : 0,
293 : object_dn,
294 : attr,
295 : ENCTYPE_NULL,
296 : blob);
297 0 : if (!NT_STATUS_IS_OK(status)) {
298 0 : return status;
299 : }
300 :
301 0 : return NT_STATUS_OK;
302 : }
303 :
304 0 : static NTSTATUS parse_user(TALLOC_CTX *mem_ctx,
305 : struct libnet_keytab_context *ctx,
306 : struct drsuapi_DsReplicaObjectListItemEx *cur)
307 : {
308 0 : NTSTATUS status = NT_STATUS_OK;
309 0 : uchar nt_passwd[16];
310 0 : DATA_BLOB *blob;
311 0 : int i = 0;
312 0 : struct drsuapi_DsReplicaAttribute *attr;
313 0 : bool got_pwd = false;
314 :
315 0 : struct package_PrimaryKerberosCtr3 *pkb3 = NULL;
316 0 : struct package_PrimaryKerberosCtr4 *pkb4 = NULL;
317 :
318 0 : char *object_dn = NULL;
319 0 : char *upn = NULL;
320 0 : char **spn = NULL;
321 0 : uint32_t num_spns = 0;
322 0 : char *name = NULL;
323 0 : uint32_t kvno = 0;
324 0 : uint32_t uacc = 0;
325 0 : uint32_t sam_type = 0;
326 :
327 0 : uint32_t pwd_history_len = 0;
328 0 : uint8_t *pwd_history = NULL;
329 :
330 0 : ZERO_STRUCT(nt_passwd);
331 :
332 0 : object_dn = talloc_strdup(mem_ctx, cur->object.identifier->dn);
333 0 : if (!object_dn) {
334 0 : return NT_STATUS_NO_MEMORY;
335 : }
336 :
337 0 : DEBUG(3, ("parsing user '%s'\n", object_dn));
338 :
339 0 : for (i=0; i < cur->object.attribute_ctr.num_attributes; i++) {
340 :
341 0 : attr = &cur->object.attribute_ctr.attributes[i];
342 :
343 0 : if (attr->attid == DRSUAPI_ATTID_servicePrincipalName) {
344 0 : uint32_t count;
345 0 : num_spns = attr->value_ctr.num_values;
346 0 : spn = talloc_array(mem_ctx, char *, num_spns);
347 0 : for (count = 0; count < num_spns; count++) {
348 0 : blob = attr->value_ctr.values[count].blob;
349 0 : if (blob == NULL) {
350 0 : continue;
351 : }
352 0 : pull_string_talloc(spn, NULL, 0,
353 0 : &spn[count],
354 0 : blob->data, blob->length,
355 : STR_UNICODE);
356 : }
357 : }
358 :
359 0 : if (attr->attid == DRSUAPI_ATTID_unicodePwd &&
360 0 : cur->meta_data_ctr != NULL &&
361 0 : cur->meta_data_ctr->count ==
362 0 : cur->object.attribute_ctr.num_attributes)
363 : {
364 : /*
365 : * pick the kvno from the unicodePwd
366 : * meta data, even without a unicodePwd blob
367 : */
368 0 : kvno = cur->meta_data_ctr->meta_data[i].version;
369 : }
370 :
371 0 : if (attr->value_ctr.num_values != 1) {
372 0 : continue;
373 : }
374 :
375 0 : if (!attr->value_ctr.values[0].blob) {
376 0 : continue;
377 : }
378 :
379 0 : blob = attr->value_ctr.values[0].blob;
380 :
381 0 : switch (attr->attid) {
382 0 : case DRSUAPI_ATTID_unicodePwd:
383 :
384 0 : if (blob->length != 16) {
385 0 : break;
386 : }
387 :
388 0 : memcpy(&nt_passwd, blob->data, 16);
389 0 : got_pwd = true;
390 0 : break;
391 0 : case DRSUAPI_ATTID_ntPwdHistory:
392 0 : pwd_history_len = blob->length / 16;
393 0 : pwd_history = blob->data;
394 0 : break;
395 0 : case DRSUAPI_ATTID_userPrincipalName:
396 0 : pull_string_talloc(mem_ctx, NULL, 0, &upn,
397 0 : blob->data, blob->length,
398 : STR_UNICODE);
399 0 : break;
400 0 : case DRSUAPI_ATTID_sAMAccountName:
401 0 : pull_string_talloc(mem_ctx, NULL, 0, &name,
402 0 : blob->data, blob->length,
403 : STR_UNICODE);
404 0 : break;
405 0 : case DRSUAPI_ATTID_sAMAccountType:
406 0 : sam_type = IVAL(blob->data, 0);
407 0 : break;
408 0 : case DRSUAPI_ATTID_userAccountControl:
409 0 : uacc = IVAL(blob->data, 0);
410 0 : break;
411 0 : case DRSUAPI_ATTID_supplementalCredentials:
412 0 : status = parse_supplemental_credentials(mem_ctx,
413 : blob,
414 : &pkb3,
415 : &pkb4);
416 0 : if (!NT_STATUS_IS_OK(status)) {
417 0 : DEBUG(2, ("parsing of supplemental "
418 : "credentials failed: %s\n",
419 : nt_errstr(status)));
420 : }
421 0 : break;
422 0 : default:
423 0 : break;
424 : }
425 : }
426 :
427 0 : status = store_or_fetch_attribute(mem_ctx,
428 : ctx,
429 : object_dn,
430 : "SAMACCOUNTNAME",
431 : &name);
432 0 : if (!NT_STATUS_IS_OK(status)) {
433 0 : DBG_ERR("store_or_fetch_attribute(%s, %s, %s): %s\n",
434 : object_dn, "SAMACCOUNTNAME", name,
435 : nt_errstr(status));
436 0 : return status;
437 : }
438 :
439 0 : if (!name) {
440 0 : DEBUG(10, ("no name (sAMAccountName) found - skipping.\n"));
441 0 : return NT_STATUS_OK;
442 : }
443 :
444 0 : DEBUG(1,("#%02d: %s:%d, ", ctx->count, name, kvno));
445 0 : DEBUGADD(1,("sAMAccountType: 0x%08x, userAccountControl: 0x%08x",
446 : sam_type, uacc));
447 0 : if (upn) {
448 0 : DEBUGADD(1,(", upn: %s", upn));
449 : }
450 0 : if (num_spns > 0) {
451 0 : DEBUGADD(1, (", spns: ["));
452 0 : for (i = 0; i < num_spns; i++) {
453 0 : DEBUGADD(1, ("%s%s", spn[i],
454 : (i+1 == num_spns)?"]":", "));
455 : }
456 : }
457 0 : DEBUGADD(1,("\n"));
458 :
459 0 : if (got_pwd) {
460 0 : status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno, name, NULL,
461 : ENCTYPE_ARCFOUR_HMAC,
462 : data_blob_talloc(mem_ctx, nt_passwd, 16));
463 :
464 0 : if (!NT_STATUS_IS_OK(status)) {
465 0 : return status;
466 : }
467 : }
468 :
469 : /* add kerberos keys (if any) */
470 :
471 0 : if (pkb4) {
472 0 : for (i=0; i < pkb4->num_keys; i++) {
473 0 : if (!pkb4->keys[i].value) {
474 0 : continue;
475 : }
476 0 : status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno,
477 : name,
478 : NULL,
479 0 : pkb4->keys[i].keytype,
480 0 : *pkb4->keys[i].value);
481 0 : if (!NT_STATUS_IS_OK(status)) {
482 0 : return status;
483 : }
484 : }
485 0 : for (i=0; i < pkb4->num_old_keys; i++) {
486 0 : if (!pkb4->old_keys[i].value) {
487 0 : continue;
488 : }
489 0 : status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno - 1,
490 : name,
491 : NULL,
492 0 : pkb4->old_keys[i].keytype,
493 0 : *pkb4->old_keys[i].value);
494 0 : if (!NT_STATUS_IS_OK(status)) {
495 0 : return status;
496 : }
497 : }
498 0 : for (i=0; i < pkb4->num_older_keys; i++) {
499 0 : if (!pkb4->older_keys[i].value) {
500 0 : continue;
501 : }
502 0 : status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno - 2,
503 : name,
504 : NULL,
505 0 : pkb4->older_keys[i].keytype,
506 0 : *pkb4->older_keys[i].value);
507 0 : if (!NT_STATUS_IS_OK(status)) {
508 0 : return status;
509 : }
510 : }
511 : }
512 :
513 0 : if (pkb3) {
514 0 : for (i=0; i < pkb3->num_keys; i++) {
515 0 : if (!pkb3->keys[i].value) {
516 0 : continue;
517 : }
518 0 : status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno, name,
519 : NULL,
520 0 : pkb3->keys[i].keytype,
521 0 : *pkb3->keys[i].value);
522 0 : if (!NT_STATUS_IS_OK(status)) {
523 0 : return status;
524 : }
525 : }
526 0 : for (i=0; i < pkb3->num_old_keys; i++) {
527 0 : if (!pkb3->old_keys[i].value) {
528 0 : continue;
529 : }
530 0 : status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno - 1,
531 : name,
532 : NULL,
533 0 : pkb3->old_keys[i].keytype,
534 0 : *pkb3->old_keys[i].value);
535 0 : if (!NT_STATUS_IS_OK(status)) {
536 0 : return status;
537 : }
538 : }
539 : }
540 :
541 0 : if (kvno < pwd_history_len) {
542 0 : return status;
543 : }
544 :
545 : /* add password history */
546 :
547 : /* skip first entry */
548 0 : if (got_pwd) {
549 0 : kvno--;
550 0 : i = 1;
551 : } else {
552 0 : i = 0;
553 : }
554 :
555 0 : for (; i<pwd_history_len; i++) {
556 0 : status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx, kvno--, name, NULL,
557 : ENCTYPE_ARCFOUR_HMAC,
558 0 : data_blob_talloc(mem_ctx, &pwd_history[i*16], 16));
559 0 : if (!NT_STATUS_IS_OK(status)) {
560 0 : break;
561 : }
562 : }
563 :
564 0 : return status;
565 : }
566 :
567 0 : static NTSTATUS parse_AuthenticationInformation(TALLOC_CTX *mem_ctx,
568 : struct libnet_keytab_context *ctx,
569 : const char *dn,
570 : const char *trust_name,
571 : const char *attr_name,
572 : const char *salt_principal,
573 : const char *type,
574 : uint32_t *kvno,
575 : const struct AuthenticationInformationArray *ia)
576 : {
577 0 : uint32_t i;
578 0 : struct samr_Password _nthash = {{ 0, }};
579 0 : const struct samr_Password *nthash = NULL;
580 0 : const struct AuthInfoClear *clear = NULL;
581 0 : DATA_BLOB password_utf8 = data_blob_null;
582 :
583 0 : for (i = 0; i < ia->count; i++) {
584 0 : const struct AuthenticationInformation *a = &ia->array[i];
585 :
586 0 : switch (a->AuthType) {
587 0 : case TRUST_AUTH_TYPE_VERSION:
588 0 : *kvno = a->AuthInfo.version.version;
589 0 : break;
590 0 : case TRUST_AUTH_TYPE_NT4OWF:
591 0 : nthash = &a->AuthInfo.nt4owf.password;
592 0 : break;
593 0 : case TRUST_AUTH_TYPE_CLEAR:
594 0 : clear = &a->AuthInfo.clear;
595 0 : break;
596 0 : default:
597 0 : break;
598 : }
599 : }
600 :
601 0 : if (clear != NULL && clear->size != 0) {
602 0 : DATA_BLOB password_utf16 = data_blob_null;
603 0 : bool ok;
604 :
605 0 : password_utf16 = data_blob_const(clear->password,
606 0 : clear->size);
607 :
608 0 : if (nthash == NULL) {
609 0 : mdfour(_nthash.hash,
610 0 : password_utf16.data,
611 0 : password_utf16.length);
612 0 : nthash = &_nthash;
613 : }
614 :
615 0 : ok = convert_string_talloc(mem_ctx,
616 : CH_UTF16MUNGED, CH_UTF8,
617 0 : password_utf16.data,
618 : password_utf16.length,
619 : (void *)&password_utf8.data,
620 : &password_utf8.length);
621 0 : if (!ok) {
622 0 : return NT_STATUS_NO_MEMORY;
623 : }
624 : }
625 :
626 0 : if (password_utf8.length != 0) {
627 0 : krb5_principal salt_princ = NULL;
628 0 : krb5_data salt = { 0, };
629 0 : krb5_data cleartext_data = { 0, };
630 0 : krb5_enctype enctypes[] = {
631 : ENCTYPE_AES256_CTS_HMAC_SHA1_96,
632 : ENCTYPE_AES128_CTS_HMAC_SHA1_96,
633 : };
634 0 : size_t ei;
635 0 : krb5_error_code kret;
636 0 : NTSTATUS status;
637 :
638 0 : kret = smb_krb5_parse_name(ctx->context,
639 : salt_principal,
640 : &salt_princ);
641 0 : if (kret != 0) {
642 0 : return NT_STATUS_NO_MEMORY;
643 : }
644 :
645 0 : cleartext_data.data = discard_const_p(char, password_utf8.data);
646 0 : cleartext_data.length = password_utf8.length;
647 :
648 0 : kret = smb_krb5_get_pw_salt(ctx->context,
649 : salt_princ,
650 : &salt);
651 0 : if (kret != 0) {
652 0 : krb5_free_principal(ctx->context, salt_princ);
653 0 : return NT_STATUS_NO_MEMORY;
654 : }
655 :
656 0 : for (ei = 0; ei < ARRAY_SIZE(enctypes); ei++) {
657 0 : krb5_keyblock keyb = { 0, };
658 0 : DATA_BLOB blob = data_blob_null;
659 :
660 0 : kret = smb_krb5_create_key_from_string(ctx->context,
661 : salt_princ,
662 : &salt,
663 : &cleartext_data,
664 : enctypes[ei],
665 : &keyb);
666 0 : if (kret != 0) {
667 0 : smb_krb5_free_data_contents(ctx->context, &salt);
668 0 : krb5_free_principal(ctx->context, salt_princ);
669 0 : return NT_STATUS_NO_MEMORY;
670 : }
671 :
672 0 : blob = data_blob_talloc(mem_ctx,
673 : KRB5_KEY_DATA(&keyb),
674 : KRB5_KEY_LENGTH(&keyb));
675 0 : krb5_free_keyblock_contents(ctx->context, &keyb);
676 :
677 0 : status = libnet_keytab_add_to_keytab_entries(mem_ctx,
678 : ctx,
679 : *kvno,
680 : trust_name,
681 : attr_name,
682 : enctypes[ei],
683 : blob);
684 0 : if (!NT_STATUS_IS_OK(status)) {
685 0 : smb_krb5_free_data_contents(ctx->context, &salt);
686 0 : krb5_free_principal(ctx->context, salt_princ);
687 0 : return status;
688 : }
689 : }
690 :
691 0 : smb_krb5_free_data_contents(ctx->context, &salt);
692 0 : krb5_free_principal(ctx->context, salt_princ);
693 : }
694 :
695 0 : if (nthash != NULL) {
696 0 : DATA_BLOB blob = data_blob_null;
697 0 : NTSTATUS status;
698 :
699 0 : blob = data_blob_talloc(mem_ctx, nthash->hash, sizeof(nthash->hash));
700 :
701 0 : status = libnet_keytab_add_to_keytab_entries(mem_ctx, ctx,
702 : *kvno,
703 : trust_name,
704 : attr_name,
705 : ENCTYPE_ARCFOUR_HMAC,
706 : blob);
707 0 : if (!NT_STATUS_IS_OK(status)) {
708 0 : return status;
709 : }
710 : }
711 :
712 0 : return NT_STATUS_OK;
713 : }
714 :
715 0 : static NTSTATUS parse_trustAuthInOutBlob(TALLOC_CTX *mem_ctx,
716 : struct libnet_keytab_context *ctx,
717 : const char *dn,
718 : const char *trust_name,
719 : const char *attr_name,
720 : const char *salt_principal,
721 : const DATA_BLOB *blob)
722 : {
723 0 : NTSTATUS status;
724 0 : enum ndr_err_code ndr_err;
725 0 : struct trustAuthInOutBlob taiob;
726 0 : uint32_t kvno = 0;
727 :
728 0 : ndr_err = ndr_pull_struct_blob_all(blob, mem_ctx, &taiob,
729 : (ndr_pull_flags_fn_t)ndr_pull_trustAuthInOutBlob);
730 0 : if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
731 0 : status = ndr_map_error2ntstatus(ndr_err);
732 0 : goto done;
733 : }
734 :
735 0 : D_WARNING("# %s %s/%s\n", dn, attr_name, trust_name);
736 :
737 0 : status = parse_AuthenticationInformation(mem_ctx,
738 : ctx,
739 : dn,
740 : trust_name,
741 : attr_name,
742 : salt_principal,
743 : "current",
744 : &kvno,
745 : &taiob.current);
746 0 : if (!NT_STATUS_IS_OK(status)) {
747 0 : DBG_ERR("parsing of %s %s/current failed: %s\n",
748 : dn, attr_name, nt_errstr(status));
749 : }
750 :
751 0 : kvno -= 1;
752 0 : status = parse_AuthenticationInformation(mem_ctx,
753 : ctx,
754 : dn,
755 : trust_name,
756 : attr_name,
757 : salt_principal,
758 : "previous",
759 : &kvno,
760 : &taiob.previous);
761 0 : if (!NT_STATUS_IS_OK(status)) {
762 0 : DBG_ERR("parsing of %s %s/previous failed: %s\n",
763 : dn, attr_name, nt_errstr(status));
764 : }
765 :
766 0 : status = NT_STATUS_OK;
767 0 : done:
768 0 : return status;
769 : }
770 :
771 0 : static NTSTATUS parse_tdo(TALLOC_CTX *mem_ctx,
772 : struct libnet_keytab_context *ctx,
773 : struct drsuapi_DsReplicaObjectListItemEx *cur)
774 : {
775 0 : uint32_t i;
776 0 : const char *dn = cur->object.identifier->dn;
777 0 : char *trustPartner = NULL;
778 0 : char *flatName = NULL;
779 0 : char *cn = NULL;
780 0 : char *trust_name = NULL;
781 0 : char *trust_realm = NULL;
782 0 : char *our_realm = NULL;
783 0 : const char *incoming_salt = NULL;
784 0 : const char *outgoing_salt = NULL;
785 0 : NTSTATUS status;
786 :
787 0 : D_NOTICE("parsing trust '%s'\n", dn);
788 :
789 0 : for (i = 0; i < cur->object.attribute_ctr.num_attributes; i++) {
790 0 : struct drsuapi_DsReplicaAttribute *attr =
791 0 : &cur->object.attribute_ctr.attributes[i];
792 0 : const DATA_BLOB *blob = NULL;
793 :
794 0 : if (attr->value_ctr.num_values != 1) {
795 0 : continue;
796 : }
797 :
798 0 : if (attr->value_ctr.values[0].blob == NULL) {
799 0 : continue;
800 : }
801 :
802 0 : blob = attr->value_ctr.values[0].blob;
803 :
804 0 : switch (attr->attid) {
805 0 : case DRSUAPI_ATTID_trustPartner:
806 0 : pull_string_talloc(mem_ctx, NULL, 0, &trustPartner,
807 0 : blob->data, blob->length,
808 : STR_UNICODE);
809 0 : break;
810 0 : case DRSUAPI_ATTID_flatName:
811 0 : pull_string_talloc(mem_ctx, NULL, 0, &flatName,
812 0 : blob->data, blob->length,
813 : STR_UNICODE);
814 0 : break;
815 0 : case DRSUAPI_ATTID_cn:
816 0 : pull_string_talloc(mem_ctx, NULL, 0, &cn,
817 0 : blob->data, blob->length,
818 : STR_UNICODE);
819 0 : break;
820 0 : default:
821 0 : break;
822 : }
823 : }
824 :
825 0 : if (trustPartner != NULL) {
826 0 : trust_name = trustPartner;
827 0 : } else if (flatName != NULL) {
828 0 : trust_name = flatName;
829 : } else {
830 0 : trust_name = cn;
831 : }
832 :
833 0 : status = store_or_fetch_attribute(mem_ctx,
834 : ctx,
835 : dn,
836 : "REMOTETRUSTNAME",
837 : &trust_name);
838 0 : if (!NT_STATUS_IS_OK(status)) {
839 0 : DBG_ERR("store_or_fetch_attribute(%s, %s, %s): %s\n",
840 : dn, "REMOTETRUSTNAME", trust_name,
841 : nt_errstr(status));
842 0 : return status;
843 : }
844 :
845 0 : if (trust_name == NULL) {
846 0 : D_DEBUG("no trust_name (trustPartner, flatName, cn) found - "
847 : "skipping.\n");
848 0 : return NT_STATUS_OK;
849 : }
850 :
851 0 : trust_realm = strupper_talloc(mem_ctx, trust_name);
852 0 : if (trust_realm == NULL) {
853 0 : return NT_STATUS_NO_MEMORY;
854 : }
855 0 : our_realm = strupper_talloc(mem_ctx, ctx->dns_domain_name);
856 0 : if (our_realm == NULL) {
857 0 : return NT_STATUS_NO_MEMORY;
858 : }
859 :
860 0 : incoming_salt = talloc_asprintf(mem_ctx,
861 : "krbtgt/%s@%s",
862 : trust_realm,
863 : our_realm);
864 0 : if (incoming_salt == NULL) {
865 0 : return NT_STATUS_NO_MEMORY;
866 : }
867 0 : outgoing_salt = talloc_asprintf(mem_ctx,
868 : "krbtgt/%s@%s",
869 : our_realm,
870 : trust_realm);
871 0 : if (outgoing_salt == NULL) {
872 0 : return NT_STATUS_NO_MEMORY;
873 : }
874 :
875 0 : for (i = 0; i < cur->object.attribute_ctr.num_attributes; i++) {
876 0 : struct drsuapi_DsReplicaAttribute *attr =
877 0 : &cur->object.attribute_ctr.attributes[i];
878 0 : const char *attr_name = NULL;
879 0 : const DATA_BLOB *blob = NULL;
880 0 : const char *salt_principal = NULL;
881 :
882 0 : if (attr->value_ctr.num_values != 1) {
883 0 : continue;
884 : }
885 :
886 0 : if (attr->value_ctr.values[0].blob == NULL) {
887 0 : continue;
888 : }
889 :
890 0 : blob = attr->value_ctr.values[0].blob;
891 :
892 0 : switch (attr->attid) {
893 0 : case DRSUAPI_ATTID_trustAuthIncoming:
894 0 : attr_name = "trustAuthIncoming";
895 0 : salt_principal = incoming_salt;
896 0 : break;
897 0 : case DRSUAPI_ATTID_trustAuthOutgoing:
898 0 : attr_name = "trustAuthOutgoing";
899 0 : salt_principal = outgoing_salt;
900 0 : break;
901 0 : default:
902 0 : break;
903 : }
904 :
905 0 : if (attr_name == NULL) {
906 0 : continue;
907 : }
908 :
909 0 : status = parse_trustAuthInOutBlob(mem_ctx,
910 : ctx,
911 : dn,
912 : trust_name,
913 : attr_name,
914 : salt_principal,
915 : blob);
916 0 : if (!NT_STATUS_IS_OK(status)) {
917 0 : DBG_ERR("parsing of %s attr %s failed: %s\n",
918 : dn, attr_name, nt_errstr(status));
919 : }
920 : }
921 :
922 0 : return NT_STATUS_OK;
923 : }
924 :
925 0 : static NTSTATUS parse_object(TALLOC_CTX *mem_ctx,
926 : struct libnet_keytab_context *ctx,
927 : struct drsuapi_DsReplicaObjectListItemEx *cur)
928 : {
929 0 : uint32_t i;
930 :
931 0 : if (cur->object.identifier->dn == NULL) {
932 0 : return NT_STATUS_OK;
933 : }
934 :
935 0 : for (i = 0; i < cur->object.attribute_ctr.num_attributes; i++) {
936 0 : struct drsuapi_DsReplicaAttribute *attr =
937 0 : &cur->object.attribute_ctr.attributes[i];
938 0 : const DATA_BLOB *blob = NULL;
939 0 : uint32_t val;
940 :
941 0 : switch (attr->attid) {
942 0 : case DRSUAPI_ATTID_isDeleted:
943 : case DRSUAPI_ATTID_isRecycled:
944 0 : break;
945 0 : default:
946 0 : continue;
947 : }
948 :
949 0 : if (attr->value_ctr.num_values != 1) {
950 0 : continue;
951 : }
952 :
953 0 : if (attr->value_ctr.values[0].blob == NULL) {
954 0 : continue;
955 : }
956 :
957 0 : blob = attr->value_ctr.values[0].blob;
958 :
959 0 : if (blob->length != 4) {
960 0 : continue;
961 : }
962 :
963 0 : val = PULL_LE_U32(blob->data, 0);
964 0 : if (val != 0) {
965 : /* ignore deleted object */
966 0 : return NT_STATUS_OK;
967 : }
968 : }
969 :
970 0 : for (i = 0; i < cur->object.attribute_ctr.num_attributes; i++) {
971 0 : struct drsuapi_DsReplicaAttribute *attr =
972 0 : &cur->object.attribute_ctr.attributes[i];
973 :
974 0 : switch (attr->attid) {
975 0 : case DRSUAPI_ATTID_unicodePwd:
976 : case DRSUAPI_ATTID_ntPwdHistory:
977 : case DRSUAPI_ATTID_supplementalCredentials:
978 0 : return parse_user(mem_ctx, ctx, cur);
979 0 : case DRSUAPI_ATTID_trustAuthIncoming:
980 : case DRSUAPI_ATTID_trustAuthOutgoing:
981 0 : return parse_tdo(mem_ctx, ctx, cur);
982 0 : default:
983 0 : continue;
984 : }
985 : }
986 :
987 0 : return NT_STATUS_OK;
988 : }
989 :
990 0 : static bool dn_is_in_object_list(struct dssync_context *ctx,
991 : const char *dn)
992 : {
993 0 : uint32_t count;
994 :
995 0 : if (ctx->object_count == 0) {
996 0 : return true;
997 : }
998 :
999 0 : for (count = 0; count < ctx->object_count; count++) {
1000 0 : if (strequal(ctx->object_dns[count], dn)) {
1001 0 : return true;
1002 : }
1003 : }
1004 :
1005 0 : return false;
1006 : }
1007 :
1008 : /****************************************************************
1009 : ****************************************************************/
1010 :
1011 0 : static NTSTATUS keytab_process_objects(struct dssync_context *ctx,
1012 : TALLOC_CTX *mem_ctx,
1013 : struct drsuapi_DsReplicaObjectListItemEx *cur,
1014 : struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
1015 : {
1016 0 : NTSTATUS status = NT_STATUS_OK;
1017 0 : struct libnet_keytab_context *keytab_ctx =
1018 : (struct libnet_keytab_context *)ctx->private_data;
1019 :
1020 0 : for (; cur; cur = cur->next_object) {
1021 : /*
1022 : * When not in single object replication mode,
1023 : * the object_dn list is used as a positive write filter.
1024 : */
1025 0 : if (!ctx->single_object_replication &&
1026 0 : !dn_is_in_object_list(ctx, cur->object.identifier->dn))
1027 : {
1028 0 : continue;
1029 : }
1030 :
1031 0 : status = parse_object(mem_ctx, keytab_ctx, cur);
1032 0 : if (!NT_STATUS_IS_OK(status)) {
1033 0 : goto out;
1034 : }
1035 : }
1036 :
1037 0 : out:
1038 0 : return status;
1039 : }
1040 :
1041 : #else
1042 :
1043 0 : static NTSTATUS keytab_startup(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
1044 : struct replUpToDateVectorBlob **pold_utdv)
1045 : {
1046 0 : return NT_STATUS_NOT_SUPPORTED;
1047 : }
1048 :
1049 0 : static NTSTATUS keytab_finish(struct dssync_context *ctx, TALLOC_CTX *mem_ctx,
1050 : struct replUpToDateVectorBlob *new_utdv)
1051 : {
1052 0 : return NT_STATUS_NOT_SUPPORTED;
1053 : }
1054 :
1055 0 : static NTSTATUS keytab_process_objects(struct dssync_context *ctx,
1056 : TALLOC_CTX *mem_ctx,
1057 : struct drsuapi_DsReplicaObjectListItemEx *cur,
1058 : struct drsuapi_DsReplicaOIDMapping_Ctr *mapping_ctr)
1059 : {
1060 0 : return NT_STATUS_NOT_SUPPORTED;
1061 : }
1062 : #endif /* defined(HAVE_ADS) */
1063 :
1064 : const struct dssync_ops libnet_dssync_keytab_ops = {
1065 : .startup = keytab_startup,
1066 : .process_objects = keytab_process_objects,
1067 : .finish = keytab_finish,
1068 : };
|