SA-2011-006 KDC denial of service [CVE-2011-1527 CVE-2011-1528 CVE-2011-1529]
[krb5.git] / src / plugins / kdb / ldap / libkdb_ldap / ldap_principal2.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  * lib/kdb/kdb_ldap/ldap_principal2.c
4  *
5  * Copyright (c) 2004-2005, Novell, Inc.
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions are met:
10  *
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.
18  *
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.
30  */
31 /*
32  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
33  * Use is subject to license terms.
34  */
35
36 #include <time.h>
37 #include "ldap_main.h"
38 #include "kdb_ldap.h"
39 #include "ldap_principal.h"
40 #include "princ_xdr.h"
41 #include "ldap_tkt_policy.h"
42 #include "ldap_pwd_policy.h"
43 #include "ldap_err.h"
44 #include <kadm5/admin.h>
45
46 extern char* principal_attributes[];
47 extern char* max_pwd_life_attr[];
48
49 static char *
50 getstringtime(krb5_timestamp);
51
52 krb5_error_code
53 berval2tl_data(struct berval *in, krb5_tl_data **out)
54 {
55     *out = (krb5_tl_data *) malloc (sizeof (krb5_tl_data));
56     if (*out == NULL)
57         return ENOMEM;
58
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) {
63         free (*out);
64         return ENOMEM;
65     }
66
67     UNSTORE16_INT (in->bv_val, (*out)->tl_data_type);
68     memcpy ((*out)->tl_data_contents, in->bv_val + 2, (*out)->tl_data_length);
69
70     return 0;
71 }
72
73 /*
74  * look up a principal in the directory.
75  */
76
77 krb5_error_code
78 krb5_ldap_get_principal(krb5_context context, krb5_const_principal searchfor,
79                         unsigned int flags, krb5_db_entry **entry_ptr)
80 {
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;
85     LDAP                        *ld=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;
93
94     *entry_ptr = NULL;
95
96     /* Clear the global error string */
97     krb5_clear_error_message(context);
98
99     if (searchfor == NULL)
100         return EINVAL;
101
102     dal_handle = context->dal_handle;
103     ldap_context = (krb5_ldap_context *) dal_handle->db_context;
104
105     CHECK_LDAP_HANDLE(ldap_context);
106
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");
110         goto cleanup;
111     }
112
113     if ((st=krb5_unparse_name(context, searchfor, &user)) != 0)
114         goto cleanup;
115
116     if ((st=krb5_ldap_unparse_principal_name(user)) != 0)
117         goto cleanup;
118
119     filtuser = ldap_filter_correct(user);
120     if (filtuser == NULL) {
121         st = ENOMEM;
122         goto cleanup;
123     }
124
125     princlen = strlen(FILTER) + strlen(filtuser) + 2 + 1;  /* 2 for closing brackets */
126     if ((filter = malloc(princlen)) == NULL) {
127         st = ENOMEM;
128         goto cleanup;
129     }
130     snprintf(filter, princlen, FILTER"%s))", filtuser);
131
132     if ((st = krb5_get_subtree_info(ldap_context, &subtree, &ntrees)) != 0)
133         goto cleanup;
134
135     GET_HANDLE();
136     for (tree=0; tree < ntrees && !found; ++tree) {
137
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)) {
140
141             /* get the associated directory user information */
142             if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
143                 int i;
144
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
148                  */
149                 for (i=0; values[i] != NULL; ++i) {
150                     if (strcmp(values[i], user) == 0) {
151                         found = TRUE;
152                         break;
153                     }
154                 }
155                 ldap_value_free(values);
156
157                 if (!found) /* no matching principal found */
158                     continue;
159             }
160
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);
166                         if (st != 0)
167                             goto cleanup;
168                         st = krb5_parse_name(context, cname, &cprinc);
169                         if (st != 0)
170                             goto cleanup;
171                     } else /* No canonicalization, so don't return aliases. */
172                         found = FALSE;
173                 }
174                 ldap_value_free(values);
175                 if (!found)
176                     continue;
177             }
178
179             entry = k5alloc(sizeof(*entry), &st);
180             if (entry == NULL)
181                 goto cleanup;
182             if ((st = populate_krb5_db_entry(context, ldap_context, ld, ent,
183                                              cprinc ? cprinc : searchfor,
184                                              entry)) != 0)
185                 goto cleanup;
186         }
187         ldap_msgfree(result);
188         result = NULL;
189     } /* for (tree=0 ... */
190
191     if (found) {
192         *entry_ptr = entry;
193         entry = NULL;
194     } else
195         st = KRB5_KDB_NOENTRY;
196
197 cleanup:
198     ldap_msgfree(result);
199     krb5_ldap_free_principal(context, entry);
200
201     if (filter)
202         free (filter);
203
204     if (subtree) {
205         for (; ntrees; --ntrees)
206             if (subtree[ntrees-1])
207                 free (subtree[ntrees-1]);
208         free (subtree);
209     }
210
211     if (ldap_server_handle)
212         krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
213
214     if (user)
215         free(user);
216
217     if (filtuser)
218         free(filtuser);
219
220     if (cname)
221         free(cname);
222
223     if (cprinc)
224         krb5_free_principal(context, cprinc);
225
226     return st;
227 }
228
229 typedef enum{ ADD_PRINCIPAL, MODIFY_PRINCIPAL } OPERATION;
230 /*
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
235  */
236
237 typedef struct _xargs_t {
238     char           *dn;
239     char           *linkdn;
240     krb5_boolean   dn_from_kbd;
241     char           *containerdn;
242     char           *tktpolicydn;
243 }xargs_t;
244
245 static void
246 free_xargs(xargs_t xargs)
247 {
248     if (xargs.dn)
249         free (xargs.dn);
250     if (xargs.linkdn)
251         free(xargs.linkdn);
252     if (xargs.containerdn)
253         free (xargs.containerdn);
254     if (xargs.tktpolicydn)
255         free (xargs.tktpolicydn);
256 }
257
258 static krb5_error_code
259 process_db_args(krb5_context context, char **db_args, xargs_t *xargs,
260                 OPERATION optype)
261 {
262     int                   i=0;
263     krb5_error_code       st=0;
264     char                  errbuf[1024];
265     char                  *arg=NULL, *arg_val=NULL;
266     char                  **dptr=NULL;
267     unsigned int          arg_val_len=0;
268
269     if (db_args) {
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;
274             } else {
275                 if (strcmp(arg, USERDN_ARG) == 0) {
276                     if (optype == MODIFY_PRINCIPAL ||
277                         xargs->dn != NULL || xargs->containerdn != NULL ||
278                         xargs->linkdn != NULL) {
279                         st = EINVAL;
280                         snprintf(errbuf, sizeof(errbuf),
281                                  "%s option not supported", arg);
282                         krb5_set_error_message(context, st, "%s", errbuf);
283                         goto cleanup;
284                     }
285                     dptr = &xargs->dn;
286                 } else if (strcmp(arg, CONTAINERDN_ARG) == 0) {
287                     if (optype == MODIFY_PRINCIPAL ||
288                         xargs->dn != NULL || xargs->containerdn != NULL) {
289                         st = EINVAL;
290                         snprintf(errbuf, sizeof(errbuf),
291                                  "%s option not supported", arg);
292                         krb5_set_error_message(context, st, "%s", errbuf);
293                         goto cleanup;
294                     }
295                     dptr = &xargs->containerdn;
296                 } else if (strcmp(arg, LINKDN_ARG) == 0) {
297                     if (xargs->dn != NULL || xargs->linkdn != NULL) {
298                         st = EINVAL;
299                         snprintf(errbuf, sizeof(errbuf),
300                                  "%s option not supported", arg);
301                         krb5_set_error_message(context, st, "%s", errbuf);
302                         goto cleanup;
303                     }
304                     dptr = &xargs->linkdn;
305                 } else {
306                     st = EINVAL;
307                     snprintf(errbuf, sizeof(errbuf), "unknown option: %s", arg);
308                     krb5_set_error_message(context, st, "%s", errbuf);
309                     goto cleanup;
310                 }
311
312                 xargs->dn_from_kbd = TRUE;
313                 if (arg_val == NULL || strlen(arg_val) == 0) {
314                     st = EINVAL;
315                     snprintf(errbuf, sizeof(errbuf),
316                              "%s option value missing", arg);
317                     krb5_set_error_message(context, st, "%s", errbuf);
318                     goto cleanup;
319                 }
320             }
321
322             if (arg_val == NULL) {
323                 st = EINVAL;
324                 snprintf(errbuf, sizeof(errbuf),
325                          "%s option value missing", arg);
326                 krb5_set_error_message(context, st, "%s", errbuf);
327                 goto cleanup;
328             }
329             arg_val_len = strlen(arg_val) + 1;
330
331             if (strcmp(arg, TKTPOLICY_ARG) == 0) {
332                 if ((st = krb5_ldap_name_to_policydn (context,
333                                                       arg_val,
334                                                       dptr)) != 0)
335                     goto cleanup;
336             } else {
337                 *dptr = calloc (1, arg_val_len);
338                 if (*dptr == NULL) {
339                     st = ENOMEM;
340                     goto cleanup;
341                 }
342                 memcpy(*dptr, arg_val, arg_val_len);
343             }
344         }
345     }
346
347 cleanup:
348     return st;
349 }
350
351 krb5int_access accessor;
352
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)
356 {
357     krb5_error_code err;
358     ldap_seqof_key_data val;
359
360     /*
361      * This should be pushed back into other library initialization
362      * code.
363      */
364     err = kldap_ensure_initialized ();
365     if (err)
366         return err;
367
368     val.key_data = key_data;
369     val.n_key_data = n_key_data;
370     val.mkvno = mkvno;
371
372     return accessor.asn1_ldap_encode_sequence_of_keys(&val, code);
373 }
374
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)
378 {
379     krb5_error_code err;
380     ldap_seqof_key_data *p;
381
382     /*
383      * This should be pushed back into other library initialization
384      * code.
385      */
386     err = kldap_ensure_initialized ();
387     if (err)
388         return err;
389
390     err = accessor.asn1_ldap_decode_sequence_of_keys(in, &p);
391     if (err)
392         return err;
393     *out = p->key_data;
394     *n_key_data = p->n_key_data;
395     *mkvno = p->mkvno;
396     free(p);
397     return 0;
398 }
399
400
401 /* Decoding ASN.1 encoded key */
402 static struct berval **
403 krb5_encode_krbsecretkey(krb5_key_data *key_data, int n_key_data,
404                          krb5_kvno mkvno) {
405     struct berval **ret = NULL;
406     int currkvno;
407     int num_versions = 1;
408     int i, j, last;
409     krb5_error_code err = 0;
410
411     if (n_key_data <= 0)
412         return NULL;
413
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)
417             num_versions++;
418
419     ret = (struct berval **) calloc (num_versions + 1, sizeof (struct berval *));
420     if (ret == NULL) {
421         err = ENOMEM;
422         goto cleanup;
423     }
424     for (i = 0, last = 0, j = 0, currkvno = key_data[0].key_data_kvno; i < n_key_data; i++) {
425         krb5_data *code;
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,
429                                           mkvno,
430                                           &code);
431             ret[j] = malloc (sizeof (struct berval));
432             if (ret[j] == NULL) {
433                 err = ENOMEM;
434                 goto cleanup;
435             }
436             /*CHECK_NULL(ret[j]); */
437             ret[j]->bv_len = code->length;
438             ret[j]->bv_val = code->data;
439             j++;
440             last = i + 1;
441
442             currkvno = key_data[i].key_data_kvno;
443         }
444     }
445     ret[num_versions] = NULL;
446
447 cleanup:
448
449     if (err != 0) {
450         if (ret != NULL) {
451             for (i = 0; i <= num_versions; i++)
452                 if (ret[i] != NULL)
453                     free (ret[i]);
454             free (ret);
455             ret = NULL;
456         }
457     }
458
459     return ret;
460 }
461
462 static krb5_error_code
463 tl_data2berval (krb5_tl_data *in, struct berval **out)
464 {
465     *out = (struct berval *) malloc (sizeof (struct berval));
466     if (*out == NULL)
467         return ENOMEM;
468
469     (*out)->bv_len = in->tl_data_length + 2;
470     (*out)->bv_val =  (char *) malloc ((*out)->bv_len);
471     if ((*out)->bv_val == NULL) {
472         free (*out);
473         return ENOMEM;
474     }
475
476     STORE16_INT((*out)->bv_val, in->tl_data_type);
477     memcpy ((*out)->bv_val + 2, in->tl_data_contents, in->tl_data_length);
478
479     return 0;
480 }
481
482 krb5_error_code
483 krb5_ldap_put_principal(krb5_context context, krb5_db_entry *entry,
484                         char **db_args)
485 {
486     int                         l=0, kerberos_principal_object_type=0;
487     krb5_error_code             st=0, tempst=0;
488     LDAP                        *ld=NULL;
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;
493     LDAPMod                     **mods=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;
503     xargs_t                     xargs = {0};
504     char                        *polname = NULL;
505     OPERATION optype;
506     krb5_boolean                found_entry = FALSE;
507
508     /* Clear the global error string */
509     krb5_clear_error_message(context);
510
511     SETUP_CONTEXT();
512     if (ldap_context->lrparams == NULL || ldap_context->krbcontainer == NULL)
513         return EINVAL;
514
515     /* get ldap handle */
516     GET_HANDLE();
517
518     if (is_principal_in_realm(ldap_context, entry->princ) != 0) {
519         st = EINVAL;
520         krb5_set_error_message(context, st, "Principal does not belong to the default realm");
521         goto cleanup;
522     }
523
524     /* get the principal information to act on */
525     if (entry->princ) {
526         if (((st=krb5_unparse_name(context, entry->princ, &user)) != 0) ||
527             ((st=krb5_ldap_unparse_principal_name(user)) != 0))
528             goto cleanup;
529     }
530
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
535      */
536     if (entry->mask & KADM5_PRINCIPAL)
537         optype = ADD_PRINCIPAL;
538     else
539         optype = MODIFY_PRINCIPAL;
540
541     if (((st=krb5_get_princ_type(context, entry, &kerberos_principal_object_type)) != 0) ||
542         ((st=krb5_get_userdn(context, entry, &principal_dn)) != 0))
543         goto cleanup;
544
545     if ((st=process_db_args(context, db_args, &xargs, optype)) != 0)
546         goto cleanup;
547
548     if (entry->mask & KADM5_LOAD) {
549         int              tree = 0, ntrees = 0, princlen = 0, numlentries = 0;
550         char             **subtreelist = NULL, *filter = NULL;
551
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).
558          */
559         if (user == NULL) {
560             /* must have principal name for search */
561             st = EINVAL;
562             krb5_set_error_message(context, st, "operation can not continue, principal name not found");
563             goto cleanup;
564         }
565         princlen = strlen(FILTER) + strlen(user) + 2 + 1;      /* 2 for closing brackets */
566         if ((filter = malloc(princlen)) == NULL) {
567             st = ENOMEM;
568             goto cleanup;
569         }
570         snprintf(filter, princlen, FILTER"%s))", user);
571
572         /* get the current subtree list */
573         if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0)
574             goto cleanup;
575
576         found_entry = FALSE;
577         /* search for entry with matching krbprincipalname attribute */
578         for (tree = 0; found_entry == FALSE && tree < ntrees; ++tree) {
579             result = NULL;
580             if (principal_dn == NULL) {
581                 LDAP_SEARCH_1(subtreelist[tree], ldap_context->lrparams->search_scope, filter, principal_attributes, IGNORE_STATUS);
582             } else {
583                 /* just look for entry with principal_dn */
584                 LDAP_SEARCH_1(principal_dn, LDAP_SCOPE_BASE, filter, principal_attributes, IGNORE_STATUS);
585             }
586             if (st == LDAP_SUCCESS) {
587                 numlentries = ldap_count_entries(ld, result);
588                 if (numlentries > 1) {
589                     ldap_msgfree(result);
590                     free(filter);
591                     st = EINVAL;
592                     krb5_set_error_message(context, st,
593                                            "operation can not continue, more than one entry with principal name \"%s\" found",
594                                            user);
595                     goto cleanup;
596                 } else if (numlentries == 1) {
597                     found_entry = TRUE;
598                     if (principal_dn == NULL) {
599                         ent = ldap_first_entry(ld, result);
600                         if (ent != NULL) {
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);
606                                 free(filter);
607                                 goto cleanup;
608                             }
609                         }
610                     }
611                 }
612                 if (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);
617                 free(filter);
618                 goto cleanup;
619             }
620             /*
621              * If it isn't found then assume a standalone princ entry is to
622              * be created.
623              */
624         } /* end for (tree = 0; principal_dn == ... */
625
626         free(filter);
627
628         if (found_entry == FALSE && principal_dn != NULL) {
629             /*
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.
634              */
635             create_standalone_prinicipal = TRUE;
636             standalone_principal_dn = strdup(principal_dn);
637             CHECK_NULL(standalone_principal_dn);
638         }
639     } /* end if (entry->mask & KADM5_LOAD */
640
641     /* time to generate the DN information with the help of
642      * containerdn, principalcontainerreference or
643      * realmcontainerdn information
644      */
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) {
654                     int ost = st;
655                     st = EINVAL;
656                     snprintf(errbuf, sizeof(errbuf), "'%s' not found: ",
657                              xargs.containerdn);
658                     prepend_err_str(context, errbuf, st, ost);
659                 }
660                 goto cleanup;
661             }
662             subtree = strdup(xargs.containerdn);
663         } else if (ldap_context->lrparams->containerref && strlen(ldap_context->lrparams->containerref) != 0) {
664             /*
665              * Here the subtree should be changed with
666              * principalcontainerreference attribute value
667              */
668             subtree = strdup(ldap_context->lrparams->containerref);
669         } else {
670             subtree = strdup(ldap_context->lrparams->realmdn);
671         }
672         CHECK_NULL(subtree);
673
674         if (asprintf(&standalone_principal_dn, "krbprincipalname=%s,%s",
675                      user, subtree) < 0)
676             standalone_principal_dn = NULL;
677         CHECK_NULL(standalone_principal_dn);
678         /*
679          * free subtree when you are done using the subtree
680          * set the boolean create_standalone_prinicipal to TRUE
681          */
682         create_standalone_prinicipal = TRUE;
683         free(subtree);
684         subtree = NULL;
685     }
686
687     /*
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
691      */
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;
696         char             *dn=NULL;
697         krb5_boolean     outofsubtree=TRUE;
698
699         if (xargs.dn != NULL) {
700             dn = xargs.dn;
701         } else if (xargs.linkdn != NULL) {
702             dn = xargs.linkdn;
703         } else if (standalone_principal_dn != NULL) {
704             /*
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.
708              */
709             dn = standalone_principal_dn;
710         }
711
712         /* get the current subtree list */
713         if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0)
714             goto cleanup;
715
716         for (tre=0; tre<ntrees; ++tre) {
717             if (subtreelist[tre] == NULL || strlen(subtreelist[tre]) == 0) {
718                 outofsubtree = FALSE;
719                 break;
720             } else {
721                 dnlen = strlen (dn);
722                 subtreelen = strlen(subtreelist[tre]);
723                 if ((dnlen >= subtreelen) && (strcasecmp((dn + dnlen - subtreelen), subtreelist[tre]) == 0)) {
724                     outofsubtree = FALSE;
725                     break;
726                 }
727             }
728         }
729
730         for (tre=0; tre < ntrees; ++tre) {
731             free(subtreelist[tre]);
732         }
733
734         if (outofsubtree == TRUE) {
735             st = EINVAL;
736             krb5_set_error_message(context, st, "DN is out of the realm subtree");
737             goto cleanup;
738         }
739
740         /*
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.
745          */
746
747         if (standalone_principal_dn == NULL) {
748             /*
749              * If the ldap object is missing, this results in an error.
750              */
751
752             /*
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.
757              */
758             char  *attributes[]={"krbticketpolicyreference", "krbprincipalname", NULL};
759
760             LDAP_SEARCH_1(dn, LDAP_SCOPE_BASE, 0, attributes, IGNORE_STATUS);
761             if (st == LDAP_SUCCESS) {
762                 ent = ldap_first_entry(ld, result);
763                 if (ent != NULL) {
764                     if ((values=ldap_get_values(ld, ent, "krbticketpolicyreference")) != NULL) {
765                         ldap_value_free(values);
766                     }
767
768                     if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
769                         krb_identity_exists = TRUE;
770                         ldap_value_free(values);
771                     }
772                 }
773                 ldap_msgfree(result);
774             } else {
775                 st = set_ldap_error(context, st, OP_SEARCH);
776                 goto cleanup;
777             }
778         }
779     }
780
781     /*
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.
786      */
787
788     if (xargs.dn != NULL && krb_identity_exists == TRUE) {
789         st = EINVAL;
790         snprintf(errbuf, sizeof(errbuf), "ldap object is already kerberized");
791         krb5_set_error_message(context, st, "%s", errbuf);
792         goto cleanup;
793     }
794
795     if (xargs.linkdn != NULL) {
796         /*
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.
802          *
803          * NOTE: kerberos principals on an ldap object can't be
804          * linked to other ldap objects.
805          */
806         if (optype == MODIFY_PRINCIPAL &&
807             kerberos_principal_object_type != KDB_STANDALONE_PRINCIPAL_OBJECT) {
808             st = EINVAL;
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);
812             goto cleanup;
813         }
814         /*
815          * Check the link information. If there is already a link
816          * existing then this operation is not allowed.
817          */
818         {
819             char **linkdns=NULL;
820             int  j=0;
821
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);
826                 goto cleanup;
827             }
828             if (linkdns != NULL) {
829                 st = EINVAL;
830                 snprintf(errbuf, sizeof(errbuf),
831                          "kerberos principal is already linked "
832                          "to a ldap object");
833                 krb5_set_error_message(context, st, "%s", errbuf);
834                 for (j=0; linkdns[j] != NULL; ++j)
835                     free (linkdns[j]);
836                 free (linkdns);
837                 goto cleanup;
838             }
839         }
840
841         establish_links = TRUE;
842     }
843
844     if (entry->mask & KADM5_LAST_SUCCESS) {
845         memset(strval, 0, sizeof(strval));
846         if ((strval[0]=getstringtime(entry->last_success)) == NULL)
847             goto cleanup;
848         if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastSuccessfulAuth", LDAP_MOD_REPLACE, strval)) != 0) {
849             free (strval[0]);
850             goto cleanup;
851         }
852         free (strval[0]);
853     }
854
855     if (entry->mask & KADM5_LAST_FAILED) {
856         memset(strval, 0, sizeof(strval));
857         if ((strval[0]=getstringtime(entry->last_failed)) == NULL)
858             goto cleanup;
859         if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastFailedAuth", LDAP_MOD_REPLACE, strval)) != 0) {
860             free (strval[0]);
861             goto cleanup;
862         }
863         free(strval[0]);
864     }
865
866     if (entry->mask & KADM5_FAIL_AUTH_COUNT) {
867         krb5_kvno fail_auth_count;
868
869         fail_auth_count = entry->fail_auth_count;
870         if (entry->mask & KADM5_FAIL_AUTH_COUNT_INCREMENT)
871             fail_auth_count++;
872
873         st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
874                                        LDAP_MOD_REPLACE,
875                                        fail_auth_count);
876         if (st != 0)
877             goto cleanup;
878     } else if (entry->mask & KADM5_FAIL_AUTH_COUNT_INCREMENT) {
879         int attr_mask = 0;
880         krb5_boolean has_fail_count;
881
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);
885         if (st != 0)
886             goto cleanup;
887         has_fail_count = ((attr_mask & KDB_FAIL_AUTH_COUNT_ATTR) != 0);
888
889         /*
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.
894          */
895 #ifdef LDAP_MOD_INCREMENT
896         if (ldap_server_handle->server_info->modify_increment &&
897             has_fail_count) {
898             st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
899                                            LDAP_MOD_INCREMENT, 1);
900             if (st != 0)
901                 goto cleanup;
902         } else {
903 #endif /* LDAP_MOD_INCREMENT */
904             if (has_fail_count) {
905                 st = krb5_add_int_mem_ldap_mod(&mods,
906                                                "krbLoginFailedCount",
907                                                LDAP_MOD_DELETE,
908                                                entry->fail_auth_count);
909                 if (st != 0)
910                     goto cleanup;
911             }
912             st = krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount",
913                                            LDAP_MOD_ADD,
914                                            entry->fail_auth_count + 1);
915             if (st != 0)
916                 goto cleanup;
917 #ifdef LDAP_MOD_INCREMENT
918         }
919 #endif
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",
924                                        LDAP_MOD_ADD, 0);
925     }
926
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)
929             goto cleanup;
930     }
931
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)
935             goto cleanup;
936     }
937
938     if (entry->mask & KADM5_ATTRIBUTES) {
939         if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbticketflags", LDAP_MOD_REPLACE,
940                                           entry->attributes)) != 0)
941             goto cleanup;
942     }
943
944     if (entry->mask & KADM5_PRINCIPAL) {
945         memset(strval, 0, sizeof(strval));
946         strval[0] = user;
947         if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalname", LDAP_MOD_REPLACE, strval)) != 0)
948             goto cleanup;
949     }
950
951     if (entry->mask & KADM5_PRINC_EXPIRE_TIME) {
952         memset(strval, 0, sizeof(strval));
953         if ((strval[0]=getstringtime(entry->expiration)) == NULL)
954             goto cleanup;
955         if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalexpiration", LDAP_MOD_REPLACE, strval)) != 0) {
956             free (strval[0]);
957             goto cleanup;
958         }
959         free (strval[0]);
960     }
961
962     if (entry->mask & KADM5_PW_EXPIRATION) {
963         memset(strval, 0, sizeof(strval));
964         if ((strval[0]=getstringtime(entry->pw_expiration)) == NULL)
965             goto cleanup;
966         if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpasswordexpiration",
967                                           LDAP_MOD_REPLACE,
968                                           strval)) != 0) {
969             free (strval[0]);
970             goto cleanup;
971         }
972         free (strval[0]);
973     }
974
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) {
981                     goto cleanup;
982                 }
983             }
984         }
985
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)
989                 goto cleanup;
990             strval[0] = polname;
991             if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, strval)) != 0)
992                 goto cleanup;
993         } else {
994             st = EINVAL;
995             krb5_set_error_message(context, st, "Password policy value null");
996             goto cleanup;
997         }
998     } else if (entry->mask & KADM5_LOAD && found_entry == TRUE) {
999         /*
1000          * a load is special in that existing entries must have attrs that
1001          * removed.
1002          */
1003
1004         if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, NULL)) != 0)
1005             goto cleanup;
1006     }
1007
1008     if (entry->mask & KADM5_POLICY_CLR) {
1009         if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_DELETE, NULL)) != 0)
1010             goto cleanup;
1011     }
1012
1013     if (entry->mask & KADM5_KEY_DATA || entry->mask & KADM5_KVNO) {
1014         krb5_kvno mkvno;
1015
1016         if ((st=krb5_dbe_lookup_mkvno(context, entry, &mkvno)) != 0)
1017             goto cleanup;
1018         bersecretkey = krb5_encode_krbsecretkey (entry->key_data,
1019                                                  entry->n_key_data, mkvno);
1020
1021         if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbprincipalkey",
1022                                           LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, bersecretkey)) != 0)
1023             goto cleanup;
1024
1025         if (!(entry->mask & KADM5_PRINCIPAL)) {
1026             memset(strval, 0, sizeof(strval));
1027             if ((strval[0]=getstringtime(entry->pw_expiration)) == NULL)
1028                 goto cleanup;
1029             if ((st=krb5_add_str_mem_ldap_mod(&mods,
1030                                               "krbpasswordexpiration",
1031                                               LDAP_MOD_REPLACE, strval)) != 0) {
1032                 free (strval[0]);
1033                 goto cleanup;
1034             }
1035             free (strval[0]);
1036         }
1037
1038         /* Update last password change whenever a new key is set */
1039         {
1040             krb5_timestamp last_pw_changed;
1041             if ((st=krb5_dbe_lookup_last_pwd_change(context, entry,
1042                                                     &last_pw_changed)) != 0)
1043                 goto cleanup;
1044
1045             memset(strval, 0, sizeof(strval));
1046             if ((strval[0] = getstringtime(last_pw_changed)) == NULL)
1047                 goto cleanup;
1048
1049             if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastPwdChange",
1050                                               LDAP_MOD_REPLACE, strval)) != 0) {
1051                 free (strval[0]);
1052                 goto cleanup;
1053             }
1054             free (strval[0]);
1055         }
1056
1057     } /* Modify Key data ends here */
1058
1059     /* Set tl_data */
1060     if (entry->tl_data != NULL) {
1061         int count = 0;
1062         struct berval **ber_tl_data = NULL;
1063         krb5_tl_data *ptr;
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
1067 #ifdef SECURID
1068                 || ptr->tl_data_type == KRB5_TL_DB_ARGS
1069 #endif
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)
1074                 continue;
1075             count++;
1076         }
1077         if (count != 0) {
1078             int j;
1079             ber_tl_data = (struct berval **) calloc (count + 1,
1080                                                      sizeof (struct berval*));
1081             if (ber_tl_data == NULL) {
1082                 st = ENOMEM;
1083                 goto cleanup;
1084             }
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
1087                  * attributes */
1088                 if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE
1089 #ifdef SECURID
1090                     || ptr->tl_data_type == KRB5_TL_DB_ARGS
1091 #endif
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)
1096                     continue;
1097                 if ((st = tl_data2berval (ptr, &ber_tl_data[j])) != 0)
1098                     break;
1099                 j++;
1100             }
1101             if (st != 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]);
1105                 }
1106                 free (ber_tl_data);
1107                 goto cleanup;
1108             }
1109             ber_tl_data[count] = NULL;
1110             if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbExtraData",
1111                                               LDAP_MOD_REPLACE | LDAP_MOD_BVALUES,
1112                                               ber_tl_data)) != 0)
1113                 goto cleanup;
1114         }
1115         if ((st=krb5_dbe_lookup_last_admin_unlock(context, entry,
1116                                                   &unlock_time)) != 0)
1117             goto cleanup;
1118         if (unlock_time != 0) {
1119             /* Update last admin unlock */
1120             memset(strval, 0, sizeof(strval));
1121             if ((strval[0] = getstringtime(unlock_time)) == NULL)
1122                 goto cleanup;
1123
1124             if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastAdminUnlock",
1125                                               LDAP_MOD_REPLACE, strval)) != 0) {
1126                 free (strval[0]);
1127                 goto cleanup;
1128             }
1129             free (strval[0]);
1130         }
1131     }
1132
1133     /* Directory specific attribute */
1134     if (xargs.tktpolicydn != NULL) {
1135         int tmask=0;
1136
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: ");
1140
1141             strval[0] = xargs.tktpolicydn;
1142             strval[1] = NULL;
1143             if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_REPLACE, strval)) != 0)
1144                 goto cleanup;
1145
1146         } else {
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)
1150                 goto cleanup;
1151         }
1152
1153     }
1154
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)
1159             goto cleanup;
1160     }
1161
1162     /*
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
1168      */
1169     if (mods == NULL)
1170         goto cleanup;
1171
1172     if (create_standalone_prinicipal == TRUE) {
1173         memset(strval, 0, sizeof(strval));
1174         strval[0] = "krbprincipal";
1175         strval[1] = "krbprincipalaux";
1176         strval[2] = "krbTicketPolicyAux";
1177
1178         if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
1179             goto cleanup;
1180
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);
1190                 goto cleanup;
1191             } else {
1192                 st = ldap_add_ext_s(ld, standalone_principal_dn, mods, NULL, NULL);
1193             }
1194         }
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);
1199             goto cleanup;
1200         }
1201     } else {
1202         /*
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
1207          * violations.
1208          */
1209         {
1210             char *attrvalues[] = {"krbprincipalaux", "krbTicketPolicyAux", NULL};
1211             int p, q, r=0, amask=0;
1212
1213             if ((st=checkattributevalue(ld, (xargs.dn) ? xargs.dn : principal_dn,
1214                                         "objectclass", attrvalues, &amask)) != 0)
1215                 goto cleanup;
1216
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];
1221             }
1222             if (r != 0) {
1223                 if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
1224                     goto cleanup;
1225             }
1226         }
1227         if (xargs.dn != NULL)
1228             st=ldap_modify_ext_s(ld, xargs.dn, mods, NULL, NULL);
1229         else
1230             st = ldap_modify_ext_s(ld, principal_dn, mods, NULL, NULL);
1231
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);
1236             goto cleanup;
1237         }
1238
1239         if (entry->mask & KADM5_FAIL_AUTH_COUNT_INCREMENT)
1240             entry->fail_auth_count++;
1241     }
1242
1243 cleanup:
1244     if (user)
1245         free(user);
1246
1247     free_xargs(xargs);
1248
1249     if (standalone_principal_dn)
1250         free(standalone_principal_dn);
1251
1252     if (principal_dn)
1253         free (principal_dn);
1254
1255     if (polname != NULL)
1256         free(polname);
1257
1258     if (subtree)
1259         free (subtree);
1260
1261     if (bersecretkey) {
1262         for (l=0; bersecretkey[l]; ++l) {
1263             if (bersecretkey[l]->bv_val)
1264                 free (bersecretkey[l]->bv_val);
1265             free (bersecretkey[l]);
1266         }
1267         free (bersecretkey);
1268     }
1269
1270     if (keys)
1271         free (keys);
1272
1273     ldap_mods_free(mods, 1);
1274     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
1275     return(st);
1276 }
1277
1278 krb5_error_code
1279 krb5_read_tkt_policy(krb5_context context, krb5_ldap_context *ldap_context,
1280                      krb5_db_entry *entries, char *policy)
1281 {
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;
1286
1287     if ((st=krb5_get_attributes_mask(context, entries, &mask)) != 0)
1288         goto cleanup;
1289
1290     if ((mask & tkt_mask) == tkt_mask)
1291         goto cleanup;
1292
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);
1297             goto cleanup;
1298         }
1299
1300         st = 0; /* reset the return status */
1301     }
1302
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;
1308     }
1309
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;
1315     }
1316
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;
1322     }
1323     krb5_ldap_free_policy(context, tktpoldnparam);
1324
1325 cleanup:
1326     return st;
1327 }
1328
1329 krb5_error_code
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)
1333 {
1334     char                        *user=NULL;
1335     int                         i=0, j=0, noofkeys=0;
1336     krb5_key_data               *key_data=NULL, *tmp;
1337     krb5_error_code             st=0;
1338
1339     if ((st=krb5_unparse_name(context, entries->princ, &user)) != 0)
1340         goto cleanup;
1341
1342     for (i=0; bvalues[i] != NULL; ++i) {
1343         krb5_int16 n_kd;
1344         krb5_key_data *kd;
1345         krb5_data in;
1346
1347         if (bvalues[i]->bv_len == 0)
1348             continue;
1349         in.length = bvalues[i]->bv_len;
1350         in.data = bvalues[i]->bv_val;
1351
1352         st = asn1_decode_sequence_of_keys (&in,
1353                                            &kd,
1354                                            &n_kd,
1355                                            mkvno);
1356
1357         if (st != 0) {
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);
1362             goto cleanup;
1363         }
1364         noofkeys += n_kd;
1365         tmp = key_data;
1366         key_data = realloc (key_data, noofkeys * sizeof (krb5_key_data));
1367         if (key_data == NULL) {
1368             key_data = tmp;
1369             st = ENOMEM;
1370             goto cleanup;
1371         }
1372         for (j = 0; j < n_kd; j++)
1373             key_data[noofkeys - n_kd + j] = kd[j];
1374         free (kd);
1375     }
1376
1377     entries->n_key_data = noofkeys;
1378     entries->key_data = key_data;
1379
1380 cleanup:
1381     ldap_value_free_len(bvalues);
1382     free (user);
1383     return st;
1384 }
1385
1386 static char *
1387 getstringtime(krb5_timestamp epochtime)
1388 {
1389     struct tm           tme;
1390     char                *strtime=NULL;
1391     time_t              posixtime = epochtime;
1392
1393     strtime = calloc (50, 1);
1394     if (strtime == NULL)
1395         return NULL;
1396
1397     if (gmtime_r(&posixtime, &tme) == NULL)
1398         return NULL;
1399
1400     strftime(strtime, 50, "%Y%m%d%H%M%SZ", &tme);
1401     return strtime;
1402 }