xref: /illumos-gate/usr/src/lib/krb5/plugins/kdb/ldap/libkdb_ldap/ldap_principal2.c (revision 1da57d551424de5a9d469760be7c4b4d4f10a755)
154925bf6Swillf /*
254925bf6Swillf  * lib/kdb/kdb_ldap/ldap_principal2.c
354925bf6Swillf  *
454925bf6Swillf  * Copyright (c) 2004-2005, Novell, Inc.
554925bf6Swillf  * All rights reserved.
654925bf6Swillf  *
754925bf6Swillf  * Redistribution and use in source and binary forms, with or without
854925bf6Swillf  * modification, are permitted provided that the following conditions are met:
954925bf6Swillf  *
1054925bf6Swillf  *   * Redistributions of source code must retain the above copyright notice,
1154925bf6Swillf  *       this list of conditions and the following disclaimer.
1254925bf6Swillf  *   * Redistributions in binary form must reproduce the above copyright
1354925bf6Swillf  *       notice, this list of conditions and the following disclaimer in the
1454925bf6Swillf  *       documentation and/or other materials provided with the distribution.
1554925bf6Swillf  *   * The copyright holder's name is not used to endorse or promote products
1654925bf6Swillf  *       derived from this software without specific prior written permission.
1754925bf6Swillf  *
1854925bf6Swillf  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
1954925bf6Swillf  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2054925bf6Swillf  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2154925bf6Swillf  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
2254925bf6Swillf  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2354925bf6Swillf  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2454925bf6Swillf  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2554925bf6Swillf  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2654925bf6Swillf  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2754925bf6Swillf  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2854925bf6Swillf  * POSSIBILITY OF SUCH DAMAGE.
2954925bf6Swillf  */
3054925bf6Swillf /*
31*2dd2efa5Swillf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
3254925bf6Swillf  * Use is subject to license terms.
3354925bf6Swillf  */
3454925bf6Swillf 
3554925bf6Swillf #include <time.h>
3654925bf6Swillf #include "ldap_main.h"
3754925bf6Swillf #include "kdb_ldap.h"
3854925bf6Swillf #include "ldap_principal.h"
3954925bf6Swillf #include "princ_xdr.h"
4054925bf6Swillf #include "ldap_tkt_policy.h"
4154925bf6Swillf #include "ldap_pwd_policy.h"
4254925bf6Swillf #include "ldap_err.h"
4354925bf6Swillf #include <kadm5/admin.h>
4454925bf6Swillf #include <libintl.h>
4554925bf6Swillf 
4654925bf6Swillf extern char* principal_attributes[];
4754925bf6Swillf extern char* max_pwd_life_attr[];
4854925bf6Swillf 
4954925bf6Swillf static char *
5054925bf6Swillf getstringtime(krb5_timestamp);
5154925bf6Swillf 
5254925bf6Swillf krb5_error_code
berval2tl_data(struct berval * in,krb5_tl_data ** out)5354925bf6Swillf berval2tl_data(struct berval *in, krb5_tl_data **out)
5454925bf6Swillf {
5554925bf6Swillf     *out = (krb5_tl_data *) malloc (sizeof (krb5_tl_data));
5654925bf6Swillf     if (*out == NULL)
5754925bf6Swillf 	return ENOMEM;
5854925bf6Swillf 
5954925bf6Swillf     (*out)->tl_data_length = in->bv_len - 2;
6054925bf6Swillf     (*out)->tl_data_contents =  (krb5_octet *) malloc
6154925bf6Swillf 	((*out)->tl_data_length * sizeof (krb5_octet));
6254925bf6Swillf     if ((*out)->tl_data_contents == NULL) {
6354925bf6Swillf 	free (*out);
6454925bf6Swillf 	return ENOMEM;
6554925bf6Swillf     }
6654925bf6Swillf 
6754925bf6Swillf     /* Solaris Kerberos: need cast */
6854925bf6Swillf     UNSTORE16_INT ((unsigned char *)in->bv_val, (*out)->tl_data_type);
6954925bf6Swillf     memcpy ((*out)->tl_data_contents, in->bv_val + 2, (*out)->tl_data_length);
7054925bf6Swillf 
7154925bf6Swillf     return 0;
7254925bf6Swillf }
7354925bf6Swillf 
7454925bf6Swillf /*
7554925bf6Swillf  * look up a principal in the directory.
7654925bf6Swillf  */
7754925bf6Swillf 
7854925bf6Swillf krb5_error_code
krb5_ldap_get_principal(context,searchfor,entries,nentries,more)7954925bf6Swillf krb5_ldap_get_principal(context, searchfor, entries, nentries, more)
8054925bf6Swillf     krb5_context context;
8154925bf6Swillf     krb5_const_principal searchfor;
8254925bf6Swillf     krb5_db_entry *entries;	/* filled in */
8354925bf6Swillf     int *nentries;		/* how much room/how many found */
8454925bf6Swillf     krb5_boolean *more;		/* are there more? */
8554925bf6Swillf {
8654925bf6Swillf     char                        *user=NULL, *filter=NULL, **subtree=NULL;
8754925bf6Swillf     unsigned int                tree=0, ntrees=1, princlen=0;
8854925bf6Swillf     krb5_error_code	        tempst=0, st=0;
8954925bf6Swillf     char                        **values=NULL;
9054925bf6Swillf     LDAP	                *ld=NULL;
9154925bf6Swillf     LDAPMessage	                *result=NULL, *ent=NULL;
9254925bf6Swillf     krb5_ldap_context           *ldap_context=NULL;
9354925bf6Swillf     kdb5_dal_handle             *dal_handle=NULL;
9454925bf6Swillf     krb5_ldap_server_handle     *ldap_server_handle=NULL;
9554925bf6Swillf 
9654925bf6Swillf     /* Clear the global error string */
9754925bf6Swillf     krb5_clear_error_message(context);
9854925bf6Swillf 
9954925bf6Swillf     /* set initial values */
10054925bf6Swillf     *nentries = 0;
10154925bf6Swillf     *more = 0;
10254925bf6Swillf     memset(entries, 0, sizeof(*entries));
10354925bf6Swillf 
10454925bf6Swillf     if (searchfor == NULL)
10554925bf6Swillf 	return EINVAL;
10654925bf6Swillf 
10754925bf6Swillf     dal_handle = (kdb5_dal_handle *) context->db_context;
10854925bf6Swillf     ldap_context = (krb5_ldap_context *) dal_handle->db_context;
10954925bf6Swillf 
11054925bf6Swillf     CHECK_LDAP_HANDLE(ldap_context);
11154925bf6Swillf 
11254925bf6Swillf     if (is_principal_in_realm(ldap_context, searchfor) != 0) {
11354925bf6Swillf 	*more = 0;
11454925bf6Swillf 	krb5_set_error_message (context, st, gettext("Principal does not belong to realm"));
11554925bf6Swillf 	goto cleanup;
11654925bf6Swillf     }
11754925bf6Swillf 
11854925bf6Swillf     if ((st=krb5_unparse_name(context, searchfor, &user)) != 0)
11954925bf6Swillf 	goto cleanup;
12054925bf6Swillf 
12154925bf6Swillf     if ((st=krb5_ldap_unparse_principal_name(user)) != 0)
12254925bf6Swillf 	goto cleanup;
12354925bf6Swillf 
12454925bf6Swillf     princlen = strlen(FILTER) + strlen(user) + 2 + 1;      /* 2 for closing brackets */
12554925bf6Swillf     if ((filter = malloc(princlen)) == NULL) {
12654925bf6Swillf 	st = ENOMEM;
12754925bf6Swillf 	goto cleanup;
12854925bf6Swillf     }
12954925bf6Swillf     snprintf(filter, princlen, FILTER"%s))", user);
13054925bf6Swillf 
13154925bf6Swillf     if ((st = krb5_get_subtree_info(ldap_context, &subtree, &ntrees)) != 0)
13254925bf6Swillf 	goto cleanup;
13354925bf6Swillf 
13454925bf6Swillf     GET_HANDLE();
13554925bf6Swillf     for (tree=0; tree < ntrees && *nentries == 0; ++tree) {
13654925bf6Swillf 
13754925bf6Swillf 	LDAP_SEARCH(subtree[tree], ldap_context->lrparams->search_scope, filter, principal_attributes);
13854925bf6Swillf 	for (ent=ldap_first_entry(ld, result); ent != NULL && *nentries == 0; ent=ldap_next_entry(ld, ent)) {
13954925bf6Swillf 
14054925bf6Swillf 	    /* get the associated directory user information */
14154925bf6Swillf 	    if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
14254925bf6Swillf 		int i;
14354925bf6Swillf 
14454925bf6Swillf 		/* a wild-card in a principal name can return a list of kerberos principals.
14554925bf6Swillf 		 * Make sure that the correct principal is returned.
14654925bf6Swillf 		 * NOTE: a principalname k* in ldap server will return all the principals starting with a k
14754925bf6Swillf 		 */
14854925bf6Swillf 		for (i=0; values[i] != NULL; ++i) {
14954925bf6Swillf 		    if (strcasecmp(values[i], user) == 0) {
15054925bf6Swillf 			*nentries = 1;
15154925bf6Swillf 			break;
15254925bf6Swillf 		    }
15354925bf6Swillf 		}
15454925bf6Swillf 		ldap_value_free(values);
15554925bf6Swillf 
15654925bf6Swillf 		if (*nentries == 0) /* no matching principal found */
15754925bf6Swillf 		    continue;
15854925bf6Swillf 	    }
15954925bf6Swillf 
16054925bf6Swillf 	    if ((st = populate_krb5_db_entry(context, ldap_context, ld, ent, searchfor,
16154925bf6Swillf 			entries)) != 0)
16254925bf6Swillf 		goto cleanup;
16354925bf6Swillf 	}
16454925bf6Swillf 	ldap_msgfree(result);
16554925bf6Swillf 	result = NULL;
16654925bf6Swillf     } /* for (tree=0 ... */
16754925bf6Swillf 
16854925bf6Swillf     /* once done, put back the ldap handle */
16954925bf6Swillf     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
17054925bf6Swillf     ldap_server_handle = NULL;
17154925bf6Swillf 
17254925bf6Swillf cleanup:
17354925bf6Swillf     ldap_msgfree(result);
17454925bf6Swillf 
17554925bf6Swillf     if (*nentries == 0 || st != 0)
17654925bf6Swillf 	krb5_dbe_free_contents(context, entries);
17754925bf6Swillf 
17854925bf6Swillf     if (filter)
17954925bf6Swillf 	free (filter);
18054925bf6Swillf 
18154925bf6Swillf     if (subtree) {
18254925bf6Swillf 	for (; ntrees; --ntrees)
18354925bf6Swillf 	    if (subtree[ntrees-1])
18454925bf6Swillf 		free (subtree[ntrees-1]);
18554925bf6Swillf 	free (subtree);
18654925bf6Swillf     }
18754925bf6Swillf 
18854925bf6Swillf     if (ldap_server_handle)
18954925bf6Swillf 	krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
19054925bf6Swillf 
19154925bf6Swillf     if (user)
19254925bf6Swillf 	free(user);
19354925bf6Swillf 
19454925bf6Swillf     return st;
19554925bf6Swillf }
19654925bf6Swillf 
19754925bf6Swillf typedef enum{ ADD_PRINCIPAL, MODIFY_PRINCIPAL } OPERATION;
19854925bf6Swillf /*
19954925bf6Swillf  * ptype is creating confusions. Additionally the logic
20054925bf6Swillf  * surronding ptype is redundunt and can be achevied
20154925bf6Swillf  * with the help of dn and containerdn members.
20254925bf6Swillf  * so dropping the ptype member
20354925bf6Swillf  */
20454925bf6Swillf 
20554925bf6Swillf typedef struct _xargs_t {
20654925bf6Swillf     char           *dn;
20754925bf6Swillf     char           *linkdn;
20854925bf6Swillf     krb5_boolean   dn_from_kbd;
20954925bf6Swillf     char           *containerdn;
21054925bf6Swillf     char           *tktpolicydn;
21154925bf6Swillf }xargs_t;
21254925bf6Swillf 
21354925bf6Swillf static void
free_xargs(xargs)21454925bf6Swillf free_xargs(xargs)
21554925bf6Swillf     xargs_t xargs;
21654925bf6Swillf {
21754925bf6Swillf     if (xargs.dn)
21854925bf6Swillf 	free (xargs.dn);
21954925bf6Swillf     if (xargs.linkdn)
22054925bf6Swillf 	free(xargs.linkdn);
22154925bf6Swillf     if (xargs.containerdn)
22254925bf6Swillf 	free (xargs.containerdn);
22354925bf6Swillf     if (xargs.tktpolicydn)
22454925bf6Swillf 	free (xargs.tktpolicydn);
22554925bf6Swillf }
22654925bf6Swillf 
22754925bf6Swillf static krb5_error_code
process_db_args(context,db_args,xargs,optype)22854925bf6Swillf process_db_args(context, db_args, xargs, optype)
22954925bf6Swillf     krb5_context   context;
23054925bf6Swillf     char           **db_args;
23154925bf6Swillf     xargs_t        *xargs;
23254925bf6Swillf     OPERATION      optype;
23354925bf6Swillf {
23454925bf6Swillf     int                   i=0;
23554925bf6Swillf     krb5_error_code       st=0;
23654925bf6Swillf     char                  errbuf[1024];
23754925bf6Swillf     char                  *arg=NULL, *arg_val=NULL;
23854925bf6Swillf     char                  **dptr=NULL;
23954925bf6Swillf     unsigned int          arg_val_len=0;
24054925bf6Swillf 
24154925bf6Swillf     if (db_args) {
24254925bf6Swillf 	for (i=0; db_args[i]; ++i) {
24354925bf6Swillf 	    arg = strtok_r(db_args[i], "=", &arg_val);
24454925bf6Swillf 	    if (strcmp(arg, TKTPOLICY_ARG) == 0) {
24554925bf6Swillf 		dptr = &xargs->tktpolicydn;
24654925bf6Swillf 	    } else {
24754925bf6Swillf 		if (strcmp(arg, USERDN_ARG) == 0) {
24854925bf6Swillf 		    if (optype == MODIFY_PRINCIPAL ||
24954925bf6Swillf 			xargs->dn != NULL || xargs->containerdn != NULL ||
25054925bf6Swillf 			xargs->linkdn != NULL) {
25154925bf6Swillf 			st = EINVAL;
25254925bf6Swillf 			snprintf(errbuf, sizeof(errbuf),
25354925bf6Swillf 				 gettext("%s option not supported"), arg);
25454925bf6Swillf 			krb5_set_error_message(context, st, "%s", errbuf);
25554925bf6Swillf 			goto cleanup;
25654925bf6Swillf 		    }
25754925bf6Swillf 		    dptr = &xargs->dn;
25854925bf6Swillf 		} else if (strcmp(arg, CONTAINERDN_ARG) == 0) {
25954925bf6Swillf 		    if (optype == MODIFY_PRINCIPAL ||
26054925bf6Swillf 			xargs->dn != NULL || xargs->containerdn != NULL) {
26154925bf6Swillf 			st = EINVAL;
26254925bf6Swillf 			snprintf(errbuf, sizeof(errbuf),
26354925bf6Swillf 				 gettext("%s option not supported"), arg);
26454925bf6Swillf 			krb5_set_error_message(context, st, "%s", errbuf);
26554925bf6Swillf 			goto cleanup;
26654925bf6Swillf 		    }
26754925bf6Swillf 		    dptr = &xargs->containerdn;
26854925bf6Swillf 		} else if (strcmp(arg, LINKDN_ARG) == 0) {
26954925bf6Swillf 		    if (xargs->dn != NULL || xargs->linkdn != NULL) {
27054925bf6Swillf 			st = EINVAL;
27154925bf6Swillf 			snprintf(errbuf, sizeof(errbuf),
27254925bf6Swillf 				 gettext("%s option not supported"), arg);
27354925bf6Swillf 			krb5_set_error_message(context, st, "%s", errbuf);
27454925bf6Swillf 			goto cleanup;
27554925bf6Swillf 		    }
27654925bf6Swillf 		    dptr = &xargs->linkdn;
27754925bf6Swillf 		} else {
27854925bf6Swillf 		    st = EINVAL;
27954925bf6Swillf 		    snprintf(errbuf, sizeof(errbuf), gettext("unknown option: %s"), arg);
28054925bf6Swillf 		    krb5_set_error_message(context, st, "%s", errbuf);
28154925bf6Swillf 		    goto cleanup;
28254925bf6Swillf 		}
28354925bf6Swillf 
28454925bf6Swillf 		xargs->dn_from_kbd = TRUE;
28554925bf6Swillf 		if (arg_val == NULL || strlen(arg_val) == 0) {
28654925bf6Swillf 		    st = EINVAL;
28754925bf6Swillf 		    snprintf(errbuf, sizeof(errbuf),
28854925bf6Swillf 			     gettext("%s option value missing"), arg);
28954925bf6Swillf 		    krb5_set_error_message(context, st, "%s", errbuf);
29054925bf6Swillf 		    goto cleanup;
29154925bf6Swillf 		}
29254925bf6Swillf 	    }
29354925bf6Swillf 
29454925bf6Swillf 	    if (arg_val == NULL) {
29554925bf6Swillf 		st = EINVAL;
29654925bf6Swillf 		snprintf(errbuf, sizeof(errbuf),
29754925bf6Swillf 			 gettext("%s option value missing"), arg);
29854925bf6Swillf 		krb5_set_error_message(context, st, "%s", errbuf);
29954925bf6Swillf 		goto cleanup;
30054925bf6Swillf 	    }
30154925bf6Swillf 	    arg_val_len = strlen(arg_val) + 1;
30254925bf6Swillf 
30354925bf6Swillf 	    if (strcmp(arg, TKTPOLICY_ARG) == 0) {
30454925bf6Swillf 		if ((st = krb5_ldap_name_to_policydn (context,
30554925bf6Swillf 						      arg_val,
30654925bf6Swillf 						      dptr)) != 0)
30754925bf6Swillf 		    goto cleanup;
30854925bf6Swillf 	    } else {
30954925bf6Swillf 		*dptr = calloc (1, arg_val_len);
31054925bf6Swillf 		if (*dptr == NULL) {
31154925bf6Swillf 		    st = ENOMEM;
31254925bf6Swillf 		    goto cleanup;
31354925bf6Swillf 		}
31454925bf6Swillf 		memcpy(*dptr, arg_val, arg_val_len);
31554925bf6Swillf 	    }
31654925bf6Swillf 	}
31754925bf6Swillf     }
31854925bf6Swillf 
31954925bf6Swillf cleanup:
32054925bf6Swillf     return st;
32154925bf6Swillf }
32254925bf6Swillf 
32354925bf6Swillf krb5int_access accessor;
32454925bf6Swillf extern int kldap_ensure_initialized (void);
32554925bf6Swillf 
32654925bf6Swillf 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)32754925bf6Swillf asn1_encode_sequence_of_keys (krb5_key_data *key_data, krb5_int16 n_key_data,
32854925bf6Swillf 			      krb5_int32 mkvno, krb5_data **code)
32954925bf6Swillf {
33054925bf6Swillf     krb5_error_code err;
33154925bf6Swillf 
33254925bf6Swillf     /*
33354925bf6Swillf      * This should be pushed back into other library initialization
33454925bf6Swillf      * code.
33554925bf6Swillf      */
33654925bf6Swillf     err = kldap_ensure_initialized ();
33754925bf6Swillf     if (err)
33854925bf6Swillf 	return err;
33954925bf6Swillf 
34054925bf6Swillf     return accessor.asn1_ldap_encode_sequence_of_keys(key_data, n_key_data,
34154925bf6Swillf 						      mkvno, code);
34254925bf6Swillf }
34354925bf6Swillf 
34454925bf6Swillf static krb5_error_code
asn1_decode_sequence_of_keys(krb5_data * in,krb5_key_data ** out,krb5_int16 * n_key_data,int * mkvno)34554925bf6Swillf asn1_decode_sequence_of_keys (krb5_data *in, krb5_key_data **out,
34654925bf6Swillf 			      krb5_int16 *n_key_data, int *mkvno)
34754925bf6Swillf {
34854925bf6Swillf     krb5_error_code err;
34954925bf6Swillf 
35054925bf6Swillf     /*
35154925bf6Swillf      * This should be pushed back into other library initialization
35254925bf6Swillf      * code.
35354925bf6Swillf      */
35454925bf6Swillf     err = kldap_ensure_initialized ();
35554925bf6Swillf     if (err)
35654925bf6Swillf 	return err;
35754925bf6Swillf 
35854925bf6Swillf     return accessor.asn1_ldap_decode_sequence_of_keys(in, out, n_key_data,
35954925bf6Swillf 						      mkvno);
36054925bf6Swillf }
36154925bf6Swillf 
36254925bf6Swillf 
36354925bf6Swillf /* Decoding ASN.1 encoded key */
36454925bf6Swillf static struct berval **
krb5_encode_krbsecretkey(krb5_key_data * key_data,int n_key_data)36554925bf6Swillf krb5_encode_krbsecretkey(krb5_key_data *key_data, int n_key_data) {
36654925bf6Swillf     struct berval **ret = NULL;
36754925bf6Swillf     int currkvno;
36854925bf6Swillf     int num_versions = 1;
36954925bf6Swillf     int i, j, last;
37054925bf6Swillf     krb5_error_code err = 0;
37154925bf6Swillf 
37254925bf6Swillf     if (n_key_data <= 0)
37354925bf6Swillf 	return NULL;
37454925bf6Swillf 
37554925bf6Swillf     /* Find the number of key versions */
37654925bf6Swillf     for (i = 0; i < n_key_data - 1; i++)
37754925bf6Swillf 	if (key_data[i].key_data_kvno != key_data[i + 1].key_data_kvno)
37854925bf6Swillf 	    num_versions++;
37954925bf6Swillf 
38054925bf6Swillf     ret = (struct berval **) calloc (num_versions + 1, sizeof (struct berval *));
38154925bf6Swillf     if (ret == NULL) {
38254925bf6Swillf 	err = ENOMEM;
38354925bf6Swillf 	goto cleanup;
38454925bf6Swillf     }
38554925bf6Swillf     for (i = 0, last = 0, j = 0, currkvno = key_data[0].key_data_kvno; i < n_key_data; i++) {
38654925bf6Swillf 	krb5_data *code;
38754925bf6Swillf 	if (i == n_key_data - 1 || key_data[i + 1].key_data_kvno != currkvno) {
38854925bf6Swillf 	    code = NULL;
38954925bf6Swillf 	    asn1_encode_sequence_of_keys (key_data+last,
39054925bf6Swillf 					  (krb5_int16) i - last + 1,
39154925bf6Swillf 					  0, /* For now, mkvno == 0*/
39254925bf6Swillf 					  &code);
39354925bf6Swillf 	    if (code == NULL) {
39454925bf6Swillf 		err = ENOMEM;
39554925bf6Swillf 		goto cleanup;
39654925bf6Swillf 	    }
39754925bf6Swillf 	    ret[j] = malloc (sizeof (struct berval));
39854925bf6Swillf 	    if (ret[j] == NULL) {
39954925bf6Swillf 		err = ENOMEM;
40054925bf6Swillf 		goto cleanup;
40154925bf6Swillf 	    }
40254925bf6Swillf 	    /*CHECK_NULL(ret[j]); */
40354925bf6Swillf 	    ret[j]->bv_len = code->length;
40454925bf6Swillf 	    ret[j]->bv_val = code->data;
40554925bf6Swillf 	    j++;
40654925bf6Swillf 	    last = i + 1;
40754925bf6Swillf 
40854925bf6Swillf 	    currkvno = key_data[i].key_data_kvno;
40954925bf6Swillf 	    /* Solaris Kerberos: fix memleak */
41054925bf6Swillf 	    free(code);
41154925bf6Swillf 	}
41254925bf6Swillf     }
41354925bf6Swillf     ret[num_versions] = NULL;
41454925bf6Swillf 
41554925bf6Swillf cleanup:
41654925bf6Swillf 
41754925bf6Swillf     if (err != 0) {
41854925bf6Swillf 	if (ret != NULL) {
41954925bf6Swillf 	    for (i = 0; i <= num_versions; i++)
42054925bf6Swillf 		if (ret[i] != NULL)
42154925bf6Swillf 		    free (ret[i]);
42254925bf6Swillf 	    free (ret);
42354925bf6Swillf 	    ret = NULL;
42454925bf6Swillf 	}
42554925bf6Swillf     }
42654925bf6Swillf 
42754925bf6Swillf     return ret;
42854925bf6Swillf }
42954925bf6Swillf 
tl_data2berval(krb5_tl_data * in,struct berval ** out)43054925bf6Swillf static krb5_error_code tl_data2berval (krb5_tl_data *in, struct berval **out) {
43154925bf6Swillf     *out = (struct berval *) malloc (sizeof (struct berval));
43254925bf6Swillf     if (*out == NULL)
43354925bf6Swillf 	return ENOMEM;
43454925bf6Swillf 
43554925bf6Swillf     (*out)->bv_len = in->tl_data_length + 2;
43654925bf6Swillf     (*out)->bv_val =  (char *) malloc ((*out)->bv_len);
43754925bf6Swillf     if ((*out)->bv_val == NULL) {
43854925bf6Swillf 	free (*out);
43954925bf6Swillf 	return ENOMEM;
44054925bf6Swillf     }
44154925bf6Swillf 
44254925bf6Swillf     /* Solaris Kerberos: need cast */
44354925bf6Swillf     STORE16_INT((unsigned char *)(*out)->bv_val, in->tl_data_type);
44454925bf6Swillf     memcpy ((*out)->bv_val + 2, in->tl_data_contents, in->tl_data_length);
44554925bf6Swillf 
44654925bf6Swillf     return 0;
44754925bf6Swillf }
44854925bf6Swillf 
44954925bf6Swillf krb5_error_code
krb5_ldap_put_principal(context,entries,nentries,db_args)45054925bf6Swillf krb5_ldap_put_principal(context, entries, nentries, db_args)
45154925bf6Swillf     krb5_context               context;
45254925bf6Swillf     krb5_db_entry              *entries;
45354925bf6Swillf     register int               *nentries;         /* number of entry structs to update */
45454925bf6Swillf     char                       **db_args;
45554925bf6Swillf {
45654925bf6Swillf     int 		        i=0, l=0, kerberos_principal_object_type=0;
45754925bf6Swillf     krb5_error_code 	        st=0, tempst=0;
45854925bf6Swillf     LDAP  		        *ld=NULL;
45954925bf6Swillf     LDAPMessage                 *result=NULL, *ent=NULL;
46054925bf6Swillf     char                        *user=NULL, *subtree=NULL, *principal_dn=NULL;
46154925bf6Swillf     char                        **values=NULL, *strval[10]={NULL}, errbuf[1024];
46254925bf6Swillf     struct berval	        **bersecretkey=NULL;
46354925bf6Swillf     LDAPMod 		        **mods=NULL;
46454925bf6Swillf     krb5_boolean                create_standalone_prinicipal=FALSE;
46554925bf6Swillf     krb5_boolean                krb_identity_exists=FALSE, establish_links=FALSE;
46654925bf6Swillf     char                        *standalone_principal_dn=NULL;
46754925bf6Swillf     krb5_tl_data                *tl_data=NULL;
46854925bf6Swillf     kdb5_dal_handle             *dal_handle=NULL;
46954925bf6Swillf     krb5_ldap_context           *ldap_context=NULL;
47054925bf6Swillf     krb5_ldap_server_handle     *ldap_server_handle=NULL;
47154925bf6Swillf     osa_princ_ent_rec 	        princ_ent;
47254925bf6Swillf     xargs_t                     xargs = {0};
47354925bf6Swillf     char                        *polname = NULL;
47454925bf6Swillf     OPERATION optype;
47554925bf6Swillf     krb5_boolean     		found_entry = FALSE;
47654925bf6Swillf     struct berval **ber_tl_data = NULL;
47754925bf6Swillf 
47854925bf6Swillf     /* Clear the global error string */
47954925bf6Swillf     krb5_clear_error_message(context);
48054925bf6Swillf 
48154925bf6Swillf     SETUP_CONTEXT();
48254925bf6Swillf     if (ldap_context->lrparams == NULL || ldap_context->krbcontainer == NULL)
48354925bf6Swillf 	return EINVAL;
48454925bf6Swillf 
48554925bf6Swillf     /* get ldap handle */
48654925bf6Swillf     GET_HANDLE();
48754925bf6Swillf 
48854925bf6Swillf     for (i=0; i < *nentries; ++i, ++entries) {
48954925bf6Swillf 	if (is_principal_in_realm(ldap_context, entries->princ) != 0) {
49054925bf6Swillf 	    st = EINVAL;
49154925bf6Swillf 	    krb5_set_error_message(context, st, gettext("Principal does not belong to the default realm"));
49254925bf6Swillf 	    goto cleanup;
49354925bf6Swillf 	}
49454925bf6Swillf 
49554925bf6Swillf 	/* get the principal information to act on */
49654925bf6Swillf 	if (entries->princ) {
49754925bf6Swillf 	    if (((st=krb5_unparse_name(context, entries->princ, &user)) != 0) ||
49854925bf6Swillf 		((st=krb5_ldap_unparse_principal_name(user)) != 0))
49954925bf6Swillf 		goto cleanup;
50054925bf6Swillf 	}
50154925bf6Swillf 
50254925bf6Swillf 	/* Identity the type of operation, it can be
50354925bf6Swillf 	 * add principal or modify principal.
50454925bf6Swillf 	 * hack if the entries->mask has KRB_PRINCIPAL flag set
50554925bf6Swillf 	 * then it is a add operation
50654925bf6Swillf 	 */
50754925bf6Swillf 	if (entries->mask & KADM5_PRINCIPAL)
50854925bf6Swillf 	    optype = ADD_PRINCIPAL;
50954925bf6Swillf 	else
51054925bf6Swillf 	    optype = MODIFY_PRINCIPAL;
51154925bf6Swillf 
51254925bf6Swillf 	if (((st=krb5_get_princ_type(context, entries, &kerberos_principal_object_type)) != 0) ||
51354925bf6Swillf 	    ((st=krb5_get_userdn(context, entries, &principal_dn)) != 0))
51454925bf6Swillf 	    goto cleanup;
51554925bf6Swillf 
51654925bf6Swillf 	if ((st=process_db_args(context, db_args, &xargs, optype)) != 0)
51754925bf6Swillf 	    goto cleanup;
51854925bf6Swillf 
51954925bf6Swillf 	if (entries->mask & KADM5_LOAD) {
52054925bf6Swillf 	    int              tree = 0, princlen = 0, numlentries = 0;
52154925bf6Swillf 	    unsigned int     ntrees = 0;
52254925bf6Swillf 	    char             **subtreelist = NULL, *filter = NULL;
52354925bf6Swillf 
52454925bf6Swillf 	    /*  A load operation is special, will do a mix-in (add krbprinc
52554925bf6Swillf 	     *  attrs to a non-krb object entry) if an object exists with a
52654925bf6Swillf 	     *  matching krbprincipalname attribute so try to find existing
52754925bf6Swillf 	     *  object and set principal_dn.  This assumes that the
52854925bf6Swillf 	     *  krbprincipalname attribute is unique (only one object entry has
52954925bf6Swillf 	     *  a particular krbprincipalname attribute).
53054925bf6Swillf 	     */
53154925bf6Swillf 	    if (user == NULL) {
53254925bf6Swillf 		/* must have principal name for search */
53354925bf6Swillf 		st = EINVAL;
53454925bf6Swillf 		krb5_set_error_message(context, st, gettext("operation can not continue, principal name not found"));
53554925bf6Swillf 		goto cleanup;
53654925bf6Swillf 	    }
53754925bf6Swillf 	    princlen = strlen(FILTER) + strlen(user) + 2 + 1;      /* 2 for closing brackets */
53854925bf6Swillf 	    if ((filter = malloc(princlen)) == NULL) {
53954925bf6Swillf 		st = ENOMEM;
54054925bf6Swillf 		goto cleanup;
54154925bf6Swillf 	    }
54254925bf6Swillf 	    snprintf(filter, princlen, FILTER"%s))", user);
54354925bf6Swillf 
54454925bf6Swillf 	    /* get the current subtree list */
54554925bf6Swillf 	    if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0)
54654925bf6Swillf 		goto cleanup;
54754925bf6Swillf 
54854925bf6Swillf 	    found_entry = FALSE;
54954925bf6Swillf 	    /* search for entry with matching krbprincipalname attribute */
55054925bf6Swillf 	    for (tree = 0; found_entry == FALSE && tree < ntrees; ++tree) {
55154925bf6Swillf 		result = NULL;
55254925bf6Swillf 		if (principal_dn == NULL) {
55354925bf6Swillf 		    LDAP_SEARCH_1(subtreelist[tree], ldap_context->lrparams->search_scope, filter, principal_attributes, IGNORE_STATUS);
55454925bf6Swillf 		} else {
55554925bf6Swillf 		    /* just look for entry with principal_dn */
55654925bf6Swillf 		    LDAP_SEARCH_1(principal_dn, LDAP_SCOPE_BASE, filter, principal_attributes, IGNORE_STATUS);
55754925bf6Swillf 		}
55854925bf6Swillf 		if (st == LDAP_SUCCESS) {
55954925bf6Swillf 		    numlentries = ldap_count_entries(ld, result);
56054925bf6Swillf 		    if (numlentries > 1) {
56154925bf6Swillf 			ldap_msgfree(result);
56254925bf6Swillf 			free(filter);
56354925bf6Swillf 			st = EINVAL;
56454925bf6Swillf 			krb5_set_error_message(context, st,
56554925bf6Swillf 			    gettext("operation can not continue, more than one entry with principal name \"%s\" found"),
56654925bf6Swillf 			    user);
56754925bf6Swillf 			goto cleanup;
56854925bf6Swillf 		    } else if (numlentries == 1) {
56954925bf6Swillf 			found_entry = TRUE;
57054925bf6Swillf 			if (principal_dn == NULL) {
57154925bf6Swillf 			    ent = ldap_first_entry(ld, result);
57254925bf6Swillf 			    if (ent != NULL) {
57354925bf6Swillf 				/* setting principal_dn will cause that entry to be modified further down */
57454925bf6Swillf 				if ((principal_dn = ldap_get_dn(ld, ent)) == NULL) {
57554925bf6Swillf 				    ldap_get_option (ld, LDAP_OPT_RESULT_CODE, &st);
57654925bf6Swillf 				    st = set_ldap_error (context, st, 0);
57754925bf6Swillf 				    ldap_msgfree(result);
57854925bf6Swillf 				    free(filter);
57954925bf6Swillf 				    goto cleanup;
58054925bf6Swillf 				}
58154925bf6Swillf 			    }
58254925bf6Swillf 			}
58354925bf6Swillf 		    }
58454925bf6Swillf 		    if (result)
58554925bf6Swillf 			ldap_msgfree(result);
58654925bf6Swillf 		} else if (st != LDAP_NO_SUCH_OBJECT) {
58754925bf6Swillf 		    /* could not perform search, return with failure */
58854925bf6Swillf 		    st = set_ldap_error (context, st, 0);
58954925bf6Swillf 		    free(filter);
59054925bf6Swillf 		    goto cleanup;
59154925bf6Swillf 		}
59254925bf6Swillf 		/*
59354925bf6Swillf 		 * If it isn't found then assume a standalone princ entry is to
59454925bf6Swillf 		 * be created.
59554925bf6Swillf 		 */
59654925bf6Swillf 	    } /* end for (tree = 0; principal_dn == ... */
59754925bf6Swillf 
59854925bf6Swillf 	    free(filter);
59954925bf6Swillf 
60054925bf6Swillf 	    if (found_entry == FALSE && principal_dn != NULL) {
60154925bf6Swillf 		/*
60254925bf6Swillf 		 * if principal_dn is null then there is code further down to
60354925bf6Swillf 		 * deal with setting standalone_principal_dn.  Also note that
60454925bf6Swillf 		 * this will set create_standalone_prinicipal true for
60554925bf6Swillf 		 * non-mix-in entries which is okay if loading from a dump.
60654925bf6Swillf 		 */
60754925bf6Swillf 		create_standalone_prinicipal = TRUE;
60854925bf6Swillf 		standalone_principal_dn = strdup(principal_dn);
60954925bf6Swillf 		CHECK_NULL(standalone_principal_dn);
61054925bf6Swillf 	    }
61154925bf6Swillf 	} /* end if (entries->mask & KADM5_LOAD */
61254925bf6Swillf 
61354925bf6Swillf 	/* time to generate the DN information with the help of
61454925bf6Swillf 	 * containerdn, principalcontainerreference or
61554925bf6Swillf 	 * realmcontainerdn information
61654925bf6Swillf 	 */
61754925bf6Swillf 	if (principal_dn == NULL && xargs.dn == NULL) { /* creation of standalone principal */
61854925bf6Swillf 	    /* get the subtree information */
61954925bf6Swillf 	    if (entries->princ->length == 2 && entries->princ->data[0].length == strlen("krbtgt") &&
62054925bf6Swillf 		strncmp(entries->princ->data[0].data, "krbtgt", entries->princ->data[0].length) == 0) {
62154925bf6Swillf 		/* if the principal is a inter-realm principal, always created in the realm container */
62254925bf6Swillf 		subtree = strdup(ldap_context->lrparams->realmdn);
62354925bf6Swillf 	    } else if (xargs.containerdn) {
62454925bf6Swillf 		if ((st=checkattributevalue(ld, xargs.containerdn, NULL, NULL, NULL)) != 0) {
62554925bf6Swillf 		    if (st == KRB5_KDB_NOENTRY || st == KRB5_KDB_CONSTRAINT_VIOLATION) {
62654925bf6Swillf 			int ost = st;
62754925bf6Swillf 			st = EINVAL;
62854925bf6Swillf 			snprintf(errbuf, sizeof(errbuf), gettext("'%s' not found: "), xargs.containerdn);
62954925bf6Swillf 			prepend_err_str(context, errbuf, st, ost);
63054925bf6Swillf 		    }
63154925bf6Swillf 		    goto cleanup;
63254925bf6Swillf 		}
63354925bf6Swillf 		subtree = strdup(xargs.containerdn);
63454925bf6Swillf 	    } else if (ldap_context->lrparams->containerref && strlen(ldap_context->lrparams->containerref) != 0) {
63554925bf6Swillf 		/*
63654925bf6Swillf 		 * Here the subtree should be changed with
63754925bf6Swillf 		 * principalcontainerreference attribute value
63854925bf6Swillf 		 */
63954925bf6Swillf 		subtree = strdup(ldap_context->lrparams->containerref);
64054925bf6Swillf 	    } else {
64154925bf6Swillf 		subtree = strdup(ldap_context->lrparams->realmdn);
64254925bf6Swillf 	    }
64354925bf6Swillf 	    CHECK_NULL(subtree);
64454925bf6Swillf 
64554925bf6Swillf 	    standalone_principal_dn = malloc(strlen("krbprincipalname=") + strlen(user) + strlen(",") +
64654925bf6Swillf 					     strlen(subtree) + 1);
64754925bf6Swillf 	    CHECK_NULL(standalone_principal_dn);
64854925bf6Swillf 	    /*LINTED*/
64954925bf6Swillf 	    sprintf(standalone_principal_dn, "krbprincipalname=%s,%s", user, subtree);
65054925bf6Swillf 	    /*
65154925bf6Swillf 	     * free subtree when you are done using the subtree
65254925bf6Swillf 	     * set the boolean create_standalone_prinicipal to TRUE
65354925bf6Swillf 	     */
65454925bf6Swillf 	    create_standalone_prinicipal = TRUE;
65554925bf6Swillf 	    free(subtree);
65654925bf6Swillf 	    subtree = NULL;
65754925bf6Swillf 	}
65854925bf6Swillf 
65954925bf6Swillf 	/*
66054925bf6Swillf 	 * If the DN information is presented by the user, time to
66154925bf6Swillf 	 * validate the input to ensure that the DN falls under
66254925bf6Swillf 	 * any of the subtrees
66354925bf6Swillf 	 */
66454925bf6Swillf 	if (xargs.dn_from_kbd == TRUE) {
66554925bf6Swillf 	    /* make sure the DN falls in the subtree */
66654925bf6Swillf 	    int              tre=0, dnlen=0, subtreelen=0;
66754925bf6Swillf 	    unsigned int     ntrees = 0;
66854925bf6Swillf 	    char             **subtreelist=NULL;
66954925bf6Swillf 	    char             *dn=NULL;
67054925bf6Swillf 	    krb5_boolean     outofsubtree=TRUE;
67154925bf6Swillf 
67254925bf6Swillf 	    if (xargs.dn != NULL) {
67354925bf6Swillf 		dn = xargs.dn;
67454925bf6Swillf 	    } else if (xargs.linkdn != NULL) {
67554925bf6Swillf 		dn = xargs.linkdn;
67654925bf6Swillf 	    } else if (standalone_principal_dn != NULL) {
67754925bf6Swillf 		/*
67854925bf6Swillf 		 * Even though the standalone_principal_dn is constructed
67954925bf6Swillf 		 * within this function, there is the containerdn input
68054925bf6Swillf 		 * from the user that can become part of the it.
68154925bf6Swillf 		 */
68254925bf6Swillf 		dn = standalone_principal_dn;
68354925bf6Swillf 	    }
68454925bf6Swillf 
68554925bf6Swillf 	    /* get the current subtree list */
68654925bf6Swillf 	    if ((st = krb5_get_subtree_info(ldap_context, &subtreelist, &ntrees)) != 0)
68754925bf6Swillf 		goto cleanup;
68854925bf6Swillf 
68954925bf6Swillf 	    for (tre=0; tre<ntrees; ++tre) {
69054925bf6Swillf 		if (subtreelist[tre] == NULL || strlen(subtreelist[tre]) == 0) {
69154925bf6Swillf 		    outofsubtree = FALSE;
69254925bf6Swillf 		    break;
69354925bf6Swillf 		} else {
69454925bf6Swillf 		    dnlen = strlen (dn);
69554925bf6Swillf 		    subtreelen = strlen(subtreelist[tre]);
69654925bf6Swillf 		    if ((dnlen >= subtreelen) && (strcasecmp((dn + dnlen - subtreelen), subtreelist[tre]) == 0)) {
69754925bf6Swillf 			outofsubtree = FALSE;
69854925bf6Swillf 			break;
69954925bf6Swillf 		    }
70054925bf6Swillf 		}
70154925bf6Swillf 	    }
70254925bf6Swillf 
70354925bf6Swillf 	    for (tre=0; tre < ntrees; ++tre) {
70454925bf6Swillf 		free(subtreelist[tre]);
70554925bf6Swillf 	    }
70654925bf6Swillf 
70754925bf6Swillf 	    if (outofsubtree == TRUE) {
70854925bf6Swillf 		st = EINVAL;
70954925bf6Swillf 		krb5_set_error_message(context, st, gettext("DN is out of the realm subtree"));
71054925bf6Swillf 		goto cleanup;
71154925bf6Swillf 	    }
71254925bf6Swillf 
71354925bf6Swillf 	    /*
71454925bf6Swillf 	     * dn value will be set either by dn, linkdn or the standalone_principal_dn
71554925bf6Swillf 	     * In the first 2 cases, the dn should be existing and in the last case we
71654925bf6Swillf 	     * are supposed to create the ldap object. so the below should not be
71754925bf6Swillf 	     * executed for the last case.
71854925bf6Swillf 	     */
71954925bf6Swillf 
72054925bf6Swillf 	    if (standalone_principal_dn == NULL) {
72154925bf6Swillf 		/*
72254925bf6Swillf 		 * If the ldap object is missing, this results in an error.
72354925bf6Swillf 		 */
72454925bf6Swillf 
72554925bf6Swillf 		/*
72654925bf6Swillf 		 * Search for krbprincipalname attribute here.
72754925bf6Swillf 		 * This is to find if a kerberos identity is already present
72854925bf6Swillf 		 * on the ldap object, in which case adding a kerberos identity
72954925bf6Swillf 		 * on the ldap object should result in an error.
73054925bf6Swillf 		 */
73154925bf6Swillf 		char  *attributes[]={"krbticketpolicyreference", "krbprincipalname", NULL};
73254925bf6Swillf 
73354925bf6Swillf 		LDAP_SEARCH_1(dn, LDAP_SCOPE_BASE, 0, attributes, IGNORE_STATUS);
73454925bf6Swillf 		if (st == LDAP_SUCCESS) {
73554925bf6Swillf 		    ent = ldap_first_entry(ld, result);
73654925bf6Swillf 		    if (ent != NULL) {
73754925bf6Swillf 			if ((values=ldap_get_values(ld, ent, "krbticketpolicyreference")) != NULL) {
73854925bf6Swillf 			    ldap_value_free(values);
73954925bf6Swillf 			}
74054925bf6Swillf 
74154925bf6Swillf 			if ((values=ldap_get_values(ld, ent, "krbprincipalname")) != NULL) {
74254925bf6Swillf 			    krb_identity_exists = TRUE;
74354925bf6Swillf 			    ldap_value_free(values);
74454925bf6Swillf 			}
74554925bf6Swillf 		    }
74654925bf6Swillf 		    ldap_msgfree(result);
74754925bf6Swillf 		} else {
74854925bf6Swillf 		    st = set_ldap_error(context, st, OP_SEARCH);
74954925bf6Swillf 		    goto cleanup;
75054925bf6Swillf 		}
75154925bf6Swillf 	    }
75254925bf6Swillf 	}
75354925bf6Swillf 
75454925bf6Swillf 	/*
75554925bf6Swillf 	 * If xargs.dn is set then the request is to add a
75654925bf6Swillf 	 * kerberos principal on a ldap object, but if
75754925bf6Swillf 	 * there is one already on the ldap object this
75854925bf6Swillf 	 * should result in an error.
75954925bf6Swillf 	 */
76054925bf6Swillf 
76154925bf6Swillf 	if (xargs.dn != NULL && krb_identity_exists == TRUE) {
76254925bf6Swillf 	    st = EINVAL;
76354925bf6Swillf 	    snprintf(errbuf, sizeof(errbuf), gettext("ldap object is already kerberized"));
76454925bf6Swillf 	    krb5_set_error_message(context, st, "%s", errbuf);
76554925bf6Swillf 	    goto cleanup;
76654925bf6Swillf 	}
76754925bf6Swillf 
76854925bf6Swillf 	if (xargs.linkdn != NULL) {
76954925bf6Swillf 	    /*
77054925bf6Swillf 	     * link information can be changed using modprinc.
77154925bf6Swillf 	     * However, link information can be changed only on the
77254925bf6Swillf 	     * standalone kerberos principal objects. A standalone
77354925bf6Swillf 	     * kerberos principal object is of type krbprincipal
77454925bf6Swillf 	     * structural objectclass.
77554925bf6Swillf 	     *
77654925bf6Swillf 	     * NOTE: kerberos principals on an ldap object can't be
77754925bf6Swillf 	     * linked to other ldap objects.
77854925bf6Swillf 	     */
77954925bf6Swillf 	    if (optype == MODIFY_PRINCIPAL &&
78054925bf6Swillf 		kerberos_principal_object_type != KDB_STANDALONE_PRINCIPAL_OBJECT) {
78154925bf6Swillf 		st = EINVAL;
78254925bf6Swillf 		snprintf(errbuf, sizeof(errbuf),
78354925bf6Swillf 		    gettext("link information can not be set/updated as the kerberos principal belongs to an ldap object"));
78454925bf6Swillf 		krb5_set_error_message(context, st, "%s", errbuf);
78554925bf6Swillf 		goto cleanup;
78654925bf6Swillf 	    }
78754925bf6Swillf             /*
78854925bf6Swillf              * Check the link information. If there is already a link
78954925bf6Swillf              * existing then this operation is not allowed.
79054925bf6Swillf              */
79154925bf6Swillf             {
79254925bf6Swillf                 char **linkdns=NULL;
79354925bf6Swillf                 int  j=0;
79454925bf6Swillf 
79554925bf6Swillf                 if ((st=krb5_get_linkdn(context, entries, &linkdns)) != 0) {
79654925bf6Swillf                     snprintf(errbuf, sizeof(errbuf),
79754925bf6Swillf                              gettext("Failed getting object references"));
79854925bf6Swillf                     krb5_set_error_message(context, st, "%s", errbuf);
79954925bf6Swillf                     goto cleanup;
80054925bf6Swillf                 }
80154925bf6Swillf                 if (linkdns != NULL) {
80254925bf6Swillf                     st = EINVAL;
80354925bf6Swillf                     snprintf(errbuf, sizeof(errbuf),
80454925bf6Swillf                              gettext("kerberos principal is already linked "
80554925bf6Swillf                              "to a ldap object"));
80654925bf6Swillf                     krb5_set_error_message(context, st, "%s", errbuf);
80754925bf6Swillf                     for (j=0; linkdns[j] != NULL; ++j)
80854925bf6Swillf                         free (linkdns[j]);
80954925bf6Swillf                     free (linkdns);
81054925bf6Swillf                     goto cleanup;
81154925bf6Swillf                 }
81254925bf6Swillf             }
81354925bf6Swillf 
81454925bf6Swillf 	    establish_links = TRUE;
81554925bf6Swillf 	}
81654925bf6Swillf 
81754925bf6Swillf 	if ((entries->last_success)!=0) {
81854925bf6Swillf 	    memset(strval, 0, sizeof(strval));
81954925bf6Swillf 	    if ((strval[0]=getstringtime(entries->last_success)) == NULL)
82054925bf6Swillf 		goto cleanup;
82154925bf6Swillf 	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastSuccessfulAuth", LDAP_MOD_REPLACE, strval)) != 0) {
82254925bf6Swillf 		free (strval[0]);
82354925bf6Swillf 		goto cleanup;
82454925bf6Swillf 	    }
82554925bf6Swillf 	    free (strval[0]);
82654925bf6Swillf 	}
82754925bf6Swillf 
82854925bf6Swillf 	if (entries->last_failed!=0) {
82954925bf6Swillf 	    memset(strval, 0, sizeof(strval));
83054925bf6Swillf 	    if ((strval[0]=getstringtime(entries->last_failed)) == NULL)
83154925bf6Swillf 		goto cleanup;
83254925bf6Swillf 	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastFailedAuth", LDAP_MOD_REPLACE, strval)) != 0) {
83354925bf6Swillf 		free (strval[0]);
83454925bf6Swillf 		goto cleanup;
83554925bf6Swillf 	    }
83654925bf6Swillf 	    free(strval[0]);
83754925bf6Swillf 	}
83854925bf6Swillf 
83954925bf6Swillf 	if (entries->fail_auth_count!=0) {
84054925bf6Swillf 	    if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbLoginFailedCount", LDAP_MOD_REPLACE, entries->fail_auth_count)) !=0)
84154925bf6Swillf 		goto cleanup;
84254925bf6Swillf 	}
84354925bf6Swillf 
84454925bf6Swillf 	if (entries->mask & KADM5_MAX_LIFE) {
84554925bf6Swillf 	    if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxticketlife", LDAP_MOD_REPLACE, entries->max_life)) != 0)
84654925bf6Swillf 		goto cleanup;
84754925bf6Swillf 	}
84854925bf6Swillf 
84954925bf6Swillf 	if (entries->mask & KADM5_MAX_RLIFE) {
85054925bf6Swillf 	    if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbmaxrenewableage", LDAP_MOD_REPLACE,
85154925bf6Swillf 					      entries->max_renewable_life)) != 0)
85254925bf6Swillf 		goto cleanup;
85354925bf6Swillf 	}
85454925bf6Swillf 
85554925bf6Swillf 	if (entries->mask & KADM5_ATTRIBUTES) {
85654925bf6Swillf 	    if ((st=krb5_add_int_mem_ldap_mod(&mods, "krbticketflags", LDAP_MOD_REPLACE,
85754925bf6Swillf 					      entries->attributes)) != 0)
85854925bf6Swillf 		goto cleanup;
85954925bf6Swillf 	}
86054925bf6Swillf 
86154925bf6Swillf 	if (entries->mask & KADM5_PRINCIPAL) {
86254925bf6Swillf 	    memset(strval, 0, sizeof(strval));
86354925bf6Swillf 	    strval[0] = user;
86454925bf6Swillf 	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalname", LDAP_MOD_REPLACE, strval)) != 0)
86554925bf6Swillf 		goto cleanup;
86654925bf6Swillf 	}
86754925bf6Swillf 
86854925bf6Swillf 	/*
86954925bf6Swillf 	 * Solaris Kerberos: this logic was not working properly when
87054925bf6Swillf 	 * default_principal_expiration set.
87154925bf6Swillf 	 */
87254925bf6Swillf 	if (entries->mask & KADM5_PRINC_EXPIRE_TIME || entries->expiration != 0) {
87354925bf6Swillf 	    memset(strval, 0, sizeof(strval));
87454925bf6Swillf 	    if ((strval[0]=getstringtime(entries->expiration)) == NULL)
87554925bf6Swillf 		goto cleanup;
87654925bf6Swillf 	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbprincipalexpiration", LDAP_MOD_REPLACE, strval)) != 0) {
87754925bf6Swillf 		free (strval[0]);
87854925bf6Swillf 		goto cleanup;
87954925bf6Swillf 	    }
88054925bf6Swillf 	    free (strval[0]);
88154925bf6Swillf 	}
88254925bf6Swillf 
88354925bf6Swillf 	/*
88454925bf6Swillf 	 * Solaris Kerberos: in case KADM5_PW_EXPIRATION isn't set, check
88554925bf6Swillf 	 * pw_expiration
88654925bf6Swillf 	 */
88754925bf6Swillf 	if (entries->mask & KADM5_PW_EXPIRATION || entries->pw_expiration != 0) {
88854925bf6Swillf 	    memset(strval, 0, sizeof(strval));
88954925bf6Swillf 	    if ((strval[0]=getstringtime(entries->pw_expiration)) == NULL)
89054925bf6Swillf 		goto cleanup;
89154925bf6Swillf 	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpasswordexpiration",
89254925bf6Swillf 					      LDAP_MOD_REPLACE,
89354925bf6Swillf 					      strval)) != 0) {
89454925bf6Swillf 		free (strval[0]);
89554925bf6Swillf 		goto cleanup;
89654925bf6Swillf 	    }
89754925bf6Swillf 	    free (strval[0]);
89854925bf6Swillf 	}
89954925bf6Swillf 
90054925bf6Swillf 	if (entries->mask & KADM5_POLICY) {
90154925bf6Swillf 	    memset(&princ_ent, 0, sizeof(princ_ent));
90254925bf6Swillf 	    for (tl_data=entries->tl_data; tl_data; tl_data=tl_data->tl_data_next) {
90354925bf6Swillf 		if (tl_data->tl_data_type == KRB5_TL_KADM_DATA) {
90454925bf6Swillf 		    /* FIX ME: I guess the princ_ent should be freed after this call */
90554925bf6Swillf 		    if ((st = krb5_lookup_tl_kadm_data(tl_data, &princ_ent)) != 0) {
90654925bf6Swillf 			goto cleanup;
90754925bf6Swillf 		    }
90854925bf6Swillf 		}
90954925bf6Swillf 	    }
91054925bf6Swillf 
91154925bf6Swillf 	    if (princ_ent.aux_attributes & KADM5_POLICY) {
91254925bf6Swillf 		memset(strval, 0, sizeof(strval));
91354925bf6Swillf 		if ((st = krb5_ldap_name_to_policydn (context, princ_ent.policy, &polname)) != 0)
91454925bf6Swillf 		    goto cleanup;
91554925bf6Swillf 		strval[0] = polname;
91654925bf6Swillf 		/* Solaris Kerberos: fix memleak */
91754925bf6Swillf 		free(princ_ent.policy);
91854925bf6Swillf 		if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, strval)) != 0)
91954925bf6Swillf 		    goto cleanup;
92054925bf6Swillf 	    } else {
92154925bf6Swillf 		st = EINVAL;
92254925bf6Swillf 		krb5_set_error_message(context, st, gettext("Password policy value null"));
92354925bf6Swillf 		goto cleanup;
92454925bf6Swillf 	    }
92554925bf6Swillf 	} else if (entries->mask & KADM5_LOAD && found_entry == TRUE) {
92654925bf6Swillf 	    /*
92754925bf6Swillf 	     * a load is special in that existing entries must have attrs that
92854925bf6Swillf 	     * removed.
92954925bf6Swillf 	     */
93054925bf6Swillf 
93154925bf6Swillf 	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_REPLACE, NULL)) != 0)
93254925bf6Swillf 		goto cleanup;
93354925bf6Swillf 	}
93454925bf6Swillf 
93554925bf6Swillf 	if (entries->mask & KADM5_POLICY_CLR) {
93654925bf6Swillf 	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbpwdpolicyreference", LDAP_MOD_DELETE, NULL)) != 0)
93754925bf6Swillf 		goto cleanup;
93854925bf6Swillf 	}
93954925bf6Swillf 
94054925bf6Swillf 	if (entries->mask & KADM5_KEY_DATA || entries->mask & KADM5_KVNO) {
94154925bf6Swillf 	    bersecretkey = krb5_encode_krbsecretkey (entries->key_data,
94254925bf6Swillf 						     entries->n_key_data);
94354925bf6Swillf 
94454925bf6Swillf 	    if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbprincipalkey",
94554925bf6Swillf 					      LDAP_MOD_REPLACE | LDAP_MOD_BVALUES, bersecretkey)) != 0)
94654925bf6Swillf 		goto cleanup;
94754925bf6Swillf 
94854925bf6Swillf 	    if (!(entries->mask & KADM5_PRINCIPAL)) {
94954925bf6Swillf 		memset(strval, 0, sizeof(strval));
95054925bf6Swillf 		if ((strval[0]=getstringtime(entries->pw_expiration)) == NULL)
95154925bf6Swillf 		    goto cleanup;
95254925bf6Swillf 		if ((st=krb5_add_str_mem_ldap_mod(&mods,
95354925bf6Swillf 						  "krbpasswordexpiration",
95454925bf6Swillf 						  LDAP_MOD_REPLACE, strval)) != 0) {
95554925bf6Swillf 		    free (strval[0]);
95654925bf6Swillf 		    goto cleanup;
95754925bf6Swillf 		}
95854925bf6Swillf 		free (strval[0]);
95954925bf6Swillf 	    }
96054925bf6Swillf 
96154925bf6Swillf 	    /* Update last password change whenever a new key is set */
96254925bf6Swillf 	    {
96354925bf6Swillf 		krb5_timestamp last_pw_changed;
96454925bf6Swillf 		if ((st=krb5_dbe_lookup_last_pwd_change(context, entries,
96554925bf6Swillf 							&last_pw_changed)) != 0)
96654925bf6Swillf 		    goto cleanup;
96754925bf6Swillf 
96854925bf6Swillf 		memset(strval, 0, sizeof(strval));
96954925bf6Swillf 		if ((strval[0] = getstringtime(last_pw_changed)) == NULL)
97054925bf6Swillf 		    goto cleanup;
97154925bf6Swillf 
97254925bf6Swillf 		if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbLastPwdChange",
97354925bf6Swillf 						  LDAP_MOD_REPLACE, strval)) != 0) {
97454925bf6Swillf 		    free (strval[0]);
97554925bf6Swillf 		    goto cleanup;
97654925bf6Swillf 		}
97754925bf6Swillf 		free (strval[0]);
97854925bf6Swillf 	    }
97954925bf6Swillf 
98054925bf6Swillf 	} /* Modify Key data ends here */
98154925bf6Swillf 
98254925bf6Swillf 	/* Set tl_data */
98354925bf6Swillf 	if (entries->tl_data != NULL) {
98454925bf6Swillf 	    int count = 0;
98554925bf6Swillf 	    /* struct berval **ber_tl_data = NULL; */
98654925bf6Swillf 	    krb5_tl_data *ptr;
98754925bf6Swillf 	    for (ptr = entries->tl_data; ptr != NULL; ptr = ptr->tl_data_next) {
98854925bf6Swillf 		if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE
98954925bf6Swillf #ifdef SECURID
99054925bf6Swillf 		    || ptr->tl_data_type == KRB5_TL_DB_ARGS
99154925bf6Swillf #endif
99254925bf6Swillf 		    || ptr->tl_data_type == KDB_TL_USER_INFO)
99354925bf6Swillf 		    continue;
994*2dd2efa5Swillf 
995*2dd2efa5Swillf 		/* Solaris Kerberos: fix key history issue */
996*2dd2efa5Swillf 		if (ptr->tl_data_type == KRB5_TL_KADM_DATA && ! entries->mask & KADM5_KEY_HIST)
997*2dd2efa5Swillf 		    continue;
998*2dd2efa5Swillf 
99954925bf6Swillf 		count++;
100054925bf6Swillf 	    }
100154925bf6Swillf 	    if (count != 0) {
100254925bf6Swillf 		int j;
100354925bf6Swillf 		ber_tl_data = (struct berval **) calloc (count + 1,
100454925bf6Swillf 							 sizeof (struct berval*));
100554925bf6Swillf 		if (ber_tl_data == NULL) {
100654925bf6Swillf 		    st = ENOMEM;
100754925bf6Swillf 		    goto cleanup;
100854925bf6Swillf 		}
100954925bf6Swillf 		for (j = 0, ptr = entries->tl_data; ptr != NULL; ptr = ptr->tl_data_next) {
101054925bf6Swillf 		    /* Ignore tl_data that are stored in separate directory
101154925bf6Swillf 		     * attributes */
101254925bf6Swillf 		    if (ptr->tl_data_type == KRB5_TL_LAST_PWD_CHANGE
101354925bf6Swillf #ifdef SECURID
101454925bf6Swillf 			|| ptr->tl_data_type == KRB5_TL_DB_ARGS
101554925bf6Swillf #endif
101654925bf6Swillf 			|| ptr->tl_data_type == KDB_TL_USER_INFO)
101754925bf6Swillf 			continue;
1018*2dd2efa5Swillf 
1019*2dd2efa5Swillf 		    /*
1020*2dd2efa5Swillf 		     * Solaris Kerberos: key history needs to be stored (it's in
1021*2dd2efa5Swillf 		     * the KRB5_TL_KADM_DATA).
1022*2dd2efa5Swillf 		     */
1023*2dd2efa5Swillf 		    if (ptr->tl_data_type == KRB5_TL_KADM_DATA && ! entries->mask & KADM5_KEY_HIST)
1024*2dd2efa5Swillf 			continue;
1025*2dd2efa5Swillf 
102654925bf6Swillf 		    if ((st = tl_data2berval (ptr, &ber_tl_data[j])) != 0)
102754925bf6Swillf 			break;
102854925bf6Swillf 		    j++;
102954925bf6Swillf 		}
103054925bf6Swillf 		if (st != 0) {
103154925bf6Swillf 		    /* Solaris Kerberos: don't free here, do it at cleanup */
103254925bf6Swillf 		    goto cleanup;
103354925bf6Swillf 		}
103454925bf6Swillf 		ber_tl_data[count] = NULL;
103554925bf6Swillf 		if ((st=krb5_add_ber_mem_ldap_mod(&mods, "krbExtraData",
103654925bf6Swillf 						  LDAP_MOD_REPLACE | LDAP_MOD_BVALUES,
103754925bf6Swillf 						  ber_tl_data)) != 0)
103854925bf6Swillf 		    goto cleanup;
103954925bf6Swillf 	    }
104054925bf6Swillf 	}
104154925bf6Swillf 
104254925bf6Swillf 	/* Directory specific attribute */
104354925bf6Swillf 	if (xargs.tktpolicydn != NULL) {
104454925bf6Swillf 	    int tmask=0;
104554925bf6Swillf 
104654925bf6Swillf 	    if (strlen(xargs.tktpolicydn) != 0) {
104754925bf6Swillf 		st = checkattributevalue(ld, xargs.tktpolicydn, "objectclass", policyclass, &tmask);
104854925bf6Swillf 		CHECK_CLASS_VALIDITY(st, tmask, "ticket policy object value: ");
104954925bf6Swillf 
105054925bf6Swillf 		strval[0] = xargs.tktpolicydn;
105154925bf6Swillf 		strval[1] = NULL;
105254925bf6Swillf 		if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_REPLACE, strval)) != 0)
105354925bf6Swillf 		    goto cleanup;
105454925bf6Swillf 
105554925bf6Swillf 	    } else {
105654925bf6Swillf 		/* if xargs.tktpolicydn is a empty string, then delete
105754925bf6Swillf 		 * already existing krbticketpolicyreference attr */
105854925bf6Swillf 		if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbticketpolicyreference", LDAP_MOD_DELETE, NULL)) != 0)
105954925bf6Swillf 		    goto cleanup;
106054925bf6Swillf 	    }
106154925bf6Swillf 
106254925bf6Swillf 	}
106354925bf6Swillf 
106454925bf6Swillf 	if (establish_links == TRUE) {
106554925bf6Swillf 	    memset(strval, 0, sizeof(strval));
106654925bf6Swillf 	    strval[0] = xargs.linkdn;
106754925bf6Swillf 	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "krbObjectReferences", LDAP_MOD_REPLACE, strval)) != 0)
106854925bf6Swillf 		goto cleanup;
106954925bf6Swillf 	}
107054925bf6Swillf 
107154925bf6Swillf 	/*
107254925bf6Swillf 	 * in case mods is NULL then return
107354925bf6Swillf 	 * not sure but can happen in a modprinc
107454925bf6Swillf 	 * so no need to return an error
107554925bf6Swillf 	 * addprinc will at least have the principal name
107654925bf6Swillf 	 * and the keys passed in
107754925bf6Swillf 	 */
107854925bf6Swillf 	if (mods == NULL)
107954925bf6Swillf 	    goto cleanup;
108054925bf6Swillf 
108154925bf6Swillf 	if (create_standalone_prinicipal == TRUE) {
108254925bf6Swillf 	    memset(strval, 0, sizeof(strval));
108354925bf6Swillf 	    strval[0] = "krbprincipal";
108454925bf6Swillf 	    strval[1] = "krbprincipalaux";
108554925bf6Swillf 	    strval[2] = "krbTicketPolicyAux";
108654925bf6Swillf 
108754925bf6Swillf 	    if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
108854925bf6Swillf 		goto cleanup;
108954925bf6Swillf 
109054925bf6Swillf 	    st = ldap_add_ext_s(ld, standalone_principal_dn, mods, NULL, NULL);
109154925bf6Swillf 	    if (st == LDAP_ALREADY_EXISTS && entries->mask & KADM5_LOAD) {
109254925bf6Swillf 		/* a load operation must replace an existing entry */
109354925bf6Swillf 		st = ldap_delete_ext_s(ld, standalone_principal_dn, NULL, NULL);
109454925bf6Swillf 		if (st != LDAP_SUCCESS) {
109554925bf6Swillf 		    snprintf(errbuf, sizeof (errbuf), gettext("Principal delete failed (trying to replace entry): %s"),
109654925bf6Swillf 			ldap_err2string(st));
109754925bf6Swillf 		    st = translate_ldap_error (st, OP_ADD);
109854925bf6Swillf 		    krb5_set_error_message(context, st, "%s", errbuf);
109954925bf6Swillf 		    goto cleanup;
110054925bf6Swillf 		} else {
110154925bf6Swillf 		    st = ldap_add_ext_s(ld, standalone_principal_dn, mods, NULL, NULL);
110254925bf6Swillf 		}
110354925bf6Swillf 	    }
110454925bf6Swillf 	    if (st != LDAP_SUCCESS) {
110554925bf6Swillf 		snprintf(errbuf, sizeof (errbuf), gettext("Principal add failed: %s"), ldap_err2string(st));
110654925bf6Swillf 		st = translate_ldap_error (st, OP_ADD);
110754925bf6Swillf 		krb5_set_error_message(context, st, "%s", errbuf);
110854925bf6Swillf 		goto cleanup;
110954925bf6Swillf 	    }
111054925bf6Swillf 	} else {
111154925bf6Swillf 	    /*
111254925bf6Swillf 	     * Here existing ldap object is modified and can be related
111354925bf6Swillf 	     * to any attribute, so always ensure that the ldap
111454925bf6Swillf 	     * object is extended with all the kerberos related
111554925bf6Swillf 	     * objectclasses so that there are no constraint
111654925bf6Swillf 	     * violations.
111754925bf6Swillf 	     */
111854925bf6Swillf 	    {
111954925bf6Swillf 		char *attrvalues[] = {"krbprincipalaux", "krbTicketPolicyAux", NULL};
112054925bf6Swillf 		int p, q, r=0, amask=0;
112154925bf6Swillf 
112254925bf6Swillf 		if ((st=checkattributevalue(ld, (xargs.dn) ? xargs.dn : principal_dn,
112354925bf6Swillf 					    "objectclass", attrvalues, &amask)) != 0)
112454925bf6Swillf 		    goto cleanup;
112554925bf6Swillf 
112654925bf6Swillf 		memset(strval, 0, sizeof(strval));
112754925bf6Swillf 		for (p=1, q=0; p<=2; p<<=1, ++q) {
112854925bf6Swillf 		    if ((p & amask) == 0)
112954925bf6Swillf 			strval[r++] = attrvalues[q];
113054925bf6Swillf 		}
113154925bf6Swillf 		if (r != 0) {
113254925bf6Swillf 		    if ((st=krb5_add_str_mem_ldap_mod(&mods, "objectclass", LDAP_MOD_ADD, strval)) != 0)
113354925bf6Swillf 			goto cleanup;
113454925bf6Swillf 		}
113554925bf6Swillf 	    }
113654925bf6Swillf 	    if (xargs.dn != NULL)
113754925bf6Swillf 		st=ldap_modify_ext_s(ld, xargs.dn, mods, NULL, NULL);
113854925bf6Swillf 	    else
113954925bf6Swillf 		st = ldap_modify_ext_s(ld, principal_dn, mods, NULL, NULL);
114054925bf6Swillf 
114154925bf6Swillf 	    if (st != LDAP_SUCCESS) {
114254925bf6Swillf 		snprintf(errbuf, sizeof (errbuf), gettext("User modification failed: %s"), ldap_err2string(st));
114354925bf6Swillf 		st = translate_ldap_error (st, OP_MOD);
114454925bf6Swillf 		krb5_set_error_message(context, st, "%s", errbuf);
114554925bf6Swillf 		goto cleanup;
114654925bf6Swillf 	    }
114754925bf6Swillf 	}
114854925bf6Swillf     }
114954925bf6Swillf 
115054925bf6Swillf cleanup:
115154925bf6Swillf     if (user)
115254925bf6Swillf 	free(user);
115354925bf6Swillf 
115454925bf6Swillf     free_xargs(xargs);
115554925bf6Swillf 
115654925bf6Swillf     if (standalone_principal_dn)
115754925bf6Swillf 	free(standalone_principal_dn);
115854925bf6Swillf 
115954925bf6Swillf     if (principal_dn)
116054925bf6Swillf 	free (principal_dn);
116154925bf6Swillf 
116254925bf6Swillf     /* Solaris Kerberos: fix memleak */
116354925bf6Swillf     if (ber_tl_data) {
116454925bf6Swillf 	int j;
116554925bf6Swillf 
116654925bf6Swillf 	for (j = 0; ber_tl_data[j] != NULL; j++) {
116754925bf6Swillf 	    free (ber_tl_data[j]->bv_val);
116854925bf6Swillf 	    free (ber_tl_data[j]);
116954925bf6Swillf 	}
117054925bf6Swillf 	free(ber_tl_data);
117154925bf6Swillf     }
117254925bf6Swillf 
117354925bf6Swillf     if (polname != NULL)
117454925bf6Swillf 	free(polname);
117554925bf6Swillf 
117654925bf6Swillf     if (subtree)
117754925bf6Swillf 	free (subtree);
117854925bf6Swillf 
117954925bf6Swillf     if (bersecretkey) {
118054925bf6Swillf 	for (l=0; bersecretkey[l]; ++l) {
118154925bf6Swillf 	    if (bersecretkey[l]->bv_val)
118254925bf6Swillf 		free (bersecretkey[l]->bv_val);
118354925bf6Swillf 	    free (bersecretkey[l]);
118454925bf6Swillf 	}
118554925bf6Swillf 	free (bersecretkey);
118654925bf6Swillf     }
118754925bf6Swillf 
118854925bf6Swillf     ldap_mods_free(mods, 1);
118954925bf6Swillf     krb5_ldap_put_handle_to_pool(ldap_context, ldap_server_handle);
119054925bf6Swillf     *nentries = i;
119154925bf6Swillf     return(st);
119254925bf6Swillf }
119354925bf6Swillf 
119454925bf6Swillf krb5_error_code
krb5_read_tkt_policy(context,ldap_context,entries,policy)119554925bf6Swillf krb5_read_tkt_policy (context, ldap_context, entries, policy)
119654925bf6Swillf     krb5_context                context;
119754925bf6Swillf     krb5_ldap_context           *ldap_context;
119854925bf6Swillf     krb5_db_entry               *entries;
119954925bf6Swillf     char                        *policy;
120054925bf6Swillf {
120154925bf6Swillf     krb5_error_code             st=0;
120254925bf6Swillf     unsigned int                mask=0, omask=0;
120354925bf6Swillf     int                         tkt_mask=(KDB_MAX_LIFE_ATTR | KDB_MAX_RLIFE_ATTR | KDB_TKT_FLAGS_ATTR);
120454925bf6Swillf     krb5_ldap_policy_params     *tktpoldnparam=NULL;
120554925bf6Swillf 
120654925bf6Swillf     if ((st=krb5_get_attributes_mask(context, entries, &mask)) != 0)
120754925bf6Swillf 	goto cleanup;
120854925bf6Swillf 
120954925bf6Swillf     if ((mask & tkt_mask) == tkt_mask)
121054925bf6Swillf 	goto cleanup;
121154925bf6Swillf 
121254925bf6Swillf     if (policy != NULL) {
121354925bf6Swillf 	st = krb5_ldap_read_policy(context, policy, &tktpoldnparam, &omask);
121454925bf6Swillf 	if (st && st != KRB5_KDB_NOENTRY) {
121554925bf6Swillf 	    prepend_err_str(context, gettext("Error reading ticket policy. "), st, st);
121654925bf6Swillf 	    goto cleanup;
121754925bf6Swillf 	}
121854925bf6Swillf 
121954925bf6Swillf 	st = 0; /* reset the return status */
122054925bf6Swillf     }
122154925bf6Swillf 
122254925bf6Swillf     if ((mask & KDB_MAX_LIFE_ATTR) == 0) {
122354925bf6Swillf 	if ((omask & KDB_MAX_LIFE_ATTR) ==  KDB_MAX_LIFE_ATTR)
122454925bf6Swillf 	    entries->max_life = tktpoldnparam->maxtktlife;
122554925bf6Swillf 	else if (ldap_context->lrparams->max_life)
122654925bf6Swillf 	    entries->max_life = ldap_context->lrparams->max_life;
122754925bf6Swillf     }
122854925bf6Swillf 
122954925bf6Swillf     if ((mask & KDB_MAX_RLIFE_ATTR) == 0) {
123054925bf6Swillf 	if ((omask & KDB_MAX_RLIFE_ATTR) == KDB_MAX_RLIFE_ATTR)
123154925bf6Swillf 	    entries->max_renewable_life = tktpoldnparam->maxrenewlife;
123254925bf6Swillf 	else if (ldap_context->lrparams->max_renewable_life)
123354925bf6Swillf 	    entries->max_renewable_life = ldap_context->lrparams->max_renewable_life;
123454925bf6Swillf     }
123554925bf6Swillf 
123654925bf6Swillf     if ((mask & KDB_TKT_FLAGS_ATTR) == 0) {
123754925bf6Swillf 	if ((omask & KDB_TKT_FLAGS_ATTR) == KDB_TKT_FLAGS_ATTR)
123854925bf6Swillf 	    entries->attributes = tktpoldnparam->tktflags;
123954925bf6Swillf 	else if (ldap_context->lrparams->tktflags)
124054925bf6Swillf 	    entries->attributes |= ldap_context->lrparams->tktflags;
124154925bf6Swillf     }
124254925bf6Swillf     krb5_ldap_free_policy(context, tktpoldnparam);
124354925bf6Swillf 
124454925bf6Swillf cleanup:
124554925bf6Swillf     return st;
124654925bf6Swillf }
124754925bf6Swillf 
124854925bf6Swillf krb5_error_code
krb5_decode_krbsecretkey(context,entries,bvalues)124954925bf6Swillf krb5_decode_krbsecretkey(context, entries, bvalues)
125054925bf6Swillf     krb5_context                context;
125154925bf6Swillf     krb5_db_entry               *entries;
125254925bf6Swillf     struct berval               **bvalues;
125354925bf6Swillf {
125454925bf6Swillf     char                        *user=NULL;
125554925bf6Swillf     int                         i=0, j=0, noofkeys=0;
125654925bf6Swillf     krb5_key_data               *key_data=NULL, *tmp;
125754925bf6Swillf     krb5_error_code             st=0;
125854925bf6Swillf 
125954925bf6Swillf     if ((st=krb5_unparse_name(context, entries->princ, &user)) != 0)
126054925bf6Swillf 	goto cleanup;
126154925bf6Swillf 
126254925bf6Swillf     for (i=0; bvalues[i] != NULL; ++i) {
126354925bf6Swillf 	int mkvno; /* Not used currently */
126454925bf6Swillf 	krb5_int16 n_kd;
126554925bf6Swillf 	krb5_key_data *kd;
126654925bf6Swillf 	krb5_data in;
126754925bf6Swillf 
126854925bf6Swillf 	if (bvalues[i]->bv_len == 0)
126954925bf6Swillf 	    continue;
127054925bf6Swillf 	in.length = bvalues[i]->bv_len;
127154925bf6Swillf 	in.data = bvalues[i]->bv_val;
127254925bf6Swillf 
127354925bf6Swillf 	st = asn1_decode_sequence_of_keys (&in,
127454925bf6Swillf 					   &kd,
127554925bf6Swillf 					   &n_kd,
127654925bf6Swillf 					   &mkvno);
127754925bf6Swillf 
127854925bf6Swillf 	if (st != 0) {
127954925bf6Swillf 	    const char *msg = error_message(st);
128054925bf6Swillf 	    st = -1; /* Something more appropriate ? */
128154925bf6Swillf 	    krb5_set_error_message (context, st,
128254925bf6Swillf 				    gettext("unable to decode stored principal key data (%s)"), msg);
128354925bf6Swillf 	    goto cleanup;
128454925bf6Swillf 	}
128554925bf6Swillf 	noofkeys += n_kd;
128654925bf6Swillf 	tmp = key_data;
128754925bf6Swillf 	key_data = realloc (key_data, noofkeys * sizeof (krb5_key_data));
128854925bf6Swillf 	if (key_data == NULL) {
128954925bf6Swillf 	    key_data = tmp;
129054925bf6Swillf 	    st = ENOMEM;
129154925bf6Swillf 	    goto cleanup;
129254925bf6Swillf 	}
129354925bf6Swillf 	for (j = 0; j < n_kd; j++)
129454925bf6Swillf 	    key_data[noofkeys - n_kd + j] = kd[j];
129554925bf6Swillf 	free (kd);
129654925bf6Swillf     }
129754925bf6Swillf 
129854925bf6Swillf     entries->n_key_data = noofkeys;
129954925bf6Swillf     entries->key_data = key_data;
130054925bf6Swillf 
130154925bf6Swillf cleanup:
130254925bf6Swillf     ldap_value_free_len(bvalues);
130354925bf6Swillf     free (user);
130454925bf6Swillf     return st;
130554925bf6Swillf }
130654925bf6Swillf 
130754925bf6Swillf static char *
getstringtime(epochtime)130854925bf6Swillf getstringtime(epochtime)
130954925bf6Swillf     krb5_timestamp    epochtime;
131054925bf6Swillf {
131154925bf6Swillf     struct tm           tme;
131254925bf6Swillf     char                *strtime=NULL;
131354925bf6Swillf     time_t		posixtime = epochtime;
131454925bf6Swillf 
131554925bf6Swillf     strtime = calloc (50, 1);
131654925bf6Swillf     if (strtime == NULL)
131754925bf6Swillf 	return NULL;
131854925bf6Swillf 
131954925bf6Swillf     if (gmtime_r(&posixtime, &tme) == NULL)
132054925bf6Swillf 	return NULL;
132154925bf6Swillf 
132254925bf6Swillf     strftime(strtime, 50, DATE_FORMAT, &tme);
132354925bf6Swillf     return strtime;
132454925bf6Swillf }
132554925bf6Swillf 
1326