1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
3 * lib/kdb/kdb_ldap/ldap_principal2.c
5 * Copyright (c) 2004-2005, Novell, Inc.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions are met:
11 * * Redistributions of source code must retain the above copyright notice,
12 * this list of conditions and the following disclaimer.
13 * * Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * * The copyright holder's name is not used to endorse or promote products
17 * derived from this software without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
33 * Use is subject to license terms.
37 #include "ldap_main.h"
39 #include "ldap_principal.h"
40 #include "princ_xdr.h"
41 #include "ldap_tkt_policy.h"
42 #include "ldap_pwd_policy.h"
44 #include <kadm5/admin.h>
46 extern char* principal_attributes[];
47 extern char* max_pwd_life_attr[];
50 getstringtime(krb5_timestamp);
53 berval2tl_data(struct berval *in, krb5_tl_data **out)
55 *out = (krb5_tl_data *) malloc (sizeof (krb5_tl_data));
59 (*out)->tl_data_length = in->bv_len - 2;
60 (*out)->tl_data_contents = (krb5_octet *) malloc
61 ((*out)->tl_data_length * sizeof (krb5_octet));
62 if ((*out)->tl_data_contents == NULL) {
67 UNSTORE16_INT (in->bv_val, (*out)->tl_data_type);
68 memcpy ((*out)->tl_data_contents, in->bv_val + 2, (*out)->tl_data_length);
74 * look up a principal in the directory.
78 krb5_ldap_get_principal(krb5_context context, krb5_const_principal searchfor,
79 unsigned int flags, krb5_db_entry **entry_ptr)
81 char *user=NULL, *filter=NULL, *filtuser=NULL;
82 unsigned int tree=0, ntrees=1, princlen=0;
83 krb5_error_code tempst=0, st=0;
84 char **values=NULL, **subtree=NULL, *cname=NULL;
86 LDAPMessage *result=NULL, *ent=NULL;
87 krb5_ldap_context *ldap_context=NULL;
88 kdb5_dal_handle *dal_handle=NULL;
89 krb5_ldap_server_handle *ldap_server_handle=NULL;
90 krb5_principal cprinc=NULL;
91 krb5_boolean found=FALSE;
92 krb5_db_entry *entry = NULL;
96 /* Clear the global error string */
97 krb5_clear_error_message(context);
99 if (searchfor == NULL)
102 dal_handle = context->dal_handle;
103 ldap_context = (krb5_ldap_context *) dal_handle->db_context;
105 CHECK_LDAP_HANDLE(ldap_context);
107 if (is_principal_in_realm(ldap_context, searchfor) != 0) {
108 st = KRB5_KDB_NOENTRY;
109 krb5_set_error_message (context, st, "Principal does not belong to realm");
113 if ((st=krb5_unparse_name(context, searchfor, &user)) != 0)
116 if ((st=krb5_ldap_unparse_principal_name(user)) != 0)
119 filtuser = ldap_filter_correct(user);
120 if (filtuser == NULL) {
125 princlen = strlen(FILTER) + strlen(filtuser) + 2 + 1; /* 2 for closing brackets */
126 if ((filter = malloc(princlen)) == NULL) {
130 snprintf(filter, princlen, FILTER"%s))", filtuser);
132 if ((st = krb5_get_subtree_info(ldap_context, &subtree, &ntrees)) != 0)
136 for (tree=0; tree < ntrees && !found; ++tree) {
138 LDAP_SEARCH(subtree[tree], ldap_context->lrparams->search_scope, filter, principal_attributes);
139 for (ent=ldap_first_entry(ld, result); ent != NULL && !found; ent=ldap_next_entry(ld, ent)) {
141 /* get the associated directory user information */
142 if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
145 /* a wild-card in a principal name can return a list of kerberos principals.
146 * Make sure that the correct principal is returned.
147 * NOTE: a principalname k* in ldap server will return all the principals starting with a k
149 for (i=0; values[i] != NULL; ++i) {
150 if (strcmp(values[i], user) == 0) {
155 ldap_value_free(values);
157 if (!found) /* no matching principal found */
161 if ((values=ldap_get_values(ld, ent, "krbcanonicalname")) != NULL) {
162 if (values[0] && strcmp(values[0], user) != 0) {
163 /* We matched an alias, not the canonical name. */
164 if (flags & KRB5_KDB_FLAG_ALIAS_OK) {
165 st = krb5_ldap_parse_principal_name(values[0], &cname);
168 st = krb5_parse_name(context, cname, &cprinc);
171 } else /* No canonicalization, so don't return aliases. */
174 ldap_value_free(values);
179 entry = k5alloc(sizeof(*entry), &st);
182 if ((st = populate_krb5_db_entry(context, ldap_context, ld, ent,
183 cprinc ? cprinc : searchfor,
187 ldap_msgfree(result);
189 } /* for (tree=0 ... */
195 st = KRB5_KDB_NOENTRY;
198 ldap_msgfree(result);
199 krb5_ldap_free_principal(context, entry);
205 for (; ntrees; --ntrees)
206 if (subtree[ntrees-1])
207 free (subtree[ntrees-1]);
211 if (ldap_server_handle)
212 krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
224 krb5_free_principal(context, cprinc);
229 typedef enum{ ADD_PRINCIPAL, MODIFY_PRINCIPAL } OPERATION;
231 * ptype is creating confusions. Additionally the logic
232 * surronding ptype is redundunt and can be achevied
233 * with the help of dn and containerdn members.
234 * so dropping the ptype member
237 typedef struct _xargs_t {
240 krb5_boolean dn_from_kbd;
246 free_xargs(xargs_t xargs)
252 if (xargs.containerdn)
253 free (xargs.containerdn);
254 if (xargs.tktpolicydn)
255 free (xargs.tktpolicydn);
258 static krb5_error_code
259 process_db_args(krb5_context context, char **db_args, xargs_t *xargs,
263 krb5_error_code st=0;
265 char *arg=NULL, *arg_val=NULL;
267 unsigned int arg_val_len=0;
270 for (i=0; db_args[i]; ++i) {
271 arg = strtok_r(db_args[i], "=", &arg_val);
272 if (strcmp(arg, TKTPOLICY_ARG) == 0) {
273 dptr = &xargs->tktpolicydn;
275 if (strcmp(arg, USERDN_ARG) == 0) {
276 if (optype == MODIFY_PRINCIPAL ||
277 xargs->dn != NULL || xargs->containerdn != NULL ||
278 xargs->linkdn != NULL) {
280 snprintf(errbuf, sizeof(errbuf),
281 "%s option not supported", arg);
282 krb5_set_error_message(context, st, "%s", errbuf);
286 } else if (strcmp(arg, CONTAINERDN_ARG) == 0) {
287 if (optype == MODIFY_PRINCIPAL ||
288 xargs->dn != NULL || xargs->containerdn != NULL) {
290 snprintf(errbuf, sizeof(errbuf),
291 "%s option not supported", arg);
292 krb5_set_error_message(context, st, "%s", errbuf);
295 dptr = &xargs->containerdn;
296 } else if (strcmp(arg, LINKDN_ARG) == 0) {
297 if (xargs->dn != NULL || xargs->linkdn != NULL) {
299 snprintf(errbuf, sizeof(errbuf),
300 "%s option not supported", arg);
301 krb5_set_error_message(context, st, "%s", errbuf);
304 dptr = &xargs->linkdn;
307 snprintf(errbuf, sizeof(errbuf), "unknown option: %s", arg);
308 krb5_set_error_message(context, st, "%s", errbuf);
312 xargs->dn_from_kbd = TRUE;
313 if (arg_val == NULL || strlen(arg_val) == 0) {
315 snprintf(errbuf, sizeof(errbuf),
316 "%s option value missing", arg);
317 krb5_set_error_message(context, st, "%s", errbuf);
322 if (arg_val == NULL) {
324 snprintf(errbuf, sizeof(errbuf),
325 "%s option value missing", arg);
326 krb5_set_error_message(context, st, "%s", errbuf);
329 arg_val_len = strlen(arg_val) + 1;
331 if (strcmp(arg, TKTPOLICY_ARG) == 0) {
332 if ((st = krb5_ldap_name_to_policydn (context,
337 *dptr = calloc (1, arg_val_len);
342 memcpy(*dptr, arg_val, arg_val_len);
351 krb5int_access accessor;
353 static krb5_error_code
354 asn1_encode_sequence_of_keys(krb5_key_data *key_data, krb5_int16 n_key_data,
355 krb5_int32 mkvno, krb5_data **code)
358 ldap_seqof_key_data val;
361 * This should be pushed back into other library initialization
364 err = kldap_ensure_initialized ();
368 val.key_data = key_data;
369 val.n_key_data = n_key_data;
372 return accessor.asn1_ldap_encode_sequence_of_keys(&val, code);
375 static krb5_error_code
376 asn1_decode_sequence_of_keys(krb5_data *in, krb5_key_data **out,
377 krb5_int16 *n_key_data, krb5_kvno *mkvno)
380 ldap_seqof_key_data *p;
383 * This should be pushed back into other library initialization
386 err = kldap_ensure_initialized ();
390 err = accessor.asn1_ldap_decode_sequence_of_keys(in, &p);
394 *n_key_data = p->n_key_data;
401 /* Decoding ASN.1 encoded key */
402 static struct berval **
403 krb5_encode_krbsecretkey(krb5_key_data *key_data, int n_key_data,
405 struct berval **ret = NULL;
407 int num_versions = 1;
409 krb5_error_code err = 0;
414 /* Find the number of key versions */
415 for (i = 0; i < n_key_data - 1; i++)
416 if (key_data[i].key_data_kvno != key_data[i + 1].key_data_kvno)
419 ret = (struct berval **) calloc (num_versions + 1, sizeof (struct berval *));
424 for (i = 0, last = 0, j = 0, currkvno = key_data[0].key_data_kvno; i < n_key_data; i++) {
426 if (i == n_key_data - 1 || key_data[i + 1].key_data_kvno != currkvno) {
427 asn1_encode_sequence_of_keys (key_data+last,
428 (krb5_int16) i - last + 1,
431 ret[j] = malloc (sizeof (struct berval));
432 if (ret[j] == NULL) {
436 /*CHECK_NULL(ret[j]); */
437 ret[j]->bv_len = code->length;
438 ret[j]->bv_val = code->data;
442 currkvno = key_data[i].key_data_kvno;
445 ret[num_versions] = NULL;
451 for (i = 0; i <= num_versions; i++)
462 static krb5_error_code
463 tl_data2berval (krb5_tl_data *in, struct berval **out)
465 *out = (struct berval *) malloc (sizeof (struct berval));
469 (*out)->bv_len = in->tl_data_length + 2;
470 (*out)->bv_val = (char *) malloc ((*out)->bv_len);
471 if ((*out)->bv_val == NULL) {
476 STORE16_INT((*out)->bv_val, in->tl_data_type);
477 memcpy ((*out)->bv_val + 2, in->tl_data_contents, in->tl_data_length);
483 krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry,
486 int l=0, kerberos_principal_object_type=0;
487 krb5_error_code st=0, tempst=0;
489 LDAPMessage *result=NULL, *ent=NULL;
490 char *user=NULL, *subtree=NULL, *principal_dn=NULL;
491 char **values=NULL, *strval[10]={NULL}, errbuf[1024];
492 struct berval **bersecretkey=NULL;
494 krb5_boolean create_standalone_prinicipal=FALSE;
495 krb5_boolean krb_identity_exists=FALSE, establish_links=FALSE;
496 char *standalone_principal_dn=NULL;
497 krb5_tl_data *tl_data=NULL;
498 krb5_key_data **keys=NULL;
499 kdb5_dal_handle *dal_handle=NULL;
500 krb5_ldap_context *ldap_context=NULL;
501 krb5_ldap_server_handle *ldap_server_handle=NULL;
502 osa_princ_ent_rec princ_ent;
504 char *polname = NULL;
506 krb5_boolean found_entry = FALSE;
508 /* Clear the global error string */
509 krb5_clear_error_message(context);
512 if (ldap_context->lrparams == NULL || ldap_context->krbcontainer == NULL)
515 /* get ldap handle */
518 if (is_principal_in_realm(ldap_context, entry->princ) != 0) {
520 krb5_set_error_message(context, st, "Principal does not belong to the default realm");
524 /* get the principal information to act on */
526 if (((st=krb5_unparse_name(context, entry->princ, &user)) != 0) ||
527 ((st=krb5_ldap_unparse_principal_name(user)) != 0))
531 /* Identity the type of operation, it can be
532 * add principal or modify principal.
533 * hack if the entry->mask has KRB_PRINCIPAL flag set
534 * then it is a add operation
536 if (entry->mask & KADM5_PRINCIPAL)
537 optype = ADD_PRINCIPAL;
539 optype = MODIFY_PRINCIPAL;
541 if (((st=krb5_get_princ_type(context, entry, &kerberos_principal_object_type)) != 0) ||
542 ((st=krb5_get_userdn(context, entry, &principal_dn)) != 0))
545 if ((st=process_db_args(context, db_args, &xargs, optype)) != 0)
548 if (entry->mask & KADM5_LOAD) {
549 int tree = 0, ntrees = 0, princlen = 0, numlentries = 0;
550 char **subtreelist = NULL, *filter = NULL;
552 /* A load operation is special, will do a mix-in (add krbprinc
553 * attrs to a non-krb object entry) if an object exists with a
554 * matching krbprincipalname attribute so try to find existing
555 * object and set principal_dn. This assumes that the
556 * krbprincipalname attribute is unique (only one object entry has
557 * a particular krbprincipalname attribute).
560 /* must have principal name for search */
562 krb5_set_error_message(context, st, "operation can not continue, principal name not found");
565 princlen = strlen(FILTER) + strlen(user) + 2 + 1; /* 2 for closing brackets */
566 if ((filter = malloc(princlen)) == NULL) {
570 snprintf(filter, princlen, FILTER"%s))", user);
572 /* get the current subtree list */
573 if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0)
577 /* search for entry with matching krbprincipalname attribute */
578 for (tree = 0; found_entry == FALSE && tree < ntrees; ++tree) {
580 if (principal_dn == NULL) {
581 LDAP_SEARCH_1(subtreelist[tree], ldap_context->lrparams->search_scope, filter, principal_attributes, IGNORE_STATUS);
583 /* just look for entry with principal_dn */
584 LDAP_SEARCH_1(principal_dn, LDAP_SCOPE_BASE, filter, principal_attributes, IGNORE_STATUS);
586 if (st == LDAP_SUCCESS) {
587 numlentries = ldap_count_entries(ld, result);
588 if (numlentries > 1) {
589 ldap_msgfree(result);
592 krb5_set_error_message(context, st,
593 "operation can not continue, more than one entry with principal name \"%s\" found",
596 } else if (numlentries == 1) {
598 if (principal_dn == NULL) {
599 ent = ldap_first_entry(ld, result);
601 /* setting principal_dn will cause that entry to be modified further down */
602 if ((principal_dn = ldap_get_dn(ld, ent)) == NULL) {
603 ldap_get_option (ld, LDAP_OPT_RESULT_CODE, &st);
604 st = set_ldap_error (context, st, 0);
605 ldap_msgfree(result);
613 ldap_msgfree(result);
614 } else if (st != LDAP_NO_SUCH_OBJECT) {
615 /* could not perform search, return with failure */
616 st = set_ldap_error (context, st, 0);
621 * If it isn't found then assume a standalone princ entry is to
624 } /* end for (tree = 0; principal_dn == ... */
628 if (found_entry == FALSE && principal_dn != NULL) {
630 * if principal_dn is null then there is code further down to
631 * deal with setting standalone_principal_dn. Also note that
632 * this will set create_standalone_prinicipal true for
633 * non-mix-in entries which is okay if loading from a dump.
635 create_standalone_prinicipal = TRUE;
636 standalone_principal_dn = strdup(principal_dn);
637 CHECK_NULL(standalone_principal_dn);
639 } /* end if (entry->mask & KADM5_LOAD */
641 /* time to generate the DN information with the help of
642 * containerdn, principalcontainerreference or
643 * realmcontainerdn information
645 if (principal_dn == NULL && xargs.dn == NULL) { /* creation of standalone principal */
646 /* get the subtree information */
647 if (entry->princ->length == 2 && entry->princ->data[0].length == strlen("krbtgt") &&
648 strncmp(entry->princ->data[0].data, "krbtgt", entry->princ->data[0].length) == 0) {
649 /* if the principal is a inter-realm principal, always created in the realm container */
650 subtree = strdup(ldap_context->lrparams->realmdn);
651 } else if (xargs.containerdn) {
652 if ((st=checkattributevalue(ld, xargs.containerdn, NULL, NULL, NULL)) != 0) {
653 if (st == KRB5_KDB_NOENTRY || st == KRB5_KDB_CONSTRAINT_VIOLATION) {
656 snprintf(errbuf, sizeof(errbuf), "'%s' not found: ",
658 prepend_err_str(context, errbuf, st, ost);
662 subtree = strdup(xargs.containerdn);
663 } else if (ldap_context->lrparams->containerref && strlen(ldap_context->lrparams->containerref) != 0) {
665 * Here the subtree should be changed with
666 * principalcontainerreference attribute value
668 subtree = strdup(ldap_context->lrparams->containerref);
670 subtree = strdup(ldap_context->lrparams->realmdn);
674 if (asprintf(&standalone_principal_dn, "krbprincipalname=%s,%s",
676 standalone_principal_dn = NULL;
677 CHECK_NULL(standalone_principal_dn);
679 * free subtree when you are done using the subtree
680 * set the boolean create_standalone_prinicipal to TRUE
682 create_standalone_prinicipal = TRUE;
688 * If the DN information is presented by the user, time to
689 * validate the input to ensure that the DN falls under
690 * any of the subtrees
692 if (xargs.dn_from_kbd == TRUE) {
693 /* make sure the DN falls in the subtree */
694 int tre=0, dnlen=0, subtreelen=0, ntrees=0;
695 char **subtreelist=NULL;
697 krb5_boolean outofsubtree=TRUE;
699 if (xargs.dn != NULL) {
701 } else if (xargs.linkdn != NULL) {
703 } else if (standalone_principal_dn != NULL) {
705 * Even though the standalone_principal_dn is constructed
706 * within this function, there is the containerdn input
707 * from the user that can become part of the it.
709 dn = standalone_principal_dn;
712 /* get the current subtree list */
713 if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0)
716 for (tre=0; tre<ntrees; ++tre) {
717 if (subtreelist[tre] == NULL || strlen(subtreelist[tre]) == 0) {
718 outofsubtree = FALSE;
722 subtreelen = strlen(subtreelist[tre]);
723 if ((dnlen >= subtreelen) && (strcasecmp((dn + dnlen - subtreelen), subtreelist[tre]) == 0)) {
724 outofsubtree = FALSE;
730 for (tre=0; tre < ntrees; ++tre) {
731 free(subtreelist[tre]);
734 if (outofsubtree == TRUE) {
736 krb5_set_error_message(context, st, "DN is out of the realm subtree");
741 * dn value will be set either by dn, linkdn or the standalone_principal_dn
742 * In the first 2 cases, the dn should be existing and in the last case we
743 * are supposed to create the ldap object. so the below should not be
744 * executed for the last case.
747 if (standalone_principal_dn == NULL) {
749 * If the ldap object is missing, this results in an error.
753 * Search for krbprincipalname attribute here.
754 * This is to find if a kerberos identity is already present
755 * on the ldap object, in which case adding a kerberos identity
756 * on the ldap object should result in an error.
758 char *attributes[]={"krbticketpolicyreference", "krbprincipalname", NULL};
760 LDAP_SEARCH_1(dn, LDAP_SCOPE_BASE, 0, attributes, IGNORE_STATUS);
761 if (st == LDAP_SUCCESS) {
762 ent = ldap_first_entry(ld, result);
764 if ((values=ldap_get_values(ld, ent, "krbticketpolicyreference")) != NULL) {
765 ldap_value_free(values);
768 if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
769 krb_identity_exists = TRUE;
770 ldap_value_free(values);
773 ldap_msgfree(result);
775 st = set_ldap_error(context, st, OP_SEARCH);
782 * If xargs.dn is set then the request is to add a
783 * kerberos principal on a ldap object, but if
784 * there is one already on the ldap object this
785 * should result in an error.
788 if (xargs.dn != NULL && krb_identity_exists == TRUE) {
790 snprintf(errbuf, sizeof(errbuf), "ldap object is already kerberized");
791 krb5_set_error_message(context, st, "%s", errbuf);
795 if (xargs.linkdn != NULL) {
797 * link information can be changed using modprinc.
798 * However, link information can be changed only on the
799 * standalone kerberos principal objects. A standalone
800 * kerberos principal object is of type krbprincipal
801 * structural objectclass.
803 * NOTE: kerberos principals on an ldap object can't be
804 * linked to other ldap objects.
806 if (optype == MODIFY_PRINCIPAL &&
807 kerberos_principal_object_type != KDB_STANDALONE_PRINCIPAL_OBJECT) {
809 snprintf(errbuf, sizeof(errbuf),
810 "link information can not be set/updated as the kerberos principal belongs to an ldap object");
811 krb5_set_error_message(context, st, "%s", errbuf);
815 * Check the link information. If there is already a link
816 * existing then this operation is not allowed.
822 if ((st=krb5_get_linkdn(context, entry, &linkdns)) != 0) {
823 snprintf(errbuf, sizeof(errbuf),
824 "Failed getting object references");
825 krb5_set_error_message(context, st, "%s", errbuf);
828 if (linkdns != NULL) {
830 snprintf(errbuf, sizeof(errbuf),
831 "kerberos principal is already linked "
833 krb5_set_error_message(context, st, "%s", errbuf);
834 for (j=0; linkdns[j] != NULL; ++j)
841 establish_links = TRUE;
844 if (entry->mask & KADM5_LAST_SUCCESS) {
845 memset(strval, 0, sizeof(strval));
846 if ((strval[0]=getstringtime(entry->last_success)) == NULL)
848 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastSuccessfulAuth", LDAP_MOD_REPLACE, strval)) != 0) {
855 if (entry->mask & KADM5_LAST_FAILED) {
856 memset(strval, 0, sizeof(strval));
857 if ((strval[0]=getstringtime(entry->last_failed)) == NULL)
859 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastFailedAuth", LDAP_MOD_REPLACE, strval)) != 0) {
866 if (entry->mask & KADM5_FAIL_AUTH_COUNT) {
867 krb5_kvno fail_auth_count;
869 fail_auth_count = entry->fail_auth_count;
870 if (entry->mask & KADM5_FAIL_AUTH_COUNT_INCREMENT)
873 st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
878 } else if (entry->mask & KADM5_FAIL_AUTH_COUNT_INCREMENT) {
880 krb5_boolean has_fail_count;
882 /* Check if the krbLoginFailedCount attribute exists. (Through
883 * krb5 1.8.1, it wasn't set in new entries.) */
884 st = krb5_get_attributes_mask(context, entry, &attr_mask);
887 has_fail_count = ((attr_mask & KDB_FAIL_AUTH_COUNT_ATTR) != 0);
890 * If the client library and server supports RFC 4525,
891 * then use it to increment by one the value of the
892 * krbLoginFailedCount attribute. Otherwise, assert the
893 * (provided) old value by deleting it before adding.
895 #ifdef LDAP_MOD_INCREMENT
896 if (ldap_server_handle->server_info->modify_increment &&
898 st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
899 LDAP_MOD_INCREMENT, 1);
903 #endif /* LDAP_MOD_INCREMENT */
904 if (has_fail_count) {
905 st = krb5_add_int_mem_ldap_mod(&mods,
906 "krbLoginFailedCount",
908 entry->fail_auth_count);
912 st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
914 entry->fail_auth_count + 1);
917 #ifdef LDAP_MOD_INCREMENT
920 } else if (optype == ADD_PRINCIPAL) {
921 /* Initialize krbLoginFailedCount in new entries to help avoid a
922 * race during the first failed login. */
923 st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
927 if (entry->mask & KADM5_MAX_LIFE) {
928 if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxticketlife", LDAP_MOD_REPLACE, entry->max_life)) != 0)
932 if (entry->mask & KADM5_MAX_RLIFE) {
933 if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxrenewableage", LDAP_MOD_REPLACE,
934 entry->max_renewable_life)) != 0)
938 if (entry->mask & KADM5_ATTRIBUTES) {
939 if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbticketflags", LDAP_MOD_REPLACE,
940 entry->attributes)) != 0)
944 if (entry->mask & KADM5_PRINCIPAL) {
945 memset(strval, 0, sizeof(strval));
947 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalname", LDAP_MOD_REPLACE, strval)) != 0)
951 if (entry->mask & KADM5_PRINC_EXPIRE_TIME) {
952 memset(strval, 0, sizeof(strval));
953 if ((strval[0]=getstringtime(entry->expiration)) == NULL)
955 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalexpiration", LDAP_MOD_REPLACE, strval)) != 0) {
962 if (entry->mask & KADM5_PW_EXPIRATION) {
963 memset(strval, 0, sizeof(strval));
964 if ((strval[0]=getstringtime(entry->pw_expiration)) == NULL)
966 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpasswordexpiration",
975 if (entry->mask & KADM5_POLICY) {
976 memset(&princ_ent, 0, sizeof(princ_ent));
977 for (tl_data=entry->tl_data; tl_data; tl_data=tl_data->tl_data_next) {
978 if (tl_data->tl_data_type == KRB5_TL_KADM_DATA) {
979 /* FIX ME: I guess the princ_ent should be freed after this call */
980 if ((st = krb5_lookup_tl_kadm_data(tl_data, &princ_ent)) != 0) {
986 if (princ_ent.aux_attributes & KADM5_POLICY) {
987 memset(strval, 0, sizeof(strval));
988 if ((st = krb5_ldap_name_to_policydn (context, princ_ent.policy, &polname)) != 0)
991 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, strval)) != 0)
995 krb5_set_error_message(context, st, "Password policy value null");
998 } else if (entry->mask & KADM5_LOAD && found_entry == TRUE) {
1000 * a load is special in that existing entries must have attrs that
1004 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, NULL)) != 0)
1008 if (entry->mask & KADM5_POLICY_CLR) {
1009 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_DELETE, NULL)) != 0)
1013 if (entry->mask & KADM5_KEY_DATA || entry->mask & KADM5_KVNO) {
1016 if ((st=krb5_dbe_lookup_mkvno(context, entry, &mkvno)) != 0)
1018 bersecretkey = krb5_encode_krbsecretkey (entry->key_data,
1019 entry->n_key_data, mkvno);
1021 if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbprincipalkey",
1022 LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, bersecretkey)) != 0)
1025 if (!(entry->mask & KADM5_PRINCIPAL)) {
1026 memset(strval, 0, sizeof(strval));
1027 if ((strval[0]=getstringtime(entry->pw_expiration)) == NULL)
1029 if ((st=krb5_add_str_mem_ldap_mod(&mods,
1030 "krbpasswordexpiration",
1031 LDAP_MOD_REPLACE, strval)) != 0) {
1038 /* Update last password change whenever a new key is set */
1040 krb5_timestamp last_pw_changed;
1041 if ((st=krb5_dbe_lookup_last_pwd_change(context, entry,
1042 &last_pw_changed)) != 0)
1045 memset(strval, 0, sizeof(strval));
1046 if ((strval[0] = getstringtime(last_pw_changed)) == NULL)
1049 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastPwdChange",
1050 LDAP_MOD_REPLACE, strval)) != 0) {
1057 } /* Modify Key data ends here */
1060 if (entry->tl_data != NULL) {
1062 struct berval **ber_tl_data = NULL;
1064 krb5_timestamp unlock_time;
1065 for (ptr = entry->tl_data; ptr != NULL; ptr = ptr->tl_data_next) {
1066 if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE
1068 || ptr->tl_data_type == KRB5_TL_DB_ARGS
1070 || ptr->tl_data_type == KRB5_TL_KADM_DATA
1071 || ptr->tl_data_type == KDB_TL_USER_INFO
1072 || ptr->tl_data_type == KRB5_TL_CONSTRAINED_DELEGATION_ACL
1073 || ptr->tl_data_type == KRB5_TL_LAST_ADMIN_UNLOCK)
1079 ber_tl_data = (struct berval **) calloc (count + 1,
1080 sizeof (struct berval*));
1081 if (ber_tl_data == NULL) {
1085 for (j = 0, ptr = entry->tl_data; ptr != NULL; ptr = ptr->tl_data_next) {
1086 /* Ignore tl_data that are stored in separate directory
1088 if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE
1090 || ptr->tl_data_type == KRB5_TL_DB_ARGS
1092 || ptr->tl_data_type == KRB5_TL_KADM_DATA
1093 || ptr->tl_data_type == KDB_TL_USER_INFO
1094 || ptr->tl_data_type == KRB5_TL_CONSTRAINED_DELEGATION_ACL
1095 || ptr->tl_data_type == KRB5_TL_LAST_ADMIN_UNLOCK)
1097 if ((st = tl_data2berval (ptr, &ber_tl_data[j])) != 0)
1102 for (j = 0; ber_tl_data[j] != NULL; j++) {
1103 free (ber_tl_data[j]->bv_val);
1104 free (ber_tl_data[j]);
1109 ber_tl_data[count] = NULL;
1110 if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbExtraData",
1111 LDAP_MOD_REPLACE | LDAP_MOD_BVALUES,
1115 if ((st=krb5_dbe_lookup_last_admin_unlock(context, entry,
1116 &unlock_time)) != 0)
1118 if (unlock_time != 0) {
1119 /* Update last admin unlock */
1120 memset(strval, 0, sizeof(strval));
1121 if ((strval[0] = getstringtime(unlock_time)) == NULL)
1124 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastAdminUnlock",
1125 LDAP_MOD_REPLACE, strval)) != 0) {
1133 /* Directory specific attribute */
1134 if (xargs.tktpolicydn != NULL) {
1137 if (strlen(xargs.tktpolicydn) != 0) {
1138 st = checkattributevalue(ld, xargs.tktpolicydn, "objectclass", policyclass, &tmask);
1139 CHECK_CLASS_VALIDITY(st, tmask, "ticket policy object value: ");
1141 strval[0] = xargs.tktpolicydn;
1143 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_REPLACE, strval)) != 0)
1147 /* if xargs.tktpolicydn is a empty string, then delete
1148 * already existing krbticketpolicyreference attr */
1149 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_DELETE, NULL)) != 0)
1155 if (establish_links == TRUE) {
1156 memset(strval, 0, sizeof(strval));
1157 strval[0] = xargs.linkdn;
1158 if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbObjectReferences", LDAP_MOD_REPLACE, strval)) != 0)
1163 * in case mods is NULL then return
1164 * not sure but can happen in a modprinc
1165 * so no need to return an error
1166 * addprinc will at least have the principal name
1167 * and the keys passed in
1172 if (create_standalone_prinicipal == TRUE) {
1173 memset(strval, 0, sizeof(strval));
1174 strval[0] = "krbprincipal";
1175 strval[1] = "krbprincipalaux";
1176 strval[2] = "krbTicketPolicyAux";
1178 if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
1181 st = ldap_add_ext_s(ld, standalone_principal_dn, mods, NULL, NULL);
1182 if (st == LDAP_ALREADY_EXISTS && entry->mask & KADM5_LOAD) {
1183 /* a load operation must replace an existing entry */
1184 st = ldap_delete_ext_s(ld, standalone_principal_dn, NULL, NULL);
1185 if (st != LDAP_SUCCESS) {
1186 snprintf(errbuf, sizeof(errbuf), "Principal delete failed (trying to replace entry): %s",
1187 ldap_err2string(st));
1188 st = translate_ldap_error (st, OP_ADD);
1189 krb5_set_error_message(context, st, "%s", errbuf);
1192 st = ldap_add_ext_s(ld, standalone_principal_dn, mods, NULL, NULL);
1195 if (st != LDAP_SUCCESS) {
1196 snprintf(errbuf, sizeof(errbuf), "Principal add failed: %s", ldap_err2string(st));
1197 st = translate_ldap_error (st, OP_ADD);
1198 krb5_set_error_message(context, st, "%s", errbuf);
1203 * Here existing ldap object is modified and can be related
1204 * to any attribute, so always ensure that the ldap
1205 * object is extended with all the kerberos related
1206 * objectclasses so that there are no constraint
1210 char *attrvalues[] = {"krbprincipalaux", "krbTicketPolicyAux", NULL};
1211 int p, q, r=0, amask=0;
1213 if ((st=checkattributevalue(ld, (xargs.dn) ? xargs.dn : principal_dn,
1214 "objectclass", attrvalues, &amask)) != 0)
1217 memset(strval, 0, sizeof(strval));
1218 for (p=1, q=0; p<=2; p<<=1, ++q) {
1219 if ((p & amask) == 0)
1220 strval[r++] = attrvalues[q];
1223 if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
1227 if (xargs.dn != NULL)
1228 st=ldap_modify_ext_s(ld, xargs.dn, mods, NULL, NULL);
1230 st = ldap_modify_ext_s(ld, principal_dn, mods, NULL, NULL);
1232 if (st != LDAP_SUCCESS) {
1233 snprintf(errbuf, sizeof(errbuf), "User modification failed: %s", ldap_err2string(st));
1234 st = translate_ldap_error (st, OP_MOD);
1235 krb5_set_error_message(context, st, "%s", errbuf);
1239 if (entry->mask & KADM5_FAIL_AUTH_COUNT_INCREMENT)
1240 entry->fail_auth_count++;
1249 if (standalone_principal_dn)
1250 free(standalone_principal_dn);
1253 free (principal_dn);
1255 if (polname != NULL)
1262 for (l=0; bersecretkey[l]; ++l) {
1263 if (bersecretkey[l]->bv_val)
1264 free (bersecretkey[l]->bv_val);
1265 free (bersecretkey[l]);
1267 free (bersecretkey);
1273 ldap_mods_free(mods, 1);
1274 krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
1279 krb5_read_tkt_policy(krb5_context context, krb5_ldap_context *ldap_context,
1280 krb5_db_entry *entries, char *policy)
1282 krb5_error_code st=0;
1283 unsigned int mask=0, omask=0;
1284 int tkt_mask=(KDB_MAX_LIFE_ATTR | KDB_MAX_RLIFE_ATTR | KDB_TKT_FLAGS_ATTR);
1285 krb5_ldap_policy_params *tktpoldnparam=NULL;
1287 if ((st=krb5_get_attributes_mask(context, entries, &mask)) != 0)
1290 if ((mask & tkt_mask) == tkt_mask)
1293 if (policy != NULL) {
1294 st = krb5_ldap_read_policy(context, policy, &tktpoldnparam, &omask);
1295 if (st && st != KRB5_KDB_NOENTRY) {
1296 prepend_err_str(context, "Error reading ticket policy. ", st, st);
1300 st = 0; /* reset the return status */
1303 if ((mask & KDB_MAX_LIFE_ATTR) == 0) {
1304 if ((omask & KDB_MAX_LIFE_ATTR) == KDB_MAX_LIFE_ATTR)
1305 entries->max_life = tktpoldnparam->maxtktlife;
1306 else if (ldap_context->lrparams->max_life)
1307 entries->max_life = ldap_context->lrparams->max_life;
1310 if ((mask & KDB_MAX_RLIFE_ATTR) == 0) {
1311 if ((omask & KDB_MAX_RLIFE_ATTR) == KDB_MAX_RLIFE_ATTR)
1312 entries->max_renewable_life = tktpoldnparam->maxrenewlife;
1313 else if (ldap_context->lrparams->max_renewable_life)
1314 entries->max_renewable_life = ldap_context->lrparams->max_renewable_life;
1317 if ((mask & KDB_TKT_FLAGS_ATTR) == 0) {
1318 if ((omask & KDB_TKT_FLAGS_ATTR) == KDB_TKT_FLAGS_ATTR)
1319 entries->attributes = tktpoldnparam->tktflags;
1320 else if (ldap_context->lrparams->tktflags)
1321 entries->attributes |= ldap_context->lrparams->tktflags;
1323 krb5_ldap_free_policy(context, tktpoldnparam);
1330 krb5_decode_krbsecretkey(krb5_context context, krb5_db_entry *entries,
1331 struct berval **bvalues,
1332 krb5_tl_data *userinfo_tl_data, krb5_kvno *mkvno)
1335 int i=0, j=0, noofkeys=0;
1336 krb5_key_data *key_data=NULL, *tmp;
1337 krb5_error_code st=0;
1339 if ((st=krb5_unparse_name(context, entries->princ, &user)) != 0)
1342 for (i=0; bvalues[i] != NULL; ++i) {
1347 if (bvalues[i]->bv_len == 0)
1349 in.length = bvalues[i]->bv_len;
1350 in.data = bvalues[i]->bv_val;
1352 st = asn1_decode_sequence_of_keys (&in,
1358 const char *msg = error_message(st);
1359 st = -1; /* Something more appropriate ? */
1360 krb5_set_error_message (context, st,
1361 "unable to decode stored principal key data (%s)", msg);
1366 key_data = realloc (key_data, noofkeys * sizeof (krb5_key_data));
1367 if (key_data == NULL) {
1372 for (j = 0; j < n_kd; j++)
1373 key_data[noofkeys - n_kd + j] = kd[j];
1377 entries->n_key_data = noofkeys;
1378 entries->key_data = key_data;
1381 ldap_value_free_len(bvalues);
1387 getstringtime(krb5_timestamp epochtime)
1391 time_t posixtime = epochtime;
1393 strtime = calloc (50, 1);
1394 if (strtime == NULL)
1397 if (gmtime_r(&posixtime, &tme) == NULL)
1400 strftime(strtime, 50, "%Y%m%d%H%M%SZ", &tme);