1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c */
3 /*
4 * Copyright (C) 2016 by the Massachusetts Institute of Technology.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 *
14 * * Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in
16 * the documentation and/or other materials provided with the
17 * distribution.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
22 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
23 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
24 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
25 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
28 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
30 * OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 /*
33 * Copyright (c) 2004-2005, Novell, Inc.
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions are met:
38 *
39 * * Redistributions of source code must retain the above copyright notice,
40 * this list of conditions and the following disclaimer.
41 * * Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 * * The copyright holder's name is not used to endorse or promote products
45 * derived from this software without specific prior written permission.
46 *
47 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
48 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
50 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
51 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
52 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
53 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
54 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
55 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
56 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
57 * POSSIBILITY OF SUCH DAMAGE.
58 */
59 /*
60 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
61 * Use is subject to license terms.
62 */
63
64 #include "ldap_main.h"
65 #include "kdb_ldap.h"
66 #include "ldap_principal.h"
67 #include "princ_xdr.h"
68 #include "ldap_tkt_policy.h"
69 #include "ldap_pwd_policy.h"
70 #include "ldap_err.h"
71 #include <kadm5/admin.h>
72 #include <time.h>
73
74 extern char* principal_attributes[];
75 extern char* max_pwd_life_attr[];
76
77 static char *
78 getstringtime(krb5_timestamp);
79
80 krb5_error_code
berval2tl_data(struct berval * in,krb5_tl_data ** out)81 berval2tl_data(struct berval *in, krb5_tl_data **out)
82 {
83 *out = (krb5_tl_data *) malloc (sizeof (krb5_tl_data));
84 if (*out == NULL)
85 return ENOMEM;
86
87 (*out)->tl_data_length = in->bv_len - 2;
88 (*out)->tl_data_contents = (krb5_octet *) malloc
89 ((*out)->tl_data_length * sizeof (krb5_octet));
90 if ((*out)->tl_data_contents == NULL) {
91 free (*out);
92 return ENOMEM;
93 }
94
95 UNSTORE16_INT (in->bv_val, (*out)->tl_data_type);
96 memcpy ((*out)->tl_data_contents, in->bv_val + 2, (*out)->tl_data_length);
97
98 return 0;
99 }
100
101 /*
102 * look up a principal in the directory.
103 */
104
105 krb5_error_code
krb5_ldap_get_principal(krb5_context context,krb5_const_principal searchfor,unsigned int flags,krb5_db_entry ** entry_ptr)106 krb5_ldap_get_principal(krb5_context context, krb5_const_principal searchfor,
107 unsigned int flags, krb5_db_entry **entry_ptr)
108 {
109 char *user=NULL, *filter=NULL, *filtuser=NULL;
110 unsigned int tree=0, ntrees=1, princlen=0;
111 krb5_error_code tempst=0, st=0;
112 char **values=NULL, **subtree=NULL, *cname=NULL;
113 LDAP *ld=NULL;
114 LDAPMessage *result=NULL, *ent=NULL;
115 krb5_ldap_context *ldap_context=NULL;
116 kdb5_dal_handle *dal_handle=NULL;
117 krb5_ldap_server_handle *ldap_server_handle=NULL;
118 krb5_principal cprinc=NULL;
119 krb5_boolean found=FALSE;
120 krb5_db_entry *entry = NULL;
121
122 *entry_ptr = NULL;
123
124 /* Clear the global error string */
125 krb5_clear_error_message(context);
126
127 if (searchfor == NULL)
128 return EINVAL;
129
130 dal_handle = context->dal_handle;
131 ldap_context = (krb5_ldap_context *) dal_handle->db_context;
132
133 CHECK_LDAP_HANDLE(ldap_context);
134
135 if (!is_principal_in_realm(ldap_context, searchfor)) {
136 st = KRB5_KDB_NOENTRY;
137 k5_setmsg(context, st, _("Principal does not belong to realm"));
138 goto cleanup;
139 }
140
141 if ((st=krb5_unparse_name(context, searchfor, &user)) != 0)
142 goto cleanup;
143
144 if ((st=krb5_ldap_unparse_principal_name(user)) != 0)
145 goto cleanup;
146
147 filtuser = ldap_filter_correct(user);
148 if (filtuser == NULL) {
149 st = ENOMEM;
150 goto cleanup;
151 }
152
153 princlen = strlen(FILTER) + strlen(filtuser) + 2 + 1; /* 2 for closing brackets */
154 if ((filter = malloc(princlen)) == NULL) {
155 st = ENOMEM;
156 goto cleanup;
157 }
158 snprintf(filter, princlen, FILTER"%s))", filtuser);
159
160 if ((st = krb5_get_subtree_info(ldap_context, &subtree, &ntrees)) != 0)
161 goto cleanup;
162
163 GET_HANDLE();
164 for (tree=0; tree < ntrees && !found; ++tree) {
165
166 LDAP_SEARCH(subtree[tree], ldap_context->lrparams->search_scope, filter, principal_attributes);
167 for (ent=ldap_first_entry(ld, result); ent != NULL && !found; ent=ldap_next_entry(ld, ent)) {
168
169 /* get the associated directory user information */
170 if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
171 int i;
172
173 /* a wild-card in a principal name can return a list of kerberos principals.
174 * Make sure that the correct principal is returned.
175 * NOTE: a principalname k* in ldap server will return all the principals starting with a k
176 */
177 for (i=0; values[i] != NULL; ++i) {
178 if (strcmp(values[i], user) == 0) {
179 found = TRUE;
180 break;
181 }
182 }
183 ldap_value_free(values);
184
185 if (!found) /* no matching principal found */
186 continue;
187 }
188
189 if ((values=ldap_get_values(ld, ent, "krbcanonicalname")) != NULL) {
190 if (values[0] && strcmp(values[0], user) != 0) {
191 /* We matched an alias, not the canonical name. */
192 st = krb5_ldap_parse_principal_name(values[0], &cname);
193 if (st != 0)
194 goto cleanup;
195 st = krb5_parse_name(context, cname, &cprinc);
196 if (st != 0)
197 goto cleanup;
198 }
199 ldap_value_free(values);
200 if (!found)
201 continue;
202 }
203
204 entry = k5alloc(sizeof(*entry), &st);
205 if (entry == NULL)
206 goto cleanup;
207 if ((st = populate_krb5_db_entry(context, ldap_context, ld, ent,
208 cprinc ? cprinc : searchfor,
209 entry)) != 0)
210 goto cleanup;
211 }
212 ldap_msgfree(result);
213 result = NULL;
214 } /* for (tree=0 ... */
215
216 if (found) {
217 *entry_ptr = entry;
218 entry = NULL;
219 } else
220 st = KRB5_KDB_NOENTRY;
221
222 cleanup:
223 ldap_msgfree(result);
224 krb5_db_free_principal(context, entry);
225
226 if (filter)
227 free (filter);
228
229 if (subtree) {
230 for (; ntrees; --ntrees)
231 if (subtree[ntrees-1])
232 free (subtree[ntrees-1]);
233 free (subtree);
234 }
235
236 if (ldap_server_handle)
237 krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
238
239 if (user)
240 free(user);
241
242 if (filtuser)
243 free(filtuser);
244
245 if (cname)
246 free(cname);
247
248 if (cprinc)
249 krb5_free_principal(context, cprinc);
250
251 return st;
252 }
253
254 typedef enum{ ADD_PRINCIPAL, MODIFY_PRINCIPAL } OPERATION;
255 /*
256 * ptype is creating confusions. Additionally the logic
257 * surronding ptype is redundunt and can be achevied
258 * with the help of dn and containerdn members.
259 * so dropping the ptype member
260 */
261
262 typedef struct _xargs_t {
263 char *dn;
264 char *linkdn;
265 krb5_boolean dn_from_kbd;
266 char *containerdn;
267 char *tktpolicydn;
268 }xargs_t;
269
270 static void
free_xargs(xargs_t xargs)271 free_xargs(xargs_t xargs)
272 {
273 if (xargs.dn)
274 free (xargs.dn);
275 if (xargs.linkdn)
276 free(xargs.linkdn);
277 if (xargs.containerdn)
278 free (xargs.containerdn);
279 if (xargs.tktpolicydn)
280 free (xargs.tktpolicydn);
281 }
282
283 static krb5_error_code
process_db_args(krb5_context context,char ** db_args,xargs_t * xargs,OPERATION optype)284 process_db_args(krb5_context context, char **db_args, xargs_t *xargs,
285 OPERATION optype)
286 {
287 int i=0;
288 krb5_error_code st=0;
289 char *arg=NULL, *arg_val=NULL;
290 char **dptr=NULL;
291 unsigned int arg_val_len=0;
292
293 if (db_args) {
294 for (i=0; db_args[i]; ++i) {
295 arg = strtok_r(db_args[i], "=", &arg_val);
296 arg = (arg != NULL) ? arg : "";
297 if (strcmp(arg, TKTPOLICY_ARG) == 0) {
298 dptr = &xargs->tktpolicydn;
299 } else {
300 if (strcmp(arg, USERDN_ARG) == 0) {
301 if (optype == MODIFY_PRINCIPAL ||
302 xargs->dn != NULL || xargs->containerdn != NULL ||
303 xargs->linkdn != NULL) {
304 st = EINVAL;
305 k5_setmsg(context, st, _("%s option not supported"),
306 arg);
307 goto cleanup;
308 }
309 dptr = &xargs->dn;
310 } else if (strcmp(arg, CONTAINERDN_ARG) == 0) {
311 if (optype == MODIFY_PRINCIPAL ||
312 xargs->dn != NULL || xargs->containerdn != NULL) {
313 st = EINVAL;
314 k5_setmsg(context, st, _("%s option not supported"),
315 arg);
316 goto cleanup;
317 }
318 dptr = &xargs->containerdn;
319 } else if (strcmp(arg, LINKDN_ARG) == 0) {
320 if (xargs->dn != NULL || xargs->linkdn != NULL) {
321 st = EINVAL;
322 k5_setmsg(context, st, _("%s option not supported"),
323 arg);
324 goto cleanup;
325 }
326 dptr = &xargs->linkdn;
327 } else {
328 st = EINVAL;
329 k5_setmsg(context, st, _("unknown option: %s"), arg);
330 goto cleanup;
331 }
332
333 xargs->dn_from_kbd = TRUE;
334 if (arg_val == NULL || strlen(arg_val) == 0) {
335 st = EINVAL;
336 k5_setmsg(context, st, _("%s option value missing"), arg);
337 goto cleanup;
338 }
339 }
340
341 if (arg_val == NULL) {
342 st = EINVAL;
343 k5_setmsg(context, st, _("%s option value missing"), arg);
344 goto cleanup;
345 }
346 arg_val_len = strlen(arg_val) + 1;
347
348 if (strcmp(arg, TKTPOLICY_ARG) == 0) {
349 if ((st = krb5_ldap_name_to_policydn (context,
350 arg_val,
351 dptr)) != 0)
352 goto cleanup;
353 } else {
354 *dptr = k5memdup(arg_val, arg_val_len, &st);
355 if (*dptr == NULL)
356 goto cleanup;
357 }
358 }
359 }
360
361 cleanup:
362 return st;
363 }
364
365 krb5int_access accessor;
366
367 static krb5_error_code
asn1_encode_sequence_of_keys(krb5_key_data * key_data,krb5_int16 n_key_data,krb5_int32 mkvno,krb5_data ** code)368 asn1_encode_sequence_of_keys(krb5_key_data *key_data, krb5_int16 n_key_data,
369 krb5_int32 mkvno, krb5_data **code)
370 {
371 krb5_error_code err;
372 ldap_seqof_key_data val;
373
374 /*
375 * This should be pushed back into other library initialization
376 * code.
377 */
378 err = kldap_ensure_initialized ();
379 if (err)
380 return err;
381
382 val.key_data = key_data;
383 val.n_key_data = n_key_data;
384 val.mkvno = mkvno;
385 val.kvno = key_data[0].key_data_kvno;
386
387 return accessor.asn1_ldap_encode_sequence_of_keys(&val, code);
388 }
389
390 static krb5_error_code
asn1_decode_sequence_of_keys(krb5_data * in,ldap_seqof_key_data * out)391 asn1_decode_sequence_of_keys(krb5_data *in, ldap_seqof_key_data *out)
392 {
393 krb5_error_code err;
394 ldap_seqof_key_data *p;
395 int i;
396
397 memset(out, 0, sizeof(*out));
398
399 /*
400 * This should be pushed back into other library initialization
401 * code.
402 */
403 err = kldap_ensure_initialized ();
404 if (err)
405 return err;
406
407 err = accessor.asn1_ldap_decode_sequence_of_keys(in, &p);
408 if (err)
409 return err;
410
411 /* Set kvno and key_data_ver in each key_data element. */
412 for (i = 0; i < p->n_key_data; i++) {
413 p->key_data[i].key_data_kvno = p->kvno;
414 /* The decoder sets key_data_ver to 1 if no salt is present, but leaves
415 * it at 0 if salt is present. */
416 if (p->key_data[i].key_data_ver == 0)
417 p->key_data[i].key_data_ver = 2;
418 }
419
420 *out = *p;
421 free(p);
422 return 0;
423 }
424
425 /*
426 * Free a NULL-terminated struct berval *array[] and all its contents.
427 * Does not set array to NULL after freeing it.
428 */
429 void
free_berdata(struct berval ** array)430 free_berdata(struct berval **array)
431 {
432 int i;
433
434 if (array != NULL) {
435 for (i = 0; array[i] != NULL; i++) {
436 if (array[i]->bv_val != NULL)
437 free(array[i]->bv_val);
438 free(array[i]);
439 }
440 free(array);
441 }
442 }
443
444 /*
445 * Encode krb5_key_data into a berval struct for insertion into LDAP.
446 */
447 static krb5_error_code
encode_keys(krb5_key_data * key_data_in,int n_key_data,krb5_kvno mkvno,struct berval ** bval_out)448 encode_keys(krb5_key_data *key_data_in, int n_key_data, krb5_kvno mkvno,
449 struct berval **bval_out)
450 {
451 krb5_error_code err = 0;
452 int i;
453 krb5_key_data *key_data = NULL;
454 struct berval *bval = NULL;
455 krb5_data *code;
456
457 *bval_out = NULL;
458 if (n_key_data <= 0) {
459 err = EINVAL;
460 goto cleanup;
461 }
462
463 /* Make a shallow copy of the key data so we can alter it. */
464 key_data = k5calloc(n_key_data, sizeof(*key_data), &err);
465 if (key_data == NULL)
466 goto cleanup;
467 memcpy(key_data, key_data_in, n_key_data * sizeof(*key_data));
468
469 /* Unpatched krb5 1.11 and 1.12 cannot decode KrbKey sequences with no salt
470 * field. For compatibility, always encode a salt field. */
471 for (i = 0; i < n_key_data; i++) {
472 if (key_data[i].key_data_ver == 1) {
473 key_data[i].key_data_ver = 2;
474 key_data[i].key_data_type[1] = KRB5_KDB_SALTTYPE_NORMAL;
475 key_data[i].key_data_length[1] = 0;
476 key_data[i].key_data_contents[1] = NULL;
477 }
478 }
479
480 bval = k5alloc(sizeof(struct berval), &err);
481 if (bval == NULL)
482 goto cleanup;
483
484 err = asn1_encode_sequence_of_keys(key_data, n_key_data, mkvno, &code);
485 if (err)
486 goto cleanup;
487
488 /* Steal the data pointer from code for bval and discard code. */
489 bval->bv_len = code->length;
490 bval->bv_val = code->data;
491 free(code);
492
493 *bval_out = bval;
494 bval = NULL;
495
496 cleanup:
497 free(key_data);
498 free(bval);
499 return err;
500 }
501
502 /* Decoding ASN.1 encoded key */
503 struct berval **
krb5_encode_krbsecretkey(krb5_key_data * key_data,int n_key_data,krb5_kvno mkvno)504 krb5_encode_krbsecretkey(krb5_key_data *key_data, int n_key_data,
505 krb5_kvno mkvno)
506 {
507 struct berval **ret = NULL;
508 int currkvno;
509 int num_versions = 0;
510 int i, j, last;
511 krb5_error_code err = 0;
512
513 if (n_key_data < 0)
514 return NULL;
515
516 /* Find the number of key versions */
517 if (n_key_data > 0) {
518 for (i = 0, num_versions = 1; i < n_key_data - 1; i++) {
519 if (key_data[i].key_data_kvno != key_data[i + 1].key_data_kvno)
520 num_versions++;
521 }
522 }
523
524 ret = calloc(num_versions + 1, sizeof(struct berval *));
525 if (ret == NULL) {
526 err = ENOMEM;
527 goto cleanup;
528 }
529 ret[num_versions] = NULL;
530
531 /* n_key_data may be 0 if a principal is created without a key. */
532 if (n_key_data == 0)
533 goto cleanup;
534
535 currkvno = key_data[0].key_data_kvno;
536 for (i = 0, last = 0, j = 0; i < n_key_data; i++) {
537 if (i == n_key_data - 1 || key_data[i + 1].key_data_kvno != currkvno) {
538 err = encode_keys(key_data + last, (krb5_int16)i - last + 1, mkvno,
539 &ret[j]);
540 if (err)
541 goto cleanup;
542 j++;
543 last = i + 1;
544
545 if (i < n_key_data - 1)
546 currkvno = key_data[i + 1].key_data_kvno;
547 }
548 }
549
550 cleanup:
551 if (err != 0) {
552 free_berdata(ret);
553 ret = NULL;
554 }
555
556 return ret;
557 }
558
559 /*
560 * Encode a principal's key history for insertion into ldap.
561 */
562 static struct berval **
krb5_encode_histkey(osa_princ_ent_rec * princ_ent)563 krb5_encode_histkey(osa_princ_ent_rec *princ_ent)
564 {
565 unsigned int i;
566 krb5_error_code err = 0;
567 struct berval **ret = NULL;
568
569 if (princ_ent->old_key_len <= 0)
570 return NULL;
571
572 ret = k5calloc(princ_ent->old_key_len + 1, sizeof(struct berval *), &err);
573 if (ret == NULL)
574 goto cleanup;
575
576 for (i = 0; i < princ_ent->old_key_len; i++) {
577 if (princ_ent->old_keys[i].n_key_data <= 0) {
578 err = EINVAL;
579 goto cleanup;
580 }
581 err = encode_keys(princ_ent->old_keys[i].key_data,
582 princ_ent->old_keys[i].n_key_data,
583 princ_ent->admin_history_kvno, &ret[i]);
584 if (err)
585 goto cleanup;
586 }
587
588 ret[princ_ent->old_key_len] = NULL;
589
590 cleanup:
591 if (err != 0) {
592 free_berdata(ret);
593 ret = NULL;
594 }
595
596 return ret;
597 }
598
599 static krb5_error_code
tl_data2berval(krb5_tl_data * in,struct berval ** out)600 tl_data2berval (krb5_tl_data *in, struct berval **out)
601 {
602 *out = (struct berval *) malloc (sizeof (struct berval));
603 if (*out == NULL)
604 return ENOMEM;
605
606 (*out)->bv_len = in->tl_data_length + 2;
607 (*out)->bv_val = (char *) malloc ((*out)->bv_len);
608 if ((*out)->bv_val == NULL) {
609 free (*out);
610 return ENOMEM;
611 }
612
613 STORE16_INT((*out)->bv_val, in->tl_data_type);
614 memcpy ((*out)->bv_val + 2, in->tl_data_contents, in->tl_data_length);
615
616 return 0;
617 }
618
619 /* Parse the "require_auth" string for auth indicators, adding them to the
620 * krbPrincipalAuthInd attribute. */
621 static krb5_error_code
update_ldap_mod_auth_ind(krb5_context context,krb5_db_entry * entry,LDAPMod *** mods)622 update_ldap_mod_auth_ind(krb5_context context, krb5_db_entry *entry,
623 LDAPMod ***mods)
624 {
625 int i = 0;
626 krb5_error_code ret;
627 char *auth_ind = NULL;
628 char *strval[10] = { 0 };
629 char *ai, *ai_save = NULL;
630 int mask, sv_num = sizeof(strval) / sizeof(*strval);
631
632 ret = krb5_dbe_get_string(context, entry, KRB5_KDB_SK_REQUIRE_AUTH,
633 &auth_ind);
634 if (ret)
635 return ret;
636 if (auth_ind == NULL) {
637 /* If we know krbPrincipalAuthInd attributes are present from loading
638 * the entry, delete them. */
639 ret = krb5_get_attributes_mask(context, entry, &mask);
640 if (!ret && (mask & KDB_AUTH_IND_ATTR)) {
641 return krb5_add_str_mem_ldap_mod(mods, "krbPrincipalAuthInd",
642 LDAP_MOD_DELETE, NULL);
643 }
644 return 0;
645 }
646
647 ai = strtok_r(auth_ind, " ", &ai_save);
648 while (ai != NULL && i < sv_num) {
649 strval[i++] = ai;
650 ai = strtok_r(NULL, " ", &ai_save);
651 }
652
653 ret = krb5_add_str_mem_ldap_mod(mods, "krbPrincipalAuthInd",
654 LDAP_MOD_REPLACE, strval);
655 krb5_dbe_free_string(context, auth_ind);
656 return ret;
657 }
658
659 static krb5_error_code
check_dn_in_container(krb5_context context,const char * dn,char * const * subtrees,unsigned int ntrees)660 check_dn_in_container(krb5_context context, const char *dn,
661 char *const *subtrees, unsigned int ntrees)
662 {
663 unsigned int i;
664 size_t dnlen = strlen(dn), stlen;
665
666 for (i = 0; i < ntrees; i++) {
667 if (subtrees[i] == NULL || *subtrees[i] == '\0')
668 return 0;
669 stlen = strlen(subtrees[i]);
670 if (dnlen >= stlen &&
671 strcasecmp(dn + dnlen - stlen, subtrees[i]) == 0 &&
672 (dnlen == stlen || dn[dnlen - stlen - 1] == ','))
673 return 0;
674 }
675
676 k5_setmsg(context, EINVAL, _("DN is out of the realm subtree"));
677 return EINVAL;
678 }
679
680 static krb5_error_code
check_dn_exists(krb5_context context,krb5_ldap_server_handle * ldap_server_handle,const char * dn,krb5_boolean nonkrb_only)681 check_dn_exists(krb5_context context,
682 krb5_ldap_server_handle *ldap_server_handle,
683 const char *dn, krb5_boolean nonkrb_only)
684 {
685 krb5_error_code st = 0, tempst;
686 krb5_ldap_context *ldap_context = context->dal_handle->db_context;
687 LDAP *ld = ldap_server_handle->ldap_handle;
688 LDAPMessage *result = NULL, *ent;
689 char *attrs[] = { "krbticketpolicyreference", "krbprincipalname", NULL };
690 char **values;
691
692 LDAP_SEARCH_1(dn, LDAP_SCOPE_BASE, 0, attrs, IGNORE_STATUS);
693 if (st != LDAP_SUCCESS)
694 return set_ldap_error(context, st, OP_SEARCH);
695
696 ent = ldap_first_entry(ld, result);
697 CHECK_NULL(ent);
698
699 values = ldap_get_values(ld, ent, "krbticketpolicyreference");
700 if (values != NULL)
701 ldap_value_free(values);
702
703 values = ldap_get_values(ld, ent, "krbprincipalname");
704 if (values != NULL) {
705 ldap_value_free(values);
706 if (nonkrb_only) {
707 st = EINVAL;
708 k5_setmsg(context, st, _("ldap object is already kerberized"));
709 goto cleanup;
710 }
711 }
712
713 cleanup:
714 ldap_msgfree(result);
715 return st;
716 }
717
718 static krb5_error_code
validate_xargs(krb5_context context,krb5_ldap_server_handle * ldap_server_handle,const xargs_t * xargs,const char * standalone_dn,char * const * subtrees,unsigned int ntrees)719 validate_xargs(krb5_context context,
720 krb5_ldap_server_handle *ldap_server_handle,
721 const xargs_t *xargs, const char *standalone_dn,
722 char *const *subtrees, unsigned int ntrees)
723 {
724 krb5_error_code st;
725
726 if (xargs->dn != NULL) {
727 /* The supplied dn must be within a realm container. */
728 st = check_dn_in_container(context, xargs->dn, subtrees, ntrees);
729 if (st)
730 return st;
731 /* The supplied dn must exist without Kerberos attributes. */
732 st = check_dn_exists(context, ldap_server_handle, xargs->dn, TRUE);
733 if (st)
734 return st;
735 }
736
737 if (xargs->linkdn != NULL) {
738 /* The supplied linkdn must be within a realm container. */
739 st = check_dn_in_container(context, xargs->linkdn, subtrees, ntrees);
740 if (st)
741 return st;
742 /* The supplied linkdn must exist. */
743 st = check_dn_exists(context, ldap_server_handle, xargs->linkdn,
744 FALSE);
745 if (st)
746 return st;
747 }
748
749 if (xargs->containerdn != NULL && standalone_dn != NULL) {
750 /* standalone_dn (likely composed using containerdn) must be within a
751 * container. */
752 st = check_dn_in_container(context, standalone_dn, subtrees, ntrees);
753 if (st)
754 return st;
755 }
756
757 return 0;
758 }
759
760 krb5_error_code
krb5_ldap_put_principal(krb5_context context,krb5_db_entry * entry,char ** db_args)761 krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry,
762 char **db_args)
763 {
764 int l=0, kerberos_principal_object_type=0;
765 unsigned int ntrees=0, tre=0;
766 krb5_error_code st=0, tempst=0;
767 LDAP *ld=NULL;
768 LDAPMessage *result=NULL, *ent=NULL;
769 char **subtreelist = NULL;
770 char *user=NULL, *subtree=NULL, *principal_dn=NULL;
771 char *strval[10]={NULL}, errbuf[1024];
772 char *filtuser=NULL;
773 struct berval **bersecretkey=NULL;
774 LDAPMod **mods=NULL;
775 krb5_boolean create_standalone=FALSE;
776 krb5_boolean establish_links=FALSE;
777 char *standalone_principal_dn=NULL;
778 krb5_tl_data *tl_data=NULL;
779 krb5_key_data **keys=NULL;
780 kdb5_dal_handle *dal_handle=NULL;
781 krb5_ldap_context *ldap_context=NULL;
782 krb5_ldap_server_handle *ldap_server_handle=NULL;
783 osa_princ_ent_rec princ_ent = {0};
784 xargs_t xargs = {0};
785 char *polname = NULL;
786 OPERATION optype;
787 krb5_boolean found_entry = FALSE;
788 char *filter = NULL;
789
790 /* Clear the global error string */
791 krb5_clear_error_message(context);
792
793 SETUP_CONTEXT();
794 if (ldap_context->lrparams == NULL || ldap_context->container_dn == NULL)
795 return EINVAL;
796
797 /* get ldap handle */
798 GET_HANDLE();
799
800 if (!is_principal_in_realm(ldap_context, entry->princ)) {
801 st = EINVAL;
802 k5_setmsg(context, st,
803 _("Principal does not belong to the default realm"));
804 goto cleanup;
805 }
806
807 /* get the principal information to act on */
808 if (((st=krb5_unparse_name(context, entry->princ, &user)) != 0) ||
809 ((st=krb5_ldap_unparse_principal_name(user)) != 0))
810 goto cleanup;
811 filtuser = ldap_filter_correct(user);
812 if (filtuser == NULL) {
813 st = ENOMEM;
814 goto cleanup;
815 }
816
817 /* Identity the type of operation, it can be
818 * add principal or modify principal.
819 * hack if the entry->mask has KRB_PRINCIPAL flag set
820 * then it is a add operation
821 */
822 if (entry->mask & KADM5_PRINCIPAL)
823 optype = ADD_PRINCIPAL;
824 else
825 optype = MODIFY_PRINCIPAL;
826
827 if (((st=krb5_get_princ_type(context, entry, &kerberos_principal_object_type)) != 0) ||
828 ((st=krb5_get_userdn(context, entry, &principal_dn)) != 0))
829 goto cleanup;
830
831 if ((st=process_db_args(context, db_args, &xargs, optype)) != 0)
832 goto cleanup;
833
834 if (entry->mask & KADM5_LOAD) {
835 unsigned int tree = 0;
836 int numlentries = 0;
837
838 /* A load operation is special, will do a mix-in (add krbprinc
839 * attrs to a non-krb object entry) if an object exists with a
840 * matching krbprincipalname attribute so try to find existing
841 * object and set principal_dn. This assumes that the
842 * krbprincipalname attribute is unique (only one object entry has
843 * a particular krbprincipalname attribute).
844 */
845 if (asprintf(&filter, FILTER"%s))", filtuser) < 0) {
846 filter = NULL;
847 st = ENOMEM;
848 goto cleanup;
849 }
850
851 /* get the current subtree list */
852 if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0)
853 goto cleanup;
854
855 found_entry = FALSE;
856 /* search for entry with matching krbprincipalname attribute */
857 for (tree = 0; found_entry == FALSE && tree < ntrees; ++tree) {
858 if (principal_dn == NULL) {
859 LDAP_SEARCH_1(subtreelist[tree], ldap_context->lrparams->search_scope, filter, principal_attributes, IGNORE_STATUS);
860 } else {
861 /* just look for entry with principal_dn */
862 LDAP_SEARCH_1(principal_dn, LDAP_SCOPE_BASE, filter, principal_attributes, IGNORE_STATUS);
863 }
864 if (st == LDAP_SUCCESS) {
865 numlentries = ldap_count_entries(ld, result);
866 if (numlentries > 1) {
867 st = EINVAL;
868 k5_setmsg(context, st,
869 _("operation can not continue, more than one "
870 "entry with principal name \"%s\" found"),
871 user);
872 goto cleanup;
873 } else if (numlentries == 1) {
874 found_entry = TRUE;
875 if (principal_dn == NULL) {
876 ent = ldap_first_entry(ld, result);
877 if (ent != NULL) {
878 /* setting principal_dn will cause that entry to be modified further down */
879 if ((principal_dn = ldap_get_dn(ld, ent)) == NULL) {
880 ldap_get_option (ld, LDAP_OPT_RESULT_CODE, &st);
881 st = set_ldap_error (context, st, 0);
882 goto cleanup;
883 }
884 }
885 }
886 }
887 } else if (st != LDAP_NO_SUCH_OBJECT) {
888 /* could not perform search, return with failure */
889 st = set_ldap_error (context, st, 0);
890 goto cleanup;
891 }
892 ldap_msgfree(result);
893 result = NULL;
894 /*
895 * If it isn't found then assume a standalone princ entry is to
896 * be created.
897 */
898 } /* end for (tree = 0; principal_dn == ... */
899
900 if (found_entry == FALSE && principal_dn != NULL) {
901 /*
902 * if principal_dn is null then there is code further down to
903 * deal with setting standalone_principal_dn. Also note that
904 * this will set create_standalone true for
905 * non-mix-in entries which is okay if loading from a dump.
906 */
907 create_standalone = TRUE;
908 standalone_principal_dn = strdup(principal_dn);
909 CHECK_NULL(standalone_principal_dn);
910 }
911 } /* end if (entry->mask & KADM5_LOAD */
912
913 /* time to generate the DN information with the help of
914 * containerdn, principalcontainerreference or
915 * realmcontainerdn information
916 */
917 if (principal_dn == NULL && xargs.dn == NULL) { /* creation of standalone principal */
918 /* get the subtree information */
919 if (entry->princ->length == 2 && entry->princ->data[0].length == strlen("krbtgt") &&
920 strncmp(entry->princ->data[0].data, "krbtgt", entry->princ->data[0].length) == 0) {
921 /* if the principal is a inter-realm principal, always created in the realm container */
922 subtree = strdup(ldap_context->lrparams->realmdn);
923 } else if (xargs.containerdn) {
924 if ((st=checkattributevalue(ld, xargs.containerdn, NULL, NULL, NULL)) != 0) {
925 if (st == KRB5_KDB_NOENTRY || st == KRB5_KDB_CONSTRAINT_VIOLATION) {
926 int ost = st;
927 st = EINVAL;
928 k5_wrapmsg(context, ost, st, _("'%s' not found"),
929 xargs.containerdn);
930 }
931 goto cleanup;
932 }
933 subtree = strdup(xargs.containerdn);
934 } else if (ldap_context->lrparams->containerref && strlen(ldap_context->lrparams->containerref) != 0) {
935 /*
936 * Here the subtree should be changed with
937 * principalcontainerreference attribute value
938 */
939 subtree = strdup(ldap_context->lrparams->containerref);
940 } else {
941 subtree = strdup(ldap_context->lrparams->realmdn);
942 }
943 CHECK_NULL(subtree);
944
945 if (asprintf(&standalone_principal_dn, "krbprincipalname=%s,%s",
946 filtuser, subtree) < 0)
947 standalone_principal_dn = NULL;
948 CHECK_NULL(standalone_principal_dn);
949 /*
950 * free subtree when you are done using the subtree
951 * set the boolean create_standalone to TRUE
952 */
953 create_standalone = TRUE;
954 free(subtree);
955 subtree = NULL;
956 }
957
958 /*
959 * If the DN information is presented by the user, time to
960 * validate the input to ensure that the DN falls under
961 * any of the subtrees
962 */
963 if (xargs.dn_from_kbd == TRUE) {
964 /* Get the current subtree list if we haven't already done so. */
965 if (subtreelist == NULL) {
966 st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees);
967 if (st)
968 goto cleanup;
969 }
970
971 st = validate_xargs(context, ldap_server_handle, &xargs,
972 standalone_principal_dn, subtreelist, ntrees);
973 if (st)
974 goto cleanup;
975 }
976
977 if (xargs.linkdn != NULL) {
978 /*
979 * link information can be changed using modprinc.
980 * However, link information can be changed only on the
981 * standalone kerberos principal objects. A standalone
982 * kerberos principal object is of type krbprincipal
983 * structural objectclass.
984 *
985 * NOTE: kerberos principals on an ldap object can't be
986 * linked to other ldap objects.
987 */
988 if (optype == MODIFY_PRINCIPAL &&
989 kerberos_principal_object_type != KDB_STANDALONE_PRINCIPAL_OBJECT) {
990 st = EINVAL;
991 snprintf(errbuf, sizeof(errbuf),
992 _("link information can not be set/updated as the "
993 "kerberos principal belongs to an ldap object"));
994 k5_setmsg(context, st, "%s", errbuf);
995 goto cleanup;
996 }
997 /*
998 * Check the link information. If there is already a link
999 * existing then this operation is not allowed.
1000 */
1001 {
1002 char **linkdns=NULL;
1003 int j=0;
1004
1005 if ((st=krb5_get_linkdn(context, entry, &linkdns)) != 0) {
1006 snprintf(errbuf, sizeof(errbuf),
1007 _("Failed getting object references"));
1008 k5_setmsg(context, st, "%s", errbuf);
1009 goto cleanup;
1010 }
1011 if (linkdns != NULL) {
1012 st = EINVAL;
1013 snprintf(errbuf, sizeof(errbuf),
1014 _("kerberos principal is already linked to a ldap "
1015 "object"));
1016 k5_setmsg(context, st, "%s", errbuf);
1017 for (j=0; linkdns[j] != NULL; ++j)
1018 free (linkdns[j]);
1019 free (linkdns);
1020 goto cleanup;
1021 }
1022 }
1023
1024 establish_links = TRUE;
1025 }
1026
1027 if (entry->mask & KADM5_LAST_SUCCESS) {
1028 memset(strval, 0, sizeof(strval));
1029 if ((strval[0]=getstringtime(entry->last_success)) == NULL)
1030 goto cleanup;
1031 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastSuccessfulAuth", LDAP_MOD_REPLACE, strval)) != 0) {
1032 free (strval[0]);
1033 goto cleanup;
1034 }
1035 free (strval[0]);
1036 }
1037
1038 if (entry->mask & KADM5_LAST_FAILED) {
1039 memset(strval, 0, sizeof(strval));
1040 if ((strval[0]=getstringtime(entry->last_failed)) == NULL)
1041 goto cleanup;
1042 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastFailedAuth", LDAP_MOD_REPLACE, strval)) != 0) {
1043 free (strval[0]);
1044 goto cleanup;
1045 }
1046 free(strval[0]);
1047 }
1048
1049 if (entry->mask & KADM5_FAIL_AUTH_COUNT) {
1050 krb5_kvno fail_auth_count;
1051
1052 fail_auth_count = entry->fail_auth_count;
1053 if (entry->mask & KADM5_FAIL_AUTH_COUNT_INCREMENT)
1054 fail_auth_count++;
1055
1056 st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
1057 LDAP_MOD_REPLACE,
1058 fail_auth_count);
1059 if (st != 0)
1060 goto cleanup;
1061 } else if (entry->mask & KADM5_FAIL_AUTH_COUNT_INCREMENT) {
1062 int attr_mask = 0;
1063 krb5_boolean has_fail_count;
1064
1065 /* Check if the krbLoginFailedCount attribute exists. (Through
1066 * krb5 1.8.1, it wasn't set in new entries.) */
1067 st = krb5_get_attributes_mask(context, entry, &attr_mask);
1068 if (st != 0)
1069 goto cleanup;
1070 has_fail_count = ((attr_mask & KDB_FAIL_AUTH_COUNT_ATTR) != 0);
1071
1072 /*
1073 * If the client library and server supports RFC 4525,
1074 * then use it to increment by one the value of the
1075 * krbLoginFailedCount attribute. Otherwise, assert the
1076 * (provided) old value by deleting it before adding.
1077 */
1078 #ifdef LDAP_MOD_INCREMENT
1079 if (ldap_server_handle->server_info->modify_increment &&
1080 has_fail_count) {
1081 st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
1082 LDAP_MOD_INCREMENT, 1);
1083 if (st != 0)
1084 goto cleanup;
1085 } else {
1086 #endif /* LDAP_MOD_INCREMENT */
1087 if (has_fail_count) {
1088 st = krb5_add_int_mem_ldap_mod(&mods,
1089 "krbLoginFailedCount",
1090 LDAP_MOD_DELETE,
1091 entry->fail_auth_count);
1092 if (st != 0)
1093 goto cleanup;
1094 }
1095 st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
1096 LDAP_MOD_ADD,
1097 entry->fail_auth_count + 1);
1098 if (st != 0)
1099 goto cleanup;
1100 #ifdef LDAP_MOD_INCREMENT
1101 }
1102 #endif
1103 } else if (optype == ADD_PRINCIPAL) {
1104 /* Initialize krbLoginFailedCount in new entries to help avoid a
1105 * race during the first failed login. */
1106 st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
1107 LDAP_MOD_ADD, 0);
1108 }
1109
1110 if (entry->mask & KADM5_MAX_LIFE) {
1111 if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxticketlife", LDAP_MOD_REPLACE, entry->max_life)) != 0)
1112 goto cleanup;
1113 }
1114
1115 if (entry->mask & KADM5_MAX_RLIFE) {
1116 if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxrenewableage", LDAP_MOD_REPLACE,
1117 entry->max_renewable_life)) != 0)
1118 goto cleanup;
1119 }
1120
1121 if (entry->mask & KADM5_ATTRIBUTES) {
1122 if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbticketflags", LDAP_MOD_REPLACE,
1123 entry->attributes)) != 0)
1124 goto cleanup;
1125 }
1126
1127 if (entry->mask & KADM5_PRINCIPAL) {
1128 memset(strval, 0, sizeof(strval));
1129 strval[0] = user;
1130 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalname", LDAP_MOD_REPLACE, strval)) != 0)
1131 goto cleanup;
1132 }
1133
1134 if (entry->mask & KADM5_PRINC_EXPIRE_TIME) {
1135 memset(strval, 0, sizeof(strval));
1136 if ((strval[0]=getstringtime(entry->expiration)) == NULL)
1137 goto cleanup;
1138 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalexpiration", LDAP_MOD_REPLACE, strval)) != 0) {
1139 free (strval[0]);
1140 goto cleanup;
1141 }
1142 free (strval[0]);
1143 }
1144
1145 if (entry->mask & KADM5_PW_EXPIRATION) {
1146 memset(strval, 0, sizeof(strval));
1147 if ((strval[0]=getstringtime(entry->pw_expiration)) == NULL)
1148 goto cleanup;
1149 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpasswordexpiration",
1150 LDAP_MOD_REPLACE,
1151 strval)) != 0) {
1152 free (strval[0]);
1153 goto cleanup;
1154 }
1155 free (strval[0]);
1156 }
1157
1158 if (entry->mask & KADM5_POLICY || entry->mask & KADM5_KEY_HIST) {
1159 memset(&princ_ent, 0, sizeof(princ_ent));
1160 for (tl_data=entry->tl_data; tl_data; tl_data=tl_data->tl_data_next) {
1161 if (tl_data->tl_data_type == KRB5_TL_KADM_DATA) {
1162 if ((st = krb5_lookup_tl_kadm_data(tl_data, &princ_ent)) != 0) {
1163 goto cleanup;
1164 }
1165 break;
1166 }
1167 }
1168 }
1169
1170 if (entry->mask & KADM5_POLICY) {
1171 if (princ_ent.aux_attributes & KADM5_POLICY) {
1172 memset(strval, 0, sizeof(strval));
1173 if ((st = krb5_ldap_name_to_policydn (context, princ_ent.policy, &polname)) != 0)
1174 goto cleanup;
1175 strval[0] = polname;
1176 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, strval)) != 0)
1177 goto cleanup;
1178 } else {
1179 st = EINVAL;
1180 k5_setmsg(context, st, "Password policy value null");
1181 goto cleanup;
1182 }
1183 } else if (entry->mask & KADM5_LOAD && found_entry == TRUE) {
1184 /*
1185 * a load is special in that existing entries must have attrs that
1186 * removed.
1187 */
1188
1189 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, NULL)) != 0)
1190 goto cleanup;
1191 }
1192
1193 if (entry->mask & KADM5_POLICY_CLR) {
1194 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_DELETE, NULL)) != 0)
1195 goto cleanup;
1196 }
1197
1198 if (entry->mask & KADM5_KEY_HIST) {
1199 bersecretkey = krb5_encode_histkey(&princ_ent);
1200 if (bersecretkey == NULL) {
1201 st = ENOMEM;
1202 goto cleanup;
1203 }
1204
1205 st = krb5_add_ber_mem_ldap_mod(&mods, "krbpwdhistory",
1206 LDAP_MOD_REPLACE | LDAP_MOD_BVALUES,
1207 bersecretkey);
1208 if (st != 0)
1209 goto cleanup;
1210 free_berdata(bersecretkey);
1211 bersecretkey = NULL;
1212 }
1213
1214 if (entry->mask & KADM5_KEY_DATA || entry->mask & KADM5_KVNO) {
1215 krb5_kvno mkvno;
1216
1217 if ((st=krb5_dbe_lookup_mkvno(context, entry, &mkvno)) != 0)
1218 goto cleanup;
1219 bersecretkey = krb5_encode_krbsecretkey (entry->key_data,
1220 entry->n_key_data, mkvno);
1221
1222 if (bersecretkey == NULL) {
1223 st = ENOMEM;
1224 goto cleanup;
1225 }
1226 /* An empty list of bervals is only accepted for modify operations,
1227 * not add operations. */
1228 if (bersecretkey[0] != NULL || !create_standalone) {
1229 st = krb5_add_ber_mem_ldap_mod(&mods, "krbprincipalkey",
1230 LDAP_MOD_REPLACE | LDAP_MOD_BVALUES,
1231 bersecretkey);
1232 if (st != 0)
1233 goto cleanup;
1234 }
1235
1236 /* Update last password change whenever a new key is set */
1237 {
1238 krb5_timestamp last_pw_changed;
1239 if ((st=krb5_dbe_lookup_last_pwd_change(context, entry,
1240 &last_pw_changed)) != 0)
1241 goto cleanup;
1242
1243 memset(strval, 0, sizeof(strval));
1244 if ((strval[0] = getstringtime(last_pw_changed)) == NULL)
1245 goto cleanup;
1246
1247 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastPwdChange",
1248 LDAP_MOD_REPLACE, strval)) != 0) {
1249 free (strval[0]);
1250 goto cleanup;
1251 }
1252 free (strval[0]);
1253 }
1254
1255 } /* Modify Key data ends here */
1256
1257 /* Set tl_data */
1258 if (entry->tl_data != NULL) {
1259 int count = 0;
1260 struct berval **ber_tl_data = NULL;
1261 krb5_tl_data *ptr;
1262 krb5_timestamp unlock_time;
1263
1264 /* Normalize required auth indicators, but also store them as string
1265 * attributes within krbExtraData. */
1266 st = update_ldap_mod_auth_ind(context, entry, &mods);
1267 if (st != 0)
1268 goto cleanup;
1269
1270 for (ptr = entry->tl_data; ptr != NULL; ptr = ptr->tl_data_next) {
1271 if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE
1272 #ifdef SECURID
1273 || ptr->tl_data_type == KRB5_TL_DB_ARGS
1274 #endif
1275 || ptr->tl_data_type == KRB5_TL_KADM_DATA
1276 || ptr->tl_data_type == KDB_TL_USER_INFO
1277 || ptr->tl_data_type == KRB5_TL_CONSTRAINED_DELEGATION_ACL
1278 || ptr->tl_data_type == KRB5_TL_LAST_ADMIN_UNLOCK)
1279 continue;
1280 count++;
1281 }
1282 if (count != 0) {
1283 int j;
1284 ber_tl_data = (struct berval **) calloc (count + 1,
1285 sizeof (struct berval*));
1286 if (ber_tl_data == NULL) {
1287 st = ENOMEM;
1288 goto cleanup;
1289 }
1290 for (j = 0, ptr = entry->tl_data; ptr != NULL; ptr = ptr->tl_data_next) {
1291 /* Ignore tl_data that are stored in separate directory
1292 * attributes */
1293 if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE
1294 #ifdef SECURID
1295 || ptr->tl_data_type == KRB5_TL_DB_ARGS
1296 #endif
1297 || ptr->tl_data_type == KRB5_TL_KADM_DATA
1298 || ptr->tl_data_type == KDB_TL_USER_INFO
1299 || ptr->tl_data_type == KRB5_TL_CONSTRAINED_DELEGATION_ACL
1300 || ptr->tl_data_type == KRB5_TL_LAST_ADMIN_UNLOCK)
1301 continue;
1302 if ((st = tl_data2berval (ptr, &ber_tl_data[j])) != 0)
1303 break;
1304 j++;
1305 }
1306 if (st == 0) {
1307 ber_tl_data[count] = NULL;
1308 st=krb5_add_ber_mem_ldap_mod(&mods, "krbExtraData",
1309 LDAP_MOD_REPLACE |
1310 LDAP_MOD_BVALUES, ber_tl_data);
1311 }
1312 free_berdata(ber_tl_data);
1313 if (st != 0)
1314 goto cleanup;
1315 }
1316 if ((st=krb5_dbe_lookup_last_admin_unlock(context, entry,
1317 &unlock_time)) != 0)
1318 goto cleanup;
1319 if (unlock_time != 0) {
1320 /* Update last admin unlock */
1321 memset(strval, 0, sizeof(strval));
1322 if ((strval[0] = getstringtime(unlock_time)) == NULL)
1323 goto cleanup;
1324
1325 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastAdminUnlock",
1326 LDAP_MOD_REPLACE, strval)) != 0) {
1327 free (strval[0]);
1328 goto cleanup;
1329 }
1330 free (strval[0]);
1331 }
1332 }
1333
1334 /* Directory specific attribute */
1335 if (xargs.tktpolicydn != NULL) {
1336 int tmask=0;
1337
1338 if (strlen(xargs.tktpolicydn) != 0) {
1339 st = checkattributevalue(ld, xargs.tktpolicydn, "objectclass", policyclass, &tmask);
1340 CHECK_CLASS_VALIDITY(st, tmask, _("ticket policy object value: "));
1341
1342 strval[0] = xargs.tktpolicydn;
1343 strval[1] = NULL;
1344 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_REPLACE, strval)) != 0)
1345 goto cleanup;
1346
1347 } else {
1348 /* if xargs.tktpolicydn is a empty string, then delete
1349 * already existing krbticketpolicyreference attr */
1350 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_DELETE, NULL)) != 0)
1351 goto cleanup;
1352 }
1353
1354 }
1355
1356 if (establish_links == TRUE) {
1357 memset(strval, 0, sizeof(strval));
1358 strval[0] = xargs.linkdn;
1359 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbObjectReferences", LDAP_MOD_REPLACE, strval)) != 0)
1360 goto cleanup;
1361 }
1362
1363 /*
1364 * in case mods is NULL then return
1365 * not sure but can happen in a modprinc
1366 * so no need to return an error
1367 * addprinc will at least have the principal name
1368 * and the keys passed in
1369 */
1370 if (mods == NULL)
1371 goto cleanup;
1372
1373 if (create_standalone == TRUE) {
1374 memset(strval, 0, sizeof(strval));
1375 strval[0] = "krbprincipal";
1376 strval[1] = "krbprincipalaux";
1377 strval[2] = "krbTicketPolicyAux";
1378
1379 if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
1380 goto cleanup;
1381
1382 st = ldap_add_ext_s(ld, standalone_principal_dn, mods, NULL, NULL);
1383 if (st == LDAP_ALREADY_EXISTS && entry->mask & KADM5_LOAD) {
1384 /* a load operation must replace an existing entry */
1385 st = ldap_delete_ext_s(ld, standalone_principal_dn, NULL, NULL);
1386 if (st != LDAP_SUCCESS) {
1387 snprintf(errbuf, sizeof(errbuf),
1388 _("Principal delete failed (trying to replace "
1389 "entry): %s"), ldap_err2string(st));
1390 st = translate_ldap_error (st, OP_ADD);
1391 k5_setmsg(context, st, "%s", errbuf);
1392 goto cleanup;
1393 } else {
1394 st = ldap_add_ext_s(ld, standalone_principal_dn, mods, NULL, NULL);
1395 }
1396 }
1397 if (st != LDAP_SUCCESS) {
1398 snprintf(errbuf, sizeof(errbuf), _("Principal add failed: %s"),
1399 ldap_err2string(st));
1400 st = translate_ldap_error (st, OP_ADD);
1401 k5_setmsg(context, st, "%s", errbuf);
1402 goto cleanup;
1403 }
1404 } else {
1405 /*
1406 * Here existing ldap object is modified and can be related
1407 * to any attribute, so always ensure that the ldap
1408 * object is extended with all the kerberos related
1409 * objectclasses so that there are no constraint
1410 * violations.
1411 */
1412 {
1413 char *attrvalues[] = {"krbprincipalaux", "krbTicketPolicyAux", NULL};
1414 int p, q, r=0, amask=0;
1415
1416 if ((st=checkattributevalue(ld, (xargs.dn) ? xargs.dn : principal_dn,
1417 "objectclass", attrvalues, &amask)) != 0)
1418 goto cleanup;
1419
1420 memset(strval, 0, sizeof(strval));
1421 for (p=1, q=0; p<=2; p<<=1, ++q) {
1422 if ((p & amask) == 0)
1423 strval[r++] = attrvalues[q];
1424 }
1425 if (r != 0) {
1426 if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
1427 goto cleanup;
1428 }
1429 }
1430 if (xargs.dn != NULL)
1431 st=ldap_modify_ext_s(ld, xargs.dn, mods, NULL, NULL);
1432 else
1433 st = ldap_modify_ext_s(ld, principal_dn, mods, NULL, NULL);
1434
1435 if (st != LDAP_SUCCESS) {
1436 snprintf(errbuf, sizeof(errbuf), _("User modification failed: %s"),
1437 ldap_err2string(st));
1438 st = translate_ldap_error (st, OP_MOD);
1439 k5_setmsg(context, st, "%s", errbuf);
1440 goto cleanup;
1441 }
1442
1443 if (entry->mask & KADM5_FAIL_AUTH_COUNT_INCREMENT)
1444 entry->fail_auth_count++;
1445 }
1446
1447 cleanup:
1448 free(filter);
1449 if (user)
1450 free(user);
1451
1452 if (filtuser)
1453 free(filtuser);
1454
1455 free_xargs(xargs);
1456
1457 if (standalone_principal_dn)
1458 free(standalone_principal_dn);
1459
1460 if (principal_dn)
1461 free (principal_dn);
1462
1463 if (polname != NULL)
1464 free(polname);
1465
1466 for (tre = 0; tre < ntrees; tre++)
1467 free(subtreelist[tre]);
1468 free(subtreelist);
1469
1470 if (subtree)
1471 free (subtree);
1472
1473 if (bersecretkey) {
1474 for (l=0; bersecretkey[l]; ++l) {
1475 if (bersecretkey[l]->bv_val)
1476 free (bersecretkey[l]->bv_val);
1477 free (bersecretkey[l]);
1478 }
1479 free (bersecretkey);
1480 }
1481
1482 if (keys)
1483 free (keys);
1484
1485 ldap_mods_free(mods, 1);
1486 ldap_osa_free_princ_ent(&princ_ent);
1487 ldap_msgfree(result);
1488 krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
1489 return(st);
1490 }
1491
1492 krb5_error_code
krb5_read_tkt_policy(krb5_context context,krb5_ldap_context * ldap_context,krb5_db_entry * entries,char * policy)1493 krb5_read_tkt_policy(krb5_context context, krb5_ldap_context *ldap_context,
1494 krb5_db_entry *entries, char *policy)
1495 {
1496 krb5_error_code st=0;
1497 int mask=0, omask=0;
1498 int tkt_mask=(KDB_MAX_LIFE_ATTR | KDB_MAX_RLIFE_ATTR | KDB_TKT_FLAGS_ATTR);
1499 krb5_ldap_policy_params *tktpoldnparam=NULL;
1500
1501 if ((st=krb5_get_attributes_mask(context, entries, &mask)) != 0)
1502 goto cleanup;
1503
1504 if ((mask & tkt_mask) == tkt_mask)
1505 goto cleanup;
1506
1507 if (policy != NULL) {
1508 st = krb5_ldap_read_policy(context, policy, &tktpoldnparam, &omask);
1509 if (st && st != KRB5_KDB_NOENTRY) {
1510 k5_prependmsg(context, st, _("Error reading ticket policy"));
1511 goto cleanup;
1512 }
1513
1514 st = 0; /* reset the return status */
1515 }
1516
1517 if ((mask & KDB_MAX_LIFE_ATTR) == 0) {
1518 if ((omask & KDB_MAX_LIFE_ATTR) == KDB_MAX_LIFE_ATTR)
1519 entries->max_life = tktpoldnparam->maxtktlife;
1520 else if (ldap_context->lrparams->max_life)
1521 entries->max_life = ldap_context->lrparams->max_life;
1522 }
1523
1524 if ((mask & KDB_MAX_RLIFE_ATTR) == 0) {
1525 if ((omask & KDB_MAX_RLIFE_ATTR) == KDB_MAX_RLIFE_ATTR)
1526 entries->max_renewable_life = tktpoldnparam->maxrenewlife;
1527 else if (ldap_context->lrparams->max_renewable_life)
1528 entries->max_renewable_life = ldap_context->lrparams->max_renewable_life;
1529 }
1530
1531 if ((mask & KDB_TKT_FLAGS_ATTR) == 0) {
1532 if ((omask & KDB_TKT_FLAGS_ATTR) == KDB_TKT_FLAGS_ATTR)
1533 entries->attributes = tktpoldnparam->tktflags;
1534 else if (ldap_context->lrparams->tktflags)
1535 entries->attributes |= ldap_context->lrparams->tktflags;
1536 }
1537 krb5_ldap_free_policy(context, tktpoldnparam);
1538
1539 cleanup:
1540 return st;
1541 }
1542
1543 static void
free_ldap_seqof_key_data(ldap_seqof_key_data * keysets,krb5_int16 n_keysets)1544 free_ldap_seqof_key_data(ldap_seqof_key_data *keysets, krb5_int16 n_keysets)
1545 {
1546 int i;
1547
1548 if (keysets == NULL)
1549 return;
1550
1551 for (i = 0; i < n_keysets; i++)
1552 k5_free_key_data(keysets[i].n_key_data, keysets[i].key_data);
1553 free(keysets);
1554 }
1555
1556 /*
1557 * Decode keys from ldap search results.
1558 *
1559 * Arguments:
1560 * - bvalues
1561 * The ldap search results containing the key data.
1562 * - mkvno
1563 * The master kvno that the keys were encrypted with.
1564 * - keysets_out
1565 * The decoded keys in a ldap_seqof_key_data struct. Must be freed using
1566 * free_ldap_seqof_key_data.
1567 * - n_keysets_out
1568 * The number of entries in keys_out.
1569 * - total_keys_out
1570 * An optional argument that if given will be set to the total number of
1571 * keys found throughout all the entries: sum(keys_out.n_key_data)
1572 * May be NULL.
1573 */
1574 static krb5_error_code
decode_keys(struct berval ** bvalues,ldap_seqof_key_data ** keysets_out,krb5_int16 * n_keysets_out,krb5_int16 * total_keys_out)1575 decode_keys(struct berval **bvalues, ldap_seqof_key_data **keysets_out,
1576 krb5_int16 *n_keysets_out, krb5_int16 *total_keys_out)
1577 {
1578 krb5_error_code err = 0;
1579 krb5_int16 n_keys, i, ki, total_keys;
1580 ldap_seqof_key_data *keysets = NULL;
1581
1582 *keysets_out = NULL;
1583 *n_keysets_out = 0;
1584 if (total_keys_out)
1585 *total_keys_out = 0;
1586
1587 /* Precount the number of keys. */
1588 for (n_keys = 0, i = 0; bvalues[i] != NULL; i++) {
1589 if (bvalues[i]->bv_len > 0)
1590 n_keys++;
1591 }
1592
1593 keysets = k5calloc(n_keys, sizeof(ldap_seqof_key_data), &err);
1594 if (keysets == NULL)
1595 goto cleanup;
1596 memset(keysets, 0, n_keys * sizeof(ldap_seqof_key_data));
1597
1598 for (i = 0, ki = 0, total_keys = 0; bvalues[i] != NULL; i++) {
1599 krb5_data in;
1600
1601 if (bvalues[i]->bv_len == 0)
1602 continue;
1603 in.length = bvalues[i]->bv_len;
1604 in.data = bvalues[i]->bv_val;
1605
1606 err = asn1_decode_sequence_of_keys(&in, &keysets[ki]);
1607 if (err)
1608 goto cleanup;
1609
1610 if (total_keys_out)
1611 total_keys += keysets[ki].n_key_data;
1612 ki++;
1613 }
1614
1615 if (total_keys_out)
1616 *total_keys_out = total_keys;
1617
1618 *n_keysets_out = n_keys;
1619 *keysets_out = keysets;
1620 keysets = NULL;
1621 n_keys = 0;
1622
1623 cleanup:
1624 free_ldap_seqof_key_data(keysets, n_keys);
1625 return err;
1626 }
1627
1628 krb5_error_code
krb5_decode_krbsecretkey(krb5_context context,krb5_db_entry * entries,struct berval ** bvalues,krb5_kvno * mkvno)1629 krb5_decode_krbsecretkey(krb5_context context, krb5_db_entry *entries,
1630 struct berval **bvalues, krb5_kvno *mkvno)
1631 {
1632 krb5_key_data *key_data = NULL, *tmp;
1633 krb5_error_code err = 0;
1634 ldap_seqof_key_data *keysets = NULL;
1635 krb5_int16 i, n_keysets = 0, total_keys = 0;
1636
1637 err = decode_keys(bvalues, &keysets, &n_keysets, &total_keys);
1638 if (err != 0) {
1639 k5_prependmsg(context, err,
1640 _("unable to decode stored principal key data"));
1641 goto cleanup;
1642 }
1643
1644 key_data = k5calloc(total_keys, sizeof(krb5_key_data), &err);
1645 if (key_data == NULL)
1646 goto cleanup;
1647 memset(key_data, 0, total_keys * sizeof(krb5_key_data));
1648
1649 if (n_keysets > 0)
1650 *mkvno = keysets[0].mkvno;
1651
1652 /* Transfer key data values from keysets to a flat list in entries. */
1653 tmp = key_data;
1654 for (i = 0; i < n_keysets; i++) {
1655 memcpy(tmp, keysets[i].key_data,
1656 sizeof(krb5_key_data) * keysets[i].n_key_data);
1657 tmp += keysets[i].n_key_data;
1658 keysets[i].n_key_data = 0;
1659 }
1660 entries->n_key_data = total_keys;
1661 entries->key_data = key_data;
1662 key_data = NULL;
1663
1664 cleanup:
1665 free_ldap_seqof_key_data(keysets, n_keysets);
1666 k5_free_key_data(total_keys, key_data);
1667 return err;
1668 }
1669
1670 static int
compare_osa_pw_hist_ent(const void * left_in,const void * right_in)1671 compare_osa_pw_hist_ent(const void *left_in, const void *right_in)
1672 {
1673 int kvno_left, kvno_right;
1674 osa_pw_hist_ent *left = (osa_pw_hist_ent *)left_in;
1675 osa_pw_hist_ent *right = (osa_pw_hist_ent *)right_in;
1676
1677 kvno_left = left->n_key_data ? left->key_data[0].key_data_kvno : 0;
1678 kvno_right = right->n_key_data ? right->key_data[0].key_data_kvno : 0;
1679 return kvno_left - kvno_right;
1680 }
1681
1682 /*
1683 * Decode the key history entries from an LDAP search.
1684 *
1685 * NOTE: the caller must free princ_ent->old_keys even on error.
1686 */
1687 krb5_error_code
krb5_decode_histkey(krb5_context context,struct berval ** bvalues,osa_princ_ent_rec * princ_ent)1688 krb5_decode_histkey(krb5_context context, struct berval **bvalues,
1689 osa_princ_ent_rec *princ_ent)
1690 {
1691 krb5_error_code err = 0;
1692 krb5_int16 i, n_keysets = 0;
1693 ldap_seqof_key_data *keysets = NULL;
1694
1695 err = decode_keys(bvalues, &keysets, &n_keysets, NULL);
1696 if (err != 0) {
1697 k5_prependmsg(context, err,
1698 _("unable to decode stored principal pw history"));
1699 goto cleanup;
1700 }
1701
1702 princ_ent->old_keys = k5calloc(n_keysets, sizeof(osa_pw_hist_ent), &err);
1703 if (princ_ent->old_keys == NULL)
1704 goto cleanup;
1705 princ_ent->old_key_len = n_keysets;
1706
1707 if (n_keysets > 0)
1708 princ_ent->admin_history_kvno = keysets[0].mkvno;
1709
1710 /* Transfer key data pointers from keysets to princ_ent. */
1711 for (i = 0; i < n_keysets; i++) {
1712 princ_ent->old_keys[i].n_key_data = keysets[i].n_key_data;
1713 princ_ent->old_keys[i].key_data = keysets[i].key_data;
1714 keysets[i].n_key_data = 0;
1715 keysets[i].key_data = NULL;
1716 }
1717
1718 /* Sort the principal entries by kvno in ascending order. */
1719 qsort(princ_ent->old_keys, princ_ent->old_key_len, sizeof(osa_pw_hist_ent),
1720 &compare_osa_pw_hist_ent);
1721
1722 princ_ent->aux_attributes |= KADM5_KEY_HIST;
1723
1724 /* Set the next key to the end of the list. The queue will be lengthened
1725 * if it isn't full yet; the first entry will be replaced if it is full. */
1726 princ_ent->old_key_next = princ_ent->old_key_len;
1727
1728 cleanup:
1729 free_ldap_seqof_key_data(keysets, n_keysets);
1730 return err;
1731 }
1732
1733 static char *
getstringtime(krb5_timestamp epochtime)1734 getstringtime(krb5_timestamp epochtime)
1735 {
1736 struct tm tme;
1737 char *strtime=NULL;
1738 time_t posixtime = ts2tt(epochtime);
1739
1740 if (gmtime_r(&posixtime, &tme) == NULL)
1741 return NULL;
1742
1743 strtime = calloc(50, 1);
1744 if (strtime == NULL)
1745 return NULL;
1746 if (strftime(strtime, 50, "%Y%m%d%H%M%SZ", &tme) == 0) {
1747 free(strtime);
1748 return NULL;
1749 }
1750 return strtime;
1751 }
1752