Bug Summary

File:daemons/ipa-kdb/ipa_kdb_mspac.c
Warning:line 2038, column 12
Potential leak of memory pointed to by 'right_krbtgt_signing_key'

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-unknown-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ipa_kdb_mspac.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mthread-model posix -mframe-pointer=all -fmath-errno -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib64/clang/10.0.0 -D HAVE_CONFIG_H -I . -I ../.. -I . -I ../../util -D PREFIX="/usr/local" -D BINDIR="/usr/local/bin" -D LIBDIR="/usr/local/lib" -D LIBEXECDIR="/usr/local/libexec" -D DATADIR="/usr/local/share" -D LDAPIDIR="/run" -I /usr/include/samba-4.0 -D _GNU_SOURCE=1 -D HAVE_IMMEDIATE_STRUCTURES=1 -I /usr/include/nss3 -I /usr/include/nspr4 -I /usr/include/nspr4 -I /usr/include/nss3 -I /usr/include/nspr4 -D __STDC_WANT_LIB_EXT1__=1 -D _DEFAULT_SOURCE=1 -D _POSIX_C_SOURCE=200809L -D PIC -internal-isystem /usr/local/include -internal-isystem /usr/lib64/clang/10.0.0/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -fdebug-compilation-dir /home/heimes/redhat/freeipa/daemons/ipa-kdb -ferror-limit 19 -fmessage-length 0 -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fdiagnostics-show-option -analyzer-output=html -faddrsig -o /home/heimes/redhat/freeipa/report/2020-06-05-101548-295465-1 -x c ipa_kdb_mspac.c
1/*
2 * MIT Kerberos KDC database backend for FreeIPA
3 *
4 * Authors: Simo Sorce <ssorce@redhat.com>
5 *
6 * Copyright (C) 2011 Simo Sorce, Red Hat
7 * see file 'COPYING' for use and warranty information
8 *
9 * This program is free software you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation, either version 3 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23#include "config.h"
24
25#include "ipa_kdb.h"
26#include "ipa_mspac.h"
27#include <talloc.h>
28#include <unicase.h>
29#include "util/time.h"
30#include "gen_ndr/ndr_krb5pac.h"
31
32#include "ipa_kdb_mspac_private.h"
33
34static char *user_pac_attrs[] = {
35 "objectClass",
36 "uid",
37 "cn",
38 "fqdn",
39 "gidNumber",
40 "krbPrincipalName",
41 "krbCanonicalName",
42 "krbTicketPolicyReference",
43 "krbPrincipalExpiration",
44 "krbPasswordExpiration",
45 "krbPwdPolicyReference",
46 "krbPrincipalType",
47 "krbLastPwdChange",
48 "krbPrincipalAliases",
49 "krbLastSuccessfulAuth",
50 "krbLastFailedAuth",
51 "krbLoginFailedCount",
52 "krbLastAdminUnlock",
53 "krbTicketFlags",
54 "ipaNTSecurityIdentifier",
55 "ipaNTLogonScript",
56 "ipaNTProfilePath",
57 "ipaNTHomeDirectory",
58 "ipaNTHomeDirectoryDrive",
59 NULL((void*)0)
60};
61
62char *deref_search_attrs[] = {
63 "memberOf",
64 NULL((void*)0)
65};
66
67static char *memberof_pac_attrs[] = {
68 "gidNumber",
69 "ipaNTSecurityIdentifier",
70 NULL((void*)0)
71};
72
73#define SID_ID_AUTHS6 6
74#define SID_SUB_AUTHS15 15
75#define MAX(a,b)(((a)>(b))?(a):(b)) (((a)>(b))?(a):(b))
76#define MIN(a,b)(((a)<(b))?(a):(b)) (((a)<(b))?(a):(b))
77
78#define AUTHZ_DATA_TYPE_PAC"MS-PAC" "MS-PAC"
79#define AUTHZ_DATA_TYPE_PAD"PAD" "PAD"
80#define AUTHZ_DATA_TYPE_NONE"NONE" "NONE"
81
82int string_to_sid(const char *str, struct dom_sid *sid)
83{
84 unsigned long val;
85 const char *s;
86 char *t;
87 int i;
88
89 if (str == NULL((void*)0)) {
90 return EINVAL22;
91 }
92
93 memset(sid, '\0', sizeof(struct dom_sid));
94
95 s = str;
96
97 if (strncasecmp(s, "S-", 2) != 0) {
98 return EINVAL22;
99 }
100 s += 2;
101
102 val = strtoul(s, &t, 10);
103 if (s == t || !t || *t != '-') {
104 return EINVAL22;
105 }
106 s = t + 1;
107 sid->sid_rev_num = val;
108
109 val = strtoul(s, &t, 10);
110 if (s == t || !t) {
111 return EINVAL22;
112 }
113 sid->id_auth[2] = (val & 0xff000000) >> 24;
114 sid->id_auth[3] = (val & 0x00ff0000) >> 16;
115 sid->id_auth[4] = (val & 0x0000ff00) >> 8;
116 sid->id_auth[5] = (val & 0x000000ff);
117
118 for (i = 0; i < SID_SUB_AUTHS15; i++) {
119 switch (*t) {
120 case '\0':
121 /* no (more) subauths, we are done with it */
122 sid->num_auths = i;
123 return 0;
124 case '-':
125 /* there are (more) subauths */
126 s = t + 1;;
127 break;
128 default:
129 /* garbage */
130 return EINVAL22;
131 }
132
133 val = strtoul(s, &t, 10);
134 if (s == t || !t) {
135 return EINVAL22;
136 }
137 sid->sub_auths[i] = val;
138 }
139
140 if (*t != '\0') {
141 return EINVAL22;
142 }
143
144 sid->num_auths = i;
145 return 0;
146}
147
148char *dom_sid_string(TALLOC_CTX *memctx, const struct dom_sid *dom_sid)
149{
150 size_t c;
151 size_t len;
152 int ofs;
153 uint32_t ia;
154 char *buf;
155
156 if (dom_sid == NULL((void*)0)
157 || dom_sid->num_auths < 0
158 || dom_sid->num_auths > SID_SUB_AUTHS15) {
159 return NULL((void*)0);
160 }
161
162 len = 25 + dom_sid->num_auths * 11;
163
164 buf = talloc_zero_size(memctx, len)_talloc_zero(memctx, len, "ipa_kdb_mspac.c" ":" "164");
165 if (buf == NULL((void*)0)) {
166 return NULL((void*)0);
167 }
168
169 ia = (dom_sid->id_auth[5]) +
170 (dom_sid->id_auth[4] << 8 ) +
171 (dom_sid->id_auth[3] << 16) +
172 (dom_sid->id_auth[2] << 24);
173
174 ofs = snprintf(buf, len, "S-%u-%lu", (unsigned int) dom_sid->sid_rev_num,
175 (unsigned long) ia);
176
177 for (c = 0; c < dom_sid->num_auths; c++) {
178 ofs += snprintf(buf + ofs, MAX(len - ofs, 0)(((len - ofs)>(0))?(len - ofs):(0)), "-%lu",
179 (unsigned long) dom_sid->sub_auths[c]);
180 }
181
182 if (ofs >= len) {
183 talloc_free(buf)_talloc_free(buf, "ipa_kdb_mspac.c" ":" "183");
184 return NULL((void*)0);
185 }
186
187 return buf;
188}
189
190static struct dom_sid *dom_sid_dup(TALLOC_CTX *memctx,
191 const struct dom_sid *dom_sid)
192{
193 struct dom_sid *new_sid;
194 size_t c;
195
196 if (dom_sid == NULL((void*)0)) {
197 return NULL((void*)0);
198 }
199
200 new_sid = talloc(memctx, struct dom_sid)(struct dom_sid *)talloc_named_const(memctx, sizeof(struct dom_sid
), "struct dom_sid")
;
201 if (new_sid == NULL((void*)0)) {
202 return NULL((void*)0);
203 }
204
205 new_sid->sid_rev_num = dom_sid->sid_rev_num;
206 for (c = 0; c < SID_ID_AUTHS6; c++) {
207 new_sid->id_auth[c] = dom_sid->id_auth[c];
208 }
209 new_sid->num_auths = dom_sid->num_auths;
210 for (c = 0; c < SID_SUB_AUTHS15; c++) {
211 new_sid->sub_auths[c] = dom_sid->sub_auths[c];
212 }
213
214 return new_sid;
215}
216
217/* checks if sid1 is a domain of sid2 or compares them exactly if exact_check is true
218 * returns
219 * true -- if sid1 is a domain of sid2 (including full exact match)
220 * false -- otherwise
221 *
222 * dom_sid_check() is supposed to be used with sid1 representing domain SID
223 * and sid2 being either domain or resource SID in the domain
224 */
225static bool_Bool dom_sid_check(const struct dom_sid *sid1, const struct dom_sid *sid2, bool_Bool exact_check)
226{
227 int c, num;
228
229 if (sid1 == sid2) {
230 return true1;
231 }
232
233 if (sid1 == NULL((void*)0)) {
234 return false0;
235 }
236
237 if (sid2 == NULL((void*)0)) {
238 return false0;
239 }
240
241 /* If SIDs have different revisions, they are different */
242 if (sid1->sid_rev_num != sid2->sid_rev_num)
243 return false0;
244
245 /* When number of authorities is different, sids are different
246 * if we were asked to check prefix exactly */
247 num = sid2->num_auths - sid1->num_auths;
248 if (num != 0) {
249 if (exact_check) {
250 return false0;
251 } else {
252 /* otherwise we are dealing with prefix check
253 * and sid2 should have RID compared to the sid1 */
254 if (num != 1) {
255 return false0;
256 }
257 }
258 }
259
260 /* now either sid1->num_auths == sid2->num_auths or sid1 has no RID */
261
262 /* for same size authorities compare them backwards
263 * since RIDs are likely different */
264 for (c = sid1->num_auths; c >= 0; --c)
265 if (sid1->sub_auths[c] != sid2->sub_auths[c])
266 return false0;
267
268 /* Finally, compare Identifier authorities */
269 for (c = 0; c < SID_ID_AUTHS6; c++)
270 if (sid1->id_auth[c] != sid2->id_auth[c])
271 return false0;
272
273 return true1;
274}
275
276static bool_Bool dom_sid_is_prefix(const struct dom_sid *sid1, const struct dom_sid *sid2)
277{
278 int c;
279
280 if (sid1 == sid2) {
281 return true1;
282 }
283
284 if (sid1 == NULL((void*)0)) {
285 return false0;
286 }
287
288 if (sid2 == NULL((void*)0)) {
289 return false0;
290 }
291
292 /* If SIDs have different revisions, they are different */
293 if (sid1->sid_rev_num != sid2->sid_rev_num)
294 return false0;
295
296 if (sid1->num_auths > sid2->num_auths)
297 return false0;
298
299 /* now sid1->num_auths <= sid2->num_auths */
300
301 /* compare up to sid1->num_auth authorities since RIDs are
302 * likely different and we are searching for the prefix */
303 for (c = 0; c < sid1->num_auths; c++)
304 if (sid1->sub_auths[c] != sid2->sub_auths[c])
305 return false0;
306
307 /* Finally, compare Identifier authorities */
308 for (c = 0; c < SID_ID_AUTHS6; c++)
309 if (sid1->id_auth[c] != sid2->id_auth[c])
310 return false0;
311
312 return true1;
313}
314
315static int sid_append_rid(struct dom_sid *sid, uint32_t rid)
316{
317 if (sid->num_auths >= SID_SUB_AUTHS15) {
318 return EINVAL22;
319 }
320
321 sid->sub_auths[sid->num_auths++] = rid;
322 return 0;
323}
324
325/**
326* @brief Takes a user sid and removes the rid.
327* The sid is changed by this function,
328* the removed rid is returned too.
329*
330* @param sid A user/group SID
331* @param rid The actual RID found.
332*
333* @return 0 on success, EINVAL otherwise.
334*/
335static int sid_split_rid(struct dom_sid *sid, uint32_t *rid)
336{
337 if (sid->num_auths == 0) {
338 return EINVAL22;
339 }
340
341 sid->num_auths--;
342 if (rid != NULL((void*)0)) {
343 *rid = sid->sub_auths[sid->num_auths];
344 }
345 sid->sub_auths[sid->num_auths] = 0;
346
347 return 0;
348}
349
350/* Add Asserted Identity SID */
351static krb5_error_code ipadb_add_asserted_identity(struct ipadb_context *ipactx,
352 unsigned int flags,
353 TALLOC_CTX *memctx,
354 struct netr_SamInfo3 *info3)
355{
356 struct netr_SidAttr *arr = NULL((void*)0);
357 uint32_t sidcount = info3->sidcount;
358 krb5_error_code ret = 0;
359
360 arr = talloc_realloc(memctx,(struct netr_SidAttr *)_talloc_realloc_array(memctx, info3->
sids, sizeof(struct netr_SidAttr), sidcount + 1, "struct netr_SidAttr"
)
361 info3->sids,(struct netr_SidAttr *)_talloc_realloc_array(memctx, info3->
sids, sizeof(struct netr_SidAttr), sidcount + 1, "struct netr_SidAttr"
)
362 struct netr_SidAttr,(struct netr_SidAttr *)_talloc_realloc_array(memctx, info3->
sids, sizeof(struct netr_SidAttr), sidcount + 1, "struct netr_SidAttr"
)
363 sidcount + 1)(struct netr_SidAttr *)_talloc_realloc_array(memctx, info3->
sids, sizeof(struct netr_SidAttr), sidcount + 1, "struct netr_SidAttr"
)
;
364 if (!arr) {
365 return ENOMEM12;
366 }
367 arr[sidcount].sid = talloc_zero(arr, struct dom_sid2)(struct dom_sid *)_talloc_zero(arr, sizeof(struct dom_sid), "struct dom_sid2"
)
;
368 if (!arr[sidcount].sid) {
369 return ENOMEM12;
370 }
371
372 /* For S4U2Self, add Service Asserted Identity SID
373 * otherwise, add Authentication Authority Asserted Identity SID */
374 ret = string_to_sid((flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION0x00000100) ?
375 "S-1-18-2" : "S-1-18-1",
376 arr[sidcount].sid);
377 if (ret) {
378 return ret;
379 }
380 arr[sidcount].attributes = SE_GROUP_MANDATORY( 0x00000001 ) |
381 SE_GROUP_ENABLED( 0x00000004 ) |
382 SE_GROUP_ENABLED_BY_DEFAULT( 0x00000002 );
383 info3->sids = arr;
384 info3->sidcount = sidcount + 1;
385 info3->base.user_flags |= NETLOGON_EXTRA_SIDS( 0x00000020 );
386
387 return 0;
388}
389
390static bool_Bool is_master_host(struct ipadb_context *ipactx, const char *fqdn)
391{
392 int ret;
393 char *master_host_base = NULL((void*)0);
394 LDAPMessage *result = NULL((void*)0);
395 krb5_error_code err;
396
397 ret = asprintf(&master_host_base, "cn=%s,cn=masters,cn=ipa,cn=etc,%s",
398 fqdn, ipactx->base);
399 if (ret == -1) {
400 return false0;
401 }
402 err = ipadb_simple_search(ipactx, master_host_base, LDAP_SCOPE_BASE((ber_int_t) 0x0000),
403 NULL((void*)0), NULL((void*)0), &result);
404 free(master_host_base);
405 ldap_msgfree(result);
406 if (err == 0) {
407 return true1;
408 }
409
410 return false0;
411}
412
413static krb5_error_code ipadb_fill_info3(struct ipadb_context *ipactx,
414 LDAPMessage *lentry,
415 unsigned int flags,
416 TALLOC_CTX *memctx,
417 struct netr_SamInfo3 *info3)
418{
419 LDAP *lcontext = ipactx->lcontext;
420 LDAPDerefRes *deref_results = NULL((void*)0);
421 struct dom_sid sid;
422 gid_t prigid = -1;
423 time_t timeres;
424 char *strres;
425 int intres;
426 int ret;
427 char **objectclasses = NULL((void*)0);
428 size_t c;
429 bool_Bool is_host = false0;
430 bool_Bool is_user = false0;
431 bool_Bool is_service = false0;
432 bool_Bool is_ipauser = false0;
433 bool_Bool is_idobject = false0;
434 krb5_principal princ;
435
436 ret = ipadb_ldap_attr_to_strlist(lcontext, lentry, "objectClass",
437 &objectclasses);
438 if (ret == 0 && objectclasses != NULL((void*)0)) {
439 for (c = 0; objectclasses[c] != NULL((void*)0); c++) {
440 if (strcasecmp(objectclasses[c], "ipaHost") == 0) {
441 is_host = true1;
442 }
443 if (strcasecmp(objectclasses[c], "ipaService") == 0) {
444 is_service = true1;
445 }
446 if (strcasecmp(objectclasses[c], "ipaNTUserAttrs") == 0) {
447 is_user = true1;
448 }
449 if (strcasecmp(objectclasses[c], "ipaIDObject") == 0) {
450 is_idobject = true1;
451 }
452 if (strcasecmp(objectclasses[c], "ipaUser") == 0) {
453 is_ipauser = true1;
454 }
455 free(objectclasses[c]);
456 }
457 }
458 free(objectclasses);
459
460 /* SMB service on IPA domain member will have both ipaIDOjbect and ipaUser
461 * object classes. Such service will have to be treated as a user in order
462 * to issue MS-PAC record for it. */
463 if (is_idobject && is_ipauser) {
464 is_user = true1;
465 }
466
467 if (!is_host && !is_user && !is_service) {
468 /* We only handle users and hosts, and services */
469 return ENOENT2;
470 }
471
472 if (is_host) {
473 ret = ipadb_ldap_attr_to_str(lcontext, lentry, "fqdn", &strres);
474 if (ret) {
475 /* fqdn is mandatory for hosts */
476 return ret;
477 }
478 } else if (is_service) {
479 ret = ipadb_ldap_attr_to_str(lcontext, lentry, "krbCanonicalName", &strres);
480 if (ret) {
481 /* krbCanonicalName is mandatory for services */
482 return ret;
483 }
484
485 ret = krb5_parse_name(ipactx->kcontext, strres, &princ);
486
487 free(strres);
488 if (ret) {
489 return ENOENT2;
490 }
491
492 ret = krb5_unparse_name_flags(ipactx->kcontext,
493 princ, KRB5_PRINCIPAL_UNPARSE_SHORT0x1,
494 &strres);
495 if (ret) {
496 return ENOENT2;
497 }
498 } else {
499 ret = ipadb_ldap_attr_to_str(lcontext, lentry, "uid", &strres);
500 if (ret) {
501 /* uid is mandatory */
502 return ret;
503 }
504 }
505
506 info3->base.account_name.string = talloc_strdup(memctx, strres);
507 free(strres);
508
509 if (is_host || is_service) {
510 prigid = 515; /* Well known RID for domain computers group */
511 } else {
512 ret = ipadb_ldap_attr_to_int(lcontext, lentry, "gidNumber", &intres);
513 if (ret) {
514 /* gidNumber is mandatory */
515 return ret;
516 }
517 prigid = intres;
518 }
519
520
521 info3->base.logon_time = 0; /* do not have this info yet */
522 info3->base.logoff_time = -1; /* do not force logoff */
523
524/* TODO: is krbPrinciplaExpiration what we want to use in kickoff_time ?
525 * Needs more investigation */
526#if 0
527 ret = ipadb_ldap_attr_to_time_t(lcontext, lentry,
528 "krbPrincipalExpiration", &timeres);
529 switch (ret) {
530 case 0:
531 unix_to_nt_time(&info3->base.acct_expiry, timeres);
532 break;
533 case ENOENT2:
534 info3->base.acct_expiry = -1;
535 break;
536 default:
537 return ret;
538 }
539#else
540 info3->base.kickoff_time = -1;
541#endif
542
543 ret = ipadb_ldap_attr_to_time_t(lcontext, lentry,
544 "krbLastPwdChange", &timeres);
545 switch (ret) {
546 case 0:
547 unix_to_nt_time(&info3->base.last_password_change, timeres);
548 break;
549 case ENOENT2:
550 info3->base.last_password_change = 0;
551 break;
552 default:
553 return ret;
554 }
555
556 /* TODO: from pw policy (ied->pol) */
557 info3->base.allow_password_change = 0;
558 info3->base.force_password_change = -1;
559
560 ret = ipadb_ldap_attr_to_str(lcontext, lentry, "cn", &strres);
561 switch (ret) {
562 case 0:
563 info3->base.full_name.string = talloc_strdup(memctx, strres);
564 free(strres);
565 break;
566 case ENOENT2:
567 info3->base.full_name.string = "";
568 break;
569 default:
570 return ret;
571 }
572
573 ret = ipadb_ldap_attr_to_str(lcontext, lentry,
574 "ipaNTLogonScript", &strres);
575 switch (ret) {
576 case 0:
577 info3->base.logon_script.string = talloc_strdup(memctx, strres);
578 free(strres);
579 break;
580 case ENOENT2:
581 info3->base.logon_script.string = "";
582 break;
583 default:
584 return ret;
585 }
586
587 ret = ipadb_ldap_attr_to_str(lcontext, lentry,
588 "ipaNTProfilePath", &strres);
589 switch (ret) {
590 case 0:
591 info3->base.profile_path.string = talloc_strdup(memctx, strres);
592 free(strres);
593 break;
594 case ENOENT2:
595 info3->base.profile_path.string = "";
596 break;
597 default:
598 return ret;
599 }
600
601 ret = ipadb_ldap_attr_to_str(lcontext, lentry,
602 "ipaNTHomeDirectory", &strres);
603 switch (ret) {
604 case 0:
605 info3->base.home_directory.string = talloc_strdup(memctx, strres);
606 free(strres);
607 break;
608 case ENOENT2:
609 info3->base.home_directory.string = "";
610 break;
611 default:
612 return ret;
613 }
614
615 ret = ipadb_ldap_attr_to_str(lcontext, lentry,
616 "ipaNTHomeDirectoryDrive", &strres);
617 switch (ret) {
618 case 0:
619 info3->base.home_drive.string = talloc_strdup(memctx, strres);
620 free(strres);
621 break;
622 case ENOENT2:
623 info3->base.home_drive.string = "";
624 break;
625 default:
626 return ret;
627 }
628
629 info3->base.logon_count = 0; /* we do not have this info yet */
630 info3->base.bad_password_count = 0; /* we do not have this info yet */
631
632 if ((is_host || is_service)) {
633 /* it is either host or service, so get the hostname first */
634 char *sep = strchr(info3->base.account_name.string, '/');
635 bool_Bool is_master = is_master_host(
636 ipactx,
637 sep ? sep + 1 : info3->base.account_name.string);
638 if (is_master) {
639 /* Well know RID of domain controllers group */
640 info3->base.rid = 516;
641 } else {
642 /* Well know RID of domain computers group */
643 info3->base.rid = 515;
644 }
645 } else {
646 ret = ipadb_ldap_attr_to_str(lcontext, lentry,
647 "ipaNTSecurityIdentifier", &strres);
648 if (ret) {
649 /* SID is mandatory */
650 return ret;
651 }
652 ret = string_to_sid(strres, &sid);
653 free(strres);
654 if (ret) {
655 return ret;
656 }
657 ret = sid_split_rid(&sid, &info3->base.rid);
658 if (ret) {
659 return ret;
660 }
661 }
662
663 ret = ipadb_ldap_deref_results(lcontext, lentry, &deref_results);
664 switch (ret) {
665 LDAPDerefRes *dres;
666 LDAPDerefVal *dval;
667 struct dom_sid gsid;
668 uint32_t trid;
669 gid_t tgid;
670 char *s;
671 int count;
672 case 0:
673 count = 0;
674 for (dres = deref_results; dres; dres = dres->next) {
675 count++; /* count*/
676 }
677 info3->base.groups.rids = talloc_array(memctx,(struct samr_RidWithAttribute *)_talloc_array(memctx, sizeof(
struct samr_RidWithAttribute), count, "struct samr_RidWithAttribute"
)
678 struct samr_RidWithAttribute, count)(struct samr_RidWithAttribute *)_talloc_array(memctx, sizeof(
struct samr_RidWithAttribute), count, "struct samr_RidWithAttribute"
)
;
679 if (!info3->base.groups.rids) {
680 ldap_derefresponse_free(deref_results);
681 return ENOMEM12;
682 }
683
684 count = 0;
685 info3->base.primary_gid = 0;
686 for (dres = deref_results; dres; dres = dres->next) {
687 gsid.sid_rev_num = 0;
688 tgid = 0;
689 for (dval = dres->attrVals; dval; dval = dval->next) {
690 if (strcasecmp(dval->type, "gidNumber") == 0) {
691 tgid = strtoul((char *)dval->vals[0].bv_val, &s, 10);
692 if (tgid == 0) {
693 continue;
694 }
695 }
696 if (strcasecmp(dval->type, "ipaNTSecurityIdentifier") == 0) {
697 ret = string_to_sid((char *)dval->vals[0].bv_val, &gsid);
698 if (ret) {
699 continue;
700 }
701 }
702 }
703 if (tgid && gsid.sid_rev_num) {
704 ret = sid_split_rid(&gsid, &trid);
705 if (ret) {
706 continue;
707 }
708 if (tgid == prigid) {
709 info3->base.primary_gid = trid;
710 }
711 info3->base.groups.rids[count].rid = trid;
712 info3->base.groups.rids[count].attributes =
713 SE_GROUP_ENABLED( 0x00000004 ) |
714 SE_GROUP_MANDATORY( 0x00000001 ) |
715 SE_GROUP_ENABLED_BY_DEFAULT( 0x00000002 );
716 count++;
717 }
718 }
719 info3->base.groups.count = count;
720
721 ldap_derefresponse_free(deref_results);
722 break;
723 case ENOENT2:
724 info3->base.groups.count = 0;
725 info3->base.groups.rids = NULL((void*)0);
726 break;
727 default:
728 return ret;
729 }
730
731 if (info3->base.primary_gid == 0) {
732 if (is_host || is_service) {
733 info3->base.primary_gid = 515; /* Well known RID for domain computers group */
734 } else {
735 if (ipactx->mspac->fallback_rid) {
736 info3->base.primary_gid = ipactx->mspac->fallback_rid;
737 } else {
738 /* can't give a pack without a primary group rid */
739 return ENOENT2;
740 }
741 }
742 }
743
744 /* always zero out, only valid flags are for extra sids with Krb */
745 info3->base.user_flags = 0; /* netr_UserFlags */
746
747 /* always zero out, not used for Krb, only NTLM */
748 memset(&info3->base.key, '\0', sizeof(info3->base.key));
749
750 if (ipactx->mspac->flat_server_name) {
751 info3->base.logon_server.string =
752 talloc_strdup(memctx, ipactx->mspac->flat_server_name);
753 if (!info3->base.logon_server.string) {
754 return ENOMEM12;
755 }
756 } else {
757 /* can't give a pack without Server NetBIOS Name :-| */
758 return ENOENT2;
759 }
760
761 if (ipactx->mspac->flat_domain_name) {
762 info3->base.logon_domain.string =
763 talloc_strdup(memctx, ipactx->mspac->flat_domain_name);
764 if (!info3->base.logon_domain.string) {
765 return ENOMEM12;
766 }
767 } else {
768 /* can't give a pack without Domain NetBIOS Name :-| */
769 return ENOENT2;
770 }
771
772 if (is_host || is_service) {
773 info3->base.domain_sid = talloc_memdup(memctx, &ipactx->mspac->domsid,_talloc_memdup(memctx, &ipactx->mspac->domsid, sizeof
(ipactx->mspac->domsid), "ipa_kdb_mspac.c" ":" "774")
774 sizeof(ipactx->mspac->domsid))_talloc_memdup(memctx, &ipactx->mspac->domsid, sizeof
(ipactx->mspac->domsid), "ipa_kdb_mspac.c" ":" "774")
;
775 } else {
776 /* we got the domain SID for the user sid */
777 info3->base.domain_sid = talloc_memdup(memctx, &sid, sizeof(sid))_talloc_memdup(memctx, &sid, sizeof(sid), "ipa_kdb_mspac.c"
":" "777")
;
778 }
779
780 /* always zero out, not used for Krb, only NTLM */
781 memset(&info3->base.LMSessKey, '\0', sizeof(info3->base.LMSessKey));
782
783 /* TODO: fill based on objectclass, user vs computer, etc... */
784 info3->base.acct_flags = ACB_NORMAL( 0x00000010 ); /* samr_AcctFlags */
785
786 info3->base.sub_auth_status = 0;
787 info3->base.last_successful_logon = 0;
788 info3->base.last_failed_logon = 0;
789 info3->base.failed_logon_count = 0; /* We do not have it */
790 info3->base.reserved = 0; /* Reserved */
791
792 ret = ipadb_add_asserted_identity(ipactx, flags, memctx, info3);
793 return ret;
794}
795
796static krb5_error_code ipadb_get_pac(krb5_context kcontext,
797 krb5_db_entry *client,
798 unsigned int flags,
799 krb5_pac *pac)
800{
801 TALLOC_CTX *tmpctx;
802 struct ipadb_e_data *ied;
803 struct ipadb_context *ipactx;
804 LDAPMessage *results = NULL((void*)0);
805 LDAPMessage *lentry;
806 DATA_BLOB pac_data;
807 krb5_data data;
808 union PAC_INFO pac_info;
809 krb5_error_code kerr;
810 enum ndr_err_code ndr_err;
811 union PAC_INFO pac_upn;
812 char *principal = NULL((void*)0);
813
814 /* When no client entry is there, we cannot generate MS-PAC */
815 if (!client) {
816 *pac = NULL((void*)0);
817 return 0;
818 }
819
820 ipactx = ipadb_get_context(kcontext);
821 if (!ipactx) {
822 return KRB5_KDB_DBNOTINITED(-1780008435L);
823 }
824
825 ied = (struct ipadb_e_data *)client->e_data;
826 if (ied->magic != IPA_E_DATA_MAGIC0x0eda7a) {
827 return EINVAL22;
828 }
829
830 tmpctx = talloc_new(NULL)talloc_named_const(((void*)0), 0, "talloc_new: " "ipa_kdb_mspac.c"
":" "830")
;
831 if (!tmpctx) {
832 return ENOMEM12;
833 }
834
835 memset(&pac_info, 0, sizeof(pac_info));
836 pac_info.logon_info.info = talloc_zero(tmpctx, struct PAC_LOGON_INFO)(struct PAC_LOGON_INFO *)_talloc_zero(tmpctx, sizeof(struct PAC_LOGON_INFO
), "struct PAC_LOGON_INFO")
;
837 if (!pac_info.logon_info.info) {
838 kerr = ENOMEM12;
839 goto done;
840 }
841
842 /* PAC_LOGON_NAME and PAC_TYPE_UPN_DNS_INFO are automatically added
843 * by krb5_pac_sign() later on */
844
845 /* == Search PAC info == */
846 kerr = ipadb_deref_search(ipactx, ied->entry_dn, LDAP_SCOPE_BASE((ber_int_t) 0x0000),
847 "(objectclass=*)", user_pac_attrs,
848 deref_search_attrs, memberof_pac_attrs,
849 &results);
850 if (kerr) {
851 goto done;
852 }
853
854 lentry = ldap_first_entry(ipactx->lcontext, results);
855 if (!lentry) {
856 kerr = ENOENT2;
857 goto done;
858 }
859
860 /* == Fill Info3 == */
861 kerr = ipadb_fill_info3(ipactx, lentry, flags, tmpctx,
862 &pac_info.logon_info.info->info3);
863 if (kerr) {
864 goto done;
865 }
866
867 /* == Package PAC == */
868 ndr_err = ndr_push_union_blob(&pac_data, tmpctx, &pac_info,
869 PAC_TYPE_LOGON_INFO,
870 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
871 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)(ndr_err == NDR_ERR_SUCCESS)) {
872 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
873 goto done;
874 }
875
876 kerr = krb5_pac_init(kcontext, pac);
877 if (kerr) {
878 goto done;
879 }
880
881 data.magic = KV5M_DATA(-1760647422L);
882 data.data = (char *)pac_data.data;
883 data.length = pac_data.length;
884
885 kerr = krb5_pac_add_buffer(kcontext, *pac, KRB5_PAC_LOGON_INFO1, &data);
886
887 /* == Package UPN_DNS_LOGON_INFO == */
888 memset(&pac_upn, 0, sizeof(pac_upn));
889 kerr = krb5_unparse_name(kcontext, client->princ, &principal);
890 if (kerr) {
891 goto done;
892 }
893
894 pac_upn.upn_dns_info.upn_name = talloc_strdup(tmpctx, principal);
895 krb5_free_unparsed_name(kcontext, principal);
896 if (pac_upn.upn_dns_info.upn_name == NULL((void*)0)) {
897 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
898 goto done;
899 }
900
901 pac_upn.upn_dns_info.dns_domain_name = talloc_strdup(tmpctx, ipactx->realm);
902 if (pac_upn.upn_dns_info.dns_domain_name == NULL((void*)0)) {
903 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
904 goto done;
905 }
906
907 /* IPA user principals are all constructed */
908 if ((pac_info.logon_info.info->info3.base.rid != 515) ||
909 (pac_info.logon_info.info->info3.base.rid != 516)) {
910 pac_upn.upn_dns_info.flags |= PAC_UPN_DNS_FLAG_CONSTRUCTED( 0x00000001 );
911 }
912
913 ndr_err = ndr_push_union_blob(&pac_data, tmpctx, &pac_upn,
914 PAC_TYPE_UPN_DNS_INFO,
915 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
916 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)(ndr_err == NDR_ERR_SUCCESS)) {
917 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
918 goto done;
919 }
920
921 data.magic = KV5M_DATA(-1760647422L);
922 data.data = (char *)pac_data.data;
923 data.length = pac_data.length;
924
925 kerr = krb5_pac_add_buffer(kcontext, *pac, KRB5_PAC_UPN_DNS_INFO12, &data);
926
927done:
928 ldap_msgfree(results);
929 talloc_free(tmpctx)_talloc_free(tmpctx, "ipa_kdb_mspac.c" ":" "929");
930 return kerr;
931}
932
933static bool_Bool is_cross_realm_krbtgt(krb5_const_principal princ)
934{
935 if ((princ->length != 2) ||
936 (princ->data[0].length != 6) ||
937 (strncasecmp(princ->data[0].data, "krbtgt", 6) != 0)) {
938 return false0;
939 }
940 if (princ->data[1].length == princ->realm.length &&
941 strncasecmp(princ->data[1].data,
942 princ->realm.data, princ->realm.length) == 0) {
943 return false0;
944 }
945
946 return true1;
947}
948
949static char *gen_sid_string(TALLOC_CTX *memctx, struct dom_sid *dom_sid,
950 uint32_t rid)
951{
952 char *str = NULL((void*)0);
953 int ret;
954
955 ret = sid_append_rid(dom_sid, rid);
956 if (ret != 0) {
957 krb5_klog_syslog(LOG_ERR3, "sid_append_rid failed");
958 return NULL((void*)0);
959 }
960
961 str = dom_sid_string(memctx, dom_sid);
962 ret = sid_split_rid(dom_sid, NULL((void*)0));
963 if (ret != 0) {
964 krb5_klog_syslog(LOG_ERR3, "sid_split_rid failed");
965 talloc_free(str)_talloc_free(str, "ipa_kdb_mspac.c" ":" "965");
966 return NULL((void*)0);
967 }
968
969 return str;
970}
971
972static int get_user_and_group_sids(TALLOC_CTX *memctx,
973 struct PAC_LOGON_INFO_CTR *logon_info,
974 char ***_group_sids)
975{
976 int ret;
977 size_t c;
978 size_t p = 0;
979 struct dom_sid *domain_sid = NULL((void*)0);
980 char **group_sids = NULL((void*)0);
981
982 domain_sid = dom_sid_dup(memctx, logon_info->info->info3.base.domain_sid);
983 if (domain_sid == NULL((void*)0)) {
984 krb5_klog_syslog(LOG_ERR3, "dom_sid_dup failed");
985 ret = ENOMEM12;
986 goto done;
987 }
988
989 group_sids = talloc_array(memctx, char *,(char * *)_talloc_array(memctx, sizeof(char *), 3 + logon_info
->info->info3.base.groups.count + logon_info->info->
info3.sidcount, "char *")
990 3 +(char * *)_talloc_array(memctx, sizeof(char *), 3 + logon_info
->info->info3.base.groups.count + logon_info->info->
info3.sidcount, "char *")
991 logon_info->info->info3.base.groups.count +(char * *)_talloc_array(memctx, sizeof(char *), 3 + logon_info
->info->info3.base.groups.count + logon_info->info->
info3.sidcount, "char *")
992 logon_info->info->info3.sidcount)(char * *)_talloc_array(memctx, sizeof(char *), 3 + logon_info
->info->info3.base.groups.count + logon_info->info->
info3.sidcount, "char *")
;
993 if (group_sids == NULL((void*)0)) {
994 krb5_klog_syslog(LOG_ERR3, "talloc_array failed");
995 ret = ENOMEM12;
996 goto done;
997 }
998
999 group_sids[p] = gen_sid_string(memctx, domain_sid,
1000 logon_info->info->info3.base.rid);
1001 if (group_sids[p] == NULL((void*)0)) {
1002 krb5_klog_syslog(LOG_ERR3, "gen_sid_string failed");
1003 ret = EINVAL22;
1004 goto done;
1005 }
1006 p++;
1007
1008 group_sids[p] = gen_sid_string(memctx, domain_sid,
1009 logon_info->info->info3.base.primary_gid);
1010 if (group_sids[p] == NULL((void*)0)) {
1011 krb5_klog_syslog(LOG_ERR3, "gen_sid_string failed");
1012 ret = EINVAL22;
1013 goto done;
1014 }
1015 p++;
1016
1017 for (c = 0; c < logon_info->info->info3.base.groups.count; c++) {
1018 group_sids[p] = gen_sid_string(memctx, domain_sid,
1019 logon_info->info->info3.base.groups.rids[c].rid);
1020 if (group_sids[p] == NULL((void*)0)) {
1021 krb5_klog_syslog(LOG_ERR3, "gen_sid_string 2 failed");
1022 ret = EINVAL22;
1023 goto done;
1024 }
1025 p++;
1026 }
1027 for (c = 0; c < logon_info->info->info3.sidcount; c++) {
1028 group_sids[p] = dom_sid_string(memctx,
1029 logon_info->info->info3.sids[c].sid);
1030 if (group_sids[p] == NULL((void*)0)) {
1031 krb5_klog_syslog(LOG_ERR3, "dom_sid_string failed");
1032 ret = EINVAL22;
1033 goto done;
1034 }
1035 p++;
1036 }
1037
1038 group_sids[p] = NULL((void*)0);
1039
1040 *_group_sids = group_sids;
1041
1042 ret = 0;
1043done:
1044 talloc_free(domain_sid)_talloc_free(domain_sid, "ipa_kdb_mspac.c" ":" "1044");
1045 if (ret != 0) {
1046 talloc_free(group_sids)_talloc_free(group_sids, "ipa_kdb_mspac.c" ":" "1046");
1047 }
1048
1049 return ret;
1050}
1051
1052static int add_groups(TALLOC_CTX *memctx,
1053 struct PAC_LOGON_INFO_CTR *logon_info,
1054 size_t ipa_group_sids_count,
1055 struct dom_sid2dom_sid *ipa_group_sids)
1056{
1057 size_t c;
1058 struct netr_SidAttr *sids = NULL((void*)0);
1059
1060 if (ipa_group_sids_count == 0) {
1061 return 0;
1062 }
1063
1064 sids = talloc_realloc(memctx, logon_info->info->info3.sids,(struct netr_SidAttr *)_talloc_realloc_array(memctx, logon_info
->info->info3.sids, sizeof(struct netr_SidAttr), logon_info
->info->info3.sidcount + ipa_group_sids_count, "struct netr_SidAttr"
)
1065 struct netr_SidAttr,(struct netr_SidAttr *)_talloc_realloc_array(memctx, logon_info
->info->info3.sids, sizeof(struct netr_SidAttr), logon_info
->info->info3.sidcount + ipa_group_sids_count, "struct netr_SidAttr"
)
1066 logon_info->info->info3.sidcount + ipa_group_sids_count)(struct netr_SidAttr *)_talloc_realloc_array(memctx, logon_info
->info->info3.sids, sizeof(struct netr_SidAttr), logon_info
->info->info3.sidcount + ipa_group_sids_count, "struct netr_SidAttr"
)
;
1067 if (sids == NULL((void*)0)) {
1068 return ENOMEM12;
1069 }
1070
1071
1072 for (c = 0; c < ipa_group_sids_count; c++) {
1073 sids[c + logon_info->info->info3.sidcount].sid = &ipa_group_sids[c];
1074 sids[c + logon_info->info->info3.sidcount].attributes =
1075 SE_GROUP_ENABLED( 0x00000004 ) |
1076 SE_GROUP_MANDATORY( 0x00000001 ) |
1077 SE_GROUP_ENABLED_BY_DEFAULT( 0x00000002 );
1078 }
1079
1080 logon_info->info->info3.sidcount += ipa_group_sids_count;
1081 logon_info->info->info3.sids = sids;
1082
1083
1084 return 0;
1085}
1086
1087static int map_groups(TALLOC_CTX *memctx, krb5_context kcontext,
1088 char **group_sids, size_t *_ipa_group_sids_count,
1089 struct dom_sid **_ipa_group_sids)
1090{
1091 struct ipadb_context *ipactx;
1092 krb5_error_code kerr;
1093 int ret;
1094 LDAPMessage *results = NULL((void*)0);
1095 LDAPMessage *lentry;
1096 char *basedn = NULL((void*)0);
1097 char *filter = NULL((void*)0);
1098 LDAPDerefRes *deref_results = NULL((void*)0);
1099 LDAPDerefRes *dres;
1100 LDAPDerefVal *dval;
1101 size_t c;
1102 size_t count = 0;
1103 size_t sid_index = 0;
1104 struct dom_sid *sids = NULL((void*)0);
1105 char *entry_attrs[] ={"1.1", NULL((void*)0)};
1106 unsigned long gid;
1107 struct dom_sid sid;
1108 char *endptr;
1109
1110 ipactx = ipadb_get_context(kcontext);
1111 if (ipactx == NULL((void*)0)) {
1112 return KRB5_KDB_DBNOTINITED(-1780008435L);
1113 }
1114
1115 basedn = talloc_asprintf(memctx, "cn=groups,cn=accounts,%s", ipactx->base);
1116 if (basedn == NULL((void*)0)) {
1117 krb5_klog_syslog(LOG_ERR3, "talloc_asprintf failed.");
1118 kerr = ENOMEM12;
1119 goto done;
1120 }
1121
1122 for (c = 0; group_sids[c] != NULL((void*)0); c++) {
1123 talloc_free(filter)_talloc_free(filter, "ipa_kdb_mspac.c" ":" "1123");
1124 filter = talloc_asprintf(memctx, "(&(objectclass=ipaExternalGroup)(ipaExternalMember=%s))",
1125 group_sids[c]);
1126 if (filter == NULL((void*)0)) {
1127 krb5_klog_syslog(LOG_ERR3, "talloc_asprintf failed.");
1128 kerr = ENOMEM12;
1129 goto done;
1130 }
1131
1132 ldap_msgfree(results);
1133 kerr = ipadb_deref_search(ipactx, basedn, LDAP_SCOPE_ONE((ber_int_t) 0x0001), filter,
1134 entry_attrs, deref_search_attrs,
1135 memberof_pac_attrs, &results);
1136 if (kerr != 0) {
1137 krb5_klog_syslog(LOG_ERR3, "ipadb_deref_search failed.");
1138 goto done;
1139 }
1140
1141 lentry = ldap_first_entry(ipactx->lcontext, results);
1142 if (lentry == NULL((void*)0)) {
1143 continue;
1144 }
1145
1146 do {
1147 ldap_derefresponse_free(deref_results);
1148 ret = ipadb_ldap_deref_results(ipactx->lcontext, lentry, &deref_results);
1149 switch (ret) {
1150 case ENOENT2:
1151 /* No entry found, try next SID */
1152 break;
1153 case 0:
1154 if (deref_results == NULL((void*)0)) {
1155 krb5_klog_syslog(LOG_ERR3, "No results.");
1156 break;
1157 }
1158
1159 for (dres = deref_results; dres; dres = dres->next) {
1160 count++;
1161 }
1162
1163 sids = talloc_realloc(memctx, sids, struct dom_sid, count)(struct dom_sid *)_talloc_realloc_array(memctx, sids, sizeof(
struct dom_sid), count, "struct dom_sid")
;
1164 if (sids == NULL((void*)0)) {
1165 krb5_klog_syslog(LOG_ERR3, "talloc_realloc failed.");
1166 kerr = ENOMEM12;
1167 goto done;
1168 }
1169
1170 for (dres = deref_results; dres; dres = dres->next) {
1171 gid = 0;
1172 memset(&sid, '\0', sizeof(struct dom_sid));
1173 for (dval = dres->attrVals; dval; dval = dval->next) {
1174 if (strcasecmp(dval->type, "gidNumber") == 0) {
1175 errno(*__errno_location ()) = 0;
1176 gid = strtoul((char *)dval->vals[0].bv_val,
1177 &endptr,10);
1178 if (gid == 0 || gid >= UINT32_MAX(4294967295U) || errno(*__errno_location ()) != 0 ||
1179 *endptr != '\0') {
1180 continue;
1181 }
1182 }
1183 if (strcasecmp(dval->type,
1184 "ipaNTSecurityIdentifier") == 0) {
1185 kerr = string_to_sid((char *)dval->vals[0].bv_val, &sid);
1186 if (kerr != 0) {
1187 continue;
1188 }
1189 }
1190 }
1191 if (gid != 0 && sid.sid_rev_num != 0) {
1192 /* TODO: check if gid maps to sid */
1193 if (sid_index >= count) {
1194 krb5_klog_syslog(LOG_ERR3, "Index larger than "
1195 "array, this shoould "
1196 "never happen.");
1197 kerr = EFAULT14;
1198 goto done;
1199 }
1200 memcpy(&sids[sid_index], &sid, sizeof(struct dom_sid));
1201 sid_index++;
1202 }
1203 }
1204
1205 break;
1206 default:
1207 goto done;
1208 }
1209
1210 lentry = ldap_next_entry(ipactx->lcontext, lentry);
1211 } while (lentry != NULL((void*)0));
1212 }
1213
1214 *_ipa_group_sids_count = sid_index;
1215 *_ipa_group_sids = sids;
1216
1217 kerr = 0;
1218
1219done:
1220 ldap_derefresponse_free(deref_results);
1221 talloc_free(basedn)_talloc_free(basedn, "ipa_kdb_mspac.c" ":" "1221");
1222 talloc_free(filter)_talloc_free(filter, "ipa_kdb_mspac.c" ":" "1222");
1223 ldap_msgfree(results);
1224 return kerr;
1225}
1226
1227static krb5_error_code get_logon_info(krb5_context context,
1228 TALLOC_CTX *memctx,
1229 krb5_data *pac_blob,
1230 struct PAC_LOGON_INFO_CTR *info)
1231{
1232 DATA_BLOB pac_data;
1233 enum ndr_err_code ndr_err;
1234
1235 pac_data.length = pac_blob->length;
1236 pac_data.data = (uint8_t *)pac_blob->data;
1237
1238 ndr_err = ndr_pull_union_blob(&pac_data, memctx, info,
1239 PAC_TYPE_LOGON_INFO,
1240 (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
1241 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)(ndr_err == NDR_ERR_SUCCESS)) {
1242 return KRB5_KDB_INTERNAL_ERROR(-1780008411L);
1243 }
1244
1245 return 0;
1246}
1247
1248static krb5_error_code add_local_groups(krb5_context context,
1249 TALLOC_CTX *memctx,
1250 struct PAC_LOGON_INFO_CTR *info)
1251{
1252 int ret;
1253 char **group_sids = NULL((void*)0);
1254 size_t ipa_group_sids_count = 0;
1255 struct dom_sid *ipa_group_sids = NULL((void*)0);
1256
1257 ret = get_user_and_group_sids(memctx, info, &group_sids);
1258 if (ret != 0) {
1259 return KRB5_KDB_INTERNAL_ERROR(-1780008411L);
1260 }
1261
1262 ret = map_groups(memctx, context, group_sids, &ipa_group_sids_count,
1263 &ipa_group_sids);
1264 if (ret != 0) {
1265 return KRB5_KDB_INTERNAL_ERROR(-1780008411L);
1266 }
1267
1268 ret = add_groups(memctx, info, ipa_group_sids_count, ipa_group_sids);
1269 if (ret != 0) {
1270 krb5_klog_syslog(LOG_ERR3, "add_groups failed");
1271 return KRB5_KDB_INTERNAL_ERROR(-1780008411L);
1272 }
1273
1274 return 0;
1275}
1276
1277static krb5_error_code save_logon_info(krb5_context context,
1278 TALLOC_CTX *memctx,
1279 struct PAC_LOGON_INFO_CTR *info,
1280 krb5_data *pac_blob)
1281{
1282 DATA_BLOB pac_data;
1283 enum ndr_err_code ndr_err;
1284
1285 ndr_err = ndr_push_union_blob(&pac_data, memctx, info,
1286 PAC_TYPE_LOGON_INFO,
1287 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
1288 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)(ndr_err == NDR_ERR_SUCCESS)) {
1289 return KRB5_KDB_INTERNAL_ERROR(-1780008411L);
1290 }
1291
1292 free(pac_blob->data);
1293 pac_blob->data = malloc(pac_data.length);
1294 if (pac_blob->data == NULL((void*)0)) {
1295 pac_blob->length = 0;
1296 return ENOMEM12;
1297 }
1298 memcpy(pac_blob->data, pac_data.data, pac_data.length);
1299 pac_blob->length = pac_data.length;
1300
1301 return 0;
1302}
1303
1304static struct ipadb_adtrusts *get_domain_from_realm(krb5_context context,
1305 krb5_data realm)
1306{
1307 struct ipadb_context *ipactx;
1308 struct ipadb_adtrusts *domain;
1309 int i;
1310
1311 ipactx = ipadb_get_context(context);
1312 if (!ipactx) {
1313 return NULL((void*)0);
1314 }
1315
1316 if (ipactx->mspac == NULL((void*)0)) {
1317 return NULL((void*)0);
1318 }
1319
1320 for (i = 0; i < ipactx->mspac->num_trusts; i++) {
1321 domain = &ipactx->mspac->trusts[i];
1322 if (strlen(domain->domain_name) != realm.length) {
1323 continue;
1324 }
1325 if (strncasecmp(domain->domain_name, realm.data, realm.length) == 0) {
1326 return domain;
1327 }
1328 }
1329
1330 return NULL((void*)0);
1331}
1332
1333static struct ipadb_adtrusts *get_domain_from_realm_update(krb5_context context,
1334 krb5_data realm)
1335{
1336 struct ipadb_context *ipactx;
1337 struct ipadb_adtrusts *domain;
1338 krb5_error_code kerr;
1339
1340 ipactx = ipadb_get_context(context);
1341 if (!ipactx) {
1342 return NULL((void*)0);
1343 }
1344
1345 /* re-init MS-PAC info using default update interval */
1346 kerr = ipadb_reinit_mspac(ipactx, false0);
1347 if (kerr != 0) {
1348 return NULL((void*)0);
1349 }
1350 domain = get_domain_from_realm(context, realm);
1351
1352 return domain;
1353}
1354
1355static void filter_logon_info_log_message(struct dom_sid *sid)
1356{
1357 char *domstr = NULL((void*)0);
1358
1359 domstr = dom_sid_string(NULL((void*)0), sid);
1360 if (domstr) {
1361 krb5_klog_syslog(LOG_ERR3, "PAC filtering issue: SID [%s] is not allowed "
1362 "from a trusted source and will be excluded.", domstr);
1363 talloc_free(domstr)_talloc_free(domstr, "ipa_kdb_mspac.c" ":" "1363");
1364 } else {
1365 krb5_klog_syslog(LOG_ERR3, "PAC filtering issue: SID is not allowed "
1366 "from a trusted source and will be excluded."
1367 "Unable to allocate memory to display SID.");
1368 }
1369}
1370
1371static void filter_logon_info_log_message_rid(struct dom_sid *sid, uint32_t rid)
1372{
1373 char *domstr = NULL((void*)0);
1374
1375 domstr = dom_sid_string(NULL((void*)0), sid);
1376 if (domstr) {
1377 krb5_klog_syslog(LOG_ERR3, "PAC filtering issue: SID [%s-%d] is not allowed "
1378 "from a trusted source and will be excluded.", domstr, rid);
1379 talloc_free(domstr)_talloc_free(domstr, "ipa_kdb_mspac.c" ":" "1379");
1380 } else {
1381 krb5_klog_syslog(LOG_ERR3, "PAC filtering issue: SID is not allowed "
1382 "from a trusted source and will be excluded."
1383 "Unable to allocate memory to display SID.");
1384 }
1385}
1386
1387krb5_error_code filter_logon_info(krb5_context context,
1388 TALLOC_CTX *memctx,
1389 krb5_data realm,
1390 struct PAC_LOGON_INFO_CTR *info)
1391{
1392
1393 /* We must refuse a PAC that comes signed with a cross realm TGT
1394 * where the client pretends to be from a different realm. It is an
1395 * attempt at getting us to sign fake credentials with the help of a
1396 * compromised trusted realm */
1397
1398 /* NOTE: there are two outcomes from filtering:
1399 * REJECT TICKET -- ticket is rejected if domain SID of
1400 * the principal with MS-PAC is filtered out or
1401 * its primary group RID is filtered out
1402 *
1403 * REMOVE SID -- SIDs are removed from the list of SIDs associated
1404 * with the principal if they are filtered out
1405 * This applies also to secondary RIDs of the principal
1406 * if domain_sid-<secondary RID> is filtered out
1407 */
1408
1409 struct ipadb_context *ipactx;
1410 struct ipadb_adtrusts *domain;
1411 int i, j, k, l, count;
1412 uint32_t rid;
1413 bool_Bool result;
1414 char *domstr = NULL((void*)0);
1415
1416 domain = get_domain_from_realm_update(context, realm);
1417 if (!domain) {
1418 return EINVAL22;
1419 }
1420
1421 /* check netbios/flat name */
1422 if (strcasecmp(info->info->info3.base.logon_domain.string,
1423 domain->flat_name) != 0) {
1424 krb5_klog_syslog(LOG_ERR3, "PAC Info mismatch: domain = %s, "
1425 "expected flat name = %s, "
1426 "found logon name = %s",
1427 domain->domain_name, domain->flat_name,
1428 info->info->info3.base.logon_domain.string);
1429 return EINVAL22;
1430 }
1431
1432 /* check exact sid */
1433 result = dom_sid_check(&domain->domsid, info->info->info3.base.domain_sid, true1);
1434 if (!result) {
1435 domstr = dom_sid_string(NULL((void*)0), info->info->info3.base.domain_sid);
1436 if (!domstr) {
1437 return EINVAL22;
1438 }
1439 krb5_klog_syslog(LOG_ERR3, "PAC Info mismatch: domain = %s, "
1440 "expected domain SID = %s, "
1441 "found domain SID = %s",
1442 domain->domain_name, domain->domain_sid, domstr);
1443 talloc_free(domstr)_talloc_free(domstr, "ipa_kdb_mspac.c" ":" "1443");
1444 return EINVAL22;
1445 }
1446
1447 /* Check if this domain has been filtered out by the trust itself*/
1448 if (domain->parent != NULL((void*)0)) {
1449 for(k = 0; k < domain->parent->len_sid_blacklist_incoming; k++) {
1450 result = dom_sid_check(info->info->info3.base.domain_sid,
1451 &domain->parent->sid_blacklist_incoming[k], true1);
1452 if (result) {
1453 filter_logon_info_log_message(info->info->info3.base.domain_sid);
1454 return KRB5KDC_ERR_POLICY(-1765328372L);
1455 }
1456 }
1457 }
1458
1459 /* Check if this user's SIDs membership is filtered too */
1460 for(k = 0; k < domain->len_sid_blacklist_incoming; k++) {
1461 /* Short-circuit if there are no RIDs. This may happen if we filtered everything already.
1462 * In normal situation there would be at least primary gid as RID in the RIDs array
1463 * but if we filtered out the primary RID, this MS-PAC is invalid */
1464 count = info->info->info3.base.groups.count;
1465 result = dom_sid_is_prefix(info->info->info3.base.domain_sid,
1466 &domain->sid_blacklist_incoming[k]);
1467 if (result) {
1468 i = 0;
1469 j = 0;
1470 if (domain->sid_blacklist_incoming[k].num_auths - info->info->info3.base.domain_sid->num_auths != 1) {
1471 krb5_klog_syslog(LOG_ERR3, "Incoming SID blacklist element matching domain [%s with SID %s] "
1472 "has more than one RID component. Invalid check skipped.",
1473 domain->domain_name, domain->domain_sid);
1474 break;
1475 }
1476 rid = domain->sid_blacklist_incoming[k].sub_auths[domain->sid_blacklist_incoming[k].num_auths - 1];
1477 if (rid == info->info->info3.base.rid) {
1478 filter_logon_info_log_message_rid(info->info->info3.base.domain_sid, rid);
1479 /* Actual user's SID is filtered out */
1480 return KRB5KDC_ERR_POLICY(-1765328372L);
1481 }
1482 if (rid == info->info->info3.base.primary_gid) {
1483 /* User's primary group SID is filtered out */
1484 return KRB5KDC_ERR_POLICY(-1765328372L);
1485 }
1486 if (count == 0) {
1487 /* Having checked actual user's SID and primary group SID, and having no other RIDs,
1488 * skip checks below and continue to next blacklist element */
1489 continue;
1490 }
1491
1492 do {
1493 if (rid == info->info->info3.base.groups.rids[i].rid) {
1494 filter_logon_info_log_message_rid(info->info->info3.base.domain_sid, rid);
1495 /* If this is just a non-primary RID, we simply remove it from the array of RIDs */
1496 l = count - i - j - 1;
1497 if (l != 0) {
1498 memmove(info->info->info3.base.groups.rids+i,
1499 info->info->info3.base.groups.rids+i+1,
1500 sizeof(struct samr_RidWithAttribute)*l);
1501 }
1502 j++;
1503 } else {
1504 i++;
1505 }
1506 } while ((i + j) < count);
1507
1508 if (j != 0) {
1509 count = count-j;
1510 if (count == 0) {
1511 /* All RIDs were filtered out. Unusual but MS-KILE 3.3.5.6.3.1 says SHOULD, not MUST for GroupCount */
1512 info->info->info3.base.groups.count = 0;
1513 talloc_free(info->info->info3.base.groups.rids)_talloc_free(info->info->info3.base.groups.rids, "ipa_kdb_mspac.c"
":" "1513")
;
1514 info->info->info3.base.groups.rids = NULL((void*)0);
1515 } else {
1516 info->info->info3.base.groups.rids = talloc_realloc(memctx,(struct samr_RidWithAttribute *)_talloc_realloc_array(memctx,
info->info->info3.base.groups.rids, sizeof(struct samr_RidWithAttribute
), count, "struct samr_RidWithAttribute")
1517 info->info->info3.base.groups.rids,(struct samr_RidWithAttribute *)_talloc_realloc_array(memctx,
info->info->info3.base.groups.rids, sizeof(struct samr_RidWithAttribute
), count, "struct samr_RidWithAttribute")
1518 struct samr_RidWithAttribute, count)(struct samr_RidWithAttribute *)_talloc_realloc_array(memctx,
info->info->info3.base.groups.rids, sizeof(struct samr_RidWithAttribute
), count, "struct samr_RidWithAttribute")
;
1519 if (!info->info->info3.base.groups.rids) {
1520 info->info->info3.base.groups.count = 0;
1521 return ENOMEM12;
1522 }
1523 info->info->info3.base.groups.count = count;
1524 }
1525 }
1526 }
1527 }
1528
1529 /* According to MS-KILE 25.0, info->info->info3.sids may be non zero, so check
1530 * should include different possibilities into account
1531 * */
1532 if (info->info->info3.sidcount != 0) {
1533 ipactx = ipadb_get_context(context);
1534 if (!ipactx || !ipactx->mspac) {
1535 return KRB5_KDB_DBNOTINITED(-1780008435L);
1536 }
1537 count = info->info->info3.sidcount;
1538 i = 0;
1539 j = 0;
1540 do {
1541 /* Compare SID with our domain without taking RID into account */
1542 result = dom_sid_check(&ipactx->mspac->domsid, info->info->info3.sids[i].sid, false0);
1543 if (result) {
1544 filter_logon_info_log_message(info->info->info3.sids[i].sid);
1545 } else {
1546 /* Go over incoming SID blacklist */
1547 for(k = 0; k < domain->len_sid_blacklist_incoming; k++) {
1548 /* if SID is an exact match, filter it out */
1549 result = dom_sid_check(&domain->sid_blacklist_incoming[k], info->info->info3.sids[i].sid, true1);
1550 if (result) {
1551 filter_logon_info_log_message(info->info->info3.sids[i].sid);
1552 break;
1553 }
1554 /* if SID is a suffix of the blacklist element, filter it out*/
1555 result = dom_sid_is_prefix(&domain->sid_blacklist_incoming[k], info->info->info3.sids[i].sid);
1556 if (result) {
1557 filter_logon_info_log_message(info->info->info3.sids[i].sid);
1558 break;
1559 }
1560 }
1561 }
1562 if (result) {
1563 k = count - i - j - 1;
1564 if (k != 0) {
1565 memmove(info->info->info3.sids+i,
1566 info->info->info3.sids+i+1,
1567 sizeof(struct netr_SidAttr)*k);
1568 }
1569 j++;
1570 } else {
1571 i++;
1572 }
1573 } while ((i + j) < count);
1574
1575 if (j != 0) {
1576 count = count-j;
1577 if (count == 0) {
1578 /* All SIDs were filtered out */
1579 info->info->info3.sidcount = 0;
1580 talloc_free(info->info->info3.sids)_talloc_free(info->info->info3.sids, "ipa_kdb_mspac.c" ":"
"1580")
;
1581 info->info->info3.sids = NULL((void*)0);
1582 } else {
1583 info->info->info3.sids = talloc_realloc(memctx,(struct netr_SidAttr *)_talloc_realloc_array(memctx, info->
info->info3.sids, sizeof(struct netr_SidAttr), count, "struct netr_SidAttr"
)
1584 info->info->info3.sids,(struct netr_SidAttr *)_talloc_realloc_array(memctx, info->
info->info3.sids, sizeof(struct netr_SidAttr), count, "struct netr_SidAttr"
)
1585 struct netr_SidAttr, count)(struct netr_SidAttr *)_talloc_realloc_array(memctx, info->
info->info3.sids, sizeof(struct netr_SidAttr), count, "struct netr_SidAttr"
)
;
1586 if (!info->info->info3.sids) {
1587 info->info->info3.sidcount = 0;
1588 return ENOMEM12;
1589 }
1590 info->info->info3.sidcount = count;
1591 }
1592 }
1593 }
1594
1595 /* According to MS-KILE, ResourceGroups must be zero, so check
1596 * that it is the case here */
1597#ifdef HAVE_STRUCT_PAC_DOMAIN_GROUP_MEMBERSHIP1
1598 if (info->info->resource_groups.domain_sid != NULL((void*)0) &&
1599 info->info->resource_groups.groups.count != 0) {
1600 return EINVAL22;
1601 }
1602#else
1603 if (info->info->res_group_dom_sid != NULL((void*)0) &&
1604 info->info->res_groups.count != 0) {
1605 return EINVAL22;
1606 }
1607#endif
1608
1609 return 0;
1610}
1611
1612
1613static krb5_error_code ipadb_check_logon_info(krb5_context context,
1614 krb5_data origin_realm,
1615 krb5_data *pac_blob)
1616{
1617 struct PAC_LOGON_INFO_CTR info;
1618 krb5_error_code kerr;
1619 TALLOC_CTX *tmpctx;
1620
1621 tmpctx = talloc_new(NULL)talloc_named_const(((void*)0), 0, "talloc_new: " "ipa_kdb_mspac.c"
":" "1621")
;
1622 if (!tmpctx) {
1623 return ENOMEM12;
1624 }
1625
1626 kerr = get_logon_info(context, tmpctx, pac_blob, &info);
1627 if (kerr) {
1628 goto done;
1629 }
1630
1631 kerr = filter_logon_info(context, tmpctx, origin_realm, &info);
1632 if (kerr) {
1633 goto done;
1634 }
1635
1636 kerr = add_local_groups(context, tmpctx, &info);
1637 if (kerr) {
1638 goto done;
1639 }
1640
1641 kerr = save_logon_info(context, tmpctx, &info, pac_blob);
1642 if (kerr) {
1643 goto done;
1644 }
1645
1646done:
1647 talloc_free(tmpctx)_talloc_free(tmpctx, "ipa_kdb_mspac.c" ":" "1647");
1648 return kerr;
1649}
1650
1651static krb5_error_code get_delegation_info(krb5_context context,
1652 TALLOC_CTX *memctx, krb5_data *pac_blob,
1653 struct PAC_CONSTRAINED_DELEGATION_CTR *info)
1654{
1655 DATA_BLOB pac_data;
1656 enum ndr_err_code ndr_err;
1657
1658 pac_data.length = pac_blob->length;
1659 pac_data.data = (uint8_t *)pac_blob->data;
1660
1661 ndr_err = ndr_pull_union_blob(&pac_data, memctx, info,
1662 PAC_TYPE_CONSTRAINED_DELEGATION,
1663 (ndr_pull_flags_fn_t)ndr_pull_PAC_INFO);
1664 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)(ndr_err == NDR_ERR_SUCCESS)) {
1665 return KRB5_KDB_INTERNAL_ERROR(-1780008411L);
1666 }
1667
1668 return 0;
1669}
1670
1671static krb5_error_code save_delegation_info(krb5_context context,
1672 TALLOC_CTX *memctx,
1673 struct PAC_CONSTRAINED_DELEGATION_CTR *info,
1674 krb5_data *pac_blob)
1675{
1676 DATA_BLOB pac_data;
1677 enum ndr_err_code ndr_err;
1678
1679 ndr_err = ndr_push_union_blob(&pac_data, memctx, info,
1680 PAC_TYPE_CONSTRAINED_DELEGATION,
1681 (ndr_push_flags_fn_t)ndr_push_PAC_INFO);
1682 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)(ndr_err == NDR_ERR_SUCCESS)) {
1683 return KRB5_KDB_INTERNAL_ERROR(-1780008411L);
1684 }
1685
1686 free(pac_blob->data);
1687 pac_blob->data = malloc(pac_data.length);
1688 if (pac_blob->data == NULL((void*)0)) {
1689 pac_blob->length = 0;
1690 return ENOMEM12;
1691 }
1692 memcpy(pac_blob->data, pac_data.data, pac_data.length);
1693 pac_blob->length = pac_data.length;
1694
1695 return 0;
1696}
1697
1698static krb5_error_code ipadb_add_transited_service(krb5_context context,
1699 krb5_db_entry *proxy,
1700 krb5_db_entry *server,
1701 krb5_pac old_pac,
1702 krb5_pac new_pac)
1703{
1704 struct PAC_CONSTRAINED_DELEGATION_CTR info;
1705 krb5_data pac_blob = { 0 , 0, NULL((void*)0) };
1706 krb5_error_code kerr;
1707 TALLOC_CTX *tmpctx;
1708 uint32_t i;
1709 char *tmpstr;
1710
1711 /* When proxy is NULL, authdata flag on the service principal was cleared
1712 * by an admin. We don't generate MS-PAC in this case */
1713 if (proxy == NULL((void*)0)) {
1714 return 0;
1715 }
1716
1717 tmpctx = talloc_new(NULL)talloc_named_const(((void*)0), 0, "talloc_new: " "ipa_kdb_mspac.c"
":" "1717")
;
1718 if (!tmpctx) {
1719 kerr = ENOMEM12;
1720 goto done;
1721 }
1722
1723 kerr = krb5_pac_get_buffer(context, old_pac,
1724 KRB5_PAC_DELEGATION_INFO11, &pac_blob);
1725 if (kerr != 0 && kerr != ENOENT2) {
1726 goto done;
1727 }
1728
1729 if (pac_blob.length != 0) {
1730 kerr = get_delegation_info(context, tmpctx, &pac_blob, &info);
1731 if (kerr != 0) {
1732 goto done;
1733 }
1734 } else {
1735 info.info = talloc_zero(tmpctx, struct PAC_CONSTRAINED_DELEGATION)(struct PAC_CONSTRAINED_DELEGATION *)_talloc_zero(tmpctx, sizeof
(struct PAC_CONSTRAINED_DELEGATION), "struct PAC_CONSTRAINED_DELEGATION"
)
;
1736 if (!info.info) {
1737 kerr = ENOMEM12;
1738 goto done;
1739 }
1740 }
1741
1742 krb5_free_data_contents(context, &pac_blob);
1743 memset(&pac_blob, 0, sizeof(krb5_data));
1744
1745 kerr = krb5_unparse_name(context, proxy->princ, &tmpstr);
1746 if (kerr != 0) {
1747 goto done;
1748 }
1749
1750 info.info->proxy_target.string = talloc_strdup(tmpctx, tmpstr);
1751 krb5_free_unparsed_name(context, tmpstr);
1752 if (!info.info->proxy_target.string) {
1753 kerr = ENOMEM12;
1754 goto done;
1755 }
1756
1757 i = info.info->num_transited_services;
1758
1759 info.info->transited_services = talloc_realloc(tmpctx,(struct lsa_String *)_talloc_realloc_array(tmpctx, info.info->
transited_services, sizeof(struct lsa_String), i + 1, "struct lsa_String"
)
1760 info.info->transited_services,(struct lsa_String *)_talloc_realloc_array(tmpctx, info.info->
transited_services, sizeof(struct lsa_String), i + 1, "struct lsa_String"
)
1761 struct lsa_String, i + 1)(struct lsa_String *)_talloc_realloc_array(tmpctx, info.info->
transited_services, sizeof(struct lsa_String), i + 1, "struct lsa_String"
)
;
1762 if (!info.info->transited_services) {
1763 kerr = ENOMEM12;
1764 goto done;
1765 }
1766
1767 kerr = krb5_unparse_name(context, server->princ, &tmpstr);
1768 if (kerr != 0) {
1769 goto done;
1770 }
1771
1772 info.info->transited_services[i].string = talloc_strdup(tmpctx, tmpstr);
1773 krb5_free_unparsed_name(context, tmpstr);
1774 if (!info.info->transited_services[i].string) {
1775 kerr = ENOMEM12;
1776 goto done;
1777 }
1778 info.info->num_transited_services = i + 1;
1779
1780 kerr = save_delegation_info(context, tmpctx, &info, &pac_blob);
1781 if (kerr != 0) {
1782 goto done;
1783 }
1784
1785 kerr = krb5_pac_add_buffer(context, new_pac,
1786 KRB5_PAC_DELEGATION_INFO11, &pac_blob);
1787 if (kerr) {
1788 goto done;
1789 }
1790
1791done:
1792 krb5_free_data_contents(context, &pac_blob);
1793 talloc_free(tmpctx)_talloc_free(tmpctx, "ipa_kdb_mspac.c" ":" "1793");
1794 return kerr;
1795}
1796
1797static krb5_error_code ipadb_verify_pac(krb5_context context,
1798 unsigned int flags,
1799 krb5_const_principal client_princ,
1800 krb5_db_entry *proxy,
1801 krb5_db_entry *server,
1802 krb5_db_entry *krbtgt,
1803 krb5_keyblock *server_key,
1804 krb5_keyblock *krbtgt_key,
1805 krb5_timestamp authtime,
1806 krb5_authdata **authdata,
1807 krb5_pac *pac)
1808{
1809 krb5_keyblock *srv_key = NULL((void*)0);
1810 krb5_keyblock *priv_key = NULL((void*)0);
1811 krb5_error_code kerr;
1812 krb5_ui_4 *types = NULL((void*)0);
1813 size_t num_buffers;
1814 krb5_pac old_pac = NULL((void*)0);
1815 krb5_pac new_pac = NULL((void*)0);
1816 krb5_data data;
1817 krb5_data pac_blob = { 0 , 0, NULL((void*)0)};
1818 bool_Bool is_cross_realm = false0;
1819 size_t i;
1820
1821 kerr = krb5_pac_parse(context,
1822 authdata[0]->contents,
1823 authdata[0]->length,
1824 &old_pac);
1825 if (kerr) {
1826 goto done;
1827 }
1828
1829 /* for cross realm trusts cases we need to check the right checksum.
1830 * when the PAC is signed by our realm, we can always just check it
1831 * passing our realm krbtgt key as the kdc checksum key (privsvr).
1832 * But when a trusted realm passes us a PAC the kdc checksum is
1833 * generated with that realm krbtgt key, so we need to use the cross
1834 * realm krbtgt to check the 'server' checksum instead. */
1835 if (is_cross_realm_krbtgt(krbtgt->princ)) {
1836 /* krbtgt from a trusted realm */
1837 is_cross_realm = true1;
1838
1839 srv_key = krbtgt_key;
1840
1841 } else {
1842 /* krbtgt from our own realm */
1843 priv_key = krbtgt_key;
1844 }
1845
1846 /* only pass with_realm TRUE when it is cross-realm ticket and S4U
1847 * extension (S4U2Self or S4U2Proxy (RBCD)) was requested */
1848 kerr = krb5_pac_verify_ext(context, old_pac, authtime,
1849 client_princ, srv_key, priv_key,
1850 (is_cross_realm &&
1851 (flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION0x00000100)));
1852 if (kerr) {
1853 goto done;
1854 }
1855
1856 /* Now that the PAC is verified augment it with additional info if
1857 * it is coming from a different realm */
1858 if (is_cross_realm) {
1859 kerr = krb5_pac_get_buffer(context, old_pac,
1860 KRB5_PAC_LOGON_INFO1, &pac_blob);
1861 if (kerr != 0) {
1862 goto done;
1863 }
1864
1865 kerr = ipadb_check_logon_info(context, client_princ->realm, &pac_blob);
1866 if (kerr != 0) {
1867 goto done;
1868 }
1869 }
1870 /* extract buffers and rebuilt pac from scratch so that when re-signing
1871 * with a different cksum type does not cause issues due to mismatching
1872 * signature buffer lengths */
1873 kerr = krb5_pac_init(context, &new_pac);
1874 if (kerr) {
1875 goto done;
1876 }
1877
1878 kerr = krb5_pac_get_types(context, old_pac, &num_buffers, &types);
1879 if (kerr) {
1880 goto done;
1881 }
1882
1883 for (i = 0; i < num_buffers; i++) {
1884 if (types[i] == KRB5_PAC_SERVER_CHECKSUM6 ||
1885 types[i] == KRB5_PAC_PRIVSVR_CHECKSUM7 ||
1886 types[i] == KRB5_PAC_CLIENT_INFO10) {
1887 continue;
1888 }
1889
1890 if (types[i] == KRB5_PAC_LOGON_INFO1 &&
1891 pac_blob.length != 0) {
1892 kerr = krb5_pac_add_buffer(context, new_pac, types[i], &pac_blob);
1893 if (kerr) {
1894 krb5_pac_free(context, new_pac);
1895 goto done;
1896 }
1897
1898 continue;
1899 }
1900
1901 if (types[i] == KRB5_PAC_DELEGATION_INFO11 &&
1902 (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION0x00000200)) {
1903 /* skip it here, we will add it explicitly later */
1904 continue;
1905 }
1906
1907 kerr = krb5_pac_get_buffer(context, old_pac, types[i], &data);
1908 if (kerr == 0) {
1909 kerr = krb5_pac_add_buffer(context, new_pac, types[i], &data);
1910 krb5_free_data_contents(context, &data);
1911 }
1912 if (kerr) {
1913 krb5_pac_free(context, new_pac);
1914 goto done;
1915 }
1916 }
1917
1918 if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION0x00000200) {
1919 if (proxy == NULL((void*)0)) {
1920 *pac = NULL((void*)0);
1921 kerr = 0;
1922 goto done;
1923 }
1924
1925 kerr = ipadb_add_transited_service(context, proxy, server,
1926 old_pac, new_pac);
1927 if (kerr) {
1928 krb5_pac_free(context, new_pac);
1929 goto done;
1930 }
1931 }
1932
1933 *pac = new_pac;
1934
1935done:
1936 krb5_free_authdata(context, authdata);
1937 krb5_pac_free(context, old_pac);
1938 krb5_free_data_contents(context, &pac_blob);
1939 free(types);
1940 return kerr;
1941}
1942
1943static krb5_error_code ipadb_sign_pac(krb5_context context,
1944 unsigned int flags,
1945 krb5_const_principal client_princ,
1946 krb5_db_entry *server,
1947 krb5_db_entry *krbtgt,
1948 krb5_keyblock *server_key,
1949 krb5_keyblock *krbtgt_key,
1950 krb5_timestamp authtime,
1951 krb5_pac pac,
1952 krb5_data *pac_data)
1953{
1954 krb5_keyblock *right_krbtgt_signing_key = NULL((void*)0);
1955 krb5_key_data *right_krbtgt_key;
1956 krb5_db_entry *right_krbtgt = NULL((void*)0);
1957 krb5_principal krbtgt_princ = NULL((void*)0);
1958 krb5_error_code kerr;
1959 char *princ = NULL((void*)0);
1960 bool_Bool is_issuing_referral = false0;
1961 int ret;
1962
1963 /* for cross realm trusts cases we need to sign with the right key.
1964 * we need to fetch the right key on our own until the DAL is fixed
1965 * to pass us separate check tgt keys and sign tgt keys */
1966
1967 /* We can only ever create the kdc checksum with our realm tgt key.
1968 * So, if we get a cross realm tgt we have to fetch our realm tgt
1969 * instead. */
1970 if (is_cross_realm_krbtgt(krbtgt->princ)) {
1
Taking true branch
1971
1972 ret = asprintf(&princ, "krbtgt/%.*s@%.*s",
1973 server->princ->realm.length,
1974 server->princ->realm.data,
1975 server->princ->realm.length,
1976 server->princ->realm.data);
1977 if (ret == -1) {
2
Assuming the condition is false
3
Taking false branch
1978 princ = NULL((void*)0);
1979 kerr = ENOMEM12;
1980 goto done;
1981 }
1982
1983 kerr = krb5_parse_name(context, princ, &krbtgt_princ);
1984 if (kerr) {
4
Assuming 'kerr' is 0
5
Taking false branch
1985 goto done;
1986 }
1987
1988 kerr = ipadb_get_principal(context, krbtgt_princ, 0, &right_krbtgt);
1989 if (kerr) {
6
Assuming 'kerr' is 0
7
Taking false branch
1990 goto done;
1991 }
1992
1993 kerr = krb5_dbe_find_enctype(context, right_krbtgt,
1994 -1, -1, 0, &right_krbtgt_key);
1995 if (kerr) {
8
Assuming 'kerr' is 0
9
Taking false branch
1996 goto done;
1997 }
1998 if (!right_krbtgt_key) {
10
Assuming 'right_krbtgt_key' is non-null
11
Taking false branch
1999 kerr = KRB5KDC_ERR_S_PRINCIPAL_UNKNOWN(-1765328377L);
2000 goto done;
2001 }
2002
2003 right_krbtgt_signing_key = malloc(sizeof(krb5_keyblock));
12
Memory is allocated
2004 if (!right_krbtgt_signing_key) {
13
Assuming 'right_krbtgt_signing_key' is non-null
14
Taking false branch
2005 kerr = ENOMEM12;
2006 goto done;
2007 }
2008
2009 kerr = krb5_dbe_decrypt_key_data(context, NULL((void*)0), right_krbtgt_key,
2010 right_krbtgt_signing_key, NULL((void*)0));
2011 if (kerr) {
15
Assuming 'kerr' is not equal to 0
16
Taking true branch
2012 goto done;
17
Control jumps to line 2032
2013 }
2014
2015 } else {
2016 right_krbtgt_signing_key = krbtgt_key;
2017 }
2018
2019#ifdef KRB5_KDB_FLAG_ISSUING_REFERRAL0x00004000
2020 is_issuing_referral = (flags & KRB5_KDB_FLAG_ISSUING_REFERRAL0x00004000) != 0;
2021#endif
2022
2023 /* only pass with_realm TRUE when it is cross-realm ticket and S4U2Self
2024 * was requested */
2025 kerr = krb5_pac_sign_ext(context, pac, authtime, client_princ, server_key,
2026 right_krbtgt_signing_key,
2027 (is_issuing_referral &&
2028 (flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION0x00000100)),
2029 pac_data);
2030
2031done:
2032 free(princ);
2033 krb5_free_principal(context, krbtgt_princ);
2034 ipadb_free_principal(context, right_krbtgt);
2035 if (right_krbtgt_signing_key
17.1
'right_krbtgt_signing_key' is not equal to 'krbtgt_key'
!= krbtgt_key) {
18
Taking true branch
2036 krb5_free_keyblock(context, right_krbtgt_signing_key);
2037 }
2038 return kerr;
19
Potential leak of memory pointed to by 'right_krbtgt_signing_key'
2039}
2040
2041void get_authz_data_types(krb5_context context, krb5_db_entry *entry,
2042 bool_Bool *_with_pac, bool_Bool *_with_pad)
2043{
2044 struct ipadb_e_data *ied = NULL((void*)0);
2045 struct ipadb_context *ipactx;
2046 size_t c;
2047 bool_Bool none_found = false0;
2048 bool_Bool srv_none_found = false0;
2049 char **authz_data_list;
2050 bool_Bool with_pac = false0;
2051 bool_Bool srv_with_pac = false0;
2052 bool_Bool with_pad = false0;
2053 bool_Bool srv_with_pad = false0;
2054 char *sep;
2055 krb5_data *service_type;
2056 char *authz_data_type;
2057 bool_Bool service_specific;
2058
2059 if (entry != NULL((void*)0)) {
2060 ied = (struct ipadb_e_data *) entry->e_data;
2061 }
2062
2063 if (ied == NULL((void*)0) || ied->authz_data == NULL((void*)0)) {
2064 const struct ipadb_global_config *gcfg = NULL((void*)0);
2065 char **tmp = NULL((void*)0);
2066
2067 if (context == NULL((void*)0)) {
2068 krb5_klog_syslog(LOG_ERR3, "Missing Kerberos context, no " \
2069 "authorization data will be added.");
2070 goto done;
2071 }
2072
2073 ipactx = ipadb_get_context(context);
2074 if (ipactx != NULL((void*)0)) {
2075 gcfg = ipadb_get_global_config(ipactx);
2076 if (gcfg != NULL((void*)0))
2077 tmp = gcfg->authz_data;
2078 }
2079 if (ipactx == NULL((void*)0) || tmp == NULL((void*)0)) {
2080 krb5_klog_syslog(LOG_ERR3, "No default authorization data types " \
2081 "available, no authorization data will " \
2082 "be added.");
2083 goto done;
2084 }
2085
2086 authz_data_list = tmp;
2087 } else {
2088 authz_data_list = ied->authz_data;
2089 }
2090
2091
2092 for (c = 0; authz_data_list[c]; c++) {
2093 service_specific = false0;
2094 authz_data_type = authz_data_list[c];
2095 sep = strchr(authz_data_list[c], ':');
2096 if (sep != NULL((void*)0) && entry != NULL((void*)0)) {
2097 if (entry->princ == NULL((void*)0)) {
2098 krb5_klog_syslog(LOG_ERR3, "Missing principal in database "
2099 "entry, no authorization data will " \
2100 "be added.");
2101 goto done;
2102 }
2103
2104 service_type = krb5_princ_component(context, entry->princ, 0)(((0) < (entry->princ)->length) ? (entry->princ)->
data + (0) : ((void*)0))
;
2105 if (service_type == NULL((void*)0)) {
2106 krb5_klog_syslog(LOG_ERR3, "Missing service type in database "
2107 "entry, no authorization data will " \
2108 "be added.");
2109 goto done;
2110 }
2111
2112 if (service_type->length == (sep - authz_data_list[c]) &&
2113 strncmp(authz_data_list[c], service_type->data,
2114 service_type->length) == 0) {
2115 service_specific = true1;
2116 authz_data_type = sep + 1;
2117 } else {
2118 /* Service specific default does not apply, skipping this
2119 * entry. */
2120 continue;
2121 }
2122 }
2123
2124 if (strcmp(authz_data_type, AUTHZ_DATA_TYPE_PAC"MS-PAC") == 0) {
2125 if (service_specific) {
2126 srv_with_pac = true1;
2127 } else {
2128 with_pac = true1;
2129 }
2130 } else if (strcmp(authz_data_type, AUTHZ_DATA_TYPE_PAD"PAD") == 0) {
2131 if (service_specific) {
2132 srv_with_pad = true1;
2133 } else {
2134 with_pad = true1;
2135 }
2136 } else if (strcmp(authz_data_type, AUTHZ_DATA_TYPE_NONE"NONE") == 0) {
2137 if (service_specific) {
2138 srv_none_found = true1;
2139 } else {
2140 none_found = true1;
2141 }
2142 } else {
2143 krb5_klog_syslog(LOG_ERR3, "Ignoring unsupported " \
2144 "authorization data type [%s].",
2145 authz_data_list[c]);
2146 }
2147 }
2148
2149done:
2150 if (srv_none_found || srv_with_pac || srv_with_pad) {
2151 none_found = srv_none_found;
2152 with_pac = srv_with_pac;
2153 with_pad = srv_with_pad;
2154 }
2155
2156 if (none_found) {
2157 with_pac = false0;
2158 with_pad = false0;
2159 }
2160
2161 if (_with_pac != NULL((void*)0)) {
2162 *_with_pac = with_pac;
2163 }
2164 if (_with_pad != NULL((void*)0)) {
2165 *_with_pad = with_pad;
2166 }
2167
2168}
2169
2170krb5_error_code ipadb_sign_authdata(krb5_context context,
2171 unsigned int flags,
2172 krb5_const_principal client_princ,
2173 krb5_db_entry *client,
2174 krb5_db_entry *server,
2175 krb5_db_entry *krbtgt,
2176 krb5_keyblock *client_key,
2177 krb5_keyblock *server_key,
2178 krb5_keyblock *krbtgt_key,
2179 krb5_keyblock *session_key,
2180 krb5_timestamp authtime,
2181 krb5_authdata **tgt_auth_data,
2182 krb5_authdata ***signed_auth_data)
2183{
2184 krb5_const_principal ks_client_princ;
2185 krb5_authdata **pac_auth_data = NULL((void*)0);
2186 krb5_authdata *authdata[2] = { NULL((void*)0), NULL((void*)0) };
2187 krb5_authdata ad;
2188 krb5_boolean is_as_req;
2189 krb5_error_code kerr;
2190 krb5_pac pac = NULL((void*)0);
2191 krb5_data pac_data;
2192 struct ipadb_context *ipactx;
2193 bool_Bool with_pac;
2194 bool_Bool with_pad;
2195 bool_Bool make_ad = false0;
2196 int result;
2197 krb5_db_entry *client_entry = NULL((void*)0);
2198 krb5_boolean is_equal;
2199 bool_Bool force_reinit_mspac = false0;
2200
2201
2202 is_as_req = ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY0x00000040) != 0);
2203
2204 /* When using s4u2proxy client_princ actually refers to the proxied user
2205 * while client->princ to the proxy service asking for the TGS on behalf
2206 * of the proxied user. So always use client_princ in preference */
2207 if (client_princ != NULL((void*)0)) {
2208 ks_client_princ = client_princ;
2209 if (!is_as_req) {
2210 is_equal = false0;
2211 if ((client != NULL((void*)0)) && (client->princ != NULL((void*)0))) {
2212 is_equal = krb5_principal_compare(context, client_princ, client->princ);
2213 }
2214 if (!is_equal) {
2215 kerr = ipadb_get_principal(context, client_princ, flags, &client_entry);
2216 /* If we didn't find client_princ in our database, it might be:
2217 * - a principal from another realm, handle it down in ipadb_get/verify_pac()
2218 */
2219 if (kerr != 0) {
2220 client_entry = NULL((void*)0);
2221 }
2222 }
2223 }
2224 } else {
2225 if (client == NULL((void*)0)) {
2226 *signed_auth_data = NULL((void*)0);
2227 return 0;
2228 }
2229 ks_client_princ = client->princ;
2230 }
2231
2232 if (client_entry == NULL((void*)0)) client_entry = client;
2233
2234 if (is_as_req) {
2235 get_authz_data_types(context, client_entry, &with_pac, &with_pad);
2236 } else {
2237 get_authz_data_types(context, server, &with_pac, &with_pad);
2238 }
2239
2240 if (with_pad) {
2241 krb5_klog_syslog(LOG_ERR3, "PAD authorization data is requested but " \
2242 "currently not supported.");
2243 }
2244
2245 /* we need to create a PAC if we are requested one and this is an AS REQ,
2246 * or we are doing protocol transition (S4USelf) but not over cross-realm
2247 */
2248 if ((is_as_req && (flags & KRB5_KDB_FLAG_INCLUDE_PAC0x00000020)) ||
2249 ((flags & KRB5_KDB_FLAG_PROTOCOL_TRANSITION0x00000100) && (client != NULL((void*)0)))) {
2250 make_ad = true1;
2251 }
2252
2253 if (with_pac && make_ad) {
2254
2255 ipactx = ipadb_get_context(context);
2256 if (!ipactx) {
2257 kerr = ENOMEM12;
2258 goto done;
2259 }
2260
2261 /* Be aggressive here: special case for discovering range type
2262 * immediately after establishing the trust by IPA framework. For all
2263 * other cases call ipadb_reinit_mspac() with force_reinit_mspac set
2264 * to 'false' to make sure the information about trusted domains is
2265 * updated on a regular basis for all worker processes. */
2266 if ((krb5_princ_size(context, ks_client_princ)(ks_client_princ)->length == 2) &&
2267 (strncmp(krb5_princ_component(context, ks_client_princ, 0)(((0) < (ks_client_princ)->length) ? (ks_client_princ)->
data + (0) : ((void*)0))
->data, "HTTP",
2268 krb5_princ_component(context, ks_client_princ, 0)(((0) < (ks_client_princ)->length) ? (ks_client_princ)->
data + (0) : ((void*)0))
->length) == 0) &&
2269 (ulc_casecmp(krb5_princ_component(context, ks_client_princ, 1)(((1) < (ks_client_princ)->length) ? (ks_client_princ)->
data + (1) : ((void*)0))
->data,
2270 krb5_princ_component(context, ks_client_princ, 1)(((1) < (ks_client_princ)->length) ? (ks_client_princ)->
data + (1) : ((void*)0))
->length,
2271 ipactx->kdc_hostname, strlen(ipactx->kdc_hostname),
2272 NULL((void*)0), NULL((void*)0), &result) == 0)) {
2273 force_reinit_mspac = true1;
2274 }
2275
2276 (void)ipadb_reinit_mspac(ipactx, force_reinit_mspac);
2277
2278 kerr = ipadb_get_pac(context, client, flags, &pac);
2279 if (kerr != 0 && kerr != ENOENT2) {
2280 goto done;
2281 }
2282 } else if (with_pac && !is_as_req) {
2283 /* find the existing PAC, if present */
2284 kerr = krb5_find_authdata(context, tgt_auth_data, NULL((void*)0),
2285 KRB5_AUTHDATA_WIN2K_PAC128, &pac_auth_data);
2286 if (kerr != 0) {
2287 goto done;
2288 }
2289 /* check or generate pac data */
2290 if ((pac_auth_data == NULL((void*)0)) || (pac_auth_data[0] == NULL((void*)0))) {
2291 if (flags & KRB5_KDB_FLAG_CONSTRAINED_DELEGATION0x00000200) {
2292 kerr = ipadb_get_pac(context, client_entry, flags, &pac);
2293 if (kerr != 0 && kerr != ENOENT2) {
2294 goto done;
2295 }
2296 }
2297 } else {
2298 if (pac_auth_data[1] != NULL((void*)0)) {
2299 kerr = KRB5KDC_ERR_BADOPTION(-1765328371L); /* FIXME: right error ? */
2300 goto done;
2301 }
2302
2303 kerr = ipadb_verify_pac(context, flags, ks_client_princ, client,
2304 server, krbtgt, server_key, krbtgt_key,
2305 authtime, pac_auth_data, &pac);
2306 if (kerr != 0) {
2307 goto done;
2308 }
2309 }
2310 }
2311
2312 if (pac == NULL((void*)0)) {
2313 /* No PAC to deal with, proceed */
2314 *signed_auth_data = NULL((void*)0);
2315 kerr = 0;
2316 goto done;
2317 }
2318
2319 kerr = ipadb_sign_pac(context, flags, ks_client_princ, server, krbtgt,
2320 server_key, krbtgt_key, authtime, pac, &pac_data);
2321 if (kerr != 0) {
2322 goto done;
2323 }
2324
2325 /* put in signed data */
2326 ad.magic = KV5M_AUTHDATA(-1760647414L);
2327 ad.ad_type = KRB5_AUTHDATA_WIN2K_PAC128;
2328 ad.contents = (krb5_octet *)pac_data.data;
2329 ad.length = pac_data.length;
2330
2331 authdata[0] = &ad;
2332
2333 kerr = krb5_encode_authdata_container(context,
2334 KRB5_AUTHDATA_IF_RELEVANT1,
2335 authdata,
2336 signed_auth_data);
2337 krb5_free_data_contents(context, &pac_data);
2338 if (kerr != 0) {
2339 goto done;
2340 }
2341
2342 kerr = 0;
2343
2344done:
2345 if (client_entry != NULL((void*)0) && client_entry != client) {
2346 ipadb_free_principal(context, client_entry);
2347 }
2348 krb5_pac_free(context, pac);
2349 return kerr;
2350}
2351
2352static char *get_server_netbios_name(struct ipadb_context *ipactx)
2353{
2354 char hostname[MAXHOSTNAMELEN64 + 1]; /* NOTE: this is 64, too little ? */
2355 char *p;
2356
2357 strncpy(hostname, ipactx->kdc_hostname, MAXHOSTNAMELEN64);
2358 /* May miss termination */
2359 hostname[MAXHOSTNAMELEN64] = '\0';
2360 for (p = hostname; *p; p++) {
2361 if (*p == '.') {
2362 *p = 0;
2363 break;
2364 } else {
2365 *p = toupper(*p);
2366 }
2367 }
2368
2369 return strdup(hostname);
2370}
2371
2372void ipadb_mspac_struct_free(struct ipadb_mspac **mspac)
2373{
2374 int i, j;
2375
2376 if (!*mspac) return;
2377
2378 free((*mspac)->flat_domain_name);
2379 free((*mspac)->flat_server_name);
2380 free((*mspac)->fallback_group);
2381
2382 if ((*mspac)->num_trusts) {
2383 for (i = 0; i < (*mspac)->num_trusts; i++) {
2384 free((*mspac)->trusts[i].domain_name);
2385 free((*mspac)->trusts[i].flat_name);
2386 free((*mspac)->trusts[i].domain_sid);
2387 free((*mspac)->trusts[i].sid_blacklist_incoming);
2388 free((*mspac)->trusts[i].sid_blacklist_outgoing);
2389 free((*mspac)->trusts[i].parent_name);
2390 (*mspac)->trusts[i].parent = NULL((void*)0);
2391 if ((*mspac)->trusts[i].upn_suffixes) {
2392 for (j = 0; (*mspac)->trusts[i].upn_suffixes[j]; j++) {
2393 free((*mspac)->trusts[i].upn_suffixes[j]);
2394 }
2395 free((*mspac)->trusts[i].upn_suffixes);
2396 }
2397 }
2398 free((*mspac)->trusts);
2399 }
2400 free(*mspac);
2401
2402 *mspac = NULL((void*)0);
2403}
2404
2405krb5_error_code ipadb_adtrusts_fill_sid_blacklist(char **source_sid_blacklist,
2406 struct dom_sid **result_sids,
2407 int *result_length)
2408{
2409 int len, i;
2410 char **source;
2411 struct dom_sid *sid_blacklist;
2412
2413 if (source_sid_blacklist) {
2414 source = source_sid_blacklist;
2415 } else {
2416 /* Use default hardcoded list */
2417 source = ipa_mspac_well_known_sids;
2418 }
2419 len = 0;
2420 for (i = 0; source && source[i]; i++) {
2421 len++;
2422 }
2423
2424 sid_blacklist = calloc(len, sizeof(struct dom_sid));
2425 if (sid_blacklist == NULL((void*)0)) {
2426 return ENOMEM12;
2427 }
2428
2429 for (i = 0; i < len; i++) {
2430 (void) string_to_sid(source[i], &sid_blacklist[i]);
2431 }
2432
2433 *result_sids = sid_blacklist;
2434 *result_length = len;
2435 return 0;
2436}
2437
2438krb5_error_code ipadb_adtrusts_fill_sid_blacklists(struct ipadb_adtrusts *adtrust,
2439 char **sid_blacklist_incoming,
2440 char **sid_blacklist_outgoing)
2441{
2442 krb5_error_code kerr;
2443
2444 kerr = ipadb_adtrusts_fill_sid_blacklist(sid_blacklist_incoming,
2445 &adtrust->sid_blacklist_incoming,
2446 &adtrust->len_sid_blacklist_incoming);
2447 if (kerr) {
2448 return kerr;
2449 }
2450
2451 kerr = ipadb_adtrusts_fill_sid_blacklist(sid_blacklist_outgoing,
2452 &adtrust->sid_blacklist_outgoing,
2453 &adtrust->len_sid_blacklist_outgoing);
2454 if (kerr) {
2455 return kerr;
2456 }
2457
2458 return 0;
2459}
2460
2461krb5_error_code ipadb_mspac_check_trusted_domains(struct ipadb_context *ipactx)
2462{
2463 char *attrs[] = { NULL((void*)0) };
2464 char *filter = "(objectclass=ipaNTTrustedDomain)";
2465 char *base = NULL((void*)0);
2466 LDAPMessage *result = NULL((void*)0);
2467 int ret;
2468
2469 ret = asprintf(&base, "cn=ad,cn=trusts,%s", ipactx->base);
2470 if (ret == -1) {
2471 ret = ENOMEM12;
2472 goto done;
2473 }
2474
2475 /* Run a quick search if there is any trust defined */
2476 ret = ipadb_simple_search(ipactx, base, LDAP_SCOPE_SUBTREE((ber_int_t) 0x0002),
2477 filter, attrs, &result);
2478
2479done:
2480 ldap_msgfree(result);
2481 free(base);
2482 return ret;
2483}
2484
2485static void ipadb_free_sid_blacklists(char ***sid_blacklist_incoming, char ***sid_blacklist_outgoing)
2486{
2487 int i;
2488
2489 if (sid_blacklist_incoming && *sid_blacklist_incoming) {
2490 for (i = 0; *sid_blacklist_incoming && (*sid_blacklist_incoming)[i]; i++) {
2491 free((*sid_blacklist_incoming)[i]);
2492 }
2493 free(*sid_blacklist_incoming);
2494 *sid_blacklist_incoming = NULL((void*)0);
2495 }
2496
2497 if (sid_blacklist_outgoing && *sid_blacklist_outgoing) {
2498 for (i = 0; *sid_blacklist_outgoing && (*sid_blacklist_outgoing)[i]; i++) {
2499 free((*sid_blacklist_outgoing)[i]);
2500 }
2501 free(*sid_blacklist_outgoing);
2502 *sid_blacklist_outgoing = NULL((void*)0);
2503 }
2504}
2505
2506krb5_error_code ipadb_mspac_get_trusted_domains(struct ipadb_context *ipactx)
2507{
2508 struct ipadb_adtrusts *t;
2509 LDAP *lc = ipactx->lcontext;
2510 char *attrs[] = { "cn", "ipaNTTrustPartner", "ipaNTFlatName",
2511 "ipaNTTrustedDomainSID", "ipaNTSIDBlacklistIncoming",
2512 "ipaNTSIDBlacklistOutgoing", "ipaNTAdditionalSuffixes", NULL((void*)0) };
2513 char *filter = "(objectclass=ipaNTTrustedDomain)";
2514 krb5_error_code kerr;
2515 LDAPMessage *res = NULL((void*)0);
2516 LDAPMessage *le;
2517 LDAPRDN rdn;
2518 char *base = NULL((void*)0);
2519 char *dnstr = NULL((void*)0);
2520 char *dnl = NULL((void*)0);
2521 LDAPDN dn = NULL((void*)0);
2522 char **sid_blacklist_incoming = NULL((void*)0);
2523 char **sid_blacklist_outgoing = NULL((void*)0);
2524 int ret, n, i;
2525
2526 ret = asprintf(&base, "cn=ad,cn=trusts,%s", ipactx->base);
2527 if (ret == -1) {
2528 ret = ENOMEM12;
2529 goto done;
2530 }
2531
2532 kerr = ipadb_simple_search(ipactx, base, LDAP_SCOPE_SUBTREE((ber_int_t) 0x0002),
2533 filter, attrs, &res);
2534 if (kerr == KRB5_KDB_NOENTRY(-1780008443L)) {
2535 /* nothing to do, there are no trusts */
2536 ret = 0;
2537 goto done;
2538 } else if (kerr != 0) {
2539 ret = EIO5;
2540 goto done;
2541 }
2542
2543 for (le = ldap_first_entry(lc, res); le; le = ldap_next_entry(lc, le)) {
2544 dnstr = ldap_get_dn(lc, le);
2545
2546 if (dnstr == NULL((void*)0)) {
2547 ret = ENOMEM12;
2548 goto done;
2549 }
2550
2551 n = ipactx->mspac->num_trusts;
2552 ipactx->mspac->num_trusts++;
2553 t = realloc(ipactx->mspac->trusts,
2554 sizeof(struct ipadb_adtrusts) * ipactx->mspac->num_trusts);
2555 if (!t) {
2556 ret = ENOMEM12;
2557 goto done;
2558 }
2559 ipactx->mspac->trusts = t;
2560
2561 memset(&t[n], 0, sizeof(t[n]));
2562
2563 ret = ipadb_ldap_attr_to_str(lc, le, "cn",
2564 &t[n].domain_name);
2565 if (ret) {
2566 ret = EINVAL22;
2567 goto done;
2568 }
2569
2570 t[n].flat_name = NULL((void*)0);
2571 ret = ipadb_ldap_attr_to_str(lc, le, "ipaNTFlatName",
2572 &t[n].flat_name);
2573 if (ret && ret != ENOENT2) {
2574 ret = EINVAL22;
2575 goto done;
2576 }
2577
2578 t[n].domain_sid = NULL((void*)0);
2579 ret = ipadb_ldap_attr_to_str(lc, le, "ipaNTTrustedDomainSID",
2580 &t[n].domain_sid);
2581 if (ret && ret != ENOENT2) {
2582 ret = EINVAL22;
2583 goto done;
2584 }
2585
2586 ret = string_to_sid(t[n].domain_sid, &t[n].domsid);
2587 if (ret && t[n].domain_sid != NULL((void*)0)) {
2588 ret = EINVAL22;
2589 goto done;
2590 }
2591
2592 ret = ipadb_ldap_attr_to_strlist(lc, le, "ipaNTAdditionalSuffixes",
2593 &t[n].upn_suffixes);
2594
2595 if (ret) {
2596 if (ret == ENOENT2) {
2597 /* This attribute is optional */
2598 ret = 0;
2599 t[n].upn_suffixes = NULL((void*)0);
2600 } else {
2601 ret = EINVAL22;
2602 goto done;
2603 }
2604 }
2605
2606 ret = ipadb_ldap_attr_to_strlist(lc, le, "ipaNTSIDBlacklistIncoming",
2607 &sid_blacklist_incoming);
2608
2609 if (ret) {
2610 if (ret == ENOENT2) {
2611 /* This attribute is optional */
2612 ret = 0;
2613 sid_blacklist_incoming = NULL((void*)0);
2614 } else {
2615 ret = EINVAL22;
2616 goto done;
2617 }
2618 }
2619
2620 ret = ipadb_ldap_attr_to_strlist(lc, le, "ipaNTSIDBlacklistOutgoing",
2621 &sid_blacklist_outgoing);
2622
2623 if (ret) {
2624 if (ret == ENOENT2) {
2625 /* This attribute is optional */
2626 ret = 0;
2627 sid_blacklist_outgoing = NULL((void*)0);
2628 } else {
2629 ret = EINVAL22;
2630 goto done;
2631 }
2632 }
2633
2634 ret = ipadb_adtrusts_fill_sid_blacklists(&t[n],
2635 sid_blacklist_incoming,
2636 sid_blacklist_outgoing);
2637 if (ret) {
2638 goto done;
2639 }
2640 ipadb_free_sid_blacklists(&sid_blacklist_incoming,
2641 &sid_blacklist_outgoing);
2642
2643 /* Parse first two RDNs of the entry to find its parent */
2644 dnl = strcasestr(dnstr, base);
2645 if (dnl == NULL((void*)0)) {
2646 goto done;
2647 }
2648
2649 dnl--; dnl[0] = '\0';
2650 /* Create a DN, which is now everything before the base,
2651 * to get list of rdn values -- the last one would be a root domain.
2652 * Since with cross-forest trust we have to route everything via root
2653 * domain, that is enough for us to assign parentship. */
2654 ret = ldap_str2dn(dnstr, &dn, LDAP_DN_FORMAT_LDAPV30x0010U);
2655 if (ret) {
2656 goto done;
2657 }
2658
2659 rdn = NULL((void*)0);
2660 for (i = 0; dn[i] != NULL((void*)0); i++) {
2661 rdn = dn[i];
2662 }
2663
2664 /* We should have a single AVA in the domain RDN */
2665 if (rdn == NULL((void*)0)) {
2666 ldap_dnfree(dn);
2667 ret = EINVAL22;
2668 goto done;
2669 }
2670
2671 t[n].parent_name = strndup(rdn[0]->la_value.bv_val, rdn[0]->la_value.bv_len);
2672
2673 ldap_dnfree(dn);
2674
2675 free(dnstr);
2676 dnstr = NULL((void*)0);
2677 }
2678
2679 /* Traverse through all trusts and resolve parents */
2680 t = ipactx->mspac->trusts;
2681 for (i = 0; i < ipactx->mspac->num_trusts; i++) {
2682 if (t[i].parent_name != NULL((void*)0)) {
2683 for (n = 0; n < ipactx->mspac->num_trusts; n++) {
2684 if (strcasecmp(t[i].parent_name, t[n].domain_name) == 0) {
2685 t[i].parent = &t[n];
2686 }
2687 }
2688 }
2689 }
2690
2691 ret = 0;
2692
2693done:
2694 if (ret != 0) {
2695 krb5_klog_syslog(LOG_ERR3, "Failed to read list of trusted domains");
2696 }
2697 free(dnstr);
2698 free(base);
2699 ipadb_free_sid_blacklists(&sid_blacklist_incoming,
2700 &sid_blacklist_outgoing);
2701 ldap_msgfree(res);
2702 return ret;
2703}
2704
2705krb5_error_code ipadb_reinit_mspac(struct ipadb_context *ipactx, bool_Bool force_reinit)
2706{
2707 char *dom_attrs[] = { "ipaNTFlatName",
2708 "ipaNTFallbackPrimaryGroup",
2709 "ipaNTSecurityIdentifier",
2710 NULL((void*)0) };
2711 char *grp_attrs[] = { "ipaNTSecurityIdentifier", NULL((void*)0) };
2712 krb5_error_code kerr;
2713 LDAPMessage *result = NULL((void*)0);
2714 LDAPMessage *lentry;
2715 struct dom_sid gsid;
2716 char *resstr;
2717 int ret;
2718 time_t now;
2719
2720 /* Do not update the mspac struct more than once a minute. This would
2721 * avoid heavy load on the directory server if there are lots of requests
2722 * from domains which we do not trust. */
2723 now = time(NULL((void*)0));
2724
2725 if (ipactx->mspac != NULL((void*)0) &&
2726 (force_reinit == false0) &&
2727 (now > ipactx->mspac->last_update) &&
2728 (now - ipactx->mspac->last_update) < 60) {
2729 return 0;
2730 }
2731
2732 if (ipactx->mspac && ipactx->mspac->num_trusts == 0) {
2733 /* Check if there is any trust configured. If not, just return
2734 * and do not re-initialize the MS-PAC structure. */
2735 kerr = ipadb_mspac_check_trusted_domains(ipactx);
2736 if (kerr == KRB5_KDB_NOENTRY(-1780008443L)) {
2737 kerr = 0;
2738 goto done;
2739 } else if (kerr != 0) {
2740 goto done;
2741 }
2742 }
2743
2744 /* clean up in case we had old values around */
2745 ipadb_mspac_struct_free(&ipactx->mspac);
2746
2747 ipactx->mspac = calloc(1, sizeof(struct ipadb_mspac));
2748 if (!ipactx->mspac) {
2749 kerr = ENOMEM12;
2750 goto done;
2751 }
2752
2753 ipactx->mspac->last_update = now;
2754
2755 kerr = ipadb_simple_search(ipactx, ipactx->base, LDAP_SCOPE_SUBTREE((ber_int_t) 0x0002),
2756 "(objectclass=ipaNTDomainAttrs)", dom_attrs,
2757 &result);
2758 if (kerr == KRB5_KDB_NOENTRY(-1780008443L)) {
2759 return ENOENT2;
2760 } else if (kerr != 0) {
2761 return EIO5;
2762 }
2763
2764 lentry = ldap_first_entry(ipactx->lcontext, result);
2765 if (!lentry) {
2766 kerr = ENOENT2;
2767 goto done;
2768 }
2769
2770 ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
2771 "ipaNTFlatName",
2772 &ipactx->mspac->flat_domain_name);
2773 if (ret) {
2774 kerr = ret;
2775 goto done;
2776 }
2777
2778 ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
2779 "ipaNTSecurityIdentifier",
2780 &resstr);
2781 if (ret) {
2782 kerr = ret;
2783 goto done;
2784 }
2785
2786 ret = string_to_sid(resstr, &ipactx->mspac->domsid);
2787 if (ret) {
2788 kerr = ret;
2789 free(resstr);
2790 goto done;
2791 }
2792 free(resstr);
2793
2794 free(ipactx->mspac->flat_server_name);
2795 ipactx->mspac->flat_server_name = get_server_netbios_name(ipactx);
2796 if (!ipactx->mspac->flat_server_name) {
2797 kerr = ENOMEM12;
2798 goto done;
2799 }
2800
2801 ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
2802 "ipaNTFallbackPrimaryGroup",
2803 &ipactx->mspac->fallback_group);
2804 if (ret && ret != ENOENT2) {
2805 kerr = ret;
2806 goto done;
2807 }
2808
2809 /* result and lentry not valid any more from here on */
2810 ldap_msgfree(result);
2811 result = NULL((void*)0);
2812 lentry = NULL((void*)0);
2813
2814 if (ret != ENOENT2) {
2815 kerr = ipadb_simple_search(ipactx, ipactx->mspac->fallback_group,
2816 LDAP_SCOPE_BASE((ber_int_t) 0x0000),
2817 "(objectclass=posixGroup)",
2818 grp_attrs, &result);
2819 if (kerr && kerr != KRB5_KDB_NOENTRY(-1780008443L)) {
2820 kerr = ret;
2821 goto done;
2822 }
2823
2824 lentry = ldap_first_entry(ipactx->lcontext, result);
2825 if (!lentry) {
2826 kerr = ENOENT2;
2827 goto done;
2828 }
2829
2830 if (kerr == 0) {
2831 ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
2832 "ipaNTSecurityIdentifier",
2833 &resstr);
2834 if (ret && ret != ENOENT2) {
2835 kerr = ret;
2836 goto done;
2837 }
2838 if (ret == 0) {
2839 ret = string_to_sid(resstr, &gsid);
2840 if (ret) {
2841 free(resstr);
2842 kerr = ret;
2843 goto done;
2844 }
2845 ret = sid_split_rid(&gsid, &ipactx->mspac->fallback_rid);
2846 if (ret) {
2847 free(resstr);
2848 kerr = ret;
2849 goto done;
2850 }
2851 free(resstr);
2852 }
2853 }
2854 }
2855
2856 kerr = ipadb_mspac_get_trusted_domains(ipactx);
2857
2858done:
2859 ldap_msgfree(result);
2860 return kerr;
2861}
2862
2863krb5_error_code ipadb_check_transited_realms(krb5_context kcontext,
2864 const krb5_data *tr_contents,
2865 const krb5_data *client_realm,
2866 const krb5_data *server_realm)
2867{
2868 struct ipadb_context *ipactx;
2869 bool_Bool has_transited_contents, has_client_realm, has_server_realm;
2870 int i;
2871 krb5_error_code ret;
2872
2873 ipactx = ipadb_get_context(kcontext);
2874 if (!ipactx || !ipactx->mspac) {
2875 return KRB5_KDB_DBNOTINITED(-1780008435L);
2876 }
2877
2878 has_transited_contents = false0;
2879 has_client_realm = false0;
2880 has_server_realm = false0;
2881
2882 /* First, compare client or server realm with ours */
2883 if (strncasecmp(client_realm->data, ipactx->realm, client_realm->length) == 0) {
2884 has_client_realm = true1;
2885 }
2886 if (strncasecmp(server_realm->data, ipactx->realm, server_realm->length) == 0) {
2887 has_server_realm = true1;
2888 }
2889
2890 if ((tr_contents->length == 0) || (tr_contents->data[0] == '\0')) {
2891 /* For in-realm case allow transition */
2892 if (has_client_realm && has_server_realm) {
2893 return 0;
2894 }
2895 /* Since transited realm is empty, we don't need to check for it, it is a direct trust case */
2896 has_transited_contents = true1;
2897 }
2898
2899 if (!ipactx->mspac || !ipactx->mspac->trusts) {
2900 return KRB5_PLUGIN_NO_HANDLE(-1765328135L);
2901 }
2902
2903 /* Iterate through list of trusts and check if any of input belongs to any of the trust */
2904 for(i=0; i < ipactx->mspac->num_trusts ; i++) {
2905 if (!has_transited_contents &&
2906 (strncasecmp(tr_contents->data, ipactx->mspac->trusts[i].domain_name, tr_contents->length) == 0)) {
2907 has_transited_contents = true1;
2908 }
2909 if (!has_client_realm &&
2910 (strncasecmp(client_realm->data, ipactx->mspac->trusts[i].domain_name, client_realm->length) == 0)) {
2911 has_client_realm = true1;
2912 }
2913 if (!has_server_realm &&
2914 (strncasecmp(server_realm->data, ipactx->mspac->trusts[i].domain_name, server_realm->length) == 0)) {
2915 has_server_realm = true1;
2916 }
2917 }
2918
2919 /* Tell to KDC that we don't handle this transition so that rules in krb5.conf could play its role */
2920 ret = KRB5_PLUGIN_NO_HANDLE(-1765328135L);
2921 if (has_client_realm && has_transited_contents && has_server_realm) {
2922 ret = 0;
2923 }
2924 return ret;
2925}
2926
2927/* Checks whether a principal's realm is one of trusted domains' realm or NetBIOS name
2928 * and returns the realm of the matched trusted domain in 'trusted_domain'
2929 * Returns 0 in case of success and KRB5_KDB_NOENTRY otherwise
2930 * If DAL driver is not initialized, returns KRB5_KDB_DBNOTINITED */
2931krb5_error_code ipadb_is_princ_from_trusted_realm(krb5_context kcontext,
2932 const char *test_realm, size_t size,
2933 char **trusted_realm)
2934{
2935 struct ipadb_context *ipactx;
2936 int i, j, length;
2937 const char *name;
2938 bool_Bool result = false0;
2939
2940 if (test_realm == NULL((void*)0) || test_realm[0] == '\0') {
2941 return KRB5_KDB_NOENTRY(-1780008443L);
2942 }
2943
2944 ipactx = ipadb_get_context(kcontext);
2945 if (!ipactx || !ipactx->mspac) {
2946 return KRB5_KDB_DBNOTINITED(-1780008435L);
2947 }
2948
2949 /* First, compare realm with ours, it would not be from a trusted realm then */
2950 if (strncasecmp(test_realm, ipactx->realm, size) == 0) {
2951 return KRB5_KDB_NOENTRY(-1780008443L);
2952 }
2953
2954 if (!ipactx->mspac || !ipactx->mspac->trusts) {
2955 return KRB5_KDB_NOENTRY(-1780008443L);
2956 }
2957
2958 /* Iterate through list of trusts and check if input realm belongs to any of the trust */
2959 for(i = 0 ; i < ipactx->mspac->num_trusts ; i++) {
2960 result = strncasecmp(test_realm,
2961 ipactx->mspac->trusts[i].domain_name,
2962 size) == 0;
2963
2964 if (!result && (ipactx->mspac->trusts[i].flat_name != NULL((void*)0))) {
2965 result = strncasecmp(test_realm,
2966 ipactx->mspac->trusts[i].flat_name,
2967 size) == 0;
2968 }
2969
2970 if (!result && (ipactx->mspac->trusts[i].upn_suffixes != NULL((void*)0))) {
2971 for (j = 0; ipactx->mspac->trusts[i].upn_suffixes[j]; j++) {
2972 result = strncasecmp(test_realm,
2973 ipactx->mspac->trusts[i].upn_suffixes[j],
2974 size) == 0;
2975 if (result)
2976 break;
2977 }
2978 }
2979
2980 if (result) {
2981 /* return the realm if caller supplied a place for it */
2982 if (trusted_realm != NULL((void*)0)) {
2983 name = (ipactx->mspac->trusts[i].parent_name != NULL((void*)0)) ?
2984 ipactx->mspac->trusts[i].parent_name :
2985 ipactx->mspac->trusts[i].domain_name;
2986 length = strlen(name) + 1;
2987 *trusted_realm = calloc(1, length);
2988 if (*trusted_realm != NULL((void*)0)) {
2989 for (j = 0; j < length; j++) {
2990 (*trusted_realm)[j] = toupper(name[j]);
2991 }
2992 } else {
2993 return KRB5_KDB_NOENTRY(-1780008443L);
2994 }
2995 }
2996 return 0;
2997 }
2998 }
2999
3000 return KRB5_KDB_NOENTRY(-1780008443L);
3001}