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