Bug Summary

File:daemons/ipa-kdb/ipa_kdb_principals.c
Warning:line 422, column 5
Value stored to 'cur' is never read

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_principals.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_principals.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 "ipa_kdb.h"
24#include "ipa_krb5.h"
25#include <unicase.h>
26
27/*
28 * During TGS request search by ipaKrbPrincipalName (case-insensitive)
29 * and krbPrincipalName (case-sensitive)
30 */
31#define PRINC_TGS_SEARCH_FILTER"(&(|(objectclass=krbprincipalaux)" "(objectclass=krbprincipal)"
"(objectclass=ipakrbprincipal))" "(|(ipakrbprincipalalias=%s)"
"(krbprincipalname:caseIgnoreIA5Match:=%s)))"
"(&(|(objectclass=krbprincipalaux)" \
32 "(objectclass=krbprincipal)" \
33 "(objectclass=ipakrbprincipal))" \
34 "(|(ipakrbprincipalalias=%s)" \
35 "(krbprincipalname:caseIgnoreIA5Match:=%s)))"
36
37#define PRINC_SEARCH_FILTER"(&(|(objectclass=krbprincipalaux)" "(objectclass=krbprincipal))"
"(krbprincipalname=%s))"
"(&(|(objectclass=krbprincipalaux)" \
38 "(objectclass=krbprincipal))" \
39 "(krbprincipalname=%s))"
40
41#define PRINC_TGS_SEARCH_FILTER_EXTRA"(&(|(objectclass=krbprincipalaux)" "(objectclass=krbprincipal)"
"(objectclass=ipakrbprincipal))" "(|(ipakrbprincipalalias=%s)"
"(krbprincipalname:caseIgnoreIA5Match:=%s))" "%s)"
"(&(|(objectclass=krbprincipalaux)" \
42 "(objectclass=krbprincipal)" \
43 "(objectclass=ipakrbprincipal))" \
44 "(|(ipakrbprincipalalias=%s)" \
45 "(krbprincipalname:caseIgnoreIA5Match:=%s))" \
46 "%s)"
47
48#define PRINC_SEARCH_FILTER_EXTRA"(&(|(objectclass=krbprincipalaux)" "(objectclass=krbprincipal))"
"(krbprincipalname=%s)" "%s)"
"(&(|(objectclass=krbprincipalaux)" \
49 "(objectclass=krbprincipal))" \
50 "(krbprincipalname=%s)" \
51 "%s)"
52static char *std_principal_attrs[] = {
53 "krbPrincipalName",
54 "krbCanonicalName",
55 "krbUPEnabled",
56 "krbPrincipalKey",
57 "krbTicketPolicyReference",
58 "krbPrincipalExpiration",
59 "krbPasswordExpiration",
60 "krbPwdPolicyReference",
61 "krbPrincipalType",
62 "krbPwdHistory",
63 "krbLastPwdChange",
64 "krbPrincipalAliases",
65 "krbLastSuccessfulAuth",
66 "krbLastFailedAuth",
67 "krbLoginFailedCount",
68 "krbPrincipalAuthInd",
69 "krbExtraData",
70 "krbLastAdminUnlock",
71 "krbObjectReferences",
72 "krbTicketFlags",
73 "krbMaxTicketLife",
74 "krbMaxRenewableAge",
75
76 /* IPA SPECIFIC ATTRIBUTES */
77 "nsaccountlock",
78 "passwordHistory",
79 IPA_KRB_AUTHZ_DATA_ATTR"ipaKrbAuthzData",
80 IPA_USER_AUTH_TYPE"ipaUserAuthType",
81 "ipatokenRadiusConfigLink",
82 "krbAuthIndMaxTicketLife",
83 "krbAuthIndMaxRenewableAge",
84
85 "objectClass",
86 NULL((void*)0)
87};
88
89static char *std_tktpolicy_attrs[] = {
90 "krbmaxticketlife",
91 "krbmaxrenewableage",
92 "krbticketflags",
93 "krbauthindmaxticketlife",
94 "krbauthindmaxrenewableage",
95
96 NULL((void*)0)
97};
98
99#define TKTFLAGS_BIT0x01 0x01
100#define MAXTKTLIFE_BIT0x02 0x02
101#define MAXRENEWABLEAGE_BIT0x04 0x04
102
103static char *std_principal_obj_classes[] = {
104 "krbprincipal",
105 "krbprincipalaux",
106 "krbTicketPolicyAux",
107
108 NULL((void*)0)
109};
110
111#define STD_PRINCIPAL_OBJ_CLASSES_SIZE(sizeof(std_principal_obj_classes) / sizeof(char *) - 1) (sizeof(std_principal_obj_classes) / sizeof(char *) - 1)
112
113#define DEFAULT_TL_DATA_CONTENT"\x00\x00\x00\x00principal@UNINITIALIZED" "\x00\x00\x00\x00principal@UNINITIALIZED"
114
115static int ipadb_ldap_attr_to_tl_data(LDAP *lcontext, LDAPMessage *le,
116 char *attrname,
117 krb5_tl_data **result, int *num)
118{
119 struct berval **vals;
120 krb5_tl_data *prev, *next;
121 krb5_int16 be_type;
122 int i;
123 int ret = ENOENT2;
124
125 *result = NULL((void*)0);
126 prev = NULL((void*)0);
127 next = NULL((void*)0);
128 vals = ldap_get_values_len(lcontext, le, attrname);
129 if (vals) {
130 for (i = 0; vals[i]; i++) {
131 next = calloc(1, sizeof(krb5_tl_data));
132 if (!next) {
133 ret = ENOMEM12;
134 goto done;
135 }
136
137 /* fill tl_data struct with the data */
138 memcpy(&be_type, vals[i]->bv_val, 2);
139 next->tl_data_type = ntohs(be_type);
140 next->tl_data_length = vals[i]->bv_len - 2;
141 next->tl_data_contents = malloc(next->tl_data_length);
142 if (!next->tl_data_contents) {
143 ret = ENOMEM12;
144 goto done;
145 }
146 memcpy(next->tl_data_contents,
147 vals[i]->bv_val + 2,
148 next->tl_data_length);
149
150 if (prev) {
151 prev->tl_data_next = next;
152 } else {
153 *result = next;
154 }
155 prev = next;
156 }
157 *num = i;
158 ret = 0;
159
160 ldap_value_free_len(vals);
161 }
162
163done:
164 if (ret) {
165 free(next);
166 if (*result) {
167 prev = *result;
168 while (prev) {
169 next = prev->tl_data_next;
170 free(prev);
171 prev = next;
172 }
173 }
174 *result = NULL((void*)0);
175 *num = 0;
176 }
177 return ret;
178}
179
180static krb5_error_code ipadb_set_tl_data(krb5_db_entry *entry,
181 krb5_int16 type,
182 krb5_ui_2 length,
183 const krb5_octet *data)
184{
185 krb5_error_code kerr;
186 krb5_tl_data *new_td = NULL((void*)0);
187 krb5_tl_data *td;
188
189 for (td = entry->tl_data; td; td = td->tl_data_next) {
190 if (td->tl_data_type == type) {
191 break;
192 }
193 }
194 if (!td) {
195 /* an existing entry was not found, make new */
196 new_td = malloc(sizeof(krb5_tl_data));
197 if (!new_td) {
198 kerr = ENOMEM12;
199 goto done;
200 }
201 td = new_td;
202 td->tl_data_next = entry->tl_data;
203 td->tl_data_type = type;
204 entry->tl_data = td;
205 entry->n_tl_data++;
206 }
207 td->tl_data_length = length;
208 td->tl_data_contents = malloc(td->tl_data_length);
209 if (!td->tl_data_contents) {
210 kerr = ENOMEM12;
211 goto done;
212 }
213 memcpy(td->tl_data_contents, data, td->tl_data_length);
214
215 new_td = NULL((void*)0);
216 kerr = 0;
217
218done:
219 free(new_td);
220 return kerr;
221}
222
223static int ipadb_ldap_attr_to_key_data(LDAP *lcontext, LDAPMessage *le,
224 char *attrname,
225 krb5_key_data **result, int *num,
226 krb5_kvno *res_mkvno)
227{
228 struct berval **vals;
229 int mkvno;
230 int ret;
231
232 vals = ldap_get_values_len(lcontext, le, attrname);
233 if (!vals) {
234 return ENOENT2;
235 }
236
237 ret = ber_decode_krb5_key_data(vals[0], &mkvno, num, result);
238 ldap_value_free_len(vals);
239 if (ret == 0) {
240 *res_mkvno = mkvno;
241 }
242 return ret;
243}
244
245static void ipadb_validate_otp(struct ipadb_context *ipactx,
246 LDAPMessage *lentry,
247 enum ipadb_user_auth *ua)
248{
249 static const char *attrs[] = { "dn", NULL((void*)0) };
250 static const char *dttmpl = "%Y%m%d%H%M%SZ";
251 static const char *ftmpl = "(&"
252 "(objectClass=ipaToken)(ipatokenOwner=%s)"
253 "(|(ipatokenNotBefore<=%s)(!(ipatokenNotBefore=*)))"
254 "(|(ipatokenNotAfter>=%s)(!(ipatokenNotAfter=*)))"
255 "(|(ipatokenDisabled=FALSE)(!(ipatokenDisabled=*)))"
256 ")";
257 krb5_error_code kerr = 0;
258 LDAPMessage *res = NULL((void*)0);
259 char datetime[16] = {};
260 char *filter = NULL((void*)0);
261 struct tm tm = {};
262 char *dn = NULL((void*)0);
263 time_t now = 0;
264 int count = 0;
265
266 if (!(*ua & IPADB_USER_AUTH_OTP))
267 return;
268
269 /* Get the current time. */
270 if (time(&now) == (time_t) -1)
271 return;
272 if (gmtime_r(&now, &tm) == NULL((void*)0))
273 return;
274
275 /* Make the current time string. */
276 if (strftime(datetime, sizeof(datetime), dttmpl, &tm) == 0)
277 return;
278
279 /* Make the filter. */
280 dn = ldap_get_dn(ipactx->lcontext, lentry);
281 if (dn == NULL((void*)0))
282 return;
283 count = asprintf(&filter, ftmpl, dn, datetime, datetime);
284 ldap_memfree(dn);
285 if (count < 0)
286 return;
287
288 /* Fetch the active token list. */
289 kerr = ipadb_simple_search(ipactx, ipactx->base, LDAP_SCOPE_SUBTREE((ber_int_t) 0x0002),
290 filter, (char**) attrs, &res);
291 free(filter);
292 if (kerr != 0 || res == NULL((void*)0))
293 return;
294
295 /* Count the number of active tokens. */
296 count = ldap_count_entries(ipactx->lcontext, res);
297 ldap_msgfree(res);
298
299 /* If the user is configured for OTP, but has no active tokens, remove
300 * OTP from the list since the user obviously can't log in this way. */
301 if (count == 0)
302 *ua &= ~IPADB_USER_AUTH_OTP;
303}
304
305static void ipadb_validate_radius(struct ipadb_context *ipactx,
306 LDAPMessage *lentry,
307 enum ipadb_user_auth *ua)
308{
309 struct berval **vals;
310
311 if (!(*ua & IPADB_USER_AUTH_RADIUS))
312 return;
313
314 /* Ensure that the user has a link to a RADIUS config. */
315 vals = ldap_get_values_len(ipactx->lcontext, lentry,
316 "ipatokenRadiusConfigLink");
317 if (vals == NULL((void*)0) || vals[0] == NULL((void*)0))
318 *ua &= ~IPADB_USER_AUTH_RADIUS;
319 else
320 *ua = IPADB_USER_AUTH_RADIUS;
321
322 if (vals != NULL((void*)0))
323 ldap_value_free_len(vals);
324}
325
326static enum ipadb_user_auth ipadb_get_user_auth(struct ipadb_context *ipactx,
327 LDAPMessage *lentry)
328{
329 enum ipadb_user_auth gua = IPADB_USER_AUTH_NONE;
330 enum ipadb_user_auth ua = IPADB_USER_AUTH_NONE;
331 const struct ipadb_global_config *gcfg = NULL((void*)0);
332
333 /* Get the global user_auth settings. */
334 gcfg = ipadb_get_global_config(ipactx);
335 if (gcfg != NULL((void*)0))
336 gua = gcfg->user_auth;
337
338 /* Get the user's user_auth settings if not disabled. */
339 if ((gua & IPADB_USER_AUTH_DISABLED) == 0)
340 ipadb_parse_user_auth(ipactx->lcontext, lentry, &ua);
341
342 /* Filter out the disabled flag. */
343 gua &= ~IPADB_USER_AUTH_DISABLED;
344 ua &= ~IPADB_USER_AUTH_DISABLED;
345
346 /* Determine which user_auth policy is active: user or global. */
347 if (ua == IPADB_USER_AUTH_NONE)
348 ua = gua;
349
350 /* Perform flag validation. */
351 ipadb_validate_otp(ipactx, lentry, &ua);
352 ipadb_validate_radius(ipactx, lentry, &ua);
353
354 return ua;
355}
356
357#define OSA_ADB_PRINC_VERSION_10x12345C01 0x12345C01
358/* The XDR encoding of OSA_PRINC_ENC is as follows:
359 version: int (signed 32 bit integer)
360 name: nullstring (null terminated variable string)
361 aux_attributes: long (signed 32 bit integer)
362 old_key_next: u_int (unsigned 32 bit integer)
363 adm_hist_kvno: u_char (unisgned char)
364 old_keys: array of keys, we do not care so alway u_int of 0
365*/
366#define OSA_PRINC_ENC_BASE_SIZE20 20
367
368static krb5_error_code ipadb_policydn_to_kdam_tl_data(const char *policydn,
369 krb5_db_entry *entry)
370{
371 krb5_error_code kerr;
372 uint32_t tmp;
373 char *policy_name = NULL((void*)0);
374 char *p;
375 uint8_t *buf = NULL((void*)0);
376 size_t buf_len;
377 int slen;
378 int plen;
379 int cur;
380
381 /* policy objects must use cn as the RDN */
382 if (strncmp(policydn, "cn=", 3) != 0) {
383 return KRB5_KDB_INTERNAL_ERROR(-1780008411L);
384 }
385
386 /* Should we try to consider the case where a ',' is part of the polict
387 * name ? */
388 policy_name = strdup(&policydn[3]);
389 if (!policy_name) {
390 kerr = ENOMEM12;
391 goto done;
392 }
393 p = strchr(policy_name, ',');
394 if (p) *p = '\0';
395
396 /* Now we open code a basic KRB5_TL_KADM_DATA which is a XDR encoded
397 * structure in MIT code */
398
399 slen = strlen(policy_name) + 1;
400 /* A xdr varstring is preceeded by a 32bit len field and is always 32
401 * bit aligned */
402 plen = slen + 4;
403 plen = (((plen + 3) / 4) * 4);
404
405 buf_len = OSA_PRINC_ENC_BASE_SIZE20 + plen;
406 buf = calloc(1, buf_len);
407 if (!buf) {
408 kerr = ENOMEM12;
409 goto done;
410 }
411
412 /* version */
413 cur = 0;
414 tmp = htobe32(OSA_ADB_PRINC_VERSION_1)__bswap_32 (0x12345C01);
415 memcpy(&buf[cur], &tmp, 4);
416 cur += 4;
417
418 /* name */
419 tmp = htobe32(slen)__bswap_32 (slen);
420 memcpy(&buf[cur], &tmp, 4);
421 memcpy(&buf[cur + 4], policy_name, slen);
422 cur += plen;
Value stored to 'cur' is never read
423
424 /* All the other fileds are left empty */
425
426 kerr = ipadb_set_tl_data(entry, KRB5_TL_KADM_DATA0x0003, buf_len, buf);
427
428done:
429 free(policy_name);
430 free(buf);
431 return kerr;
432}
433
434static void strv_free(char **strv)
435{
436 int i;
437
438 if (strv == NULL((void*)0)) {
439 return;
440 }
441
442 for (i = 0; strv[i] != NULL((void*)0); i++) {
443 free(strv[i]);
444 }
445
446 free(strv);
447}
448
449static krb5_error_code ipadb_get_ldap_auth_ind(krb5_context kcontext,
450 LDAP *lcontext,
451 LDAPMessage *lentry,
452 krb5_db_entry *entry)
453{
454 krb5_error_code ret = 0;
455 char **authinds = NULL((void*)0);
456 char *aistr = NULL((void*)0);
457 char *ap = NULL((void*)0);
458 size_t len = 0;
459 size_t l = 0;
460 int count = 0;
461 int i = 0;
462
463 ret = ipadb_ldap_attr_to_strlist(lcontext, lentry, "krbPrincipalAuthInd",
464 &authinds);
465 switch (ret) {
466 case 0:
467 break;
468 case ENOENT2:
469 return 0;
470 default:
471 return ret;
472 }
473
474 for (count = 0; authinds != NULL((void*)0) && authinds[count] != NULL((void*)0); count++) {
475 len += strlen(authinds[count]) + 1;
476 }
477
478 if (len == 0) {
479 strv_free(authinds);
480 return 0;
481 }
482
483 aistr = malloc(len);
484 if (aistr == NULL((void*)0)) {
485 ret = errno(*__errno_location ());
486 goto cleanup;
487 }
488
489 /* Create a space-separated string of authinds. */
490 ap = aistr;
491 l = len;
492 for (i = 0; i < count; i++) {
493 ret = snprintf(ap, l, "%s ", authinds[i]);
494 if (ret <= 0 || ret > l) {
495 ret = ENOMEM12;
496 goto cleanup;
497 }
498 ap += ret;
499 l -= ret;
500 }
501 aistr[len - 1] = '\0';
502
503 ret = krb5_dbe_set_string(kcontext, entry, "require_auth",
504 aistr);
505
506cleanup:
507 strv_free(authinds);
508 free(aistr);
509
510 return ret;
511}
512
513static void ipadb_parse_authind_policies(krb5_context kcontext,
514 LDAP *lcontext,
515 LDAPMessage *lentry,
516 krb5_db_entry *entry,
517 enum ipadb_user_auth ua)
518{
519 int result;
520 int ret;
521 struct ipadb_e_data *ied;
522 const struct {
523 char *attribute;
524 enum ipadb_user_auth flag;
525 enum ipadb_user_auth_idx idx;
526 } life_authind_map[] = {
527 {"krbAuthIndMaxTicketLife;otp",
528 IPADB_USER_AUTH_OTP, IPADB_USER_AUTH_IDX_OTP},
529 {"krbAuthIndMaxTicketLife;radius",
530 IPADB_USER_AUTH_RADIUS, IPADB_USER_AUTH_IDX_RADIUS},
531 {"krbAuthIndMaxTicketLife;pkinit",
532 IPADB_USER_AUTH_PKINIT, IPADB_USER_AUTH_IDX_PKINIT},
533 {"krbAuthIndMaxTicketLife;hardened",
534 IPADB_USER_AUTH_HARDENED, IPADB_USER_AUTH_IDX_HARDENED},
535 {NULL((void*)0), IPADB_USER_AUTH_NONE, IPADB_USER_AUTH_IDX_MAX},
536 }, age_authind_map[] = {
537 {"krbAuthIndMaxRenewableAge;otp",
538 IPADB_USER_AUTH_OTP, IPADB_USER_AUTH_IDX_OTP},
539 {"krbAuthIndMaxRenewableAge;radius",
540 IPADB_USER_AUTH_RADIUS, IPADB_USER_AUTH_IDX_RADIUS},
541 {"krbAuthIndMaxRenewableAge;pkinit",
542 IPADB_USER_AUTH_PKINIT, IPADB_USER_AUTH_IDX_PKINIT},
543 {"krbAuthIndMaxRenewableAge;hardened",
544 IPADB_USER_AUTH_HARDENED, IPADB_USER_AUTH_IDX_HARDENED},
545 {NULL((void*)0), IPADB_USER_AUTH_NONE, IPADB_USER_AUTH_IDX_MAX},
546 };
547
548 ied = (struct ipadb_e_data *)entry->e_data;
549 if (ied == NULL((void*)0)) {
550 return;
551 }
552
553 for (size_t i = 0; life_authind_map[i].attribute != NULL((void*)0); i++) {
554 if (ua & life_authind_map[i].flag) {
555 ret = ipadb_ldap_attr_to_int(lcontext, lentry,
556 life_authind_map[i].attribute,
557 &result);
558 if (ret == 0) {
559 ied->pol_limits[life_authind_map[i].idx].max_life = result;
560 }
561
562 ret = ipadb_ldap_attr_to_int(lcontext, lentry,
563 age_authind_map[i].attribute,
564 &result);
565 if (ret == 0) {
566 ied->pol_limits[age_authind_map[i].idx].max_renewable_life = result;
567 }
568 }
569 }
570}
571
572
573static krb5_error_code ipadb_parse_ldap_entry(krb5_context kcontext,
574 char *principal,
575 LDAPMessage *lentry,
576 krb5_db_entry **kentry,
577 uint32_t *polmask)
578{
579 const krb5_octet rad_string[] = "otp\0[{\"indicators\": [\"radius\"]}]";
580 const krb5_octet otp_string[] = "otp\0[{\"indicators\": [\"otp\"]}]";
581 struct ipadb_context *ipactx;
582 enum ipadb_user_auth ua;
583 LDAP *lcontext;
584 krb5_db_entry *entry;
585 struct ipadb_e_data *ied;
586 krb5_error_code kerr;
587 krb5_tl_data *res_tl_data;
588 krb5_key_data *res_key_data;
589 krb5_kvno mkvno = 0;
590 char **restrlist;
591 char *restring;
592 char **authz_data_list;
593 krb5_timestamp restime;
594 bool_Bool resbool;
595 int result;
596 int ret;
597
598 *polmask = 0;
599 entry = calloc(1, sizeof(krb5_db_entry));
600 if (!entry) {
601 return ENOMEM12;
602 }
603
604 /* proceed to fill in attributes in the order they are defined in
605 * krb5_db_entry in kdb.h */
606 ipactx = ipadb_get_context(kcontext);
607 if (!ipactx) {
608 free(entry);
609 return KRB5_KDB_DBNOTINITED(-1780008435L);
610 }
611 lcontext = ipactx->lcontext;
612 if (!lcontext) {
613 krb5_klog_syslog(LOG_INFO6,
614 "No LDAP connection in ipadb_parse_ldap_entry(); retrying...\n");
615 ret = ipadb_get_connection(ipactx);
616 if (ret != 0) {
617 krb5_klog_syslog(LOG_ERR3,
618 "No LDAP connection on retry in ipadb_parse_ldap_entry()!\n");
619 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
620 goto done;
621 }
622 }
623
624 entry->magic = KRB5_KDB_MAGIC_NUMBER0xdbdbdbdb;
625 entry->len = KRB5_KDB_V1_BASE_LENGTH38;
626
627 /* Get User Auth configuration. */
628 ua = ipadb_get_user_auth(ipactx, lentry);
629
630 /* ignore mask for now */
631
632 ret = ipadb_ldap_attr_to_int(lcontext, lentry,
633 "krbTicketFlags", &result);
634 if (ret == 0) {
635 entry->attributes = result;
636 } else {
637 *polmask |= TKTFLAGS_BIT0x01;
638 }
639
640 ret = ipadb_ldap_attr_to_int(lcontext, lentry,
641 "krbMaxTicketLife", &result);
642 if (ret == 0) {
643 entry->max_life = result;
644 } else {
645 *polmask |= MAXTKTLIFE_BIT0x02;
646 }
647
648 ret = ipadb_ldap_attr_to_int(lcontext, lentry,
649 "krbMaxRenewableAge", &result);
650 if (ret == 0) {
651 entry->max_renewable_life = result;
652 } else {
653 *polmask |= MAXRENEWABLEAGE_BIT0x04;
654 }
655
656 ret = ipadb_ldap_attr_to_krb5_timestamp(lcontext, lentry,
657 "krbPrincipalexpiration", &restime);
658 switch (ret) {
659 case 0:
660 entry->expiration = restime;
661 case ENOENT2:
662 break;
663 default:
664 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
665 goto done;
666 }
667
668 ret = ipadb_ldap_attr_to_krb5_timestamp(lcontext, lentry,
669 "krbPasswordExpiration", &restime);
670 switch (ret) {
671 case 0:
672 entry->pw_expiration = restime;
673
674 /* If we are using only RADIUS, we don't know expiration. */
675 if (ua == IPADB_USER_AUTH_RADIUS)
676 entry->pw_expiration = 0;
677 case ENOENT2:
678 break;
679 default:
680 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
681 goto done;
682 }
683
684 ret = ipadb_ldap_attr_to_krb5_timestamp(lcontext, lentry,
685 "krbLastSuccessfulAuth", &restime);
686 switch (ret) {
687 case 0:
688 entry->last_success = restime;
689 case ENOENT2:
690 break;
691 default:
692 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
693 goto done;
694 }
695
696 ret = ipadb_ldap_attr_to_krb5_timestamp(lcontext, lentry,
697 "krbLastFailedAuth", &restime);
698 switch (ret) {
699 case 0:
700 entry->last_failed = restime;
701 case ENOENT2:
702 break;
703 default:
704 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
705 goto done;
706 }
707
708 ret = ipadb_ldap_attr_to_int(lcontext, lentry,
709 "krbLoginFailedCount", &result);
710 if (ret == 0) {
711 entry->fail_auth_count = result;
712 }
713
714 /* TODO: e_length, e_data */
715
716 if (principal) {
717 kerr = krb5_parse_name(kcontext, principal, &entry->princ);
718 if (kerr != 0) {
719 goto done;
720 }
721 } else {
722 /* see if canonical name is available */
723 ret = ipadb_ldap_attr_to_str(lcontext, lentry,
724 "krbCanonicalName", &restring);
725 switch (ret) {
726 case ENOENT2:
727 /* if not pick the first principal name in the entry */
728 ret = ipadb_ldap_attr_to_str(lcontext, lentry,
729 "krbPrincipalName", &restring);
730 if (ret != 0) {
731 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
732 goto done;
733 }
734 case 0:
735 break;
736 default:
737 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
738 goto done;
739 }
740 kerr = krb5_parse_name(kcontext, restring, &entry->princ);
741 free(restring);
742 if (kerr != 0) {
743 goto done;
744 }
745 }
746
747 ret = ipadb_ldap_attr_to_tl_data(lcontext, lentry,
748 "krbExtraData", &res_tl_data, &result);
749 switch (ret) {
750 case 0:
751 entry->tl_data = res_tl_data;
752 entry->n_tl_data = result;
753 break;
754 case ENOENT2:
755 /* The kadmin utility expects always at least KRB5_TL_MOD_PRINC tl_data
756 * to be available. So if krbExtraData is missing (may happen when a
757 * user is created but no password has been set yet) then add a default
758 * one. */
759 kerr = ipadb_set_tl_data(entry, KRB5_TL_MOD_PRINC0x0002,
760 sizeof(DEFAULT_TL_DATA_CONTENT"\x00\x00\x00\x00principal@UNINITIALIZED"),
761 (const krb5_octet *)DEFAULT_TL_DATA_CONTENT"\x00\x00\x00\x00principal@UNINITIALIZED");
762 break;
763 default:
764 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
765 goto done;
766 }
767
768 ret = ipadb_get_ldap_auth_ind(kcontext, lcontext, lentry, entry);
769 if (ret)
770 goto done;
771
772 ret = ipadb_ldap_attr_to_key_data(lcontext, lentry,
773 "krbPrincipalKey",
774 &res_key_data, &result, &mkvno);
775 switch (ret) {
776 case 0:
777 /* Only set a principal's key if password auth can be used. Otherwise
778 * the KDC would add pre-authentication methods to the NEEDED_PREAUTH
779 * reply for AS-REQs which indicate the password authentication is
780 * available. This might confuse applications like e.g. SSSD which try
781 * to determine suitable authentication methods and corresponding
782 * prompts with the help of MIT Kerberos' responder interface which
783 * acts on the returned pre-authentication methods. A typical example
784 * is enforced OTP authentication where of course keys are available
785 * for the first factor but password authentication should not be
786 * advertised by the KDC. */
787 if (!(ua & IPADB_USER_AUTH_PASSWORD) && (ua != IPADB_USER_AUTH_NONE)) {
788 /* This is the same behavior as ENOENT below. */
789 ipa_krb5_free_key_data(res_key_data, result);
790 break;
791 }
792
793 entry->key_data = res_key_data;
794 entry->n_key_data = result;
795 if (mkvno) {
796 krb5_int16 kvno16le = htole16((krb5_int16)mkvno)__uint16_identity ((krb5_int16)mkvno);
797
798 kerr = ipadb_set_tl_data(entry, KRB5_TL_MKVNO0x0008,
799 sizeof(kvno16le),
800 (krb5_octet *)&kvno16le);
801 if (kerr) {
802 goto done;
803 }
804 }
805 case ENOENT2:
806 break;
807 default:
808 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
809 goto done;
810 }
811
812 ret = ipadb_ldap_attr_to_bool(lcontext, lentry,
813 "nsAccountLock", &resbool);
814 if ((ret == 0 && resbool == true1) || (ret != 0 && ret != ENOENT2)) {
815 entry->attributes |= KRB5_KDB_DISALLOW_ALL_TIX0x00000040;
816 }
817
818 ied = calloc(1, sizeof(struct ipadb_e_data));
819 if (!ied) {
820 kerr = ENOMEM12;
821 goto done;
822 }
823 ied->magic = IPA_E_DATA_MAGIC0x0eda7a;
824
825 entry->e_data = (krb5_octet *)ied;
826
827 ied->entry_dn = ldap_get_dn(lcontext, lentry);
828 if (!ied->entry_dn) {
829 kerr = ENOMEM12;
830 goto done;
831 }
832
833 /* mark this as an ipa_user if it has the posixaccount objectclass */
834 ret = ipadb_ldap_attr_has_value(lcontext, lentry,
835 "objectClass", "posixAccount");
836 if (ret != 0 && ret != ENOENT2) {
837 kerr = ret;
838 goto done;
839 }
840 if (ret == 0) {
841 ied->ipa_user = true1;
842 }
843
844 /* check if it has the krbTicketPolicyAux objectclass */
845 ret = ipadb_ldap_attr_has_value(lcontext, lentry,
846 "objectClass", "krbTicketPolicyAux");
847 if (ret != 0 && ret != ENOENT2) {
848 kerr = ret;
849 goto done;
850 }
851 if (ret == 0) {
852 ied->has_tktpolaux = true1;
853 }
854
855 ret = ipadb_ldap_attr_to_str(lcontext, lentry,
856 "krbPwdPolicyReference", &restring);
857 switch (ret) {
858 case ENOENT2:
859 /* use the default policy if ref. is not available */
860 ret = asprintf(&restring,
861 "cn=global_policy,%s", ipactx->realm_base);
862 if (ret == -1) {
863 kerr = ENOMEM12;
864 goto done;
865 }
866 case 0:
867 break;
868 default:
869 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
870 goto done;
871 }
872 ied->pw_policy_dn = restring;
873
874 kerr = ipadb_policydn_to_kdam_tl_data(restring, entry);
875 if (kerr) goto done;
876
877 ret = ipadb_ldap_attr_to_strlist(lcontext, lentry,
878 "passwordHistory", &restrlist);
879 if (ret != 0 && ret != ENOENT2) {
880 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
881 goto done;
882 }
883 if (ret == 0) {
884 ied->pw_history = restrlist;
885 }
886
887 ret = ipadb_ldap_attr_to_krb5_timestamp(lcontext, lentry,
888 "krbLastPwdChange", &restime);
889 if (ret == 0) {
890 krb5_int32 time32le = htole32((krb5_int32)restime)__uint32_identity ((krb5_int32)restime);
891
892 kerr = ipadb_set_tl_data(entry,
893 KRB5_TL_LAST_PWD_CHANGE0x0001,
894 sizeof(time32le),
895 (krb5_octet *)&time32le);
896 if (kerr) {
897 goto done;
898 }
899
900 ied->last_pwd_change = restime;
901 }
902
903 ret = ipadb_ldap_attr_to_krb5_timestamp(lcontext, lentry,
904 "krbLastAdminUnlock", &restime);
905 if (ret == 0) {
906 krb5_int32 time32le = htole32((krb5_int32)restime)__uint32_identity ((krb5_int32)restime);
907
908 kerr = ipadb_set_tl_data(entry,
909 KRB5_TL_LAST_ADMIN_UNLOCK0x0700,
910 sizeof(time32le),
911 (krb5_octet *)&time32le);
912 if (kerr) {
913 goto done;
914 }
915
916 ied->last_admin_unlock = restime;
917 }
918
919 ret = ipadb_ldap_attr_to_strlist(lcontext, lentry,
920 IPA_KRB_AUTHZ_DATA_ATTR"ipaKrbAuthzData", &authz_data_list);
921 if (ret != 0 && ret != ENOENT2) {
922 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
923 goto done;
924 }
925 if (ret == 0) {
926 ied->authz_data = authz_data_list;
927 }
928
929 ied->user_auth = ua;
930
931 /* If enabled, set the otp user string, enabling otp. */
932 if (ua & IPADB_USER_AUTH_OTP) {
933 kerr = ipadb_set_tl_data(entry, KRB5_TL_STRING_ATTRS0x000b,
934 sizeof(otp_string), otp_string);
935 if (kerr)
936 goto done;
937 } else if (ua & IPADB_USER_AUTH_RADIUS) {
938 kerr = ipadb_set_tl_data(entry, KRB5_TL_STRING_ATTRS0x000b,
939 sizeof(rad_string), rad_string);
940 if (kerr)
941 goto done;
942 }
943
944 if (ua & ~IPADB_USER_AUTH_NONE) {
945 ipadb_parse_authind_policies(kcontext, lcontext, lentry, entry, ua);
946 }
947
948 kerr = 0;
949
950done:
951 if (kerr) {
952 ipadb_free_principal(kcontext, entry);
953 entry = NULL((void*)0);
954 }
955 *kentry = entry;
956 return kerr;
957}
958
959krb5_error_code
960ipadb_fetch_principals_with_extra_filter(struct ipadb_context *ipactx,
961 unsigned int flags,
962 const char *principal,
963 const char *filter,
964 LDAPMessage **result)
965{
966 krb5_error_code kerr;
967 char *src_filter = NULL((void*)0), *esc_original_princ = NULL((void*)0);
968 int ret;
969
970 if (!ipactx->lcontext) {
971 ret = ipadb_get_connection(ipactx);
972 if (ret != 0) {
973 kerr = KRB5_KDB_SERVER_INTERNAL_ERR(-1780008413L);
974 goto done;
975 }
976 }
977
978 /* Escape filter but do not touch '*' as this function accepts
979 * wildcards in names. */
980 esc_original_princ = ipadb_filter_escape(principal, false0);
981 if (!esc_original_princ) {
982 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
983 goto done;
984 }
985
986 /* Starting in DAL 8.0, aliases are always okay. */
987#ifdef KRB5_KDB_FLAG_ALIAS_OK
988 if (!(flags & KRB5_KDB_FLAG_ALIAS_OK)) {
989 if (filter == NULL((void*)0)) {
990 ret = asprintf(&src_filter, PRINC_SEARCH_FILTER"(&(|(objectclass=krbprincipalaux)" "(objectclass=krbprincipal))"
"(krbprincipalname=%s))"
,
991 esc_original_princ);
992 } else {
993 ret = asprintf(&src_filter, PRINC_SEARCH_FILTER_EXTRA"(&(|(objectclass=krbprincipalaux)" "(objectclass=krbprincipal))"
"(krbprincipalname=%s)" "%s)"
,
994 esc_original_princ, filter);
995 }
996 } else
997#endif
998 {
999 if (filter == NULL((void*)0)) {
1000 ret = asprintf(&src_filter, PRINC_TGS_SEARCH_FILTER"(&(|(objectclass=krbprincipalaux)" "(objectclass=krbprincipal)"
"(objectclass=ipakrbprincipal))" "(|(ipakrbprincipalalias=%s)"
"(krbprincipalname:caseIgnoreIA5Match:=%s)))"
,
1001 esc_original_princ, esc_original_princ);
1002 } else {
1003 ret = asprintf(&src_filter, PRINC_TGS_SEARCH_FILTER_EXTRA"(&(|(objectclass=krbprincipalaux)" "(objectclass=krbprincipal)"
"(objectclass=ipakrbprincipal))" "(|(ipakrbprincipalalias=%s)"
"(krbprincipalname:caseIgnoreIA5Match:=%s))" "%s)"
,
1004 esc_original_princ, esc_original_princ, filter);
1005 }
1006 }
1007
1008 if (ret == -1) {
1009 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
1010 goto done;
1011 }
1012
1013 kerr = ipadb_simple_search(ipactx, ipactx->base, LDAP_SCOPE_SUBTREE((ber_int_t) 0x0002),
1014 src_filter, std_principal_attrs, result);
1015done:
1016 free(src_filter);
1017 free(esc_original_princ);
1018 return kerr;
1019}
1020
1021static krb5_error_code ipadb_fetch_principals(struct ipadb_context *ipactx,
1022 unsigned int flags,
1023 char *principal,
1024 LDAPMessage **result)
1025{
1026 return ipadb_fetch_principals_with_extra_filter(ipactx, flags, principal,
1027 NULL((void*)0), result);
1028}
1029
1030krb5_error_code ipadb_find_principal(krb5_context kcontext,
1031 unsigned int flags,
1032 LDAPMessage *res,
1033 char **principal,
1034 LDAPMessage **entry)
1035{
1036 struct ipadb_context *ipactx;
1037 bool_Bool found = false0;
1038 LDAPMessage *le = NULL((void*)0);
1039 struct berval **vals = NULL((void*)0);
1040 int result;
1041 krb5_error_code ret;
1042 size_t princ_len = 0;
1043
1044 ipactx = ipadb_get_context(kcontext);
1045 if (!ipactx) {
1046 ret = KRB5_KDB_DBNOTINITED(-1780008435L);
1047 goto done;
1048 }
1049
1050 princ_len = strlen(*principal);
1051 for (le = ldap_first_entry(ipactx->lcontext, res); le != NULL((void*)0);
1052 le = ldap_next_entry(ipactx->lcontext, le)) {
1053 vals = ldap_get_values_len(ipactx->lcontext, le, "krbprincipalname");
1054 if (vals == NULL((void*)0))
1055 continue;
1056
1057 /* We need to check for a strict match as a '*' in the name may have
1058 * caused the ldap server to return multiple entries. */
1059 for (int i = 0; vals[i]; i++) {
1060#ifdef KRB5_KDB_FLAG_ALIAS_OK
1061 if ((flags & KRB5_KDB_FLAG_ALIAS_OK) == 0) {
1062 found = ((vals[i]->bv_len == princ_len) &&
1063 strncmp(vals[i]->bv_val, *principal, vals[i]->bv_len) == 0);
1064 if (found)
1065 break;
1066
1067 continue;
1068 }
1069#endif
1070
1071 /* The KDC will accept aliases when doing TGT lookup
1072 * (ref_tgt_again in do_tgs_req.c), so use case-insensitive
1073 * comparison. */
1074 if (ulc_casecmp(vals[i]->bv_val, vals[i]->bv_len, *principal,
1075 princ_len, NULL((void*)0), NULL((void*)0), &result) != 0) {
1076 ret = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
1077 goto done;
1078 }
1079 if (result != 0)
1080 continue;
1081
1082 /* Fix case on the incoming principal to ensure that a valid
1083 * name/alias is returned even if krbCanonicalName is not
1084 * present. */
1085 free(*principal);
1086 *principal = strndup(vals[i]->bv_val, vals[i]->bv_len);
1087 if (!*principal) {
1088 ret = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
1089 goto done;
1090 }
1091 princ_len = strlen(*principal);
1092 found = true1;
1093 break;
1094 }
1095
1096 ldap_value_free_len(vals);
1097 vals = NULL((void*)0);
1098 if (!found) {
1099 continue;
1100 }
1101
1102 /* We need to check if this is the canonical name. */
1103 vals = ldap_get_values_len(ipactx->lcontext, le, "krbcanonicalname");
1104 if (vals == NULL((void*)0))
1105 break;
1106
1107#ifdef KRB5_KDB_FLAG_ALIAS_OK
1108 /* If aliases aren't accepted by the KDC, use case-sensitive
1109 * comparison. */
1110 if ((flags & KRB5_KDB_FLAG_ALIAS_OK) == 0) {
1111 found = ((vals[0]->bv_len == strlen(*principal)) &&
1112 strncmp(vals[0]->bv_val, *principal, vals[0]->bv_len) == 0);
1113 if (!found) {
1114 ldap_value_free_len(vals);
1115 vals = NULL((void*)0);
1116 continue;
1117 }
1118 }
1119#endif
1120
1121 free(*principal);
1122 *principal = strndup(vals[0]->bv_val, vals[0]->bv_len);
1123 if (!*principal) {
1124 ret = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
1125 goto done;
1126 }
1127 break;
1128 }
1129
1130 if (!found || !le) {
1131 ret = KRB5_KDB_NOENTRY(-1780008443L);
1132 goto done;
1133 }
1134
1135 ret = 0;
1136 *entry = le;
1137done:
1138 if (vals)
1139 ldap_value_free_len(vals);
1140
1141 return ret;
1142}
1143
1144static krb5_flags maybe_require_preauth(struct ipadb_context *ipactx,
1145 krb5_db_entry *entry)
1146{
1147 const struct ipadb_global_config *config;
1148 struct ipadb_e_data *ied;
1149
1150 config = ipadb_get_global_config(ipactx);
1151 if (config && config->disable_preauth_for_spns) {
1152 ied = (struct ipadb_e_data *)entry->e_data;
1153 if (ied && ied->ipa_user != true1) {
1154 /* not a user, assume SPN */
1155 return 0;
1156 }
1157 }
1158
1159 /* By default require preauth for all principals */
1160 return KRB5_KDB_REQUIRES_PRE_AUTH0x00000080;
1161}
1162
1163static krb5_error_code ipadb_fetch_tktpolicy(krb5_context kcontext,
1164 LDAPMessage *lentry,
1165 krb5_db_entry *entry,
1166 uint32_t polmask)
1167{
1168 struct ipadb_context *ipactx;
1169 krb5_error_code kerr;
1170 char *policy_dn = NULL((void*)0);
1171 LDAPMessage *res = NULL((void*)0);
1172 LDAPMessage *first;
1173 int result;
1174 int ret;
1175
1176 ipactx = ipadb_get_context(kcontext);
1177 if (!ipactx) {
1178 return KRB5_KDB_DBNOTINITED(-1780008435L);
1179 }
1180
1181 ret = ipadb_ldap_attr_to_str(ipactx->lcontext, lentry,
1182 "krbticketpolicyreference", &policy_dn);
1183 switch (ret) {
1184 case 0:
1185 break;
1186 case ENOENT2:
1187 ret = asprintf(&policy_dn, "cn=%s,cn=kerberos,%s",
1188 ipactx->realm, ipactx->base);
1189 if (ret == -1) {
1190 kerr = ENOMEM12;
1191 goto done;
1192 }
1193 break;
1194 default:
1195 kerr = ret;
1196 goto done;
1197 }
1198
1199 kerr = ipadb_simple_search(ipactx,
1200 policy_dn, LDAP_SCOPE_BASE((ber_int_t) 0x0000),
1201 "(objectclass=krbticketpolicyaux)",
1202 std_tktpolicy_attrs,
1203 &res);
1204 if (kerr == 0) {
1205 first = ldap_first_entry(ipactx->lcontext, res);
1206 if (!first) {
1207 kerr = KRB5_KDB_NOENTRY(-1780008443L);
1208 } else {
1209 if (polmask & MAXTKTLIFE_BIT0x02) {
1210 ret = ipadb_ldap_attr_to_int(ipactx->lcontext, first,
1211 "krbmaxticketlife", &result);
1212 if (ret == 0) {
1213 entry->max_life = result;
1214 } else {
1215 entry->max_life = 86400;
1216 }
1217 }
1218 if (polmask & MAXRENEWABLEAGE_BIT0x04) {
1219 ret = ipadb_ldap_attr_to_int(ipactx->lcontext, first,
1220 "krbmaxrenewableage", &result);
1221 if (ret == 0) {
1222 entry->max_renewable_life = result;
1223 } else {
1224 entry->max_renewable_life = 604800;
1225 }
1226 }
1227 if (polmask & TKTFLAGS_BIT0x01) {
1228 ret = ipadb_ldap_attr_to_int(ipactx->lcontext, first,
1229 "krbticketflags", &result);
1230 if (ret == 0) {
1231 entry->attributes |= result;
1232 } else {
1233 entry->attributes |= maybe_require_preauth(ipactx, entry);
1234 }
1235 }
1236 }
1237 }
1238
1239 if (kerr == KRB5_KDB_NOENTRY(-1780008443L)) {
1240 /* No policy at all ??
1241 * set hardcoded default policy for now */
1242 if (polmask & MAXTKTLIFE_BIT0x02) {
1243 entry->max_life = 86400;
1244 }
1245 if (polmask & MAXRENEWABLEAGE_BIT0x04) {
1246 entry->max_renewable_life = 604800;
1247 }
1248 if (polmask & TKTFLAGS_BIT0x01) {
1249 entry->attributes |= maybe_require_preauth(ipactx, entry);
1250 }
1251
1252 kerr = 0;
1253 }
1254
1255done:
1256 ldap_msgfree(res);
1257 free(policy_dn);
1258 return kerr;
1259}
1260
1261static krb5_boolean is_request_for_us(krb5_context kcontext,
1262 krb5_principal local_tgs,
1263 krb5_const_principal search_for)
1264{
1265 krb5_boolean for_us;
1266
1267 for_us = krb5_realm_compare(kcontext, local_tgs, search_for) ||
1268 krb5_principal_compare_any_realm(kcontext,
1269 local_tgs, search_for);
1270 return for_us;
1271}
1272
1273static krb5_error_code dbget_princ(krb5_context kcontext,
1274 struct ipadb_context *ipactx,
1275 krb5_const_principal search_for,
1276 unsigned int flags,
1277 krb5_db_entry **entry)
1278{
1279 krb5_error_code kerr;
1280 char *principal = NULL((void*)0);
1281 LDAPMessage *res = NULL((void*)0);
1282 LDAPMessage *lentry;
1283 uint32_t pol;
1284
1285 /* Unparse without escaping '@' and '/' because we are going to use them
1286 * in LDAP filters where escaping character '\' will be escaped and the
1287 * result will never match. */
1288 kerr = krb5_unparse_name_flags(kcontext, search_for,
1289 KRB5_PRINCIPAL_UNPARSE_DISPLAY0x4, &principal);
1290 if (kerr != 0) {
1291 goto done;
1292 }
1293
1294 kerr = ipadb_fetch_principals(ipactx, flags, principal, &res);
1295 if (kerr != 0) {
1296 goto done;
1297 }
1298
1299 kerr = ipadb_find_principal(kcontext, flags, res, &principal, &lentry);
1300 if (kerr != 0) {
1301 goto done;
1302 }
1303
1304 kerr = ipadb_parse_ldap_entry(kcontext, principal, lentry, entry, &pol);
1305 if (kerr != 0) {
1306 goto done;
1307 }
1308
1309 if (pol) {
1310 kerr = ipadb_fetch_tktpolicy(kcontext, lentry, *entry, pol);
1311 if (kerr != 0) {
1312 goto done;
1313 }
1314 }
1315
1316done:
1317 ldap_msgfree(res);
1318 krb5_free_unparsed_name(kcontext, principal);
1319
1320 return kerr;
1321}
1322
1323static krb5_error_code dbget_alias(krb5_context kcontext,
1324 struct ipadb_context *ipactx,
1325 krb5_const_principal search_for,
1326 unsigned int flags,
1327 krb5_db_entry **entry)
1328{
1329 krb5_error_code kerr = 0;
1330 char *principal = NULL((void*)0);
1331 krb5_principal norm_princ = NULL((void*)0);
1332 char *trusted_realm = NULL((void*)0);
1333 krb5_db_entry *kentry = NULL((void*)0);
1334 krb5_data *realm;
1335
1336 /* TODO: also support hostbased aliases */
1337
1338 /* Enterprise principal name type is for potential aliases or principals
1339 * from trusted realms. The logic below only applies to this type */
1340 if (krb5_princ_type(kcontext, search_for)(search_for)->type != KRB5_NT_ENTERPRISE_PRINCIPAL10) {
1341 return KRB5_KDB_NOENTRY(-1780008443L);
1342 }
1343
1344 /* enterprise principal can only have single component in the name
1345 * according to RFC6806 section 5. */
1346 if (krb5_princ_size(kcontext, search_for)(search_for)->length != 1) {
1347 return KRB5_KDB_NOENTRY(-1780008443L);
1348 }
1349
1350 /* unparse the Kerberos principal without (our) outer realm. */
1351 kerr = krb5_unparse_name_flags(kcontext, search_for,
1352 KRB5_PRINCIPAL_UNPARSE_NO_REALM0x2 |
1353 KRB5_PRINCIPAL_UNPARSE_DISPLAY0x4,
1354 &principal);
1355 if (kerr != 0) {
1356 goto done;
1357 }
1358
1359 /* Re-parse the principal to normalize it. Innner realm becomes
1360 * the realm if present. If no inner realm, our default realm
1361 * will be used instead (as it was before). */
1362 kerr = krb5_parse_name(kcontext, principal, &norm_princ);
1363 if (kerr != 0) {
1364 goto done;
1365 }
1366
1367 if (krb5_realm_compare(kcontext, ipactx->local_tgs, norm_princ)) {
1368 /* In realm alias, try to retrieve it and let the caller handle it. */
1369 kerr = dbget_princ(kcontext, ipactx, norm_princ, flags, entry);
1370 goto done;
1371 }
1372
1373 /* The request is out of realm starting from here */
1374
1375 /*
1376 * Per RFC6806 section 7 and 8, the canonicalize flag is required for
1377 * both client and server referrals. But it is more useful to ignore it
1378 * like Windows KDC does for client referrals.
1379 */
1380 if (((flags & KRB5_KDB_FLAG_CANONICALIZE0x00000010) == 0) &&
1381 ((flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY0x00000040) == 0)) {
1382 kerr = KRB5_KDB_NOENTRY(-1780008443L);
1383 goto done;
1384 }
1385
1386 /* Determine the trusted realm to refer to. We don't need the principal
1387 * itself, only its realm */
1388 realm = krb5_princ_realm(kcontext, norm_princ)(&(norm_princ)->realm);
1389 kerr = ipadb_is_princ_from_trusted_realm(kcontext,
1390 realm->data,
1391 realm->length,
1392 &trusted_realm);
1393 if (kerr == KRB5_KDB_NOENTRY(-1780008443L)) {
1394 /* If no trusted realm found, refresh trusted domain data and try again
1395 * because it might be a freshly added trust to AD */
1396 kerr = ipadb_reinit_mspac(ipactx, false0);
1397 if (kerr != 0) {
1398 kerr = KRB5_KDB_NOENTRY(-1780008443L);
1399 goto done;
1400 }
1401 kerr = ipadb_is_princ_from_trusted_realm(kcontext,
1402 realm->data,
1403 realm->length,
1404 &trusted_realm);
1405 }
1406
1407 if (kerr != 0) {
1408 goto done;
1409 }
1410
1411 /* This is a known trusted realm. Issue a referral depending on whether this
1412 * is client or server referral request */
1413 if (flags & KRB5_KDB_FLAG_CLIENT_REFERRALS_ONLY0x00000040) {
1414 /* client referral out of realm, set next realm. */
1415 kerr = krb5_set_principal_realm(kcontext, norm_princ, trusted_realm);
1416 if (kerr != 0) {
1417 goto done;
1418 }
1419 kentry = calloc(1, sizeof(krb5_db_entry));
1420 if (!kentry) {
1421 kerr = ENOMEM12;
1422 goto done;
1423 }
1424
1425 kentry->princ = norm_princ;
1426 norm_princ = NULL((void*)0);
1427 *entry = kentry;
1428
1429 goto done;
1430 }
1431
1432 if (flags & KRB5_KDB_FLAG_INCLUDE_PAC0x00000020) {
1433 /* TGS request where KDC wants to generate PAC
1434 * but the principal is out of our realm */
1435 kerr = KRB5_KDB_NOENTRY(-1780008443L);
1436 goto done;
1437 }
1438
1439 /* server referrals: lookup krbtgt/next_realm@our_realm */
1440
1441 krb5_free_principal(kcontext, norm_princ);
1442 norm_princ = NULL((void*)0);
1443 kerr = krb5_build_principal_ext(kcontext, &norm_princ,
1444 strlen(ipactx->realm),
1445 ipactx->realm,
1446 KRB5_TGS_NAME_SIZE6,
1447 KRB5_TGS_NAME"krbtgt",
1448 strlen(trusted_realm),
1449 trusted_realm, 0);
1450 if (kerr != 0) {
1451 goto done;
1452 }
1453
1454 kerr = dbget_princ(kcontext, ipactx, norm_princ, flags, entry);
1455
1456done:
1457 free(trusted_realm);
1458 krb5_free_principal(kcontext, norm_princ);
1459 krb5_free_unparsed_name(kcontext, principal);
1460
1461 return kerr;
1462}
1463
1464/* TODO: handle case where main object and krbprincipal data are not
1465 * the same object but linked objects ?
1466 * (by way of krbprincipalaux being in a separate object from krbprincipal).
1467 * Currently we only support objcts with both objectclasses present at the
1468 * same time. */
1469
1470krb5_error_code ipadb_get_principal(krb5_context kcontext,
1471 krb5_const_principal search_for,
1472 unsigned int flags,
1473 krb5_db_entry **entry)
1474{
1475 struct ipadb_context *ipactx;
1476 krb5_error_code kerr;
1477
1478 *entry = NULL((void*)0);
1479
1480 ipactx = ipadb_get_context(kcontext);
1481 if (!ipactx) {
1482 return KRB5_KDB_DBNOTINITED(-1780008435L);
1483 }
1484
1485 if (!is_request_for_us(kcontext, ipactx->local_tgs, search_for)) {
1486 krb5_klog_syslog(LOG_INFO6,
1487 "ipadb_get_principal: requested principal "
1488 "is not for our realm\n");
1489 return KRB5_KDB_NOENTRY(-1780008443L);
1490 }
1491
1492 /* Lookup local names and aliases first. */
1493 kerr = dbget_princ(kcontext, ipactx, search_for, flags, entry);
1494 if (kerr != KRB5_KDB_NOENTRY(-1780008443L)) {
1495 return kerr;
1496 }
1497
1498 return dbget_alias(kcontext, ipactx, search_for, flags, entry);
1499}
1500
1501void ipadb_free_principal_e_data(krb5_context kcontext, krb5_octet *e_data)
1502{
1503 struct ipadb_e_data *ied;
1504 int i;
1505
1506 ied = (struct ipadb_e_data *)e_data;
1507 if (ied->magic == IPA_E_DATA_MAGIC0x0eda7a) {
1508 ldap_memfree(ied->entry_dn);
1509 free(ied->passwd);
1510 free(ied->pw_policy_dn);
1511 for (i = 0; ied->pw_history && ied->pw_history[i]; i++) {
1512 free(ied->pw_history[i]);
1513 }
1514 free(ied->pw_history);
1515 for (i = 0; ied->authz_data && ied->authz_data[i]; i++) {
1516 free(ied->authz_data[i]);
1517 }
1518 free(ied->authz_data);
1519 free(ied->pol);
1520 free(ied);
1521 }
1522}
1523
1524void ipadb_free_principal(krb5_context kcontext, krb5_db_entry *entry)
1525{
1526 krb5_tl_data *prev, *next;
1527
1528 if (entry) {
1529 krb5_free_principal(kcontext, entry->princ);
1530 prev = entry->tl_data;
1531 while(prev) {
1532 next = prev->tl_data_next;
1533 free(prev->tl_data_contents);
1534 free(prev);
1535 prev = next;
1536 }
1537 ipa_krb5_free_key_data(entry->key_data, entry->n_key_data);
1538
1539 if (entry->e_data) {
1540 ipadb_free_principal_e_data(kcontext, entry->e_data);
1541 }
1542
1543 free(entry);
1544 }
1545}
1546
1547static krb5_error_code ipadb_get_tl_data(krb5_db_entry *entry,
1548 krb5_int16 type,
1549 krb5_ui_2 length,
1550 krb5_octet *data)
1551{
1552 krb5_tl_data *td;
1553
1554 for (td = entry->tl_data; td; td = td->tl_data_next) {
1555 if (td->tl_data_type == type) {
1556 break;
1557 }
1558 }
1559 if (!td) {
1560 return ENOENT2;
1561 }
1562
1563 if (td->tl_data_length != length) {
1564 return EINVAL22;
1565 }
1566
1567 memcpy(data, td->tl_data_contents, length);
1568
1569 return 0;
1570}
1571
1572struct ipadb_mods {
1573 LDAPMod **mods;
1574 int alloc_size;
1575 int tip;
1576};
1577
1578static int new_ipadb_mods(struct ipadb_mods **imods)
1579{
1580 struct ipadb_mods *r;
1581
1582 r = malloc(sizeof(struct ipadb_mods));
1583 if (!r) {
1584 return ENOMEM12;
1585 }
1586
1587 /* alloc the average space for a full change of all ldap attrinbutes */
1588 r->alloc_size = 15;
1589 r->mods = calloc(r->alloc_size, sizeof(LDAPMod *));
1590 if (!r->mods) {
1591 free(r);
1592 return ENOMEM12;
1593 }
1594 r->tip = 0;
1595
1596 *imods = r;
1597 return 0;
1598}
1599
1600static void ipadb_mods_free(struct ipadb_mods *imods)
1601{
1602 if (imods == NULL((void*)0)) {
1603 return;
1604 }
1605
1606 ldap_mods_free(imods->mods, 1);
1607 free(imods);
1608}
1609
1610static krb5_error_code ipadb_mods_new(struct ipadb_mods *imods,
1611 LDAPMod **slot)
1612{
1613 LDAPMod **lmods = NULL((void*)0);
1614 LDAPMod *m;
1615 int n;
1616
1617 lmods = imods->mods;
1618 for (n = imods->tip; n < imods->alloc_size && lmods[n] != NULL((void*)0); n++) {
1619 /* find empty slot */ ;
1620 }
1621
1622 if (n + 1 > imods->alloc_size) {
1623 /* need to increase size */
1624 lmods = realloc(imods->mods, (n * 2) * sizeof(LDAPMod *));
1625 if (!lmods) {
1626 return ENOMEM12;
1627 }
1628 imods->mods = lmods;
1629 imods->alloc_size = n * 2;
1630 memset(&lmods[n + 1], 0,
1631 (imods->alloc_size - n - 1) * sizeof(LDAPMod *));
1632 }
1633
1634 m = calloc(1, sizeof(LDAPMod));
1635 if (!m) {
1636 return ENOMEM12;
1637 }
1638 imods->tip = n;
1639 *slot = imods->mods[n] = m;
1640 return 0;
1641}
1642
1643static void ipadb_mods_free_tip(struct ipadb_mods *imods)
1644{
1645 LDAPMod *m;
1646 int i;
1647
1648 if (imods->alloc_size == 0) {
1649 return;
1650 }
1651
1652 m = imods->mods[imods->tip];
1653
1654 if (!m) {
1655 return;
1656 }
1657
1658 free(m->mod_type);
1659 if (m->mod_valuesmod_vals.modv_strvals) {
1660 for (i = 0; m->mod_valuesmod_vals.modv_strvals[i]; i++) {
1661 free(m->mod_valuesmod_vals.modv_strvals[i]);
1662 }
1663 }
1664 free(m->mod_valuesmod_vals.modv_strvals);
1665 free(m);
1666
1667 imods->mods[imods->tip] = NULL((void*)0);
1668 imods->tip--;
1669}
1670
1671static krb5_error_code ipadb_get_ldap_mod_str(struct ipadb_mods *imods,
1672 char *attribute, char *value,
1673 int mod_op)
1674{
1675 krb5_error_code kerr;
1676 LDAPMod *m = NULL((void*)0);
1677
1678 kerr = ipadb_mods_new(imods, &m);
1679 if (kerr) {
1680 return kerr;
1681 }
1682
1683 m->mod_op = mod_op;
1684 m->mod_type = strdup(attribute);
1685 if (!m->mod_type) {
1686 kerr = ENOMEM12;
1687 goto done;
1688 }
1689 m->mod_valuesmod_vals.modv_strvals = calloc(2, sizeof(char *));
1690 if (!m->mod_valuesmod_vals.modv_strvals) {
1691 kerr = ENOMEM12;
1692 goto done;
1693 }
1694 m->mod_valuesmod_vals.modv_strvals[0] = strdup(value);
1695 if (!m->mod_valuesmod_vals.modv_strvals[0]) {
1696 kerr = ENOMEM12;
1697 goto done;
1698 }
1699
1700 kerr = 0;
1701
1702done:
1703 if (kerr) {
1704 ipadb_mods_free_tip(imods);
1705 }
1706 return kerr;
1707}
1708
1709static krb5_error_code ipadb_get_ldap_mod_int(struct ipadb_mods *imods,
1710 char *attribute, int value,
1711 int mod_op)
1712{
1713 krb5_error_code kerr;
1714 char *v = NULL((void*)0);
1715 int ret;
1716
1717 ret = asprintf(&v, "%d", value);
1718 if (ret == -1) {
1719 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
1720 goto done;
1721 }
1722
1723 kerr = ipadb_get_ldap_mod_str(imods, attribute, v, mod_op);
1724
1725done:
1726 free(v);
1727 return kerr;
1728}
1729
1730static krb5_error_code ipadb_get_ldap_mod_time(struct ipadb_mods *imods,
1731 char *attribute,
1732 krb5_timestamp value,
1733 int mod_op)
1734{
1735 struct tm date, *t;
1736 time_t timeval;
1737 char v[20];
1738
1739 timeval = (time_t)value;
1740 t = gmtime_r(&timeval, &date);
1741 if (t == NULL((void*)0)) {
1742 return EINVAL22;
1743 }
1744
1745 strftime(v, 20, "%Y%m%d%H%M%SZ", &date);
1746
1747 return ipadb_get_ldap_mod_str(imods, attribute, v, mod_op);
1748}
1749
1750static krb5_error_code ipadb_get_ldap_mod_bvalues(struct ipadb_mods *imods,
1751 char *attribute,
1752 struct berval **values,
1753 int num_values,
1754 int mod_op)
1755{
1756 krb5_error_code kerr;
1757 LDAPMod *m = NULL((void*)0);
1758 int i;
1759
1760 if (values == NULL((void*)0) || values[0] == NULL((void*)0) || num_values <= 0) {
1761 return EINVAL22;
1762 }
1763
1764 kerr = ipadb_mods_new(imods, &m);
1765 if (kerr) {
1766 return kerr;
1767 }
1768
1769 m->mod_op = mod_op | LDAP_MOD_BVALUES(0x0080);
1770 m->mod_type = strdup(attribute);
1771 if (!m->mod_type) {
1772 kerr = ENOMEM12;
1773 goto done;
1774 }
1775 m->mod_bvaluesmod_vals.modv_bvals = calloc(num_values + 1, sizeof(struct berval *));
1776 if (!m->mod_bvaluesmod_vals.modv_bvals) {
1777 kerr = ENOMEM12;
1778 goto done;
1779 }
1780
1781 for (i = 0; i < num_values; i++) {
1782 m->mod_bvaluesmod_vals.modv_bvals[i] = values[i];
1783 }
1784
1785 kerr = 0;
1786
1787done:
1788 if (kerr) {
1789 /* we need to free bvalues manually here otherwise
1790 * ipadb_mods_free_tip will free contents which we
1791 * did not allocate here */
1792 free(m->mod_bvaluesmod_vals.modv_bvals);
1793 m->mod_bvaluesmod_vals.modv_bvals = NULL((void*)0);
1794 ipadb_mods_free_tip(imods);
1795 }
1796 return kerr;
1797}
1798
1799static krb5_error_code ipadb_get_ldap_mod_extra_data(struct ipadb_mods *imods,
1800 krb5_tl_data *tl_data,
1801 int mod_op)
1802{
1803 krb5_error_code kerr;
1804 krb5_tl_data *data;
1805 struct berval **bvs = NULL((void*)0);
1806 krb5_int16 be_type;
1807 int n, i;
1808
1809 for (n = 0, data = tl_data; data; data = data->tl_data_next) {
1810 if (data->tl_data_type == KRB5_TL_LAST_PWD_CHANGE0x0001 ||
1811 data->tl_data_type == KRB5_TL_KADM_DATA0x0003 ||
1812 data->tl_data_type == KRB5_TL_DB_ARGS0x7fff ||
1813 data->tl_data_type == KRB5_TL_MKVNO0x0008 ||
1814 data->tl_data_type == KRB5_TL_LAST_ADMIN_UNLOCK0x0700) {
1815 continue;
1816 }
1817 n++;
1818 }
1819
1820 if (n == 0) {
1821 return ENOENT2;
1822 }
1823
1824 bvs = calloc(n + 1, sizeof(struct berval *));
1825 if (!bvs) {
1826 kerr = ENOMEM12;
1827 goto done;
1828 }
1829
1830 for (i = 0, data = tl_data; data; data = data->tl_data_next) {
1831
1832 if (data->tl_data_type == KRB5_TL_LAST_PWD_CHANGE0x0001 ||
1833 data->tl_data_type == KRB5_TL_KADM_DATA0x0003 ||
1834 data->tl_data_type == KRB5_TL_DB_ARGS0x7fff ||
1835 data->tl_data_type == KRB5_TL_MKVNO0x0008 ||
1836 data->tl_data_type == KRB5_TL_LAST_ADMIN_UNLOCK0x0700) {
1837 continue;
1838 }
1839
1840 be_type = htons(data->tl_data_type);
1841
1842 bvs[i] = calloc(1, sizeof(struct berval));
1843 if (!bvs[i]) {
1844 kerr = ENOMEM12;
1845 goto done;
1846 }
1847
1848 bvs[i]->bv_len = data->tl_data_length + 2;
1849 bvs[i]->bv_val = malloc(bvs[i]->bv_len);
1850 if (!bvs[i]->bv_val) {
1851 kerr = ENOMEM12;
1852 goto done;
1853 }
1854 memcpy(bvs[i]->bv_val, &be_type, 2);
1855 memcpy(&(bvs[i]->bv_val[2]), data->tl_data_contents, data->tl_data_length);
1856
1857 i++;
1858
1859 if (i > n) {
1860 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
1861 goto done;
1862 }
1863 }
1864
1865 kerr = ipadb_get_ldap_mod_bvalues(imods, "krbExtraData", bvs, i, mod_op);
1866
1867done:
1868 if (kerr) {
1869 for (i = 0; bvs && bvs[i]; i++) {
1870 free(bvs[i]->bv_val);
1871 free(bvs[i]);
1872 }
1873 }
1874 free(bvs);
1875 return kerr;
1876}
1877
1878static krb5_error_code ipadb_get_mkvno_from_tl_data(krb5_tl_data *tl_data,
1879 int *mkvno)
1880{
1881 krb5_tl_data *data;
1882 int master_kvno = 0;
1883 krb5_int16 tmp;
1884
1885 for (data = tl_data; data; data = data->tl_data_next) {
1886
1887 if (data->tl_data_type != KRB5_TL_MKVNO0x0008) {
1888 continue;
1889 }
1890
1891 if (data->tl_data_length != 2) {
1892 return KRB5_KDB_TRUNCATED_RECORD(-1780008439L);
1893 }
1894
1895 memcpy(&tmp, data->tl_data_contents, 2);
1896 master_kvno = le16toh(tmp)__uint16_identity (tmp);
1897
1898 break;
1899 }
1900
1901 if (master_kvno == 0) {
1902 /* fall back to std mkvno of 1 */
1903 *mkvno = 1;
1904 } else {
1905 *mkvno = master_kvno;
1906 }
1907
1908 return 0;
1909}
1910
1911static krb5_error_code ipadb_get_ldap_mod_key_data(struct ipadb_mods *imods,
1912 krb5_key_data *key_data,
1913 int n_key_data, int mkvno,
1914 int mod_op)
1915{
1916 krb5_error_code kerr;
1917 struct berval *bval = NULL((void*)0);
1918 LDAPMod *mod;
1919 int ret;
1920
1921 /* If the key data is empty, remove all keys. */
1922 if (n_key_data == 0 || key_data == NULL((void*)0)) {
1923 kerr = ipadb_mods_new(imods, &mod);
1924 if (kerr != 0)
1925 return kerr;
1926
1927 mod->mod_op = LDAP_MOD_DELETE(0x0001);
1928 mod->mod_bvaluesmod_vals.modv_bvals = NULL((void*)0);
1929 mod->mod_type = strdup("krbPrincipalKey");
1930 if (mod->mod_type == NULL((void*)0)) {
1931 ipadb_mods_free_tip(imods);
1932 return ENOMEM12;
1933 }
1934
1935 return 0;
1936 }
1937
1938 ret = ber_encode_krb5_key_data(key_data, n_key_data, mkvno, &bval);
1939 if (ret != 0) {
1940 kerr = ret;
1941 goto done;
1942 }
1943
1944 kerr = ipadb_get_ldap_mod_bvalues(imods, "krbPrincipalKey",
1945 &bval, 1, mod_op);
1946
1947done:
1948 if (kerr) {
1949 ber_bvfree(bval);
1950 }
1951 return kerr;
1952}
1953
1954static krb5_error_code ipadb_get_ldap_mod_str_list(struct ipadb_mods *imods,
1955 char *attrname,
1956 char **strlist, int len,
1957 int mod_op)
1958{
1959 krb5_error_code kerr;
1960 struct berval **bvs = NULL((void*)0);
1961 int i;
1962
1963 bvs = calloc(len + 1, sizeof(struct berval *));
1964 if (!bvs) {
1965 kerr = ENOMEM12;
1966 goto done;
1967 }
1968
1969 for (i = 0; i < len; i++) {
1970 bvs[i] = calloc(1, sizeof(struct berval));
1971 if (!bvs[i]) {
1972 kerr = ENOMEM12;
1973 goto done;
1974 }
1975
1976 bvs[i]->bv_val = strdup(strlist[i]);
1977 if (!bvs[i]->bv_val) {
1978 kerr = ENOMEM12;
1979 goto done;
1980 }
1981 bvs[i]->bv_len = strlen(strlist[i]) + 1;
1982 }
1983
1984 kerr = ipadb_get_ldap_mod_bvalues(imods, attrname, bvs, len, mod_op);
1985
1986done:
1987 if (kerr) {
1988 for (i = 0; bvs && bvs[i]; i++) {
1989 free(bvs[i]->bv_val);
1990 free(bvs[i]);
1991 }
1992 }
1993 free(bvs);
1994 return kerr;
1995}
1996
1997static krb5_error_code ipadb_principal_to_mods(krb5_context kcontext,
1998 struct ipadb_mods *imods,
1999 char *principal,
2000 int mod_op)
2001{
2002 krb5_error_code kerr;
2003
2004 if (principal == NULL((void*)0)) {
2005 kerr = EINVAL22;
2006 goto done;
2007 }
2008
2009 kerr = ipadb_get_ldap_mod_str(imods, "krbPrincipalName",
2010 principal, mod_op);
2011 if (kerr) {
2012 goto done;
2013 }
2014 kerr = ipadb_get_ldap_mod_str(imods, "krbCanonicalName",
2015 principal, mod_op);
2016 if (kerr) {
2017 goto done;
2018 }
2019
2020 kerr = 0;
2021
2022done:
2023 return kerr;
2024}
2025
2026static krb5_error_code ipadb_get_ldap_mod_auth_ind(krb5_context kcontext,
2027 struct ipadb_mods *imods,
2028 krb5_db_entry *entry,
2029 int mod_op)
2030{
2031 krb5_error_code ret = 0;
2032 char **strlist = NULL((void*)0);
2033 char *ais = NULL((void*)0);
2034 char *ai = NULL((void*)0);
2035 char *s = NULL((void*)0);
2036 size_t ai_size = 0;
2037 int cnt = 0;
2038 int i = 0;
2039
2040 ret = krb5_dbe_get_string(kcontext, entry, "require_auth", &ais);
2041 if (ret) {
2042 return ret;
2043 }
2044 if (ais == NULL((void*)0)) {
2045 return 0;
2046 }
2047
2048 ai_size = strlen(ais) + 1;
2049
2050 for (i = 0; i < ai_size; i++) {
2051 if (ais[i] != ' ') {
2052 continue;
2053 }
2054 if (i > 0 && ais[i - 1] != ' ') {
2055 cnt++;
2056 }
2057 }
2058
2059 strlist = calloc(cnt + 2, sizeof(*strlist));
2060 if (strlist == NULL((void*)0)) {
2061 free(ais);
2062 return errno(*__errno_location ());
2063 }
2064
2065 cnt = 0;
2066 ai = strtok_r(ais, " ", &s);
2067 while (ai != NULL((void*)0)) {
2068 if (ai[0] != '\0') {
2069 strlist[cnt++] = ai;
2070 }
2071 ai = strtok_r(NULL((void*)0), " ", &s);
2072 }
2073
2074 ret = ipadb_get_ldap_mod_str_list(imods, "krbPrincipalAuthInd",
2075 strlist, cnt, mod_op);
2076
2077 free(ais);
2078 free(strlist);
2079 return ret;
2080}
2081
2082static krb5_error_code ipadb_entry_to_mods(krb5_context kcontext,
2083 struct ipadb_mods *imods,
2084 krb5_db_entry *entry,
2085 int mod_op)
2086{
2087 krb5_error_code kerr;
2088 krb5_int32 time32le;
2089 int mkvno;
2090 char *req_auth_str = NULL((void*)0);
2091
2092 /* check each mask flag in order */
2093
2094 /* KADM5_PRINC_EXPIRE_TIME */
2095 if (entry->mask & KMASK_PRINC_EXPIRE_TIME0x000002) {
2096 kerr = ipadb_get_ldap_mod_time(imods,
2097 "krbPrincipalExpiration",
2098 entry->expiration,
2099 mod_op);
2100 if (kerr) {
2101 goto done;
2102 }
2103 }
2104
2105 /* KADM5_PW_EXPIRATION */
2106 if (entry->mask & KMASK_PW_EXPIRATION0x000004) {
2107 kerr = ipadb_get_ldap_mod_time(imods,
2108 "krbPasswordExpiration",
2109 entry->pw_expiration,
2110 mod_op);
2111 if (entry->pw_expiration == 0) {
2112 kerr = ipadb_get_ldap_mod_time(imods,
2113 "krbPasswordExpiration",
2114 entry->pw_expiration, LDAP_MOD_DELETE(0x0001));
2115 }
2116 if (kerr) {
2117 goto done;
2118 }
2119 }
2120
2121 /* KADM5_LAST_PWD_CHANGE */
2122 /* apparently, at least some versions of kadmin fail to set this flag
2123 * when they do include a pwd change timestamp in TL_DATA.
2124 * So for now check if KADM5_KEY_DATA has been set, which kadm5
2125 * always does on password changes */
2126#if KADM5_ACTUALLY_SETS_LAST_PWD_CHANGE
2127 if (entry->mask & KMASK_LAST_PWD_CHANGE0x000008) {
2128 if (!entry->n_tl_data) {
2129 kerr = EINVAL22;
2130 goto done;
2131 }
2132
2133#else
2134 if (entry->n_tl_data &&
2135 entry->mask & KMASK_KEY_DATA0x020000) {
2136#endif
2137 kerr = ipadb_get_tl_data(entry,
2138 KRB5_TL_LAST_PWD_CHANGE0x0001,
2139 sizeof(time32le),
2140 (krb5_octet *)&time32le);
2141 if (kerr && kerr != ENOENT2) {
2142 goto done;
2143 }
2144 if (kerr == 0) {
2145 kerr = ipadb_get_ldap_mod_time(imods,
2146 "krbLastPwdChange",
2147 le32toh(time32le)__uint32_identity (time32le),
2148 mod_op);
2149 if (kerr) {
2150 goto done;
2151 }
2152 }
2153 }
2154
2155 /* KADM5_ATTRIBUTES */
2156 if (entry->mask & KMASK_ATTRIBUTES0x000010) {
2157 /* if the object does not have the krbTicketPolicyAux class
2158 * we need to add it or this will fail, only for modifications.
2159 * We always add this objectclass by default when doing an add
2160 * from scratch. */
2161 if ((mod_op == LDAP_MOD_REPLACE(0x0002)) && entry->e_data) {
2162 struct ipadb_e_data *ied;
2163
2164 ied = (struct ipadb_e_data *)entry->e_data;
2165 if (ied->magic != IPA_E_DATA_MAGIC0x0eda7a) {
2166 kerr = EINVAL22;
2167 goto done;
2168 }
2169
2170 if (!ied->has_tktpolaux) {
2171 kerr = ipadb_get_ldap_mod_str(imods, "objectclass",
2172 "krbTicketPolicyAux",
2173 LDAP_MOD_ADD(0x0000));
2174 if (kerr) {
2175 goto done;
2176 }
2177 }
2178 }
2179
2180 kerr = ipadb_get_ldap_mod_int(imods,
2181 "krbTicketFlags",
2182 (int)entry->attributes,
2183 mod_op);
2184 if (kerr) {
2185 goto done;
2186 }
2187 }
2188
2189 /* KADM5_MAX_LIFE */
2190 if (entry->mask & KMASK_MAX_LIFE0x000020) {
2191 kerr = ipadb_get_ldap_mod_int(imods,
2192 "krbMaxTicketLife",
2193 (int)entry->max_life,
2194 mod_op);
2195 if (kerr) {
2196 goto done;
2197 }
2198 }
2199
2200 /* KADM5_MOD_TIME */
2201 /* KADM5_MOD_NAME */
2202 /* KADM5_KVNO */
2203 /* KADM5_MKVNO */
2204 /* KADM5_AUX_ATTRIBUTES */
2205 /* KADM5_POLICY */
2206 /* KADM5_POLICY_CLR */
2207
2208 /* version 2 masks */
2209 /* KADM5_MAX_RLIFE */
2210 if (entry->mask & KMASK_MAX_RLIFE0x002000) {
2211 kerr = ipadb_get_ldap_mod_int(imods,
2212 "krbMaxRenewableAge",
2213 (int)entry->max_renewable_life,
2214 mod_op);
2215 if (kerr) {
2216 goto done;
2217 }
2218 }
2219
2220 /* KADM5_LAST_SUCCESS */
2221 if (entry->mask & KMASK_LAST_SUCCESS0x004000) {
2222 kerr = ipadb_get_ldap_mod_time(imods,
2223 "krbLastSuccessfulAuth",
2224 entry->last_success,
2225 mod_op);
2226 if (kerr) {
2227 goto done;
2228 }
2229 }
2230
2231 /* KADM5_LAST_FAILED */
2232 if (entry->mask & KMASK_LAST_FAILED0x008000) {
2233 kerr = ipadb_get_ldap_mod_time(imods,
2234 "krbLastFailedAuth",
2235 entry->last_failed,
2236 mod_op);
2237 if (kerr) {
2238 goto done;
2239 }
2240 }
2241
2242 /* KADM5_FAIL_AUTH_COUNT */
2243 if (entry->mask & KMASK_FAIL_AUTH_COUNT0x010000) {
2244 kerr = ipadb_get_ldap_mod_int(imods,
2245 "krbLoginFailedCount",
2246 (int)entry->fail_auth_count,
2247 mod_op);
2248 if (kerr) {
2249 goto done;
2250 }
2251 }
2252
2253 /* KADM5_KEY_DATA */
2254 if (entry->mask & KMASK_KEY_DATA0x020000) {
2255 /* TODO: password changes should go via change_pwd
2256 * then we can get clear text and set all needed
2257 * LDAP attributes */
2258
2259 kerr = ipadb_get_mkvno_from_tl_data(entry->tl_data, &mkvno);
2260 if (kerr) {
2261 goto done;
2262 }
2263
2264 kerr = ipadb_get_ldap_mod_key_data(imods,
2265 entry->key_data,
2266 entry->n_key_data,
2267 mkvno,
2268 mod_op);
2269 if (kerr) {
2270 goto done;
2271 }
2272 }
2273
2274 kerr = ipadb_get_ldap_mod_auth_ind(kcontext, imods, entry, mod_op);
2275 if (kerr)
2276 goto done;
2277
2278 /* KADM5_TL_DATA */
2279 if (entry->mask & KMASK_TL_DATA0x040000) {
2280 kerr = ipadb_get_tl_data(entry,
2281 KRB5_TL_LAST_ADMIN_UNLOCK0x0700,
2282 sizeof(time32le),
2283 (krb5_octet *)&time32le);
2284 if (kerr && kerr != ENOENT2) {
2285 goto done;
2286 }
2287 if (kerr == 0) {
2288 kerr = ipadb_get_ldap_mod_time(imods,
2289 "krbLastAdminUnlock",
2290 le32toh(time32le)__uint32_identity (time32le),
2291 mod_op);
2292 if (kerr) {
2293 goto done;
2294 }
2295 }
2296
2297 kerr = krb5_dbe_get_string(kcontext, entry, "require_auth",
2298 &req_auth_str);
2299 if (kerr) {
2300 goto done;
2301 }
2302
2303 /* Do not store auth indicators from the string attribute in
2304 * krbExtraData. Remove require_auth value from the entry temporarily. */
2305 if (req_auth_str != NULL((void*)0)) {
2306 kerr = krb5_dbe_set_string(kcontext, entry, "require_auth", NULL((void*)0));
2307 if (kerr) {
2308 goto done;
2309 }
2310 }
2311
2312 kerr = ipadb_get_ldap_mod_extra_data(imods,
2313 entry->tl_data,
2314 mod_op);
2315 if (kerr && kerr != ENOENT2) {
2316 goto done;
2317 }
2318
2319 /* Restore require_auth value */
2320 if (req_auth_str != NULL((void*)0)) {
2321 kerr = krb5_dbe_set_string(kcontext, entry, "require_auth",
2322 req_auth_str);
2323 if (kerr) {
2324 goto done;
2325 }
2326 }
2327 }
2328
2329 /* KADM5_LOAD */
2330
2331 /* Handle password change related operations. */
2332 if (entry->e_data) {
2333 struct ipadb_e_data *ied;
2334 time_t now = time(NULL((void*)0));
2335 time_t expire_time;
2336 char **new_history;
2337 int nh_len;
2338 int ret;
2339 int i;
2340
2341 ied = (struct ipadb_e_data *)entry->e_data;
2342 if (ied->magic != IPA_E_DATA_MAGIC0x0eda7a) {
2343 kerr = EINVAL22;
2344 goto done;
2345 }
2346
2347 /*
2348 * We need to set userPassword and history only if this is
2349 * a IPA User, we don't do that for simple service principals
2350 */
2351 if (ied->ipa_user && ied->passwd) {
2352 kerr = ipadb_get_ldap_mod_str(imods, "userPassword",
2353 ied->passwd, mod_op);
2354 if (kerr) {
2355 goto done;
2356 }
2357
2358 /* Also set new password expiration time.
2359 * Have to do it here because kadmin doesn't know policies and
2360 * resets entry->mask after we have gone through the password
2361 * change code. */
2362 kerr = ipadb_get_pwd_expiration(kcontext, entry,
2363 ied, &expire_time);
2364 if (kerr) {
2365 goto done;
2366 }
2367
2368 kerr = ipadb_get_ldap_mod_time(imods,
2369 "krbPasswordExpiration",
2370 expire_time, mod_op);
2371 if (expire_time == 0) {
2372 kerr = ipadb_get_ldap_mod_time(imods,
2373 "krbPasswordExpiration",
2374 expire_time, LDAP_MOD_DELETE(0x0001));
2375 }
2376
2377 if (kerr) {
2378 goto done;
2379 }
2380 }
2381
2382 if (ied->ipa_user && ied->passwd &&
2383 ied->pol && ied->pol->history_length) {
2384 ret = ipapwd_generate_new_history(ied->passwd, now,
2385 ied->pol->history_length,
2386 ied->pw_history,
2387 &new_history, &nh_len);
2388 if (ret) {
2389 kerr = ret;
2390 goto done;
2391 }
2392
2393 kerr = ipadb_get_ldap_mod_str_list(imods, "passwordHistory",
2394 new_history, nh_len, mod_op);
2395
2396 for (i = 0; i < nh_len; i++) {
2397 free(new_history[i]);
2398 }
2399 free(new_history);
2400
2401 if (kerr) {
2402 goto done;
2403 }
2404 }
2405 }
2406
2407 kerr = 0;
2408
2409done:
2410 free(req_auth_str);
2411 return kerr;
2412}
2413
2414/* adds default objectclasses and attributes */
2415static krb5_error_code ipadb_entry_default_attrs(struct ipadb_mods *imods)
2416{
2417 krb5_error_code kerr;
2418 LDAPMod *m = NULL((void*)0);
2419 int i;
2420
2421 kerr = ipadb_mods_new(imods, &m);
2422 if (kerr) {
2423 return kerr;
2424 }
2425
2426 m->mod_op = LDAP_MOD_ADD(0x0000);
2427 m->mod_type = strdup("objectClass");
2428 if (!m->mod_type) {
2429 kerr = ENOMEM12;
2430 goto done;
2431 }
2432 m->mod_valuesmod_vals.modv_strvals = calloc(STD_PRINCIPAL_OBJ_CLASSES_SIZE(sizeof(std_principal_obj_classes) / sizeof(char *) - 1) + 1, sizeof(char *));
2433 if (!m->mod_valuesmod_vals.modv_strvals) {
2434 kerr = ENOMEM12;
2435 goto done;
2436 }
2437 for (i = 0; i < STD_PRINCIPAL_OBJ_CLASSES_SIZE(sizeof(std_principal_obj_classes) / sizeof(char *) - 1); i++) {
2438 m->mod_valuesmod_vals.modv_strvals[i] = strdup(std_principal_obj_classes[i]);
2439 if (!m->mod_valuesmod_vals.modv_strvals[i]) {
2440 kerr = ENOMEM12;
2441 goto done;
2442 }
2443 }
2444
2445 kerr = 0;
2446
2447done:
2448 if (kerr) {
2449 ipadb_mods_free_tip(imods);
2450 }
2451 return kerr;
2452}
2453
2454static krb5_error_code ipadb_add_principal(krb5_context kcontext,
2455 krb5_db_entry *entry)
2456{
2457 struct ipadb_context *ipactx;
2458 krb5_error_code kerr;
2459 char *principal = NULL((void*)0);
2460 struct ipadb_mods *imods = NULL((void*)0);
2461 char *dn = NULL((void*)0);
2462 int ret;
2463
2464 ipactx = ipadb_get_context(kcontext);
2465 if (!ipactx) {
2466 kerr = KRB5_KDB_DBNOTINITED(-1780008435L);
2467 goto done;
2468 }
2469
2470 if (!ipactx->override_restrictions) {
2471 return KRB5_KDB_CONSTRAINT_VIOLATION(-1780008410L);
2472 }
2473
2474 kerr = krb5_unparse_name(kcontext, entry->princ, &principal);
2475 if (kerr != 0) {
2476 goto done;
2477 }
2478
2479 ret = asprintf(&dn, "krbPrincipalName=%s,cn=%s,cn=kerberos,%s",
2480 principal, ipactx->realm, ipactx->base);
2481 if (ret == -1) {
2482 kerr = ENOMEM12;
2483 goto done;
2484 }
2485
2486 ret = new_ipadb_mods(&imods);
2487 if (ret != 0) {
2488 kerr = ret;
2489 goto done;
2490 }
2491
2492 kerr = ipadb_entry_default_attrs(imods);
2493 if (kerr != 0) {
2494 goto done;
2495 }
2496
2497 kerr = ipadb_principal_to_mods(kcontext, imods, principal, LDAP_MOD_ADD(0x0000));
2498 if (kerr != 0) {
2499 goto done;
2500 }
2501
2502 kerr = ipadb_entry_to_mods(kcontext, imods, entry, LDAP_MOD_ADD(0x0000));
2503 if (kerr != 0) {
2504 goto done;
2505 }
2506
2507 kerr = ipadb_simple_add(ipactx, dn, imods->mods);
2508
2509done:
2510 ipadb_mods_free(imods);
2511 krb5_free_unparsed_name(kcontext, principal);
2512 ldap_memfree(dn);
2513 return kerr;
2514}
2515
2516static krb5_error_code ipadb_modify_principal(krb5_context kcontext,
2517 krb5_db_entry *entry)
2518{
2519 struct ipadb_context *ipactx;
2520 krb5_error_code kerr;
2521 char *principal = NULL((void*)0);
2522 LDAPMessage *res = NULL((void*)0);
2523 LDAPMessage *lentry;
2524 struct ipadb_mods *imods = NULL((void*)0);
2525 char *dn = NULL((void*)0);
2526 struct ipadb_e_data *ied;
2527
2528 ipactx = ipadb_get_context(kcontext);
2529 if (!ipactx) {
2530 return KRB5_KDB_DBNOTINITED(-1780008435L);
2531 }
2532
2533 kerr = new_ipadb_mods(&imods);
2534 if (kerr) {
2535 goto done;
2536 }
2537
2538 ied = (struct ipadb_e_data *)entry->e_data;
2539 if (!ied || !ied->entry_dn) {
2540 kerr = krb5_unparse_name(kcontext, entry->princ, &principal);
2541 if (kerr != 0) {
2542 goto done;
2543 }
2544
2545 kerr = ipadb_fetch_principals(ipactx, 0, principal, &res);
2546 if (kerr != 0) {
2547 goto done;
2548 }
2549
2550 /* FIXME: no alias allowed for now, should we allow modifies
2551 * by alias name ? */
2552 kerr = ipadb_find_principal(kcontext, 0, res, &principal, &lentry);
2553 if (kerr != 0) {
2554 goto done;
2555 }
2556
2557 dn = ldap_get_dn(ipactx->lcontext, lentry);
2558 if (!dn) {
2559 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
2560 goto done;
2561 }
2562
2563 kerr = ipadb_principal_to_mods(kcontext, imods, principal,
2564 LDAP_MOD_REPLACE(0x0002));
2565 if (kerr != 0) {
2566 goto done;
2567 }
2568
2569 }
2570
2571 kerr = ipadb_entry_to_mods(kcontext, imods, entry, LDAP_MOD_REPLACE(0x0002));
2572 if (kerr != 0) {
2573 goto done;
2574 }
2575
2576 if (!ied || !ied->entry_dn) {
2577 kerr = ipadb_simple_modify(ipactx, dn, imods->mods);
2578 } else {
2579 kerr = ipadb_simple_modify(ipactx, ied->entry_dn, imods->mods);
2580 }
2581
2582done:
2583 ipadb_mods_free(imods);
2584 ldap_msgfree(res);
2585 krb5_free_unparsed_name(kcontext, principal);
2586 ldap_memfree(dn);
2587 return kerr;
2588}
2589
2590krb5_error_code ipadb_put_principal(krb5_context kcontext,
2591 krb5_db_entry *entry,
2592 char **db_args)
2593{
2594 if (entry->mask & KMASK_PRINCIPAL0x000001) {
2595 return ipadb_add_principal(kcontext, entry);
2596 } else {
2597 return ipadb_modify_principal(kcontext, entry);
2598 }
2599}
2600
2601static krb5_error_code ipadb_delete_entry(krb5_context kcontext,
2602 LDAPMessage *lentry)
2603{
2604 struct ipadb_context *ipactx;
2605 krb5_error_code kerr;
2606 char *dn = NULL((void*)0);
2607 int ret;
2608
2609 ipactx = ipadb_get_context(kcontext);
2610 if (!ipactx) {
2611 kerr = KRB5_KDB_DBNOTINITED(-1780008435L);
2612 goto done;
2613 }
2614
2615 if (!ipactx->lcontext) {
2616 ret = ipadb_get_connection(ipactx);
2617 if (ret != 0) {
2618 kerr = KRB5_KDB_SERVER_INTERNAL_ERR(-1780008413L);
2619 goto done;
2620 }
2621 }
2622
2623 dn = ldap_get_dn(ipactx->lcontext, lentry);
2624 if (!dn) {
2625 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
2626 goto done;
2627 }
2628
2629 kerr = ipadb_simple_delete(ipactx, dn);
2630
2631done:
2632 ldap_memfree(dn);
2633 return kerr;
2634}
2635
2636static krb5_error_code ipadb_delete_alias(krb5_context kcontext,
2637 LDAPMessage *lentry,
2638 char *principal)
2639{
2640 struct ipadb_context *ipactx;
2641 krb5_error_code kerr;
2642 char *dn = NULL((void*)0);
2643 int ret;
2644
2645 ipactx = ipadb_get_context(kcontext);
2646 if (!ipactx) {
2647 kerr = KRB5_KDB_DBNOTINITED(-1780008435L);
2648 goto done;
2649 }
2650
2651 if (!ipactx->lcontext) {
2652 ret = ipadb_get_connection(ipactx);
2653 if (ret != 0) {
2654 kerr = KRB5_KDB_SERVER_INTERNAL_ERR(-1780008413L);
2655 goto done;
2656 }
2657 }
2658
2659 dn = ldap_get_dn(ipactx->lcontext, lentry);
2660 if (!dn) {
2661 kerr = KRB5_KDB_INTERNAL_ERROR(-1780008411L);
2662 goto done;
2663 }
2664
2665 kerr = ipadb_simple_delete_val(ipactx, dn, "krbprincipalname", principal);
2666
2667done:
2668 ldap_memfree(dn);
2669 return kerr;
2670}
2671
2672krb5_error_code ipadb_delete_principal(krb5_context kcontext,
2673 krb5_const_principal search_for)
2674{
2675 struct ipadb_context *ipactx;
2676 krb5_error_code kerr;
2677 char *principal = NULL((void*)0);
2678 char *canonicalized = NULL((void*)0);
2679 LDAPMessage *res = NULL((void*)0);
2680 LDAPMessage *lentry;
2681 unsigned int flags = 0;
2682
2683 ipactx = ipadb_get_context(kcontext);
2684 if (!ipactx) {
2685 return KRB5_KDB_DBNOTINITED(-1780008435L);
2686 }
2687
2688 if (!ipactx->override_restrictions) {
2689 return KRB5_KDB_CONSTRAINT_VIOLATION(-1780008410L);
2690 }
2691
2692 kerr = krb5_unparse_name(kcontext, search_for, &principal);
2693 if (kerr != 0) {
2694 goto done;
2695 }
2696
2697 kerr = ipadb_fetch_principals(ipactx, 0, principal, &res);
2698 if (kerr != 0) {
2699 goto done;
2700 }
2701
2702 canonicalized = strdup(principal);
2703 if (!canonicalized) {
2704 kerr = ENOMEM12;
2705 goto done;
2706 }
2707
2708#ifdef KRB5_KDB_FLAG_ALIAS_OK
2709 flags = KRB5_KDB_FLAG_ALIAS_OK;
2710#endif
2711 kerr = ipadb_find_principal(kcontext, flags, res, &canonicalized, &lentry);
2712 if (kerr != 0) {
2713 goto done;
2714 }
2715
2716 /* check if this is an alias (remove it) or if we should remove the whole
2717 * ldap record */
2718
2719 /* TODO: should we use case insensitive matching here ? */
2720 if (strcmp(canonicalized, principal) == 0) {
2721 kerr = ipadb_delete_entry(kcontext, lentry);
2722 } else {
2723 kerr = ipadb_delete_alias(kcontext, lentry, principal);
2724 }
2725
2726done:
2727 ldap_msgfree(res);
2728 free(canonicalized);
2729 krb5_free_unparsed_name(kcontext, principal);
2730 return kerr;
2731}
2732
2733#if KRB5_KDB_API_VERSION10 < 8
2734krb5_error_code ipadb_iterate(krb5_context kcontext,
2735 char *match_entry,
2736 int (*func)(krb5_pointer, krb5_db_entry *),
2737 krb5_pointer func_arg)
2738#else
2739krb5_error_code ipadb_iterate(krb5_context kcontext,
2740 char *match_entry,
2741 int (*func)(krb5_pointer, krb5_db_entry *),
2742 krb5_pointer func_arg, krb5_flags iterflags)
2743#endif
2744{
2745 struct ipadb_context *ipactx;
2746 krb5_error_code kerr;
2747 LDAPMessage *res = NULL((void*)0);
2748 LDAPMessage *lentry;
2749 krb5_db_entry *kentry;
2750 uint32_t pol;
2751
2752 ipactx = ipadb_get_context(kcontext);
2753 if (!ipactx) {
2754 return KRB5_KDB_DBNOTINITED(-1780008435L);
2755 }
2756
2757 /* If no match_entry is given iterate through all krb princs like the db2
2758 * or ldap plugin */
2759 if (match_entry == NULL((void*)0)) {
2760 match_entry = "*";
2761 }
2762
2763 /* fetch list of principal matching filter */
2764 kerr = ipadb_fetch_principals(ipactx, 0, match_entry, &res);
2765 if (kerr != 0) {
2766 goto done;
2767 }
2768
2769 lentry = ldap_first_entry(ipactx->lcontext, res);
2770
2771 while (lentry) {
2772
2773 kentry = NULL((void*)0);
2774 kerr = ipadb_parse_ldap_entry(kcontext, NULL((void*)0), lentry, &kentry, &pol);
2775 if (kerr == 0 && pol != 0) {
2776 kerr = ipadb_fetch_tktpolicy(kcontext, lentry, kentry, pol);
2777 }
2778 if (kerr == 0) {
2779 /* Now call the callback with the entry */
2780 func(func_arg, kentry);
2781 }
2782 ipadb_free_principal(kcontext, kentry);
2783
2784 lentry = ldap_next_entry(ipactx->lcontext, lentry);
2785 }
2786
2787 kerr = 0;
2788
2789done:
2790 ldap_msgfree(res);
2791 return kerr;
2792}
2793