s4:kdc: Fix typos
[asn/samba.git] / source4 / kdc / ad_claims.c
1 /*
2    Unix SMB/CIFS implementation.
3    Samba Active Directory claims utility functions
4
5    Copyright (C) Catalyst.Net Ltd 2023
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 "lib/replace/replace.h"
22 #include "lib/util/debug.h"
23 #include "lib/util/samba_util.h"
24 #include "source4/kdc/ad_claims.h"
25 #include "ldb_module.h"
26 #include "libcli/security/security.h"
27 #include "libcli/util/werror.h"
28 #include "dsdb/samdb/samdb.h"
29 #include "dsdb/samdb/ldb_modules/util.h"
30 #include "librpc/gen_ndr/claims.h"
31 #include "librpc/gen_ndr/ndr_claims.h"
32 #include "librpc/gen_ndr/krb5pac.h"
33 #include "librpc/gen_ndr/ndr_krb5pac.h"
34 #include "lzxpress_huffman.h"
35 #include "lib/util/binsearch.h"
36
37 #undef strcasecmp
38
39 static int acl_attr_cmp_fn(const char *a, const char * const *b)
40 {
41         return ldb_attr_cmp(a, *b);
42 }
43
44 /*
45  * Add a single attribute to a list of attributes if it is not already
46  * present. The list is maintained in case-insensitive sorted order.
47  */
48 static int add_attr_unique(TALLOC_CTX *mem_ctx,
49                            const char **attrs,
50                            unsigned *ad_claim_attrs_count,
51                            const char *attr)
52 {
53         const unsigned count = *ad_claim_attrs_count;
54         const char * const *exact = NULL;
55         const char * const *next = NULL;
56
57         BINARY_ARRAY_SEARCH_GTE(attrs,
58                                 count,
59                                 attr,
60                                 acl_attr_cmp_fn,
61                                 exact,
62                                 next);
63         if (exact != NULL) {
64                 /* The attribute is already present; there's nothing to do. */
65                 return LDB_SUCCESS;
66         }
67
68         /* Make sure we don't overflow the array. */
69         SMB_ASSERT(count < talloc_array_length(attrs));
70         *ad_claim_attrs_count = count + 1;
71
72         if (next == NULL) {
73                 /* Just add the new element on the end. */
74                 attrs[count] = attr;
75         } else {
76                 /* Shift all following elements over to make room. */
77                 size_t next_idx = next - attrs;
78                 size_t bytes_to_move = (count - next_idx) * sizeof (attrs[0]);
79                 memmove(&attrs[next_idx + 1],
80                         &attrs[next_idx],
81                         bytes_to_move);
82
83                 attrs[next_idx] = attr;
84         }
85
86         return LDB_SUCCESS;
87 }
88
89 /*
90  * Return true if a data_blob, interpreted as a string, is equal to another
91  * string. This is more efficient than strcmp(), particularly when comparing
92  * against a string constant. This assumes the data_blob's length does not
93  * include the zero-terminator.
94  */
95 static inline bool data_blob_equals_str(const DATA_BLOB val, const char *str)
96 {
97         size_t len = strlen(str);
98         if (val.length != len) {
99                 return false;
100         }
101
102         return memcmp(val.data, str, len) == 0;
103 }
104
105 static int fill_claim_int64(TALLOC_CTX *mem_ctx,
106                             struct ldb_context *ldb,
107                             const struct ldb_message_element *principal_attribute,
108                             const struct ldb_val name,
109                             struct CLAIM_INT64 *claim)
110 {
111         uint32_t i;
112
113         claim->value_count = 0;
114         claim->values = talloc_array(mem_ctx,
115                                      int64_t,
116                                      principal_attribute->num_values);
117         if (claim->values == NULL) {
118                 return ldb_oom(ldb);
119         }
120
121         for (i = 0; i < principal_attribute->num_values; ++i) {
122                 const struct ldb_val *value = &principal_attribute->values[i];
123                 int ret = ldb_val_as_int64(value, &claim->values[i]);
124                 if (ret) {
125                         char buf[1024];
126                         const char *reason = NULL;
127                         int err = strerror_r(ret, buf, sizeof(buf));
128                         if (err == 0) {
129                                 reason = buf;
130                         } else {
131                                 reason = "Unknown error";
132                         }
133                         DBG_WARNING("Failed to interpret value %s as INT64 "
134                                     "while creating claim %s for attribute %s (%s); "
135                                     "skipping value\n",
136                                     (value->data != NULL) ? (const char *)value->data : "<unknown>",
137                                     name.data, principal_attribute->name,
138                                     reason);
139                         continue;
140                 }
141
142                 ++claim->value_count;
143         }
144
145         /* Shrink the array to fit. */
146         claim->values = talloc_realloc(mem_ctx,
147                                        claim->values,
148                                        int64_t,
149                                        claim->value_count);
150         if (claim->value_count && claim->values == NULL) {
151                 return ldb_oom(ldb);
152         }
153
154         return LDB_SUCCESS;
155 }
156
157 static int fill_claim_uint64(TALLOC_CTX *mem_ctx,
158                              struct ldb_context *ldb,
159                              const struct ldb_message_element *principal_attribute,
160                              const struct ldb_val name,
161                              struct CLAIM_UINT64 *claim)
162 {
163         uint32_t i;
164
165         claim->value_count = 0;
166         claim->values = talloc_array(mem_ctx,
167                                      uint64_t,
168                                      principal_attribute->num_values);
169         if (claim->values == NULL) {
170                 return ldb_oom(ldb);
171         }
172
173         for (i = 0; i < principal_attribute->num_values; ++i) {
174                 const struct ldb_val *value = &principal_attribute->values[i];
175                 int ret = ldb_val_as_uint64(value, &claim->values[i]);
176                 if (ret) {
177                         char buf[1024];
178                         const char *reason = NULL;
179                         int err = strerror_r(ret, buf, sizeof(buf));
180                         if (err == 0) {
181                                 reason = buf;
182                         } else {
183                                 reason = "Unknown error";
184                         }
185                         DBG_WARNING("Failed to interpret value %s as UINT64 "
186                                     "while creating claim %s for attribute %s (%s); "
187                                     "skipping value\n",
188                                     (value->data != NULL) ? (const char *)value->data : "<unknown>",
189                                     name.data, principal_attribute->name,
190                                     reason);
191                         continue;
192                 }
193
194                 ++claim->value_count;
195         }
196
197         /* Shrink the array to fit. */
198         claim->values = talloc_realloc(mem_ctx,
199                                        claim->values,
200                                        uint64_t,
201                                        claim->value_count);
202         if (claim->value_count && claim->values == NULL) {
203                 return ldb_oom(ldb);
204         }
205
206         return LDB_SUCCESS;
207 }
208
209 static int fill_claim_uint64_oid_syntax(TALLOC_CTX *mem_ctx,
210                                         struct ldb_context *ldb,
211                                         const struct dsdb_schema *schema,
212                                         const struct ldb_message_element *principal_attribute,
213                                         const struct ldb_val name,
214                                         struct CLAIM_UINT64 *claim)
215 {
216         uint32_t i;
217
218         claim->value_count = 0;
219         claim->values = talloc_array(mem_ctx,
220                                      uint64_t,
221                                      principal_attribute->num_values);
222         if (claim->values == NULL) {
223                 return ldb_oom(ldb);
224         }
225
226         for (i = 0; i < principal_attribute->num_values; ++i) {
227                 const struct dsdb_class *class_val = NULL;
228
229                 /*
230                  * OID values for objectClass
231                  * are presented in reverse
232                  * order.
233                  */
234                 const struct ldb_val *display_name = &principal_attribute->values[
235                         principal_attribute->num_values - 1 - i];
236
237                 class_val = dsdb_class_by_lDAPDisplayName_ldb_val(schema, display_name);
238                 if (class_val == NULL) {
239                         DBG_WARNING("Failed to look up OID for value %s "
240                                     "while creating claim %s for attribute %s; "
241                                     "skipping value\n",
242                                     (display_name->data != NULL) ? (const char *)display_name->data : "<unknown>",
243                                     name.data, principal_attribute->name);
244                         continue;
245                 }
246
247                 claim->values[i] = class_val->governsID_id;
248                 ++claim->value_count;
249         }
250
251         /* Shrink the array to fit. */
252         claim->values = talloc_realloc(mem_ctx,
253                                        claim->values,
254                                        uint64_t,
255                                        claim->value_count);
256         if (claim->value_count && claim->values == NULL) {
257                 return ldb_oom(ldb);
258         }
259
260         return LDB_SUCCESS;
261 }
262
263 static int fill_claim_boolean(TALLOC_CTX *mem_ctx,
264                               struct ldb_context *ldb,
265                               const struct ldb_message_element *principal_attribute,
266                               const struct ldb_val name,
267                               struct CLAIM_UINT64 *claim)
268 {
269         uint32_t i;
270
271         claim->value_count = 0;
272         claim->values = talloc_array(mem_ctx,
273                                      uint64_t,
274                                      principal_attribute->num_values);
275         if (claim->values == NULL) {
276                 return ldb_oom(ldb);
277         }
278
279         for (i = 0; i < principal_attribute->num_values; ++i) {
280                 const struct ldb_val *value = &principal_attribute->values[i];
281                 bool val = false;
282                 int ret = ldb_val_as_bool(value, &val);
283                 if (ret) {
284                         char buf[1024];
285                         const char *reason = NULL;
286                         int err = strerror_r(ret, buf, sizeof(buf));
287                         if (err == 0) {
288                                 reason = buf;
289                         } else {
290                                 reason = "Unknown error";
291                         }
292                         DBG_WARNING("Failed to interpret value %s as BOOL "
293                                     "while creating claim %s for attribute %s (%s); "
294                                     "skipping value\n",
295                                     (value->data != NULL) ? (const char *)value->data : "<unknown>",
296                                     name.data, principal_attribute->name,
297                                     reason);
298                         continue;
299                 }
300
301                 claim->values[i] = val;
302                 ++claim->value_count;
303         }
304
305         /* Shrink the array to fit. */
306         claim->values = talloc_realloc(mem_ctx,
307                                        claim->values,
308                                        uint64_t,
309                                        claim->value_count);
310         if (claim->value_count && claim->values == NULL) {
311                 return ldb_oom(ldb);
312         }
313
314         return LDB_SUCCESS;
315 }
316
317 static int fill_claim_string(TALLOC_CTX *mem_ctx,
318                              struct ldb_context *ldb,
319                              const struct ldb_message_element *principal_attribute,
320                              struct CLAIM_STRING *claim)
321 {
322         uint32_t i;
323
324         claim->value_count = 0;
325         claim->values = talloc_array(mem_ctx,
326                                      const char *,
327                                      principal_attribute->num_values);
328         if (claim->values == NULL) {
329                 return ldb_oom(ldb);
330         }
331
332         for (i = 0; i < principal_attribute->num_values; ++i) {
333                 const char *val = NULL;
334                 const struct ldb_val *v = &principal_attribute->values[i];
335
336                 if (v == NULL || v->data == NULL) {
337                         continue;
338                 }
339
340                 val = talloc_strndup(claim->values,
341                                      (const char *)v->data,
342                                      v->length);
343                 if (val == NULL) {
344                         return ldb_oom(ldb);
345                 }
346
347                 claim->values[i] = val;
348                 ++claim->value_count;
349         }
350
351         /* Shrink the array to fit. */
352         claim->values = talloc_realloc(mem_ctx,
353                                        claim->values,
354                                        const char *,
355                                        claim->value_count);
356         if (claim->value_count && claim->values == NULL) {
357                 return ldb_oom(ldb);
358         }
359
360         return LDB_SUCCESS;
361 }
362
363 static int fill_claim_string_sec_desc_syntax(TALLOC_CTX *mem_ctx,
364                                              struct ldb_context *ldb,
365                                              const struct ldb_message_element *principal_attribute,
366                                              struct CLAIM_STRING *claim)
367 {
368         TALLOC_CTX *tmp_ctx = NULL;
369         const struct dom_sid *domain_sid = NULL;
370         uint32_t i;
371
372         claim->value_count = 0;
373         claim->values = talloc_array(mem_ctx,
374                                      const char *,
375                                      principal_attribute->num_values);
376         if (claim->values == NULL) {
377                 return ldb_oom(ldb);
378         }
379
380         domain_sid = samdb_domain_sid(ldb);
381         if (domain_sid == NULL) {
382                 return ldb_oom(ldb);
383         }
384
385         tmp_ctx = talloc_new(mem_ctx);
386         if (tmp_ctx == NULL) {
387                 return ldb_oom(ldb);
388         }
389
390         for (i = 0; i < principal_attribute->num_values; ++i) {
391                 const struct ldb_val *v = &principal_attribute->values[i];
392
393                 enum ndr_err_code ndr_err;
394                 struct security_descriptor desc = {};
395                 const char *sddl = NULL;
396
397                 if (v == NULL || v->data == NULL) {
398                         continue;
399                 }
400
401                 ndr_err = ndr_pull_struct_blob(v,
402                                                tmp_ctx,
403                                                &desc,
404                                                (ndr_pull_flags_fn_t)ndr_pull_security_descriptor);
405                 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
406                         NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
407                         DBG_ERR("security_descriptor pull failed: %s\n",
408                                 nt_errstr(nt_status));
409                         talloc_free(tmp_ctx);
410                         return ldb_operr(ldb);
411                 }
412
413                 sddl = sddl_encode(mem_ctx,
414                                    &desc,
415                                    domain_sid);
416                 if (sddl == NULL) {
417                         talloc_free(tmp_ctx);
418                         return ldb_oom(ldb);
419                 }
420
421                 claim->values[i] = sddl;
422                 ++claim->value_count;
423         }
424
425         talloc_free(tmp_ctx);
426
427         /* Shrink the array to fit. */
428         claim->values = talloc_realloc(mem_ctx,
429                                        claim->values,
430                                        const char *,
431                                        claim->value_count);
432         if (claim->value_count && claim->values == NULL) {
433                 return ldb_oom(ldb);
434         }
435
436         return LDB_SUCCESS;
437 }
438
439 static int fill_claim_entry(TALLOC_CTX *mem_ctx,
440                             struct ldb_context *ldb,
441                             const struct dsdb_schema *schema,
442                             const struct ldb_message_element *principal_attribute,
443                             const struct ldb_val name,
444                             const DATA_BLOB syntax,
445                             enum CLAIM_TYPE claim_type,
446                             struct CLAIM_ENTRY *claim_entry)
447 {
448
449         claim_entry->id = (const char *)name.data;
450         claim_entry->type = claim_type;
451
452         switch (claim_type) {
453         case CLAIM_TYPE_INT64:
454                 return fill_claim_int64(mem_ctx,
455                                         ldb,
456                                         principal_attribute,
457                                         name,
458                                         &claim_entry->values.claim_int64);
459         case CLAIM_TYPE_UINT64:
460                 if (syntax.data != NULL && data_blob_equals_str(syntax, "2.5.5.2")) {
461                         return fill_claim_uint64_oid_syntax(mem_ctx,
462                                                  ldb,
463                                                  schema,
464                                                  principal_attribute,
465                                                  name,
466                                                  &claim_entry->values.claim_uint64);
467                 } else {
468                         return fill_claim_uint64(mem_ctx,
469                                                  ldb,
470                                                  principal_attribute,
471                                                  name,
472                                                  &claim_entry->values.claim_uint64);
473                 }
474         case CLAIM_TYPE_BOOLEAN:
475                 return fill_claim_boolean(mem_ctx,
476                                           ldb,
477                                           principal_attribute,
478                                           name,
479                                           &claim_entry->values.claim_boolean);
480         case CLAIM_TYPE_STRING:
481         default:
482                 if (syntax.data != NULL && data_blob_equals_str(syntax, "2.5.5.15")) {
483                         return fill_claim_string_sec_desc_syntax(mem_ctx,
484                                                                  ldb,
485                                                                  principal_attribute,
486                                                                  &claim_entry->values.claim_string);
487                 } else {
488                         return fill_claim_string(mem_ctx,
489                                                  ldb,
490                                                  principal_attribute,
491                                                  &claim_entry->values.claim_string);
492                 }
493         }
494 }
495
496 /*
497  * Determine wheter a claim applies to the most specific objectClass of the
498  * principal.
499  */
500 static int claim_applies_to_class(TALLOC_CTX *mem_ctx,
501                                   struct ldb_context *ldb,
502                                   const struct dsdb_schema *schema,
503                                   const struct ldb_message *claim_msg,
504                                   const uint32_t principal_class_id,
505                                   bool *applies)
506 {
507         struct ldb_message_element *applies_to_class = NULL;
508         unsigned i;
509
510         applies_to_class = ldb_msg_find_element(claim_msg,
511                                                 "msDS-ClaimTypeAppliesToClass");
512         if (applies_to_class == NULL) {
513                 *applies = false;
514                 return LDB_SUCCESS;
515         }
516
517         for (i = 0; i < applies_to_class->num_values; ++i) {
518                 struct ldb_dn *class_dn = NULL;
519                 const struct dsdb_class *class_val = NULL;
520                 const struct ldb_val *class_rdn = NULL;
521
522                 class_dn = ldb_dn_from_ldb_val(mem_ctx,
523                                                ldb,
524                                                &applies_to_class->values[i]);
525                 if (class_dn == NULL) {
526                         return ldb_oom(ldb);
527                 }
528
529                 class_rdn = ldb_dn_get_rdn_val(class_dn);
530                 if (class_rdn == NULL) {
531                         TALLOC_FREE(class_dn);
532                         continue;
533                 }
534
535                 class_val = dsdb_class_by_cn_ldb_val(schema, class_rdn);
536                 TALLOC_FREE(class_dn);
537                 if (class_val == NULL) {
538                         continue;
539                 }
540
541                 if (class_val->governsID_id == principal_class_id) {
542                         *applies = true;
543                         return LDB_SUCCESS;
544                 }
545         }
546
547         *applies = false;
548         return LDB_SUCCESS;
549 }
550
551 static inline struct ldb_val talloc_steal_ldb_val(TALLOC_CTX *mem_ctx, struct ldb_val val)
552 {
553         val.data = talloc_steal(mem_ctx, val.data);
554         return val;
555 }
556
557 static uint32_t claim_get_value_count(const struct CLAIM_ENTRY *claim)
558 {
559         switch (claim->type) {
560         case CLAIM_TYPE_INT64:
561                 return claim->values.claim_int64.value_count;
562         case CLAIM_TYPE_UINT64:
563                 return claim->values.claim_uint64.value_count;
564         case CLAIM_TYPE_STRING:
565                 return claim->values.claim_string.value_count;
566         case CLAIM_TYPE_BOOLEAN:
567                 return claim->values.claim_boolean.value_count;
568         }
569
570         smb_panic(__location__ ": unknown claim type");
571         return 0;
572 }
573
574 static int encode_claims_set(struct ldb_context *ldb,
575                              TALLOC_CTX *mem_ctx,
576                              struct CLAIMS_SET *claims_set,
577                              DATA_BLOB *claims_blob)
578 {
579         TALLOC_CTX *tmp_ctx = NULL;
580         enum ndr_err_code ndr_err;
581         struct CLAIMS_SET_NDR *claims_set_info = NULL;
582         struct CLAIMS_SET_METADATA *metadata = NULL;
583         struct CLAIMS_SET_METADATA_NDR *metadata_ndr = NULL;
584
585         tmp_ctx = talloc_new(mem_ctx);
586         if (tmp_ctx == NULL) {
587                 return ldb_oom(ldb);
588         }
589
590         metadata_ndr = talloc_zero(tmp_ctx, struct CLAIMS_SET_METADATA_NDR);
591         if (metadata_ndr == NULL) {
592                 talloc_free(tmp_ctx);
593                 return ldb_oom(ldb);
594         }
595
596         metadata = talloc_zero(metadata_ndr, struct CLAIMS_SET_METADATA);
597         if (metadata == NULL) {
598                 talloc_free(tmp_ctx);
599                 return ldb_oom(ldb);
600         }
601
602         claims_set_info = talloc_zero(metadata, struct CLAIMS_SET_NDR);
603         if (claims_set_info == NULL) {
604                 talloc_free(tmp_ctx);
605                 return ldb_oom(ldb);
606         }
607
608         metadata_ndr->claims.metadata = metadata;
609
610         metadata->claims_set = claims_set_info;
611         metadata->compression_format = CLAIMS_COMPRESSION_FORMAT_XPRESS_HUFF;
612
613         claims_set_info->claims.claims = claims_set;
614
615         ndr_err = ndr_push_struct_blob(claims_blob, mem_ctx, metadata_ndr,
616                                        (ndr_push_flags_fn_t)ndr_push_CLAIMS_SET_METADATA_NDR);
617         if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
618                 NTSTATUS nt_status = ndr_map_error2ntstatus(ndr_err);
619                 DBG_ERR("CLAIMS_SET_METADATA_NDR push failed: %s\n",
620                         nt_errstr(nt_status));
621
622                 talloc_free(tmp_ctx);
623                 return ldb_operr(ldb);
624         }
625
626         talloc_free(tmp_ctx);
627         return LDB_SUCCESS;
628 }
629
630 static bool is_schema_dn(struct ldb_dn *dn,
631                          struct ldb_dn *schema_dn)
632 {
633         if (ldb_dn_get_comp_num(dn) != (ldb_dn_get_comp_num(schema_dn) + 1)) {
634                 return false;
635         }
636
637         return ldb_dn_compare_base(schema_dn, dn) == 0;
638 }
639
640 static bool is_valid_claim_attribute_syntax(const DATA_BLOB source_syntax,
641                                             uint64_t claim_value_type)
642 {
643         switch (claim_value_type) {
644         case CLAIM_TYPE_STRING:
645                 if (data_blob_equals_str(source_syntax, "2.5.5.1")) {
646                         return true;
647                 }
648                 if (data_blob_equals_str(source_syntax, "2.5.5.12")) {
649                         return true;
650                 }
651                 if (data_blob_equals_str(source_syntax, "2.5.5.15")) {
652                         return true;
653                 }
654                 break;
655         case CLAIM_TYPE_UINT64:
656                 if (data_blob_equals_str(source_syntax, "2.5.5.2")) {
657                         return true;
658                 }
659                 break;
660         case CLAIM_TYPE_INT64:
661                 if (data_blob_equals_str(source_syntax, "2.5.5.9")) {
662                         return true;
663                 }
664                 if (data_blob_equals_str(source_syntax, "2.5.5.16")) {
665                         return true;
666                 }
667                 break;
668         case CLAIM_TYPE_BOOLEAN:
669                 /* Note: MS-ADTS has a typo (2.2.5.8 instead of 2.5.5.8) */
670                 if (data_blob_equals_str(source_syntax, "2.5.5.8")) {
671                         return true;
672                 }
673                 break;
674         default:
675                 break;
676         }
677
678         return false;
679 }
680
681 static int get_all_claims(struct ldb_context *ldb,
682                           TALLOC_CTX *mem_ctx,
683                           struct ldb_dn *principal_dn,
684                           uint32_t principal_class_id,
685                           DATA_BLOB *claims_blob)
686 {
687         TALLOC_CTX *tmp_ctx = NULL;
688
689         const struct dsdb_schema *schema = NULL;
690
691         struct ldb_dn *claim_config_container = NULL;
692         struct ldb_dn *claim_types_child = NULL;
693         struct ldb_dn *config_dn = ldb_get_config_basedn(ldb);
694         struct ldb_dn *schema_dn = ldb_get_schema_basedn(ldb);
695         bool ok;
696         int ret;
697         struct ldb_result *res = NULL;
698         static const char * const attrs[] = {
699                 "Enabled",
700                 "msDS-ClaimAttributeSource",
701                 "msDS-ClaimSource",
702                 "msDS-ClaimSourceType",
703                 "msDS-ClaimTypeAppliesToClass",
704                 "msDS-ClaimValueType",
705                 "name",
706                 NULL
707         };
708
709         const char **ad_claim_attrs = NULL;
710         unsigned int ad_claim_attrs_count;
711         struct ad_claim_info {
712                 struct ldb_val name;
713                 DATA_BLOB syntax;
714                 const char *attribute;
715                 enum CLAIM_TYPE claim_type;
716         } *ad_claims = NULL;
717         unsigned ad_claims_count;
718
719         unsigned i;
720
721         /* The structure which we'll use to build up the claims. */
722         struct CLAIMS_SET claims_set = {};
723
724         struct CLAIMS_ARRAY *ad_sourced_constructed = NULL;
725
726         *claims_blob = data_blob_null;
727
728         tmp_ctx = talloc_new(mem_ctx);
729         if (tmp_ctx == NULL) {
730                 return ldb_oom(ldb);
731         }
732
733         schema = dsdb_get_schema(ldb, tmp_ctx);
734         if (schema == NULL) {
735                 talloc_free(tmp_ctx);
736                 return ldb_operr(ldb);
737         }
738
739         /* Get the DN of the claims container. */
740         claim_config_container = ldb_dn_copy(tmp_ctx, config_dn);
741         if (claim_config_container == NULL) {
742                 talloc_free(tmp_ctx);
743                 return ldb_oom(ldb);
744         }
745
746         claim_types_child = ldb_dn_new(tmp_ctx, ldb,
747                                        "CN=Claim Types,CN=Claims Configuration,CN=Services");
748         if (claim_types_child == NULL) {
749                 talloc_free(tmp_ctx);
750                 return ldb_oom(ldb);
751         }
752
753         ok = ldb_dn_add_child(claim_config_container, claim_types_child);
754         TALLOC_FREE(claim_types_child);
755         if (!ok) {
756                 talloc_free(tmp_ctx);
757                 return ldb_operr(ldb);
758         }
759
760         /* Search for the claims container's children. */
761         ret = ldb_search(ldb, tmp_ctx, &res,
762                          claim_config_container,
763                          LDB_SCOPE_ONELEVEL,
764                          attrs, NULL);
765         if (ret) {
766                 if (ret == LDB_ERR_NO_SUCH_OBJECT) {
767                         ret = LDB_SUCCESS;
768                 }
769
770                 talloc_free(tmp_ctx);
771                 return ret;
772         }
773
774         /*
775          * Allocate enough space for all AD claim attributes, followed by space
776          * for a NULL marker (so it can be passed as the attributes filter to
777          * ldb_search()).
778          */
779         ad_claim_attrs = talloc_array(tmp_ctx,
780                                       const char *,
781                                       res->count + 1);
782         if (ad_claim_attrs == NULL) {
783                 talloc_free(tmp_ctx);
784                 return ldb_oom(ldb);
785         }
786         ad_claims = talloc_array(tmp_ctx,
787                                  struct ad_claim_info,
788                                  res->count);
789         if (ad_claims == NULL) {
790                 talloc_free(tmp_ctx);
791                 return ldb_oom(ldb);
792         }
793         ad_claims_count = ad_claim_attrs_count = 0;
794
795         /* Loop through each child of the claims container. */
796         for (i = 0; i < res->count; ++i) {
797                 bool claim_applies = false;
798
799                 int enabled;
800                 uint64_t claim_value_type;
801
802                 const char *claim_source_type = NULL;
803                 const struct ldb_val *claim_attribute_source = NULL;
804
805                 /*
806                  * Does this claim apply to the most specific objectClass of the
807                  * principal?
808                  */
809                 ret = claim_applies_to_class(tmp_ctx,
810                                              ldb,
811                                              schema,
812                                              res->msgs[i],
813                                              principal_class_id,
814                                              &claim_applies);
815                 if (ret) {
816                         talloc_free(tmp_ctx);
817                         return ret;
818                 }
819                 if (!claim_applies) {
820                         /* If the claim doesn't apply, skip it. */
821                         continue;
822                 }
823
824                 enabled = ldb_msg_find_attr_as_bool(res->msgs[i], "Enabled", 0);
825                 if (!enabled) {
826                         /* If the claim isn't enabled, skip it. */
827                         continue;
828                 }
829
830                 claim_value_type = ldb_msg_find_attr_as_uint64(res->msgs[i],
831                                                                "msDS-ClaimValueType",
832                                                                0);
833                 if (!claim_value_type) {
834                         continue;
835                 }
836
837                 claim_source_type = ldb_msg_find_attr_as_string(res->msgs[i],
838                                                                 "msDS-ClaimSourceType",
839                                                                 "");
840
841                 /* Get the attribute used by the claim. */
842                 claim_attribute_source = ldb_msg_find_ldb_val(res->msgs[i],
843                                                               "msDS-ClaimAttributeSource");
844
845                 if (strcasecmp(claim_source_type, "AD") == 0) {
846                         struct ldb_dn *claim_attribute_source_dn = NULL;
847                         const struct ldb_val *claim_attribute_source_rdn = NULL;
848                         const struct dsdb_attribute *claim_attribute_source_class = NULL;
849
850                         DATA_BLOB source_syntax;
851                         const char *attribute = NULL;
852                         const struct ldb_val *name = NULL;
853
854                         if (claim_attribute_source == NULL) {
855                                 continue;
856                         }
857
858                         claim_attribute_source_dn = ldb_val_as_dn(ldb,
859                                                                   tmp_ctx,
860                                                                   claim_attribute_source);
861                         if (claim_attribute_source_dn == NULL) {
862                                 talloc_free(tmp_ctx);
863                                 return ldb_operr(ldb);
864                         }
865
866                         if (!is_schema_dn(claim_attribute_source_dn, schema_dn)) {
867                                 /* This DN doesn't belong to the schema. */
868                                 continue;
869                         }
870
871                         claim_attribute_source_rdn = ldb_dn_get_rdn_val(claim_attribute_source_dn);
872                         if (claim_attribute_source_rdn == NULL) {
873                                 /* No RDN, skip it. */
874                                 continue;
875                         }
876
877                         claim_attribute_source_class = dsdb_attribute_by_cn_ldb_val(schema,
878                                                                                     claim_attribute_source_rdn);
879                         claim_attribute_source_rdn = NULL;
880                         TALLOC_FREE(claim_attribute_source_dn);
881                         if (claim_attribute_source_class == NULL) {
882                                 continue;
883                         }
884
885                         source_syntax = data_blob_string_const(claim_attribute_source_class->attributeSyntax_oid);
886                         if (source_syntax.data == NULL) {
887                                 continue;
888                         }
889
890                         if (!is_valid_claim_attribute_syntax(source_syntax, claim_value_type)) {
891                                 continue;
892                         }
893
894                         attribute = claim_attribute_source_class->lDAPDisplayName;
895                         if (attribute == NULL) {
896                                 continue;
897                         }
898
899                         ret = add_attr_unique(tmp_ctx,
900                                               ad_claim_attrs,
901                                               &ad_claim_attrs_count,
902                                               attribute);
903                         if (ret) {
904                                 talloc_free(tmp_ctx);
905                                 return ret;
906                         }
907
908                         name = ldb_msg_find_ldb_val(res->msgs[i], "name");
909                         if (name == NULL) {
910                                 name = &data_blob_null;
911                         }
912
913                         ad_claims[ad_claims_count++] = (struct ad_claim_info) {
914                                 .name = *name,
915                                 .syntax = source_syntax,
916                                 .attribute = attribute,
917                                 .claim_type = claim_value_type,
918                         };
919                 }
920         }
921
922         if (ad_claims_count) {
923                 struct ldb_result *principal_res = NULL;
924                 const struct ldb_message *principal_msg = NULL;
925
926                 /* Shrink the arrays to remove any unused space. */
927                 ad_claim_attrs = talloc_realloc(tmp_ctx,
928                                                 ad_claim_attrs,
929                                                 const char *,
930                                                 ad_claim_attrs_count + 1);
931                 if (ad_claim_attrs == NULL) {
932                         talloc_free(tmp_ctx);
933                         return ldb_oom(ldb);
934                 }
935                 ad_claim_attrs[ad_claim_attrs_count] = NULL;
936
937                 ad_claims = talloc_realloc(tmp_ctx,
938                                            ad_claims,
939                                            struct ad_claim_info,
940                                            ad_claims_count);
941                 if (ad_claims == NULL) {
942                         talloc_free(tmp_ctx);
943                         return ldb_oom(ldb);
944                 }
945
946                 ret = ldb_search(ldb, tmp_ctx, &principal_res,
947                                  principal_dn,
948                                  LDB_SCOPE_BASE,
949                                  ad_claim_attrs, NULL);
950                 if (ret != LDB_SUCCESS) {
951                         DBG_ERR("Failed to find principal %s to construct claims\n",
952                                 ldb_dn_get_linearized(principal_dn));
953                         talloc_free(tmp_ctx);
954                         return ret;
955                 }
956
957                 principal_msg = principal_res->msgs[0];
958
959                 /*
960                  * Ensure that only the attrs we asked for end up in the results
961                  * (it's fine if some are missing)
962                  */
963                 SMB_ASSERT(principal_msg->num_elements <= ad_claim_attrs_count);
964
965                 for (i = 0; i < ad_claims_count; ++i) {
966                         const struct ldb_message_element *principal_attribute = NULL;
967                         struct CLAIM_ENTRY *claim_entry = NULL;
968                         uint32_t new_claims_array_count = claims_set.claims_array_count;
969
970                         /* Get the value of the claim attribute for the principal. */
971                         principal_attribute = ldb_msg_find_element(principal_res->msgs[0],
972                                                                    ad_claims[i].attribute);
973                         if (principal_attribute == NULL) {
974                                 continue;
975                         }
976
977                         /* Add the claim to the array. */
978
979                         if (ad_sourced_constructed == NULL) {
980                                 claims_set.claims_arrays = talloc_realloc(tmp_ctx,
981                                                                           claims_set.claims_arrays,
982                                                                           struct CLAIMS_ARRAY,
983                                                                           new_claims_array_count + 1);
984                                 if (claims_set.claims_arrays == NULL) {
985                                         talloc_free(tmp_ctx);
986                                         return ldb_oom(ldb);
987                                 }
988
989                                 ad_sourced_constructed = &claims_set.claims_arrays[new_claims_array_count++];
990                                 *ad_sourced_constructed = (struct CLAIMS_ARRAY) {
991                                         .claims_source_type = CLAIMS_SOURCE_TYPE_AD,
992                                 };
993                         }
994
995                         ad_sourced_constructed->claim_entries = talloc_realloc(
996                                 tmp_ctx,
997                                 ad_sourced_constructed->claim_entries,
998                                 struct CLAIM_ENTRY,
999                                 ad_sourced_constructed->claims_count + 1);
1000                         if (ad_sourced_constructed->claim_entries == NULL) {
1001                                 talloc_free(tmp_ctx);
1002                                 return ldb_oom(ldb);
1003                         }
1004
1005                         claim_entry = &ad_sourced_constructed->claim_entries[
1006                                 ad_sourced_constructed->claims_count];
1007
1008                         ret = fill_claim_entry(ad_sourced_constructed->claim_entries,
1009                                                ldb,
1010                                                schema,
1011                                                principal_attribute,
1012                                                ad_claims[i].name,
1013                                                ad_claims[i].syntax,
1014                                                ad_claims[i].claim_type,
1015                                                claim_entry);
1016                         if (ret != LDB_SUCCESS) {
1017                                 talloc_free(tmp_ctx);
1018                                 return ret;
1019                         }
1020
1021                         if (claim_get_value_count(claim_entry) > 0) {
1022                                 /*
1023                                  * If the claim contains values, add it to the
1024                                  * array(s).
1025                                  */
1026                                 ++ad_sourced_constructed->claims_count;
1027                                 claims_set.claims_array_count = new_claims_array_count;
1028                         }
1029                 }
1030         }
1031
1032         if (claims_set.claims_array_count == 0) {
1033                 /* If we have no claims, we're done. */
1034                 talloc_free(tmp_ctx);
1035                 return LDB_SUCCESS;
1036         }
1037
1038         /* Encode the claims ready to go into a PAC buffer. */
1039         ret = encode_claims_set(ldb, mem_ctx, &claims_set, claims_blob);
1040
1041         talloc_free(tmp_ctx);
1042         return ret;
1043 }
1044
1045 int get_claims_for_principal(struct ldb_context *ldb,
1046                              TALLOC_CTX *mem_ctx,
1047                              struct ldb_dn *principal_dn,
1048                              DATA_BLOB *claims_blob)
1049 {
1050         struct ldb_result *principal_res = NULL;
1051         static const char * const principal_attrs[] = {
1052                 "objectClass",
1053                 NULL
1054         };
1055
1056         struct ldb_message_element *principal_class_el = NULL;
1057         struct dsdb_schema *schema = NULL;
1058         const struct dsdb_class *principal_class = NULL;
1059
1060         int ret;
1061
1062         *claims_blob = data_blob_null;
1063
1064         ret = ldb_search(ldb, mem_ctx, &principal_res,
1065                          principal_dn,
1066                          LDB_SCOPE_BASE,
1067                          principal_attrs, NULL);
1068         if (ret != LDB_SUCCESS) {
1069                 return ret;
1070         }
1071
1072         principal_class_el = ldb_msg_find_element(principal_res->msgs[0],
1073                                                   "objectClass");
1074         if (principal_class_el == NULL) {
1075                 return ldb_operr(ldb);
1076         }
1077
1078         schema = dsdb_get_schema(ldb, mem_ctx);
1079         if (schema == NULL) {
1080                 return ldb_operr(ldb);
1081         }
1082
1083         principal_class = dsdb_get_last_structural_class(schema, principal_class_el);
1084         if (principal_class == NULL) {
1085                 return ldb_operr(ldb);
1086         }
1087
1088         return get_all_claims(ldb,
1089                               mem_ctx,
1090                               principal_dn,
1091                               principal_class->governsID_id,
1092                               claims_blob);
1093 }