1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c */
4 * Copyright (C) 2016 by the Massachusetts Institute of Technology.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * * Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
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
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.
33 * Copyright (c) 2004-2005, Novell, Inc.
34 * All rights reserved.
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions are met:
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.
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.
60 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
61 * Use is subject to license terms.
64 #include "ldap_main.h"
66 #include "ldap_principal.h"
67 #include "princ_xdr.h"
68 #include "ldap_tkt_policy.h"
69 #include "ldap_pwd_policy.h"
71 #include <kadm5/admin.h>
74 extern char* principal_attributes[];
75 extern char* max_pwd_life_attr[];
78 getstringtime(krb5_timestamp);
81 berval2tl_data(struct berval *in, krb5_tl_data **out)
83 *out = (krb5_tl_data *) malloc (sizeof (krb5_tl_data));
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) {
95 UNSTORE16_INT (in->bv_val, (*out)->tl_data_type);
96 memcpy ((*out)->tl_data_contents, in->bv_val + 2, (*out)->tl_data_length);
102 * look up a principal in the directory.
106 krb5_ldap_get_principal(krb5_context context, krb5_const_principal searchfor,
107 unsigned int flags, krb5_db_entry **entry_ptr)
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;
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;
124 /* Clear the global error string */
125 krb5_clear_error_message(context);
127 if (searchfor == NULL)
130 dal_handle = context->dal_handle;
131 ldap_context = (krb5_ldap_context *) dal_handle->db_context;
133 CHECK_LDAP_HANDLE(ldap_context);
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"));
141 if ((st=krb5_unparse_name(context, searchfor, &user)) != 0)
144 if ((st=krb5_ldap_unparse_principal_name(user)) != 0)
147 filtuser = ldap_filter_correct(user);
148 if (filtuser == NULL) {
153 princlen = strlen(FILTER) + strlen(filtuser) + 2 + 1; /* 2 for closing brackets */
154 if ((filter = malloc(princlen)) == NULL) {
158 snprintf(filter, princlen, FILTER"%s))", filtuser);
160 if ((st = krb5_get_subtree_info(ldap_context, &subtree, &ntrees)) != 0)
164 for (tree=0; tree < ntrees && !found; ++tree) {
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)) {
169 /* get the associated directory user information */
170 if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
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
177 for (i=0; values[i] != NULL; ++i) {
178 if (strcmp(values[i], user) == 0) {
183 ldap_value_free(values);
185 if (!found) /* no matching principal found */
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 if (flags & KRB5_KDB_FLAG_ALIAS_OK) {
193 st = krb5_ldap_parse_principal_name(values[0], &cname);
196 st = krb5_parse_name(context, cname, &cprinc);
199 } else /* No canonicalization, so don't return aliases. */
202 ldap_value_free(values);
207 entry = k5alloc(sizeof(*entry), &st);
210 if ((st = populate_krb5_db_entry(context, ldap_context, ld, ent,
211 cprinc ? cprinc : searchfor,
215 ldap_msgfree(result);
217 } /* for (tree=0 ... */
223 st = KRB5_KDB_NOENTRY;
226 ldap_msgfree(result);
227 krb5_db_free_principal(context, entry);
233 for (; ntrees; --ntrees)
234 if (subtree[ntrees-1])
235 free (subtree[ntrees-1]);
239 if (ldap_server_handle)
240 krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
252 krb5_free_principal(context, cprinc);
257 typedef enum{ ADD_PRINCIPAL, MODIFY_PRINCIPAL } OPERATION;
259 * ptype is creating confusions. Additionally the logic
260 * surronding ptype is redundunt and can be achevied
261 * with the help of dn and containerdn members.
262 * so dropping the ptype member
265 typedef struct _xargs_t {
268 krb5_boolean dn_from_kbd;
274 free_xargs(xargs_t xargs)
280 if (xargs.containerdn)
281 free (xargs.containerdn);
282 if (xargs.tktpolicydn)
283 free (xargs.tktpolicydn);
286 static krb5_error_code
287 process_db_args(krb5_context context, char **db_args, xargs_t *xargs,
291 krb5_error_code st=0;
292 char *arg=NULL, *arg_val=NULL;
294 unsigned int arg_val_len=0;
297 for (i=0; db_args[i]; ++i) {
298 arg = strtok_r(db_args[i], "=", &arg_val);
299 arg = (arg != NULL) ? arg : "";
300 if (strcmp(arg, TKTPOLICY_ARG) == 0) {
301 dptr = &xargs->tktpolicydn;
303 if (strcmp(arg, USERDN_ARG) == 0) {
304 if (optype == MODIFY_PRINCIPAL ||
305 xargs->dn != NULL || xargs->containerdn != NULL ||
306 xargs->linkdn != NULL) {
308 k5_setmsg(context, st, _("%s option not supported"),
313 } else if (strcmp(arg, CONTAINERDN_ARG) == 0) {
314 if (optype == MODIFY_PRINCIPAL ||
315 xargs->dn != NULL || xargs->containerdn != NULL) {
317 k5_setmsg(context, st, _("%s option not supported"),
321 dptr = &xargs->containerdn;
322 } else if (strcmp(arg, LINKDN_ARG) == 0) {
323 if (xargs->dn != NULL || xargs->linkdn != NULL) {
325 k5_setmsg(context, st, _("%s option not supported"),
329 dptr = &xargs->linkdn;
332 k5_setmsg(context, st, _("unknown option: %s"), arg);
336 xargs->dn_from_kbd = TRUE;
337 if (arg_val == NULL || strlen(arg_val) == 0) {
339 k5_setmsg(context, st, _("%s option value missing"), arg);
344 if (arg_val == NULL) {
346 k5_setmsg(context, st, _("%s option value missing"), arg);
349 arg_val_len = strlen(arg_val) + 1;
351 if (strcmp(arg, TKTPOLICY_ARG) == 0) {
352 if ((st = krb5_ldap_name_to_policydn (context,
357 *dptr = k5memdup(arg_val, arg_val_len, &st);
368 krb5int_access accessor;
370 static krb5_error_code
371 asn1_encode_sequence_of_keys(krb5_key_data *key_data, krb5_int16 n_key_data,
372 krb5_int32 mkvno, krb5_data **code)
375 ldap_seqof_key_data val;
378 * This should be pushed back into other library initialization
381 err = kldap_ensure_initialized ();
385 val.key_data = key_data;
386 val.n_key_data = n_key_data;
388 val.kvno = key_data[0].key_data_kvno;
390 return accessor.asn1_ldap_encode_sequence_of_keys(&val, code);
393 static krb5_error_code
394 asn1_decode_sequence_of_keys(krb5_data *in, ldap_seqof_key_data *out)
397 ldap_seqof_key_data *p;
400 memset(out, 0, sizeof(*out));
403 * This should be pushed back into other library initialization
406 err = kldap_ensure_initialized ();
410 err = accessor.asn1_ldap_decode_sequence_of_keys(in, &p);
414 /* Set kvno and key_data_ver in each key_data element. */
415 for (i = 0; i < p->n_key_data; i++) {
416 p->key_data[i].key_data_kvno = p->kvno;
417 /* The decoder sets key_data_ver to 1 if no salt is present, but leaves
418 * it at 0 if salt is present. */
419 if (p->key_data[i].key_data_ver == 0)
420 p->key_data[i].key_data_ver = 2;
429 * Free a NULL-terminated struct berval *array[] and all its contents.
430 * Does not set array to NULL after freeing it.
433 free_berdata(struct berval **array)
438 for (i = 0; array[i] != NULL; i++) {
439 if (array[i]->bv_val != NULL)
440 free(array[i]->bv_val);
448 * Encode krb5_key_data into a berval struct for insertion into LDAP.
450 static krb5_error_code
451 encode_keys(krb5_key_data *key_data_in, int n_key_data, krb5_kvno mkvno,
452 struct berval **bval_out)
454 krb5_error_code err = 0;
456 krb5_key_data *key_data = NULL;
457 struct berval *bval = NULL;
461 if (n_key_data <= 0) {
466 /* Make a shallow copy of the key data so we can alter it. */
467 key_data = k5calloc(n_key_data, sizeof(*key_data), &err);
468 if (key_data == NULL)
470 memcpy(key_data, key_data_in, n_key_data * sizeof(*key_data));
472 /* Unpatched krb5 1.11 and 1.12 cannot decode KrbKey sequences with no salt
473 * field. For compatibility, always encode a salt field. */
474 for (i = 0; i < n_key_data; i++) {
475 if (key_data[i].key_data_ver == 1) {
476 key_data[i].key_data_ver = 2;
477 key_data[i].key_data_type[1] = KRB5_KDB_SALTTYPE_NORMAL;
478 key_data[i].key_data_length[1] = 0;
479 key_data[i].key_data_contents[1] = NULL;
483 bval = k5alloc(sizeof(struct berval), &err);
487 err = asn1_encode_sequence_of_keys(key_data, n_key_data, mkvno, &code);
491 /* Steal the data pointer from code for bval and discard code. */
492 bval->bv_len = code->length;
493 bval->bv_val = code->data;
505 /* Decoding ASN.1 encoded key */
507 krb5_encode_krbsecretkey(krb5_key_data *key_data, int n_key_data,
510 struct berval **ret = NULL;
512 int num_versions = 0;
514 krb5_error_code err = 0;
519 /* Find the number of key versions */
520 if (n_key_data > 0) {
521 for (i = 0, num_versions = 1; i < n_key_data - 1; i++) {
522 if (key_data[i].key_data_kvno != key_data[i + 1].key_data_kvno)
527 ret = calloc(num_versions + 1, sizeof(struct berval *));
532 ret[num_versions] = NULL;
534 /* n_key_data may be 0 if a principal is created without a key. */
538 currkvno = key_data[0].key_data_kvno;
539 for (i = 0, last = 0, j = 0; i < n_key_data; i++) {
540 if (i == n_key_data - 1 || key_data[i + 1].key_data_kvno != currkvno) {
541 err = encode_keys(key_data + last, (krb5_int16)i - last + 1, mkvno,
548 if (i < n_key_data - 1)
549 currkvno = key_data[i + 1].key_data_kvno;
563 * Encode a principal's key history for insertion into ldap.
565 static struct berval **
566 krb5_encode_histkey(osa_princ_ent_rec *princ_ent)
569 krb5_error_code err = 0;
570 struct berval **ret = NULL;
572 if (princ_ent->old_key_len <= 0)
575 ret = k5calloc(princ_ent->old_key_len + 1, sizeof(struct berval *), &err);
579 for (i = 0; i < princ_ent->old_key_len; i++) {
580 if (princ_ent->old_keys[i].n_key_data <= 0) {
584 err = encode_keys(princ_ent->old_keys[i].key_data,
585 princ_ent->old_keys[i].n_key_data,
586 princ_ent->admin_history_kvno, &ret[i]);
591 ret[princ_ent->old_key_len] = NULL;
602 static krb5_error_code
603 tl_data2berval (krb5_tl_data *in, struct berval **out)
605 *out = (struct berval *) malloc (sizeof (struct berval));
609 (*out)->bv_len = in->tl_data_length + 2;
610 (*out)->bv_val = (char *) malloc ((*out)->bv_len);
611 if ((*out)->bv_val == NULL) {
616 STORE16_INT((*out)->bv_val, in->tl_data_type);
617 memcpy ((*out)->bv_val + 2, in->tl_data_contents, in->tl_data_length);
622 /* Parse the "require_auth" string for auth indicators, adding them to the
623 * krbPrincipalAuthInd attribute. */
624 static krb5_error_code
625 update_ldap_mod_auth_ind(krb5_context context, krb5_db_entry *entry,
630 char *auth_ind = NULL;
631 char *strval[10] = {};
632 char *ai, *ai_save = NULL;
633 int sv_num = sizeof(strval) / sizeof(*strval);
635 ret = krb5_dbe_get_string(context, entry, KRB5_KDB_SK_REQUIRE_AUTH,
637 if (ret || auth_ind == NULL)
640 ai = strtok_r(auth_ind, " ", &ai_save);
641 while (ai != NULL && i < sv_num) {
643 ai = strtok_r(NULL, " ", &ai_save);
646 ret = krb5_add_str_mem_ldap_mod(mods, "krbPrincipalAuthInd",
647 LDAP_MOD_REPLACE, strval);
650 krb5_dbe_free_string(context, auth_ind);
655 krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry,
658 int l=0, kerberos_principal_object_type=0;
659 unsigned int ntrees=0, tre=0;
660 krb5_error_code st=0, tempst=0;
662 LDAPMessage *result=NULL, *ent=NULL;
663 char **subtreelist = NULL;
664 char *user=NULL, *subtree=NULL, *principal_dn=NULL;
665 char **values=NULL, *strval[10]={NULL}, errbuf[1024];
667 struct berval **bersecretkey=NULL;
669 krb5_boolean create_standalone=FALSE;
670 krb5_boolean krb_identity_exists=FALSE, establish_links=FALSE;
671 char *standalone_principal_dn=NULL;
672 krb5_tl_data *tl_data=NULL;
673 krb5_key_data **keys=NULL;
674 kdb5_dal_handle *dal_handle=NULL;
675 krb5_ldap_context *ldap_context=NULL;
676 krb5_ldap_server_handle *ldap_server_handle=NULL;
677 osa_princ_ent_rec princ_ent = {0};
679 char *polname = NULL;
681 krb5_boolean found_entry = FALSE;
683 /* Clear the global error string */
684 krb5_clear_error_message(context);
687 if (ldap_context->lrparams == NULL || ldap_context->container_dn == NULL)
690 /* get ldap handle */
693 if (!is_principal_in_realm(ldap_context, entry->princ)) {
695 k5_setmsg(context, st,
696 _("Principal does not belong to the default realm"));
700 /* get the principal information to act on */
701 if (((st=krb5_unparse_name(context, entry->princ, &user)) != 0) ||
702 ((st=krb5_ldap_unparse_principal_name(user)) != 0))
704 filtuser = ldap_filter_correct(user);
705 if (filtuser == NULL) {
710 /* Identity the type of operation, it can be
711 * add principal or modify principal.
712 * hack if the entry->mask has KRB_PRINCIPAL flag set
713 * then it is a add operation
715 if (entry->mask & KADM5_PRINCIPAL)
716 optype = ADD_PRINCIPAL;
718 optype = MODIFY_PRINCIPAL;
720 if (((st=krb5_get_princ_type(context, entry, &kerberos_principal_object_type)) != 0) ||
721 ((st=krb5_get_userdn(context, entry, &principal_dn)) != 0))
724 if ((st=process_db_args(context, db_args, &xargs, optype)) != 0)
727 if (entry->mask & KADM5_LOAD) {
728 unsigned int tree = 0;
732 /* A load operation is special, will do a mix-in (add krbprinc
733 * attrs to a non-krb object entry) if an object exists with a
734 * matching krbprincipalname attribute so try to find existing
735 * object and set principal_dn. This assumes that the
736 * krbprincipalname attribute is unique (only one object entry has
737 * a particular krbprincipalname attribute).
739 if (asprintf(&filter, FILTER"%s))", filtuser) < 0) {
745 /* get the current subtree list */
746 if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0)
750 /* search for entry with matching krbprincipalname attribute */
751 for (tree = 0; found_entry == FALSE && tree < ntrees; ++tree) {
752 if (principal_dn == NULL) {
753 LDAP_SEARCH_1(subtreelist[tree], ldap_context->lrparams->search_scope, filter, principal_attributes, IGNORE_STATUS);
755 /* just look for entry with principal_dn */
756 LDAP_SEARCH_1(principal_dn, LDAP_SCOPE_BASE, filter, principal_attributes, IGNORE_STATUS);
758 if (st == LDAP_SUCCESS) {
759 numlentries = ldap_count_entries(ld, result);
760 if (numlentries > 1) {
763 k5_setmsg(context, st,
764 _("operation can not continue, more than one "
765 "entry with principal name \"%s\" found"),
768 } else if (numlentries == 1) {
770 if (principal_dn == NULL) {
771 ent = ldap_first_entry(ld, result);
773 /* setting principal_dn will cause that entry to be modified further down */
774 if ((principal_dn = ldap_get_dn(ld, ent)) == NULL) {
775 ldap_get_option (ld, LDAP_OPT_RESULT_CODE, &st);
776 st = set_ldap_error (context, st, 0);
783 } else if (st != LDAP_NO_SUCH_OBJECT) {
784 /* could not perform search, return with failure */
785 st = set_ldap_error (context, st, 0);
789 ldap_msgfree(result);
792 * If it isn't found then assume a standalone princ entry is to
795 } /* end for (tree = 0; principal_dn == ... */
799 if (found_entry == FALSE && principal_dn != NULL) {
801 * if principal_dn is null then there is code further down to
802 * deal with setting standalone_principal_dn. Also note that
803 * this will set create_standalone true for
804 * non-mix-in entries which is okay if loading from a dump.
806 create_standalone = TRUE;
807 standalone_principal_dn = strdup(principal_dn);
808 CHECK_NULL(standalone_principal_dn);
810 } /* end if (entry->mask & KADM5_LOAD */
812 /* time to generate the DN information with the help of
813 * containerdn, principalcontainerreference or
814 * realmcontainerdn information
816 if (principal_dn == NULL && xargs.dn == NULL) { /* creation of standalone principal */
817 /* get the subtree information */
818 if (entry->princ->length == 2 && entry->princ->data[0].length == strlen("krbtgt") &&
819 strncmp(entry->princ->data[0].data, "krbtgt", entry->princ->data[0].length) == 0) {
820 /* if the principal is a inter-realm principal, always created in the realm container */
821 subtree = strdup(ldap_context->lrparams->realmdn);
822 } else if (xargs.containerdn) {
823 if ((st=checkattributevalue(ld, xargs.containerdn, NULL, NULL, NULL)) != 0) {
824 if (st == KRB5_KDB_NOENTRY || st == KRB5_KDB_CONSTRAINT_VIOLATION) {
827 k5_wrapmsg(context, ost, st, _("'%s' not found"),
832 subtree = strdup(xargs.containerdn);
833 } else if (ldap_context->lrparams->containerref && strlen(ldap_context->lrparams->containerref) != 0) {
835 * Here the subtree should be changed with
836 * principalcontainerreference attribute value
838 subtree = strdup(ldap_context->lrparams->containerref);
840 subtree = strdup(ldap_context->lrparams->realmdn);
844 if (asprintf(&standalone_principal_dn, "krbprincipalname=%s,%s",
845 filtuser, subtree) < 0)
846 standalone_principal_dn = NULL;
847 CHECK_NULL(standalone_principal_dn);
849 * free subtree when you are done using the subtree
850 * set the boolean create_standalone to TRUE
852 create_standalone = TRUE;
858 * If the DN information is presented by the user, time to
859 * validate the input to ensure that the DN falls under
860 * any of the subtrees
862 if (xargs.dn_from_kbd == TRUE) {
863 /* make sure the DN falls in the subtree */
864 int dnlen=0, subtreelen=0;
866 krb5_boolean outofsubtree=TRUE;
868 if (xargs.dn != NULL) {
870 } else if (xargs.linkdn != NULL) {
872 } else if (standalone_principal_dn != NULL) {
874 * Even though the standalone_principal_dn is constructed
875 * within this function, there is the containerdn input
876 * from the user that can become part of the it.
878 dn = standalone_principal_dn;
881 /* Get the current subtree list if we haven't already done so. */
882 if (subtreelist == NULL) {
883 st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees);
888 for (tre=0; tre<ntrees; ++tre) {
889 if (subtreelist[tre] == NULL || strlen(subtreelist[tre]) == 0) {
890 outofsubtree = FALSE;
894 subtreelen = strlen(subtreelist[tre]);
895 if ((dnlen >= subtreelen) && (strcasecmp((dn + dnlen - subtreelen), subtreelist[tre]) == 0)) {
896 outofsubtree = FALSE;
902 if (outofsubtree == TRUE) {
904 k5_setmsg(context, st, _("DN is out of the realm subtree"));
909 * dn value will be set either by dn, linkdn or the standalone_principal_dn
910 * In the first 2 cases, the dn should be existing and in the last case we
911 * are supposed to create the ldap object. so the below should not be
912 * executed for the last case.
915 if (standalone_principal_dn == NULL) {
917 * If the ldap object is missing, this results in an error.
921 * Search for krbprincipalname attribute here.
922 * This is to find if a kerberos identity is already present
923 * on the ldap object, in which case adding a kerberos identity
924 * on the ldap object should result in an error.
926 char *attributes[]={"krbticketpolicyreference", "krbprincipalname", NULL};
928 ldap_msgfree(result);
930 LDAP_SEARCH_1(dn, LDAP_SCOPE_BASE, 0, attributes, IGNORE_STATUS);
931 if (st == LDAP_SUCCESS) {
932 ent = ldap_first_entry(ld, result);
934 if ((values=ldap_get_values(ld, ent, "krbticketpolicyreference")) != NULL) {
935 ldap_value_free(values);
938 if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
939 krb_identity_exists = TRUE;
940 ldap_value_free(values);
944 st = set_ldap_error(context, st, OP_SEARCH);
951 * If xargs.dn is set then the request is to add a
952 * kerberos principal on a ldap object, but if
953 * there is one already on the ldap object this
954 * should result in an error.
957 if (xargs.dn != NULL && krb_identity_exists == TRUE) {
959 snprintf(errbuf, sizeof(errbuf),
960 _("ldap object is already kerberized"));
961 k5_setmsg(context, st, "%s", errbuf);
965 if (xargs.linkdn != NULL) {
967 * link information can be changed using modprinc.
968 * However, link information can be changed only on the
969 * standalone kerberos principal objects. A standalone
970 * kerberos principal object is of type krbprincipal
971 * structural objectclass.
973 * NOTE: kerberos principals on an ldap object can't be
974 * linked to other ldap objects.
976 if (optype == MODIFY_PRINCIPAL &&
977 kerberos_principal_object_type != KDB_STANDALONE_PRINCIPAL_OBJECT) {
979 snprintf(errbuf, sizeof(errbuf),
980 _("link information can not be set/updated as the "
981 "kerberos principal belongs to an ldap object"));
982 k5_setmsg(context, st, "%s", errbuf);
986 * Check the link information. If there is already a link
987 * existing then this operation is not allowed.
993 if ((st=krb5_get_linkdn(context, entry, &linkdns)) != 0) {
994 snprintf(errbuf, sizeof(errbuf),
995 _("Failed getting object references"));
996 k5_setmsg(context, st, "%s", errbuf);
999 if (linkdns != NULL) {
1001 snprintf(errbuf, sizeof(errbuf),
1002 _("kerberos principal is already linked to a ldap "
1004 k5_setmsg(context, st, "%s", errbuf);
1005 for (j=0; linkdns[j] != NULL; ++j)
1012 establish_links = TRUE;
1015 if (entry->mask & KADM5_LAST_SUCCESS) {
1016 memset(strval, 0, sizeof(strval));
1017 if ((strval[0]=getstringtime(entry->last_success)) == NULL)
1019 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastSuccessfulAuth", LDAP_MOD_REPLACE, strval)) != 0) {
1026 if (entry->mask & KADM5_LAST_FAILED) {
1027 memset(strval, 0, sizeof(strval));
1028 if ((strval[0]=getstringtime(entry->last_failed)) == NULL)
1030 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastFailedAuth", LDAP_MOD_REPLACE, strval)) != 0) {
1037 if (entry->mask & KADM5_FAIL_AUTH_COUNT) {
1038 krb5_kvno fail_auth_count;
1040 fail_auth_count = entry->fail_auth_count;
1041 if (entry->mask & KADM5_FAIL_AUTH_COUNT_INCREMENT)
1044 st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
1049 } else if (entry->mask & KADM5_FAIL_AUTH_COUNT_INCREMENT) {
1051 krb5_boolean has_fail_count;
1053 /* Check if the krbLoginFailedCount attribute exists. (Through
1054 * krb5 1.8.1, it wasn't set in new entries.) */
1055 st = krb5_get_attributes_mask(context, entry, &attr_mask);
1058 has_fail_count = ((attr_mask & KDB_FAIL_AUTH_COUNT_ATTR) != 0);
1061 * If the client library and server supports RFC 4525,
1062 * then use it to increment by one the value of the
1063 * krbLoginFailedCount attribute. Otherwise, assert the
1064 * (provided) old value by deleting it before adding.
1066 #ifdef LDAP_MOD_INCREMENT
1067 if (ldap_server_handle->server_info->modify_increment &&
1069 st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
1070 LDAP_MOD_INCREMENT, 1);
1074 #endif /* LDAP_MOD_INCREMENT */
1075 if (has_fail_count) {
1076 st = krb5_add_int_mem_ldap_mod(&mods,
1077 "krbLoginFailedCount",
1079 entry->fail_auth_count);
1083 st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
1085 entry->fail_auth_count + 1);
1088 #ifdef LDAP_MOD_INCREMENT
1091 } else if (optype == ADD_PRINCIPAL) {
1092 /* Initialize krbLoginFailedCount in new entries to help avoid a
1093 * race during the first failed login. */
1094 st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
1098 if (entry->mask & KADM5_MAX_LIFE) {
1099 if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxticketlife", LDAP_MOD_REPLACE, entry->max_life)) != 0)
1103 if (entry->mask & KADM5_MAX_RLIFE) {
1104 if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxrenewableage", LDAP_MOD_REPLACE,
1105 entry->max_renewable_life)) != 0)
1109 if (entry->mask & KADM5_ATTRIBUTES) {
1110 if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbticketflags", LDAP_MOD_REPLACE,
1111 entry->attributes)) != 0)
1115 if (entry->mask & KADM5_PRINCIPAL) {
1116 memset(strval, 0, sizeof(strval));
1118 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalname", LDAP_MOD_REPLACE, strval)) != 0)
1122 if (entry->mask & KADM5_PRINC_EXPIRE_TIME) {
1123 memset(strval, 0, sizeof(strval));
1124 if ((strval[0]=getstringtime(entry->expiration)) == NULL)
1126 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalexpiration", LDAP_MOD_REPLACE, strval)) != 0) {
1133 if (entry->mask & KADM5_PW_EXPIRATION) {
1134 memset(strval, 0, sizeof(strval));
1135 if ((strval[0]=getstringtime(entry->pw_expiration)) == NULL)
1137 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpasswordexpiration",
1146 if (entry->mask & KADM5_POLICY || entry->mask & KADM5_KEY_HIST) {
1147 memset(&princ_ent, 0, sizeof(princ_ent));
1148 for (tl_data=entry->tl_data; tl_data; tl_data=tl_data->tl_data_next) {
1149 if (tl_data->tl_data_type == KRB5_TL_KADM_DATA) {
1150 if ((st = krb5_lookup_tl_kadm_data(tl_data, &princ_ent)) != 0) {
1158 if (entry->mask & KADM5_POLICY) {
1159 if (princ_ent.aux_attributes & KADM5_POLICY) {
1160 memset(strval, 0, sizeof(strval));
1161 if ((st = krb5_ldap_name_to_policydn (context, princ_ent.policy, &polname)) != 0)
1163 strval[0] = polname;
1164 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, strval)) != 0)
1168 k5_setmsg(context, st, "Password policy value null");
1171 } else if (entry->mask & KADM5_LOAD && found_entry == TRUE) {
1173 * a load is special in that existing entries must have attrs that
1177 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, NULL)) != 0)
1181 if (entry->mask & KADM5_POLICY_CLR) {
1182 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_DELETE, NULL)) != 0)
1186 if (entry->mask & KADM5_KEY_HIST) {
1187 bersecretkey = krb5_encode_histkey(&princ_ent);
1188 if (bersecretkey == NULL) {
1193 st = krb5_add_ber_mem_ldap_mod(&mods, "krbpwdhistory",
1194 LDAP_MOD_REPLACE | LDAP_MOD_BVALUES,
1198 free_berdata(bersecretkey);
1199 bersecretkey = NULL;
1202 if (entry->mask & KADM5_KEY_DATA || entry->mask & KADM5_KVNO) {
1205 if ((st=krb5_dbe_lookup_mkvno(context, entry, &mkvno)) != 0)
1207 bersecretkey = krb5_encode_krbsecretkey (entry->key_data,
1208 entry->n_key_data, mkvno);
1210 if (bersecretkey == NULL) {
1214 /* An empty list of bervals is only accepted for modify operations,
1215 * not add operations. */
1216 if (bersecretkey[0] != NULL || !create_standalone) {
1217 st = krb5_add_ber_mem_ldap_mod(&mods, "krbprincipalkey",
1218 LDAP_MOD_REPLACE | LDAP_MOD_BVALUES,
1224 if (!(entry->mask & KADM5_PRINCIPAL)) {
1225 memset(strval, 0, sizeof(strval));
1226 if ((strval[0]=getstringtime(entry->pw_expiration)) == NULL)
1228 if ((st=krb5_add_str_mem_ldap_mod(&mods,
1229 "krbpasswordexpiration",
1230 LDAP_MOD_REPLACE, strval)) != 0) {
1237 /* Update last password change whenever a new key is set */
1239 krb5_timestamp last_pw_changed;
1240 if ((st=krb5_dbe_lookup_last_pwd_change(context, entry,
1241 &last_pw_changed)) != 0)
1244 memset(strval, 0, sizeof(strval));
1245 if ((strval[0] = getstringtime(last_pw_changed)) == NULL)
1248 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastPwdChange",
1249 LDAP_MOD_REPLACE, strval)) != 0) {
1256 } /* Modify Key data ends here */
1258 /* Auth indicators will also be stored in krbExtraData when processing
1260 st = update_ldap_mod_auth_ind(context, entry, &mods);
1265 if (entry->tl_data != NULL) {
1267 struct berval **ber_tl_data = NULL;
1269 krb5_timestamp unlock_time;
1270 for (ptr = entry->tl_data; ptr != NULL; ptr = ptr->tl_data_next) {
1271 if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE
1273 || ptr->tl_data_type == KRB5_TL_DB_ARGS
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)
1284 ber_tl_data = (struct berval **) calloc (count + 1,
1285 sizeof (struct berval*));
1286 if (ber_tl_data == NULL) {
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
1293 if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE
1295 || ptr->tl_data_type == KRB5_TL_DB_ARGS
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)
1302 if ((st = tl_data2berval (ptr, &ber_tl_data[j])) != 0)
1307 ber_tl_data[count] = NULL;
1308 st=krb5_add_ber_mem_ldap_mod(&mods, "krbExtraData",
1310 LDAP_MOD_BVALUES, ber_tl_data);
1312 free_berdata(ber_tl_data);
1316 if ((st=krb5_dbe_lookup_last_admin_unlock(context, entry,
1317 &unlock_time)) != 0)
1319 if (unlock_time != 0) {
1320 /* Update last admin unlock */
1321 memset(strval, 0, sizeof(strval));
1322 if ((strval[0] = getstringtime(unlock_time)) == NULL)
1325 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastAdminUnlock",
1326 LDAP_MOD_REPLACE, strval)) != 0) {
1334 /* Directory specific attribute */
1335 if (xargs.tktpolicydn != NULL) {
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: "));
1342 strval[0] = xargs.tktpolicydn;
1344 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_REPLACE, strval)) != 0)
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)
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)
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
1373 if (create_standalone == TRUE) {
1374 memset(strval, 0, sizeof(strval));
1375 strval[0] = "krbprincipal";
1376 strval[1] = "krbprincipalaux";
1377 strval[2] = "krbTicketPolicyAux";
1379 if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
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);
1394 st = ldap_add_ext_s(ld, standalone_principal_dn, mods, NULL, NULL);
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);
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
1413 char *attrvalues[] = {"krbprincipalaux", "krbTicketPolicyAux", NULL};
1414 int p, q, r=0, amask=0;
1416 if ((st=checkattributevalue(ld, (xargs.dn) ? xargs.dn : principal_dn,
1417 "objectclass", attrvalues, &amask)) != 0)
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];
1426 if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
1430 if (xargs.dn != NULL)
1431 st=ldap_modify_ext_s(ld, xargs.dn, mods, NULL, NULL);
1433 st = ldap_modify_ext_s(ld, principal_dn, mods, NULL, NULL);
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);
1443 if (entry->mask & KADM5_FAIL_AUTH_COUNT_INCREMENT)
1444 entry->fail_auth_count++;
1456 if (standalone_principal_dn)
1457 free(standalone_principal_dn);
1460 free (principal_dn);
1462 if (polname != NULL)
1465 for (tre = 0; tre < ntrees; tre++)
1466 free(subtreelist[tre]);
1473 for (l=0; bersecretkey[l]; ++l) {
1474 if (bersecretkey[l]->bv_val)
1475 free (bersecretkey[l]->bv_val);
1476 free (bersecretkey[l]);
1478 free (bersecretkey);
1484 ldap_mods_free(mods, 1);
1485 ldap_osa_free_princ_ent(&princ_ent);
1486 ldap_msgfree(result);
1487 krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
1492 krb5_read_tkt_policy(krb5_context context, krb5_ldap_context *ldap_context,
1493 krb5_db_entry *entries, char *policy)
1495 krb5_error_code st=0;
1496 int mask=0, omask=0;
1497 int tkt_mask=(KDB_MAX_LIFE_ATTR | KDB_MAX_RLIFE_ATTR | KDB_TKT_FLAGS_ATTR);
1498 krb5_ldap_policy_params *tktpoldnparam=NULL;
1500 if ((st=krb5_get_attributes_mask(context, entries, &mask)) != 0)
1503 if ((mask & tkt_mask) == tkt_mask)
1506 if (policy != NULL) {
1507 st = krb5_ldap_read_policy(context, policy, &tktpoldnparam, &omask);
1508 if (st && st != KRB5_KDB_NOENTRY) {
1509 k5_prependmsg(context, st, _("Error reading ticket policy"));
1513 st = 0; /* reset the return status */
1516 if ((mask & KDB_MAX_LIFE_ATTR) == 0) {
1517 if ((omask & KDB_MAX_LIFE_ATTR) == KDB_MAX_LIFE_ATTR)
1518 entries->max_life = tktpoldnparam->maxtktlife;
1519 else if (ldap_context->lrparams->max_life)
1520 entries->max_life = ldap_context->lrparams->max_life;
1523 if ((mask & KDB_MAX_RLIFE_ATTR) == 0) {
1524 if ((omask & KDB_MAX_RLIFE_ATTR) == KDB_MAX_RLIFE_ATTR)
1525 entries->max_renewable_life = tktpoldnparam->maxrenewlife;
1526 else if (ldap_context->lrparams->max_renewable_life)
1527 entries->max_renewable_life = ldap_context->lrparams->max_renewable_life;
1530 if ((mask & KDB_TKT_FLAGS_ATTR) == 0) {
1531 if ((omask & KDB_TKT_FLAGS_ATTR) == KDB_TKT_FLAGS_ATTR)
1532 entries->attributes = tktpoldnparam->tktflags;
1533 else if (ldap_context->lrparams->tktflags)
1534 entries->attributes |= ldap_context->lrparams->tktflags;
1536 krb5_ldap_free_policy(context, tktpoldnparam);
1543 free_ldap_seqof_key_data(ldap_seqof_key_data *keysets, krb5_int16 n_keysets)
1547 if (keysets == NULL)
1550 for (i = 0; i < n_keysets; i++)
1551 k5_free_key_data(keysets[i].n_key_data, keysets[i].key_data);
1556 * Decode keys from ldap search results.
1560 * The ldap search results containing the key data.
1562 * The master kvno that the keys were encrypted with.
1564 * The decoded keys in a ldap_seqof_key_data struct. Must be freed using
1565 * free_ldap_seqof_key_data.
1567 * The number of entries in keys_out.
1569 * An optional argument that if given will be set to the total number of
1570 * keys found throughout all the entries: sum(keys_out.n_key_data)
1573 static krb5_error_code
1574 decode_keys(struct berval **bvalues, ldap_seqof_key_data **keysets_out,
1575 krb5_int16 *n_keysets_out, krb5_int16 *total_keys_out)
1577 krb5_error_code err = 0;
1578 krb5_int16 n_keys, i, ki, total_keys;
1579 ldap_seqof_key_data *keysets = NULL;
1581 *keysets_out = NULL;
1584 *total_keys_out = 0;
1586 /* Precount the number of keys. */
1587 for (n_keys = 0, i = 0; bvalues[i] != NULL; i++) {
1588 if (bvalues[i]->bv_len > 0)
1592 keysets = k5calloc(n_keys, sizeof(ldap_seqof_key_data), &err);
1593 if (keysets == NULL)
1595 memset(keysets, 0, n_keys * sizeof(ldap_seqof_key_data));
1597 for (i = 0, ki = 0, total_keys = 0; bvalues[i] != NULL; i++) {
1600 if (bvalues[i]->bv_len == 0)
1602 in.length = bvalues[i]->bv_len;
1603 in.data = bvalues[i]->bv_val;
1605 err = asn1_decode_sequence_of_keys(&in, &keysets[ki]);
1610 total_keys += keysets[ki].n_key_data;
1615 *total_keys_out = total_keys;
1617 *n_keysets_out = n_keys;
1618 *keysets_out = keysets;
1623 free_ldap_seqof_key_data(keysets, n_keys);
1628 krb5_decode_krbsecretkey(krb5_context context, krb5_db_entry *entries,
1629 struct berval **bvalues, krb5_kvno *mkvno)
1631 krb5_key_data *key_data = NULL, *tmp;
1632 krb5_error_code err = 0;
1633 ldap_seqof_key_data *keysets = NULL;
1634 krb5_int16 i, n_keysets = 0, total_keys = 0;
1636 err = decode_keys(bvalues, &keysets, &n_keysets, &total_keys);
1638 k5_prependmsg(context, err,
1639 _("unable to decode stored principal key data"));
1643 key_data = k5calloc(total_keys, sizeof(krb5_key_data), &err);
1644 if (key_data == NULL)
1646 memset(key_data, 0, total_keys * sizeof(krb5_key_data));
1649 *mkvno = keysets[0].mkvno;
1651 /* Transfer key data values from keysets to a flat list in entries. */
1653 for (i = 0; i < n_keysets; i++) {
1654 memcpy(tmp, keysets[i].key_data,
1655 sizeof(krb5_key_data) * keysets[i].n_key_data);
1656 tmp += keysets[i].n_key_data;
1657 keysets[i].n_key_data = 0;
1659 entries->n_key_data = total_keys;
1660 entries->key_data = key_data;
1664 free_ldap_seqof_key_data(keysets, n_keysets);
1665 k5_free_key_data(total_keys, key_data);
1670 compare_osa_pw_hist_ent(const void *left_in, const void *right_in)
1672 int kvno_left, kvno_right;
1673 osa_pw_hist_ent *left = (osa_pw_hist_ent *)left_in;
1674 osa_pw_hist_ent *right = (osa_pw_hist_ent *)right_in;
1676 kvno_left = left->n_key_data ? left->key_data[0].key_data_kvno : 0;
1677 kvno_right = right->n_key_data ? right->key_data[0].key_data_kvno : 0;
1678 return kvno_left - kvno_right;
1682 * Decode the key history entries from an LDAP search.
1684 * NOTE: the caller must free princ_ent->old_keys even on error.
1687 krb5_decode_histkey(krb5_context context, struct berval **bvalues,
1688 osa_princ_ent_rec *princ_ent)
1690 krb5_error_code err = 0;
1691 krb5_int16 i, n_keysets = 0;
1692 ldap_seqof_key_data *keysets = NULL;
1694 err = decode_keys(bvalues, &keysets, &n_keysets, NULL);
1696 k5_prependmsg(context, err,
1697 _("unable to decode stored principal pw history"));
1701 princ_ent->old_keys = k5calloc(n_keysets, sizeof(osa_pw_hist_ent), &err);
1702 if (princ_ent->old_keys == NULL)
1704 princ_ent->old_key_len = n_keysets;
1707 princ_ent->admin_history_kvno = keysets[0].mkvno;
1709 /* Transfer key data pointers from keysets to princ_ent. */
1710 for (i = 0; i < n_keysets; i++) {
1711 princ_ent->old_keys[i].n_key_data = keysets[i].n_key_data;
1712 princ_ent->old_keys[i].key_data = keysets[i].key_data;
1713 keysets[i].n_key_data = 0;
1714 keysets[i].key_data = NULL;
1717 /* Sort the principal entries by kvno in ascending order. */
1718 qsort(princ_ent->old_keys, princ_ent->old_key_len, sizeof(osa_pw_hist_ent),
1719 &compare_osa_pw_hist_ent);
1721 princ_ent->aux_attributes |= KADM5_KEY_HIST;
1723 /* Set the next key to the end of the list. The queue will be lengthened
1724 * if it isn't full yet; the first entry will be replaced if it is full. */
1725 princ_ent->old_key_next = princ_ent->old_key_len;
1728 free_ldap_seqof_key_data(keysets, n_keysets);
1733 getstringtime(krb5_timestamp epochtime)
1737 time_t posixtime = epochtime;
1739 strtime = calloc (50, 1);
1740 if (strtime == NULL)
1743 if (gmtime_r(&posixtime, &tme) == NULL)
1746 strftime(strtime, 50, "%Y%m%d%H%M%SZ", &tme);