xref: /illumos-gate/usr/src/lib/krb5/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c (revision 1da57d551424de5a9d469760be7c4b4d4f10a755)
1 /*
2  * lib/kdb/kdb_ldap/ldap_principal2.c
3  *
4  * Copyright (c) 2004-2005, Novell, Inc.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  *   * Redistributions of source code must retain the above copyright notice,
11  *       this list of conditions and the following disclaimer.
12  *   * Redistributions in binary form must reproduce the above copyright
13  *       notice, this list of conditions and the following disclaimer in the
14  *       documentation and/or other materials provided with the distribution.
15  *   * The copyright holder's name is not used to endorse or promote products
16  *       derived from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
22  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  */
30 /*
31  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
32  * Use is subject to license terms.
33  */
34 
35 #include <time.h>
36 #include "ldap_main.h"
37 #include "kdb_ldap.h"
38 #include "ldap_principal.h"
39 #include "princ_xdr.h"
40 #include "ldap_tkt_policy.h"
41 #include "ldap_pwd_policy.h"
42 #include "ldap_err.h"
43 #include <kadm5/admin.h>
44 #include <libintl.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
berval2tl_data(struct berval * in,krb5_tl_data ** out)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     /* Solaris Kerberos: need cast */
68     UNSTORE16_INT ((unsigned char *)in->bv_val, (*out)->tl_data_type);
69     memcpy ((*out)->tl_data_contents, in->bv_val + 2, (*out)->tl_data_length);
70 
71     return 0;
72 }
73 
74 /*
75  * look up a principal in the directory.
76  */
77 
78 krb5_error_code
krb5_ldap_get_principal(context,searchfor,entries,nentries,more)79 krb5_ldap_get_principal(context, searchfor, entries, nentries, more)
80     krb5_context context;
81     krb5_const_principal searchfor;
82     krb5_db_entry *entries;	/* filled in */
83     int *nentries;		/* how much room/how many found */
84     krb5_boolean *more;		/* are there more? */
85 {
86     char                        *user=NULL, *filter=NULL, **subtree=NULL;
87     unsigned int                tree=0, ntrees=1, princlen=0;
88     krb5_error_code	        tempst=0, st=0;
89     char                        **values=NULL;
90     LDAP	                *ld=NULL;
91     LDAPMessage	                *result=NULL, *ent=NULL;
92     krb5_ldap_context           *ldap_context=NULL;
93     kdb5_dal_handle             *dal_handle=NULL;
94     krb5_ldap_server_handle     *ldap_server_handle=NULL;
95 
96     /* Clear the global error string */
97     krb5_clear_error_message(context);
98 
99     /* set initial values */
100     *nentries = 0;
101     *more = 0;
102     memset(entries, 0, sizeof(*entries));
103 
104     if (searchfor == NULL)
105 	return EINVAL;
106 
107     dal_handle = (kdb5_dal_handle *) context->db_context;
108     ldap_context = (krb5_ldap_context *) dal_handle->db_context;
109 
110     CHECK_LDAP_HANDLE(ldap_context);
111 
112     if (is_principal_in_realm(ldap_context, searchfor) != 0) {
113 	*more = 0;
114 	krb5_set_error_message (context, st, gettext("Principal does not belong to realm"));
115 	goto cleanup;
116     }
117 
118     if ((st=krb5_unparse_name(context, searchfor, &user)) != 0)
119 	goto cleanup;
120 
121     if ((st=krb5_ldap_unparse_principal_name(user)) != 0)
122 	goto cleanup;
123 
124     princlen = strlen(FILTER) + strlen(user) + 2 + 1;      /* 2 for closing brackets */
125     if ((filter = malloc(princlen)) == NULL) {
126 	st = ENOMEM;
127 	goto cleanup;
128     }
129     snprintf(filter, princlen, FILTER"%s))", user);
130 
131     if ((st = krb5_get_subtree_info(ldap_context, &subtree, &ntrees)) != 0)
132 	goto cleanup;
133 
134     GET_HANDLE();
135     for (tree=0; tree < ntrees && *nentries == 0; ++tree) {
136 
137 	LDAP_SEARCH(subtree[tree], ldap_context->lrparams->search_scope, filter, principal_attributes);
138 	for (ent=ldap_first_entry(ld, result); ent != NULL && *nentries == 0; ent=ldap_next_entry(ld, ent)) {
139 
140 	    /* get the associated directory user information */
141 	    if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
142 		int i;
143 
144 		/* a wild-card in a principal name can return a list of kerberos principals.
145 		 * Make sure that the correct principal is returned.
146 		 * NOTE: a principalname k* in ldap server will return all the principals starting with a k
147 		 */
148 		for (i=0; values[i] != NULL; ++i) {
149 		    if (strcasecmp(values[i], user) == 0) {
150 			*nentries = 1;
151 			break;
152 		    }
153 		}
154 		ldap_value_free(values);
155 
156 		if (*nentries == 0) /* no matching principal found */
157 		    continue;
158 	    }
159 
160 	    if ((st = populate_krb5_db_entry(context, ldap_context, ld, ent, searchfor,
161 			entries)) != 0)
162 		goto cleanup;
163 	}
164 	ldap_msgfree(result);
165 	result = NULL;
166     } /* for (tree=0 ... */
167 
168     /* once done, put back the ldap handle */
169     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
170     ldap_server_handle = NULL;
171 
172 cleanup:
173     ldap_msgfree(result);
174 
175     if (*nentries == 0 || st != 0)
176 	krb5_dbe_free_contents(context, entries);
177 
178     if (filter)
179 	free (filter);
180 
181     if (subtree) {
182 	for (; ntrees; --ntrees)
183 	    if (subtree[ntrees-1])
184 		free (subtree[ntrees-1]);
185 	free (subtree);
186     }
187 
188     if (ldap_server_handle)
189 	krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
190 
191     if (user)
192 	free(user);
193 
194     return st;
195 }
196 
197 typedef enum{ ADD_PRINCIPAL, MODIFY_PRINCIPAL } OPERATION;
198 /*
199  * ptype is creating confusions. Additionally the logic
200  * surronding ptype is redundunt and can be achevied
201  * with the help of dn and containerdn members.
202  * so dropping the ptype member
203  */
204 
205 typedef struct _xargs_t {
206     char           *dn;
207     char           *linkdn;
208     krb5_boolean   dn_from_kbd;
209     char           *containerdn;
210     char           *tktpolicydn;
211 }xargs_t;
212 
213 static void
free_xargs(xargs)214 free_xargs(xargs)
215     xargs_t xargs;
216 {
217     if (xargs.dn)
218 	free (xargs.dn);
219     if (xargs.linkdn)
220 	free(xargs.linkdn);
221     if (xargs.containerdn)
222 	free (xargs.containerdn);
223     if (xargs.tktpolicydn)
224 	free (xargs.tktpolicydn);
225 }
226 
227 static krb5_error_code
process_db_args(context,db_args,xargs,optype)228 process_db_args(context, db_args, xargs, optype)
229     krb5_context   context;
230     char           **db_args;
231     xargs_t        *xargs;
232     OPERATION      optype;
233 {
234     int                   i=0;
235     krb5_error_code       st=0;
236     char                  errbuf[1024];
237     char                  *arg=NULL, *arg_val=NULL;
238     char                  **dptr=NULL;
239     unsigned int          arg_val_len=0;
240 
241     if (db_args) {
242 	for (i=0; db_args[i]; ++i) {
243 	    arg = strtok_r(db_args[i], "=", &arg_val);
244 	    if (strcmp(arg, TKTPOLICY_ARG) == 0) {
245 		dptr = &xargs->tktpolicydn;
246 	    } else {
247 		if (strcmp(arg, USERDN_ARG) == 0) {
248 		    if (optype == MODIFY_PRINCIPAL ||
249 			xargs->dn != NULL || xargs->containerdn != NULL ||
250 			xargs->linkdn != NULL) {
251 			st = EINVAL;
252 			snprintf(errbuf, sizeof(errbuf),
253 				 gettext("%s option not supported"), arg);
254 			krb5_set_error_message(context, st, "%s", errbuf);
255 			goto cleanup;
256 		    }
257 		    dptr = &xargs->dn;
258 		} else if (strcmp(arg, CONTAINERDN_ARG) == 0) {
259 		    if (optype == MODIFY_PRINCIPAL ||
260 			xargs->dn != NULL || xargs->containerdn != NULL) {
261 			st = EINVAL;
262 			snprintf(errbuf, sizeof(errbuf),
263 				 gettext("%s option not supported"), arg);
264 			krb5_set_error_message(context, st, "%s", errbuf);
265 			goto cleanup;
266 		    }
267 		    dptr = &xargs->containerdn;
268 		} else if (strcmp(arg, LINKDN_ARG) == 0) {
269 		    if (xargs->dn != NULL || xargs->linkdn != NULL) {
270 			st = EINVAL;
271 			snprintf(errbuf, sizeof(errbuf),
272 				 gettext("%s option not supported"), arg);
273 			krb5_set_error_message(context, st, "%s", errbuf);
274 			goto cleanup;
275 		    }
276 		    dptr = &xargs->linkdn;
277 		} else {
278 		    st = EINVAL;
279 		    snprintf(errbuf, sizeof(errbuf), gettext("unknown option: %s"), arg);
280 		    krb5_set_error_message(context, st, "%s", errbuf);
281 		    goto cleanup;
282 		}
283 
284 		xargs->dn_from_kbd = TRUE;
285 		if (arg_val == NULL || strlen(arg_val) == 0) {
286 		    st = EINVAL;
287 		    snprintf(errbuf, sizeof(errbuf),
288 			     gettext("%s option value missing"), arg);
289 		    krb5_set_error_message(context, st, "%s", errbuf);
290 		    goto cleanup;
291 		}
292 	    }
293 
294 	    if (arg_val == NULL) {
295 		st = EINVAL;
296 		snprintf(errbuf, sizeof(errbuf),
297 			 gettext("%s option value missing"), arg);
298 		krb5_set_error_message(context, st, "%s", errbuf);
299 		goto cleanup;
300 	    }
301 	    arg_val_len = strlen(arg_val) + 1;
302 
303 	    if (strcmp(arg, TKTPOLICY_ARG) == 0) {
304 		if ((st = krb5_ldap_name_to_policydn (context,
305 						      arg_val,
306 						      dptr)) != 0)
307 		    goto cleanup;
308 	    } else {
309 		*dptr = calloc (1, arg_val_len);
310 		if (*dptr == NULL) {
311 		    st = ENOMEM;
312 		    goto cleanup;
313 		}
314 		memcpy(*dptr, arg_val, arg_val_len);
315 	    }
316 	}
317     }
318 
319 cleanup:
320     return st;
321 }
322 
323 krb5int_access accessor;
324 extern int kldap_ensure_initialized (void);
325 
326 static krb5_error_code
asn1_encode_sequence_of_keys(krb5_key_data * key_data,krb5_int16 n_key_data,krb5_int32 mkvno,krb5_data ** code)327 asn1_encode_sequence_of_keys (krb5_key_data *key_data, krb5_int16 n_key_data,
328 			      krb5_int32 mkvno, krb5_data **code)
329 {
330     krb5_error_code err;
331 
332     /*
333      * This should be pushed back into other library initialization
334      * code.
335      */
336     err = kldap_ensure_initialized ();
337     if (err)
338 	return err;
339 
340     return accessor.asn1_ldap_encode_sequence_of_keys(key_data, n_key_data,
341 						      mkvno, code);
342 }
343 
344 static krb5_error_code
asn1_decode_sequence_of_keys(krb5_data * in,krb5_key_data ** out,krb5_int16 * n_key_data,int * mkvno)345 asn1_decode_sequence_of_keys (krb5_data *in, krb5_key_data **out,
346 			      krb5_int16 *n_key_data, int *mkvno)
347 {
348     krb5_error_code err;
349 
350     /*
351      * This should be pushed back into other library initialization
352      * code.
353      */
354     err = kldap_ensure_initialized ();
355     if (err)
356 	return err;
357 
358     return accessor.asn1_ldap_decode_sequence_of_keys(in, out, n_key_data,
359 						      mkvno);
360 }
361 
362 
363 /* Decoding ASN.1 encoded key */
364 static struct berval **
krb5_encode_krbsecretkey(krb5_key_data * key_data,int n_key_data)365 krb5_encode_krbsecretkey(krb5_key_data *key_data, int n_key_data) {
366     struct berval **ret = NULL;
367     int currkvno;
368     int num_versions = 1;
369     int i, j, last;
370     krb5_error_code err = 0;
371 
372     if (n_key_data <= 0)
373 	return NULL;
374 
375     /* Find the number of key versions */
376     for (i = 0; i < n_key_data - 1; i++)
377 	if (key_data[i].key_data_kvno != key_data[i + 1].key_data_kvno)
378 	    num_versions++;
379 
380     ret = (struct berval **) calloc (num_versions + 1, sizeof (struct berval *));
381     if (ret == NULL) {
382 	err = ENOMEM;
383 	goto cleanup;
384     }
385     for (i = 0, last = 0, j = 0, currkvno = key_data[0].key_data_kvno; i < n_key_data; i++) {
386 	krb5_data *code;
387 	if (i == n_key_data - 1 || key_data[i + 1].key_data_kvno != currkvno) {
388 	    code = NULL;
389 	    asn1_encode_sequence_of_keys (key_data+last,
390 					  (krb5_int16) i - last + 1,
391 					  0, /* For now, mkvno == 0*/
392 					  &code);
393 	    if (code == NULL) {
394 		err = ENOMEM;
395 		goto cleanup;
396 	    }
397 	    ret[j] = malloc (sizeof (struct berval));
398 	    if (ret[j] == NULL) {
399 		err = ENOMEM;
400 		goto cleanup;
401 	    }
402 	    /*CHECK_NULL(ret[j]); */
403 	    ret[j]->bv_len = code->length;
404 	    ret[j]->bv_val = code->data;
405 	    j++;
406 	    last = i + 1;
407 
408 	    currkvno = key_data[i].key_data_kvno;
409 	    /* Solaris Kerberos: fix memleak */
410 	    free(code);
411 	}
412     }
413     ret[num_versions] = NULL;
414 
415 cleanup:
416 
417     if (err != 0) {
418 	if (ret != NULL) {
419 	    for (i = 0; i <= num_versions; i++)
420 		if (ret[i] != NULL)
421 		    free (ret[i]);
422 	    free (ret);
423 	    ret = NULL;
424 	}
425     }
426 
427     return ret;
428 }
429 
tl_data2berval(krb5_tl_data * in,struct berval ** out)430 static krb5_error_code tl_data2berval (krb5_tl_data *in, struct berval **out) {
431     *out = (struct berval *) malloc (sizeof (struct berval));
432     if (*out == NULL)
433 	return ENOMEM;
434 
435     (*out)->bv_len = in->tl_data_length + 2;
436     (*out)->bv_val =  (char *) malloc ((*out)->bv_len);
437     if ((*out)->bv_val == NULL) {
438 	free (*out);
439 	return ENOMEM;
440     }
441 
442     /* Solaris Kerberos: need cast */
443     STORE16_INT((unsigned char *)(*out)->bv_val, in->tl_data_type);
444     memcpy ((*out)->bv_val + 2, in->tl_data_contents, in->tl_data_length);
445 
446     return 0;
447 }
448 
449 krb5_error_code
krb5_ldap_put_principal(context,entries,nentries,db_args)450 krb5_ldap_put_principal(context, entries, nentries, db_args)
451     krb5_context               context;
452     krb5_db_entry              *entries;
453     register int               *nentries;         /* number of entry structs to update */
454     char                       **db_args;
455 {
456     int 		        i=0, l=0, kerberos_principal_object_type=0;
457     krb5_error_code 	        st=0, tempst=0;
458     LDAP  		        *ld=NULL;
459     LDAPMessage                 *result=NULL, *ent=NULL;
460     char                        *user=NULL, *subtree=NULL, *principal_dn=NULL;
461     char                        **values=NULL, *strval[10]={NULL}, errbuf[1024];
462     struct berval	        **bersecretkey=NULL;
463     LDAPMod 		        **mods=NULL;
464     krb5_boolean                create_standalone_prinicipal=FALSE;
465     krb5_boolean                krb_identity_exists=FALSE, establish_links=FALSE;
466     char                        *standalone_principal_dn=NULL;
467     krb5_tl_data                *tl_data=NULL;
468     kdb5_dal_handle             *dal_handle=NULL;
469     krb5_ldap_context           *ldap_context=NULL;
470     krb5_ldap_server_handle     *ldap_server_handle=NULL;
471     osa_princ_ent_rec 	        princ_ent;
472     xargs_t                     xargs = {0};
473     char                        *polname = NULL;
474     OPERATION optype;
475     krb5_boolean     		found_entry = FALSE;
476     struct berval **ber_tl_data = NULL;
477 
478     /* Clear the global error string */
479     krb5_clear_error_message(context);
480 
481     SETUP_CONTEXT();
482     if (ldap_context->lrparams == NULL || ldap_context->krbcontainer == NULL)
483 	return EINVAL;
484 
485     /* get ldap handle */
486     GET_HANDLE();
487 
488     for (i=0; i < *nentries; ++i, ++entries) {
489 	if (is_principal_in_realm(ldap_context, entries->princ) != 0) {
490 	    st = EINVAL;
491 	    krb5_set_error_message(context, st, gettext("Principal does not belong to the default realm"));
492 	    goto cleanup;
493 	}
494 
495 	/* get the principal information to act on */
496 	if (entries->princ) {
497 	    if (((st=krb5_unparse_name(context, entries->princ, &user)) != 0) ||
498 		((st=krb5_ldap_unparse_principal_name(user)) != 0))
499 		goto cleanup;
500 	}
501 
502 	/* Identity the type of operation, it can be
503 	 * add principal or modify principal.
504 	 * hack if the entries->mask has KRB_PRINCIPAL flag set
505 	 * then it is a add operation
506 	 */
507 	if (entries->mask & KADM5_PRINCIPAL)
508 	    optype = ADD_PRINCIPAL;
509 	else
510 	    optype = MODIFY_PRINCIPAL;
511 
512 	if (((st=krb5_get_princ_type(context, entries, &kerberos_principal_object_type)) != 0) ||
513 	    ((st=krb5_get_userdn(context, entries, &principal_dn)) != 0))
514 	    goto cleanup;
515 
516 	if ((st=process_db_args(context, db_args, &xargs, optype)) != 0)
517 	    goto cleanup;
518 
519 	if (entries->mask & KADM5_LOAD) {
520 	    int              tree = 0, princlen = 0, numlentries = 0;
521 	    unsigned int     ntrees = 0;
522 	    char             **subtreelist = NULL, *filter = NULL;
523 
524 	    /*  A load operation is special, will do a mix-in (add krbprinc
525 	     *  attrs to a non-krb object entry) if an object exists with a
526 	     *  matching krbprincipalname attribute so try to find existing
527 	     *  object and set principal_dn.  This assumes that the
528 	     *  krbprincipalname attribute is unique (only one object entry has
529 	     *  a particular krbprincipalname attribute).
530 	     */
531 	    if (user == NULL) {
532 		/* must have principal name for search */
533 		st = EINVAL;
534 		krb5_set_error_message(context, st, gettext("operation can not continue, principal name not found"));
535 		goto cleanup;
536 	    }
537 	    princlen = strlen(FILTER) + strlen(user) + 2 + 1;      /* 2 for closing brackets */
538 	    if ((filter = malloc(princlen)) == NULL) {
539 		st = ENOMEM;
540 		goto cleanup;
541 	    }
542 	    snprintf(filter, princlen, FILTER"%s))", user);
543 
544 	    /* get the current subtree list */
545 	    if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0)
546 		goto cleanup;
547 
548 	    found_entry = FALSE;
549 	    /* search for entry with matching krbprincipalname attribute */
550 	    for (tree = 0; found_entry == FALSE && tree < ntrees; ++tree) {
551 		result = NULL;
552 		if (principal_dn == NULL) {
553 		    LDAP_SEARCH_1(subtreelist[tree], ldap_context->lrparams->search_scope, filter, principal_attributes, IGNORE_STATUS);
554 		} else {
555 		    /* just look for entry with principal_dn */
556 		    LDAP_SEARCH_1(principal_dn, LDAP_SCOPE_BASE, filter, principal_attributes, IGNORE_STATUS);
557 		}
558 		if (st == LDAP_SUCCESS) {
559 		    numlentries = ldap_count_entries(ld, result);
560 		    if (numlentries > 1) {
561 			ldap_msgfree(result);
562 			free(filter);
563 			st = EINVAL;
564 			krb5_set_error_message(context, st,
565 			    gettext("operation can not continue, more than one entry with principal name \"%s\" found"),
566 			    user);
567 			goto cleanup;
568 		    } else if (numlentries == 1) {
569 			found_entry = TRUE;
570 			if (principal_dn == NULL) {
571 			    ent = ldap_first_entry(ld, result);
572 			    if (ent != NULL) {
573 				/* setting principal_dn will cause that entry to be modified further down */
574 				if ((principal_dn = ldap_get_dn(ld, ent)) == NULL) {
575 				    ldap_get_option (ld, LDAP_OPT_RESULT_CODE, &st);
576 				    st = set_ldap_error (context, st, 0);
577 				    ldap_msgfree(result);
578 				    free(filter);
579 				    goto cleanup;
580 				}
581 			    }
582 			}
583 		    }
584 		    if (result)
585 			ldap_msgfree(result);
586 		} else if (st != LDAP_NO_SUCH_OBJECT) {
587 		    /* could not perform search, return with failure */
588 		    st = set_ldap_error (context, st, 0);
589 		    free(filter);
590 		    goto cleanup;
591 		}
592 		/*
593 		 * If it isn't found then assume a standalone princ entry is to
594 		 * be created.
595 		 */
596 	    } /* end for (tree = 0; principal_dn == ... */
597 
598 	    free(filter);
599 
600 	    if (found_entry == FALSE && principal_dn != NULL) {
601 		/*
602 		 * if principal_dn is null then there is code further down to
603 		 * deal with setting standalone_principal_dn.  Also note that
604 		 * this will set create_standalone_prinicipal true for
605 		 * non-mix-in entries which is okay if loading from a dump.
606 		 */
607 		create_standalone_prinicipal = TRUE;
608 		standalone_principal_dn = strdup(principal_dn);
609 		CHECK_NULL(standalone_principal_dn);
610 	    }
611 	} /* end if (entries->mask & KADM5_LOAD */
612 
613 	/* time to generate the DN information with the help of
614 	 * containerdn, principalcontainerreference or
615 	 * realmcontainerdn information
616 	 */
617 	if (principal_dn == NULL && xargs.dn == NULL) { /* creation of standalone principal */
618 	    /* get the subtree information */
619 	    if (entries->princ->length == 2 && entries->princ->data[0].length == strlen("krbtgt") &&
620 		strncmp(entries->princ->data[0].data, "krbtgt", entries->princ->data[0].length) == 0) {
621 		/* if the principal is a inter-realm principal, always created in the realm container */
622 		subtree = strdup(ldap_context->lrparams->realmdn);
623 	    } else if (xargs.containerdn) {
624 		if ((st=checkattributevalue(ld, xargs.containerdn, NULL, NULL, NULL)) != 0) {
625 		    if (st == KRB5_KDB_NOENTRY || st == KRB5_KDB_CONSTRAINT_VIOLATION) {
626 			int ost = st;
627 			st = EINVAL;
628 			snprintf(errbuf, sizeof(errbuf), gettext("'%s' not found: "), xargs.containerdn);
629 			prepend_err_str(context, errbuf, st, ost);
630 		    }
631 		    goto cleanup;
632 		}
633 		subtree = strdup(xargs.containerdn);
634 	    } else if (ldap_context->lrparams->containerref && strlen(ldap_context->lrparams->containerref) != 0) {
635 		/*
636 		 * Here the subtree should be changed with
637 		 * principalcontainerreference attribute value
638 		 */
639 		subtree = strdup(ldap_context->lrparams->containerref);
640 	    } else {
641 		subtree = strdup(ldap_context->lrparams->realmdn);
642 	    }
643 	    CHECK_NULL(subtree);
644 
645 	    standalone_principal_dn = malloc(strlen("krbprincipalname=") + strlen(user) + strlen(",") +
646 					     strlen(subtree) + 1);
647 	    CHECK_NULL(standalone_principal_dn);
648 	    /*LINTED*/
649 	    sprintf(standalone_principal_dn, "krbprincipalname=%s,%s", user, subtree);
650 	    /*
651 	     * free subtree when you are done using the subtree
652 	     * set the boolean create_standalone_prinicipal to TRUE
653 	     */
654 	    create_standalone_prinicipal = TRUE;
655 	    free(subtree);
656 	    subtree = NULL;
657 	}
658 
659 	/*
660 	 * If the DN information is presented by the user, time to
661 	 * validate the input to ensure that the DN falls under
662 	 * any of the subtrees
663 	 */
664 	if (xargs.dn_from_kbd == TRUE) {
665 	    /* make sure the DN falls in the subtree */
666 	    int              tre=0, dnlen=0, subtreelen=0;
667 	    unsigned int     ntrees = 0;
668 	    char             **subtreelist=NULL;
669 	    char             *dn=NULL;
670 	    krb5_boolean     outofsubtree=TRUE;
671 
672 	    if (xargs.dn != NULL) {
673 		dn = xargs.dn;
674 	    } else if (xargs.linkdn != NULL) {
675 		dn = xargs.linkdn;
676 	    } else if (standalone_principal_dn != NULL) {
677 		/*
678 		 * Even though the standalone_principal_dn is constructed
679 		 * within this function, there is the containerdn input
680 		 * from the user that can become part of the it.
681 		 */
682 		dn = standalone_principal_dn;
683 	    }
684 
685 	    /* get the current subtree list */
686 	    if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0)
687 		goto cleanup;
688 
689 	    for (tre=0; tre<ntrees; ++tre) {
690 		if (subtreelist[tre] == NULL || strlen(subtreelist[tre]) == 0) {
691 		    outofsubtree = FALSE;
692 		    break;
693 		} else {
694 		    dnlen = strlen (dn);
695 		    subtreelen = strlen(subtreelist[tre]);
696 		    if ((dnlen >= subtreelen) && (strcasecmp((dn + dnlen - subtreelen), subtreelist[tre]) == 0)) {
697 			outofsubtree = FALSE;
698 			break;
699 		    }
700 		}
701 	    }
702 
703 	    for (tre=0; tre < ntrees; ++tre) {
704 		free(subtreelist[tre]);
705 	    }
706 
707 	    if (outofsubtree == TRUE) {
708 		st = EINVAL;
709 		krb5_set_error_message(context, st, gettext("DN is out of the realm subtree"));
710 		goto cleanup;
711 	    }
712 
713 	    /*
714 	     * dn value will be set either by dn, linkdn or the standalone_principal_dn
715 	     * In the first 2 cases, the dn should be existing and in the last case we
716 	     * are supposed to create the ldap object. so the below should not be
717 	     * executed for the last case.
718 	     */
719 
720 	    if (standalone_principal_dn == NULL) {
721 		/*
722 		 * If the ldap object is missing, this results in an error.
723 		 */
724 
725 		/*
726 		 * Search for krbprincipalname attribute here.
727 		 * This is to find if a kerberos identity is already present
728 		 * on the ldap object, in which case adding a kerberos identity
729 		 * on the ldap object should result in an error.
730 		 */
731 		char  *attributes[]={"krbticketpolicyreference", "krbprincipalname", NULL};
732 
733 		LDAP_SEARCH_1(dn, LDAP_SCOPE_BASE, 0, attributes, IGNORE_STATUS);
734 		if (st == LDAP_SUCCESS) {
735 		    ent = ldap_first_entry(ld, result);
736 		    if (ent != NULL) {
737 			if ((values=ldap_get_values(ld, ent, "krbticketpolicyreference")) != NULL) {
738 			    ldap_value_free(values);
739 			}
740 
741 			if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
742 			    krb_identity_exists = TRUE;
743 			    ldap_value_free(values);
744 			}
745 		    }
746 		    ldap_msgfree(result);
747 		} else {
748 		    st = set_ldap_error(context, st, OP_SEARCH);
749 		    goto cleanup;
750 		}
751 	    }
752 	}
753 
754 	/*
755 	 * If xargs.dn is set then the request is to add a
756 	 * kerberos principal on a ldap object, but if
757 	 * there is one already on the ldap object this
758 	 * should result in an error.
759 	 */
760 
761 	if (xargs.dn != NULL && krb_identity_exists == TRUE) {
762 	    st = EINVAL;
763 	    snprintf(errbuf, sizeof(errbuf), gettext("ldap object is already kerberized"));
764 	    krb5_set_error_message(context, st, "%s", errbuf);
765 	    goto cleanup;
766 	}
767 
768 	if (xargs.linkdn != NULL) {
769 	    /*
770 	     * link information can be changed using modprinc.
771 	     * However, link information can be changed only on the
772 	     * standalone kerberos principal objects. A standalone
773 	     * kerberos principal object is of type krbprincipal
774 	     * structural objectclass.
775 	     *
776 	     * NOTE: kerberos principals on an ldap object can't be
777 	     * linked to other ldap objects.
778 	     */
779 	    if (optype == MODIFY_PRINCIPAL &&
780 		kerberos_principal_object_type != KDB_STANDALONE_PRINCIPAL_OBJECT) {
781 		st = EINVAL;
782 		snprintf(errbuf, sizeof(errbuf),
783 		    gettext("link information can not be set/updated as the kerberos principal belongs to an ldap object"));
784 		krb5_set_error_message(context, st, "%s", errbuf);
785 		goto cleanup;
786 	    }
787             /*
788              * Check the link information. If there is already a link
789              * existing then this operation is not allowed.
790              */
791             {
792                 char **linkdns=NULL;
793                 int  j=0;
794 
795                 if ((st=krb5_get_linkdn(context, entries, &linkdns)) != 0) {
796                     snprintf(errbuf, sizeof(errbuf),
797                              gettext("Failed getting object references"));
798                     krb5_set_error_message(context, st, "%s", errbuf);
799                     goto cleanup;
800                 }
801                 if (linkdns != NULL) {
802                     st = EINVAL;
803                     snprintf(errbuf, sizeof(errbuf),
804                              gettext("kerberos principal is already linked "
805                              "to a ldap object"));
806                     krb5_set_error_message(context, st, "%s", errbuf);
807                     for (j=0; linkdns[j] != NULL; ++j)
808                         free (linkdns[j]);
809                     free (linkdns);
810                     goto cleanup;
811                 }
812             }
813 
814 	    establish_links = TRUE;
815 	}
816 
817 	if ((entries->last_success)!=0) {
818 	    memset(strval, 0, sizeof(strval));
819 	    if ((strval[0]=getstringtime(entries->last_success)) == NULL)
820 		goto cleanup;
821 	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastSuccessfulAuth", LDAP_MOD_REPLACE, strval)) != 0) {
822 		free (strval[0]);
823 		goto cleanup;
824 	    }
825 	    free (strval[0]);
826 	}
827 
828 	if (entries->last_failed!=0) {
829 	    memset(strval, 0, sizeof(strval));
830 	    if ((strval[0]=getstringtime(entries->last_failed)) == NULL)
831 		goto cleanup;
832 	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastFailedAuth", LDAP_MOD_REPLACE, strval)) != 0) {
833 		free (strval[0]);
834 		goto cleanup;
835 	    }
836 	    free(strval[0]);
837 	}
838 
839 	if (entries->fail_auth_count!=0) {
840 	    if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount", LDAP_MOD_REPLACE, entries->fail_auth_count)) !=0)
841 		goto cleanup;
842 	}
843 
844 	if (entries->mask & KADM5_MAX_LIFE) {
845 	    if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxticketlife", LDAP_MOD_REPLACE, entries->max_life)) != 0)
846 		goto cleanup;
847 	}
848 
849 	if (entries->mask & KADM5_MAX_RLIFE) {
850 	    if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxrenewableage", LDAP_MOD_REPLACE,
851 					      entries->max_renewable_life)) != 0)
852 		goto cleanup;
853 	}
854 
855 	if (entries->mask & KADM5_ATTRIBUTES) {
856 	    if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbticketflags", LDAP_MOD_REPLACE,
857 					      entries->attributes)) != 0)
858 		goto cleanup;
859 	}
860 
861 	if (entries->mask & KADM5_PRINCIPAL) {
862 	    memset(strval, 0, sizeof(strval));
863 	    strval[0] = user;
864 	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalname", LDAP_MOD_REPLACE, strval)) != 0)
865 		goto cleanup;
866 	}
867 
868 	/*
869 	 * Solaris Kerberos: this logic was not working properly when
870 	 * default_principal_expiration set.
871 	 */
872 	if (entries->mask & KADM5_PRINC_EXPIRE_TIME || entries->expiration != 0) {
873 	    memset(strval, 0, sizeof(strval));
874 	    if ((strval[0]=getstringtime(entries->expiration)) == NULL)
875 		goto cleanup;
876 	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalexpiration", LDAP_MOD_REPLACE, strval)) != 0) {
877 		free (strval[0]);
878 		goto cleanup;
879 	    }
880 	    free (strval[0]);
881 	}
882 
883 	/*
884 	 * Solaris Kerberos: in case KADM5_PW_EXPIRATION isn't set, check
885 	 * pw_expiration
886 	 */
887 	if (entries->mask & KADM5_PW_EXPIRATION || entries->pw_expiration != 0) {
888 	    memset(strval, 0, sizeof(strval));
889 	    if ((strval[0]=getstringtime(entries->pw_expiration)) == NULL)
890 		goto cleanup;
891 	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpasswordexpiration",
892 					      LDAP_MOD_REPLACE,
893 					      strval)) != 0) {
894 		free (strval[0]);
895 		goto cleanup;
896 	    }
897 	    free (strval[0]);
898 	}
899 
900 	if (entries->mask & KADM5_POLICY) {
901 	    memset(&princ_ent, 0, sizeof(princ_ent));
902 	    for (tl_data=entries->tl_data; tl_data; tl_data=tl_data->tl_data_next) {
903 		if (tl_data->tl_data_type == KRB5_TL_KADM_DATA) {
904 		    /* FIX ME: I guess the princ_ent should be freed after this call */
905 		    if ((st = krb5_lookup_tl_kadm_data(tl_data, &princ_ent)) != 0) {
906 			goto cleanup;
907 		    }
908 		}
909 	    }
910 
911 	    if (princ_ent.aux_attributes & KADM5_POLICY) {
912 		memset(strval, 0, sizeof(strval));
913 		if ((st = krb5_ldap_name_to_policydn (context, princ_ent.policy, &polname)) != 0)
914 		    goto cleanup;
915 		strval[0] = polname;
916 		/* Solaris Kerberos: fix memleak */
917 		free(princ_ent.policy);
918 		if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, strval)) != 0)
919 		    goto cleanup;
920 	    } else {
921 		st = EINVAL;
922 		krb5_set_error_message(context, st, gettext("Password policy value null"));
923 		goto cleanup;
924 	    }
925 	} else if (entries->mask & KADM5_LOAD && found_entry == TRUE) {
926 	    /*
927 	     * a load is special in that existing entries must have attrs that
928 	     * removed.
929 	     */
930 
931 	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, NULL)) != 0)
932 		goto cleanup;
933 	}
934 
935 	if (entries->mask & KADM5_POLICY_CLR) {
936 	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_DELETE, NULL)) != 0)
937 		goto cleanup;
938 	}
939 
940 	if (entries->mask & KADM5_KEY_DATA || entries->mask & KADM5_KVNO) {
941 	    bersecretkey = krb5_encode_krbsecretkey (entries->key_data,
942 						     entries->n_key_data);
943 
944 	    if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbprincipalkey",
945 					      LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, bersecretkey)) != 0)
946 		goto cleanup;
947 
948 	    if (!(entries->mask & KADM5_PRINCIPAL)) {
949 		memset(strval, 0, sizeof(strval));
950 		if ((strval[0]=getstringtime(entries->pw_expiration)) == NULL)
951 		    goto cleanup;
952 		if ((st=krb5_add_str_mem_ldap_mod(&mods,
953 						  "krbpasswordexpiration",
954 						  LDAP_MOD_REPLACE, strval)) != 0) {
955 		    free (strval[0]);
956 		    goto cleanup;
957 		}
958 		free (strval[0]);
959 	    }
960 
961 	    /* Update last password change whenever a new key is set */
962 	    {
963 		krb5_timestamp last_pw_changed;
964 		if ((st=krb5_dbe_lookup_last_pwd_change(context, entries,
965 							&last_pw_changed)) != 0)
966 		    goto cleanup;
967 
968 		memset(strval, 0, sizeof(strval));
969 		if ((strval[0] = getstringtime(last_pw_changed)) == NULL)
970 		    goto cleanup;
971 
972 		if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastPwdChange",
973 						  LDAP_MOD_REPLACE, strval)) != 0) {
974 		    free (strval[0]);
975 		    goto cleanup;
976 		}
977 		free (strval[0]);
978 	    }
979 
980 	} /* Modify Key data ends here */
981 
982 	/* Set tl_data */
983 	if (entries->tl_data != NULL) {
984 	    int count = 0;
985 	    /* struct berval **ber_tl_data = NULL; */
986 	    krb5_tl_data *ptr;
987 	    for (ptr = entries->tl_data; ptr != NULL; ptr = ptr->tl_data_next) {
988 		if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE
989 #ifdef SECURID
990 		    || ptr->tl_data_type == KRB5_TL_DB_ARGS
991 #endif
992 		    || ptr->tl_data_type == KDB_TL_USER_INFO)
993 		    continue;
994 
995 		/* Solaris Kerberos: fix key history issue */
996 		if (ptr->tl_data_type == KRB5_TL_KADM_DATA && ! entries->mask & KADM5_KEY_HIST)
997 		    continue;
998 
999 		count++;
1000 	    }
1001 	    if (count != 0) {
1002 		int j;
1003 		ber_tl_data = (struct berval **) calloc (count + 1,
1004 							 sizeof (struct berval*));
1005 		if (ber_tl_data == NULL) {
1006 		    st = ENOMEM;
1007 		    goto cleanup;
1008 		}
1009 		for (j = 0, ptr = entries->tl_data; ptr != NULL; ptr = ptr->tl_data_next) {
1010 		    /* Ignore tl_data that are stored in separate directory
1011 		     * attributes */
1012 		    if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE
1013 #ifdef SECURID
1014 			|| ptr->tl_data_type == KRB5_TL_DB_ARGS
1015 #endif
1016 			|| ptr->tl_data_type == KDB_TL_USER_INFO)
1017 			continue;
1018 
1019 		    /*
1020 		     * Solaris Kerberos: key history needs to be stored (it's in
1021 		     * the KRB5_TL_KADM_DATA).
1022 		     */
1023 		    if (ptr->tl_data_type == KRB5_TL_KADM_DATA && ! entries->mask & KADM5_KEY_HIST)
1024 			continue;
1025 
1026 		    if ((st = tl_data2berval (ptr, &ber_tl_data[j])) != 0)
1027 			break;
1028 		    j++;
1029 		}
1030 		if (st != 0) {
1031 		    /* Solaris Kerberos: don't free here, do it at cleanup */
1032 		    goto cleanup;
1033 		}
1034 		ber_tl_data[count] = NULL;
1035 		if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbExtraData",
1036 						  LDAP_MOD_REPLACE | LDAP_MOD_BVALUES,
1037 						  ber_tl_data)) != 0)
1038 		    goto cleanup;
1039 	    }
1040 	}
1041 
1042 	/* Directory specific attribute */
1043 	if (xargs.tktpolicydn != NULL) {
1044 	    int tmask=0;
1045 
1046 	    if (strlen(xargs.tktpolicydn) != 0) {
1047 		st = checkattributevalue(ld, xargs.tktpolicydn, "objectclass", policyclass, &tmask);
1048 		CHECK_CLASS_VALIDITY(st, tmask, "ticket policy object value: ");
1049 
1050 		strval[0] = xargs.tktpolicydn;
1051 		strval[1] = NULL;
1052 		if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_REPLACE, strval)) != 0)
1053 		    goto cleanup;
1054 
1055 	    } else {
1056 		/* if xargs.tktpolicydn is a empty string, then delete
1057 		 * already existing krbticketpolicyreference attr */
1058 		if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_DELETE, NULL)) != 0)
1059 		    goto cleanup;
1060 	    }
1061 
1062 	}
1063 
1064 	if (establish_links == TRUE) {
1065 	    memset(strval, 0, sizeof(strval));
1066 	    strval[0] = xargs.linkdn;
1067 	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbObjectReferences", LDAP_MOD_REPLACE, strval)) != 0)
1068 		goto cleanup;
1069 	}
1070 
1071 	/*
1072 	 * in case mods is NULL then return
1073 	 * not sure but can happen in a modprinc
1074 	 * so no need to return an error
1075 	 * addprinc will at least have the principal name
1076 	 * and the keys passed in
1077 	 */
1078 	if (mods == NULL)
1079 	    goto cleanup;
1080 
1081 	if (create_standalone_prinicipal == TRUE) {
1082 	    memset(strval, 0, sizeof(strval));
1083 	    strval[0] = "krbprincipal";
1084 	    strval[1] = "krbprincipalaux";
1085 	    strval[2] = "krbTicketPolicyAux";
1086 
1087 	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
1088 		goto cleanup;
1089 
1090 	    st = ldap_add_ext_s(ld, standalone_principal_dn, mods, NULL, NULL);
1091 	    if (st == LDAP_ALREADY_EXISTS && entries->mask & KADM5_LOAD) {
1092 		/* a load operation must replace an existing entry */
1093 		st = ldap_delete_ext_s(ld, standalone_principal_dn, NULL, NULL);
1094 		if (st != LDAP_SUCCESS) {
1095 		    snprintf(errbuf, sizeof (errbuf), gettext("Principal delete failed (trying to replace entry): %s"),
1096 			ldap_err2string(st));
1097 		    st = translate_ldap_error (st, OP_ADD);
1098 		    krb5_set_error_message(context, st, "%s", errbuf);
1099 		    goto cleanup;
1100 		} else {
1101 		    st = ldap_add_ext_s(ld, standalone_principal_dn, mods, NULL, NULL);
1102 		}
1103 	    }
1104 	    if (st != LDAP_SUCCESS) {
1105 		snprintf(errbuf, sizeof (errbuf), gettext("Principal add failed: %s"), ldap_err2string(st));
1106 		st = translate_ldap_error (st, OP_ADD);
1107 		krb5_set_error_message(context, st, "%s", errbuf);
1108 		goto cleanup;
1109 	    }
1110 	} else {
1111 	    /*
1112 	     * Here existing ldap object is modified and can be related
1113 	     * to any attribute, so always ensure that the ldap
1114 	     * object is extended with all the kerberos related
1115 	     * objectclasses so that there are no constraint
1116 	     * violations.
1117 	     */
1118 	    {
1119 		char *attrvalues[] = {"krbprincipalaux", "krbTicketPolicyAux", NULL};
1120 		int p, q, r=0, amask=0;
1121 
1122 		if ((st=checkattributevalue(ld, (xargs.dn) ? xargs.dn : principal_dn,
1123 					    "objectclass", attrvalues, &amask)) != 0)
1124 		    goto cleanup;
1125 
1126 		memset(strval, 0, sizeof(strval));
1127 		for (p=1, q=0; p<=2; p<<=1, ++q) {
1128 		    if ((p & amask) == 0)
1129 			strval[r++] = attrvalues[q];
1130 		}
1131 		if (r != 0) {
1132 		    if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
1133 			goto cleanup;
1134 		}
1135 	    }
1136 	    if (xargs.dn != NULL)
1137 		st=ldap_modify_ext_s(ld, xargs.dn, mods, NULL, NULL);
1138 	    else
1139 		st = ldap_modify_ext_s(ld, principal_dn, mods, NULL, NULL);
1140 
1141 	    if (st != LDAP_SUCCESS) {
1142 		snprintf(errbuf, sizeof (errbuf), gettext("User modification failed: %s"), ldap_err2string(st));
1143 		st = translate_ldap_error (st, OP_MOD);
1144 		krb5_set_error_message(context, st, "%s", errbuf);
1145 		goto cleanup;
1146 	    }
1147 	}
1148     }
1149 
1150 cleanup:
1151     if (user)
1152 	free(user);
1153 
1154     free_xargs(xargs);
1155 
1156     if (standalone_principal_dn)
1157 	free(standalone_principal_dn);
1158 
1159     if (principal_dn)
1160 	free (principal_dn);
1161 
1162     /* Solaris Kerberos: fix memleak */
1163     if (ber_tl_data) {
1164 	int j;
1165 
1166 	for (j = 0; ber_tl_data[j] != NULL; j++) {
1167 	    free (ber_tl_data[j]->bv_val);
1168 	    free (ber_tl_data[j]);
1169 	}
1170 	free(ber_tl_data);
1171     }
1172 
1173     if (polname != NULL)
1174 	free(polname);
1175 
1176     if (subtree)
1177 	free (subtree);
1178 
1179     if (bersecretkey) {
1180 	for (l=0; bersecretkey[l]; ++l) {
1181 	    if (bersecretkey[l]->bv_val)
1182 		free (bersecretkey[l]->bv_val);
1183 	    free (bersecretkey[l]);
1184 	}
1185 	free (bersecretkey);
1186     }
1187 
1188     ldap_mods_free(mods, 1);
1189     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
1190     *nentries = i;
1191     return(st);
1192 }
1193 
1194 krb5_error_code
krb5_read_tkt_policy(context,ldap_context,entries,policy)1195 krb5_read_tkt_policy (context, ldap_context, entries, policy)
1196     krb5_context                context;
1197     krb5_ldap_context           *ldap_context;
1198     krb5_db_entry               *entries;
1199     char                        *policy;
1200 {
1201     krb5_error_code             st=0;
1202     unsigned int                mask=0, omask=0;
1203     int                         tkt_mask=(KDB_MAX_LIFE_ATTR | KDB_MAX_RLIFE_ATTR | KDB_TKT_FLAGS_ATTR);
1204     krb5_ldap_policy_params     *tktpoldnparam=NULL;
1205 
1206     if ((st=krb5_get_attributes_mask(context, entries, &mask)) != 0)
1207 	goto cleanup;
1208 
1209     if ((mask & tkt_mask) == tkt_mask)
1210 	goto cleanup;
1211 
1212     if (policy != NULL) {
1213 	st = krb5_ldap_read_policy(context, policy, &tktpoldnparam, &omask);
1214 	if (st && st != KRB5_KDB_NOENTRY) {
1215 	    prepend_err_str(context, gettext("Error reading ticket policy. "), st, st);
1216 	    goto cleanup;
1217 	}
1218 
1219 	st = 0; /* reset the return status */
1220     }
1221 
1222     if ((mask & KDB_MAX_LIFE_ATTR) == 0) {
1223 	if ((omask & KDB_MAX_LIFE_ATTR) ==  KDB_MAX_LIFE_ATTR)
1224 	    entries->max_life = tktpoldnparam->maxtktlife;
1225 	else if (ldap_context->lrparams->max_life)
1226 	    entries->max_life = ldap_context->lrparams->max_life;
1227     }
1228 
1229     if ((mask & KDB_MAX_RLIFE_ATTR) == 0) {
1230 	if ((omask & KDB_MAX_RLIFE_ATTR) == KDB_MAX_RLIFE_ATTR)
1231 	    entries->max_renewable_life = tktpoldnparam->maxrenewlife;
1232 	else if (ldap_context->lrparams->max_renewable_life)
1233 	    entries->max_renewable_life = ldap_context->lrparams->max_renewable_life;
1234     }
1235 
1236     if ((mask & KDB_TKT_FLAGS_ATTR) == 0) {
1237 	if ((omask & KDB_TKT_FLAGS_ATTR) == KDB_TKT_FLAGS_ATTR)
1238 	    entries->attributes = tktpoldnparam->tktflags;
1239 	else if (ldap_context->lrparams->tktflags)
1240 	    entries->attributes |= ldap_context->lrparams->tktflags;
1241     }
1242     krb5_ldap_free_policy(context, tktpoldnparam);
1243 
1244 cleanup:
1245     return st;
1246 }
1247 
1248 krb5_error_code
krb5_decode_krbsecretkey(context,entries,bvalues)1249 krb5_decode_krbsecretkey(context, entries, bvalues)
1250     krb5_context                context;
1251     krb5_db_entry               *entries;
1252     struct berval               **bvalues;
1253 {
1254     char                        *user=NULL;
1255     int                         i=0, j=0, noofkeys=0;
1256     krb5_key_data               *key_data=NULL, *tmp;
1257     krb5_error_code             st=0;
1258 
1259     if ((st=krb5_unparse_name(context, entries->princ, &user)) != 0)
1260 	goto cleanup;
1261 
1262     for (i=0; bvalues[i] != NULL; ++i) {
1263 	int mkvno; /* Not used currently */
1264 	krb5_int16 n_kd;
1265 	krb5_key_data *kd;
1266 	krb5_data in;
1267 
1268 	if (bvalues[i]->bv_len == 0)
1269 	    continue;
1270 	in.length = bvalues[i]->bv_len;
1271 	in.data = bvalues[i]->bv_val;
1272 
1273 	st = asn1_decode_sequence_of_keys (&in,
1274 					   &kd,
1275 					   &n_kd,
1276 					   &mkvno);
1277 
1278 	if (st != 0) {
1279 	    const char *msg = error_message(st);
1280 	    st = -1; /* Something more appropriate ? */
1281 	    krb5_set_error_message (context, st,
1282 				    gettext("unable to decode stored principal key data (%s)"), msg);
1283 	    goto cleanup;
1284 	}
1285 	noofkeys += n_kd;
1286 	tmp = key_data;
1287 	key_data = realloc (key_data, noofkeys * sizeof (krb5_key_data));
1288 	if (key_data == NULL) {
1289 	    key_data = tmp;
1290 	    st = ENOMEM;
1291 	    goto cleanup;
1292 	}
1293 	for (j = 0; j < n_kd; j++)
1294 	    key_data[noofkeys - n_kd + j] = kd[j];
1295 	free (kd);
1296     }
1297 
1298     entries->n_key_data = noofkeys;
1299     entries->key_data = key_data;
1300 
1301 cleanup:
1302     ldap_value_free_len(bvalues);
1303     free (user);
1304     return st;
1305 }
1306 
1307 static char *
getstringtime(epochtime)1308 getstringtime(epochtime)
1309     krb5_timestamp    epochtime;
1310 {
1311     struct tm           tme;
1312     char                *strtime=NULL;
1313     time_t		posixtime = epochtime;
1314 
1315     strtime = calloc (50, 1);
1316     if (strtime == NULL)
1317 	return NULL;
1318 
1319     if (gmtime_r(&posixtime, &tme) == NULL)
1320 	return NULL;
1321 
1322     strftime(strtime, 50, DATE_FORMAT, &tme);
1323     return strtime;
1324 }
1325 
1326