1*159d09a2SMark Phalan #include "k5-int.h"
2*159d09a2SMark Phalan #include "int-proto.h"
3*159d09a2SMark Phalan 
4*159d09a2SMark Phalan static void
5*159d09a2SMark Phalan init_common(krb5_get_init_creds_opt *opt)
6*159d09a2SMark Phalan {
7*159d09a2SMark Phalan     opt->flags |= KRB5_GET_INIT_CREDS_OPT_CHG_PWD_PRMPT;
8*159d09a2SMark Phalan }
97c478bd9Sstevel@tonic-gate 
10505d05c7Sgtb void KRB5_CALLCONV
11505d05c7Sgtb krb5_get_init_creds_opt_init(krb5_get_init_creds_opt *opt)
127c478bd9Sstevel@tonic-gate {
13*159d09a2SMark Phalan     opt->flags = 0;
14*159d09a2SMark Phalan     init_common(opt);
157c478bd9Sstevel@tonic-gate }
167c478bd9Sstevel@tonic-gate 
17505d05c7Sgtb void KRB5_CALLCONV
18505d05c7Sgtb krb5_get_init_creds_opt_set_tkt_life(krb5_get_init_creds_opt *opt, krb5_deltat tkt_life)
197c478bd9Sstevel@tonic-gate {
207c478bd9Sstevel@tonic-gate    opt->flags |= KRB5_GET_INIT_CREDS_OPT_TKT_LIFE;
217c478bd9Sstevel@tonic-gate    opt->tkt_life = tkt_life;
227c478bd9Sstevel@tonic-gate }
237c478bd9Sstevel@tonic-gate 
24505d05c7Sgtb void KRB5_CALLCONV
25505d05c7Sgtb krb5_get_init_creds_opt_set_renew_life(krb5_get_init_creds_opt *opt, krb5_deltat renew_life)
267c478bd9Sstevel@tonic-gate {
277c478bd9Sstevel@tonic-gate    opt->flags |= KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE;
287c478bd9Sstevel@tonic-gate    opt->renew_life = renew_life;
297c478bd9Sstevel@tonic-gate }
307c478bd9Sstevel@tonic-gate 
31505d05c7Sgtb void KRB5_CALLCONV
32505d05c7Sgtb krb5_get_init_creds_opt_set_forwardable(krb5_get_init_creds_opt *opt, int forwardable)
337c478bd9Sstevel@tonic-gate {
347c478bd9Sstevel@tonic-gate    opt->flags |= KRB5_GET_INIT_CREDS_OPT_FORWARDABLE;
357c478bd9Sstevel@tonic-gate    opt->forwardable = forwardable;
367c478bd9Sstevel@tonic-gate }
377c478bd9Sstevel@tonic-gate 
38505d05c7Sgtb void KRB5_CALLCONV
39505d05c7Sgtb krb5_get_init_creds_opt_set_proxiable(krb5_get_init_creds_opt *opt, int proxiable)
407c478bd9Sstevel@tonic-gate {
417c478bd9Sstevel@tonic-gate    opt->flags |= KRB5_GET_INIT_CREDS_OPT_PROXIABLE;
427c478bd9Sstevel@tonic-gate    opt->proxiable = proxiable;
437c478bd9Sstevel@tonic-gate }
447c478bd9Sstevel@tonic-gate 
45505d05c7Sgtb void KRB5_CALLCONV
46505d05c7Sgtb krb5_get_init_creds_opt_set_etype_list(krb5_get_init_creds_opt *opt, krb5_enctype *etype_list, int etype_list_length)
477c478bd9Sstevel@tonic-gate {
487c478bd9Sstevel@tonic-gate    opt->flags |= KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST;
497c478bd9Sstevel@tonic-gate    opt->etype_list = etype_list;
507c478bd9Sstevel@tonic-gate    opt->etype_list_length = etype_list_length;
517c478bd9Sstevel@tonic-gate }
527c478bd9Sstevel@tonic-gate 
53505d05c7Sgtb void KRB5_CALLCONV
54505d05c7Sgtb krb5_get_init_creds_opt_set_address_list(krb5_get_init_creds_opt *opt, krb5_address **addresses)
557c478bd9Sstevel@tonic-gate {
567c478bd9Sstevel@tonic-gate    opt->flags |= KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST;
577c478bd9Sstevel@tonic-gate    opt->address_list = addresses;
587c478bd9Sstevel@tonic-gate }
597c478bd9Sstevel@tonic-gate 
60505d05c7Sgtb void KRB5_CALLCONV
61505d05c7Sgtb krb5_get_init_creds_opt_set_preauth_list(krb5_get_init_creds_opt *opt, krb5_preauthtype *preauth_list, int preauth_list_length)
627c478bd9Sstevel@tonic-gate {
637c478bd9Sstevel@tonic-gate    opt->flags |= KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST;
647c478bd9Sstevel@tonic-gate    opt->preauth_list = preauth_list;
657c478bd9Sstevel@tonic-gate    opt->preauth_list_length = preauth_list_length;
667c478bd9Sstevel@tonic-gate }
677c478bd9Sstevel@tonic-gate 
68505d05c7Sgtb void KRB5_CALLCONV
69505d05c7Sgtb krb5_get_init_creds_opt_set_salt(krb5_get_init_creds_opt *opt, krb5_data *salt)
707c478bd9Sstevel@tonic-gate {
717c478bd9Sstevel@tonic-gate    opt->flags |= KRB5_GET_INIT_CREDS_OPT_SALT;
727c478bd9Sstevel@tonic-gate    opt->salt = salt;
737c478bd9Sstevel@tonic-gate }
74*159d09a2SMark Phalan 
75*159d09a2SMark Phalan void KRB5_CALLCONV
76*159d09a2SMark Phalan krb5_get_init_creds_opt_set_change_password_prompt(krb5_get_init_creds_opt *opt, int prompt)
77*159d09a2SMark Phalan {
78*159d09a2SMark Phalan    if (prompt)
79*159d09a2SMark Phalan      opt->flags |= KRB5_GET_INIT_CREDS_OPT_CHG_PWD_PRMPT;
80*159d09a2SMark Phalan    else
81*159d09a2SMark Phalan      opt->flags &= ~KRB5_GET_INIT_CREDS_OPT_CHG_PWD_PRMPT;
82*159d09a2SMark Phalan }
83*159d09a2SMark Phalan 
84*159d09a2SMark Phalan /*
85*159d09a2SMark Phalan  * Extending the krb5_get_init_creds_opt structure.  The original
86*159d09a2SMark Phalan  * krb5_get_init_creds_opt structure is defined publicly.  The
87*159d09a2SMark Phalan  * new extended version is private.  The original interface
88*159d09a2SMark Phalan  * assumed a pre-allocated structure which was passed to
89*159d09a2SMark Phalan  * krb5_get_init_creds_init().  The new interface assumes that
90*159d09a2SMark Phalan  * the caller will call krb5_get_init_creds_alloc() and
91*159d09a2SMark Phalan  * krb5_get_init_creds_free().
92*159d09a2SMark Phalan  *
93*159d09a2SMark Phalan  * Callers MUST NOT call krb5_get_init_creds_init() after allocating an
94*159d09a2SMark Phalan  * opts structure using krb5_get_init_creds_alloc().  To do so will
95*159d09a2SMark Phalan  * introduce memory leaks.  Unfortunately, there is no way to enforce
96*159d09a2SMark Phalan  * this behavior.
97*159d09a2SMark Phalan  *
98*159d09a2SMark Phalan  * Two private flags are added for backward compatibility.
99*159d09a2SMark Phalan  * KRB5_GET_INIT_CREDS_OPT_EXTENDED says that the structure was allocated
100*159d09a2SMark Phalan  * with the new krb5_get_init_creds_opt_alloc() function.
101*159d09a2SMark Phalan  * KRB5_GET_INIT_CREDS_OPT_SHADOWED is set to indicate that the extended
102*159d09a2SMark Phalan  * structure is a shadow copy of an original krb5_get_init_creds_opt
103*159d09a2SMark Phalan  * structure.
104*159d09a2SMark Phalan  * If KRB5_GET_INIT_CREDS_OPT_SHADOWED is set after a call to
105*159d09a2SMark Phalan  * krb5int_gic_opt_to_opte(), the resulting extended structure should be
106*159d09a2SMark Phalan  * freed (using krb5_get_init_creds_free).  Otherwise, the original
107*159d09a2SMark Phalan  * structure was already extended and there is no need to free it.
108*159d09a2SMark Phalan  */
109*159d09a2SMark Phalan 
110*159d09a2SMark Phalan /* Forward prototype */
111*159d09a2SMark Phalan static void
112*159d09a2SMark Phalan free_gic_opt_ext_preauth_data(krb5_context context,
113*159d09a2SMark Phalan 			      krb5_gic_opt_ext *opte);
114*159d09a2SMark Phalan 
115*159d09a2SMark Phalan static krb5_error_code
116*159d09a2SMark Phalan krb5int_gic_opte_private_alloc(krb5_context context, krb5_gic_opt_ext *opte)
117*159d09a2SMark Phalan {
118*159d09a2SMark Phalan     if (NULL == opte || !krb5_gic_opt_is_extended(opte))
119*159d09a2SMark Phalan 	return EINVAL;
120*159d09a2SMark Phalan 
121*159d09a2SMark Phalan     opte->opt_private = calloc(1, sizeof(*opte->opt_private));
122*159d09a2SMark Phalan     if (NULL == opte->opt_private) {
123*159d09a2SMark Phalan 	return ENOMEM;
124*159d09a2SMark Phalan     }
125*159d09a2SMark Phalan     /* Allocate any private stuff */
126*159d09a2SMark Phalan     opte->opt_private->num_preauth_data = 0;
127*159d09a2SMark Phalan     opte->opt_private->preauth_data = NULL;
128*159d09a2SMark Phalan     return 0;
129*159d09a2SMark Phalan }
130*159d09a2SMark Phalan 
131*159d09a2SMark Phalan static krb5_error_code
132*159d09a2SMark Phalan krb5int_gic_opte_private_free(krb5_context context, krb5_gic_opt_ext *opte)
133*159d09a2SMark Phalan {
134*159d09a2SMark Phalan     if (NULL == opte || !krb5_gic_opt_is_extended(opte))
135*159d09a2SMark Phalan 	return EINVAL;
136*159d09a2SMark Phalan 
137*159d09a2SMark Phalan     /* Free up any private stuff */
138*159d09a2SMark Phalan     if (opte->opt_private->preauth_data != NULL)
139*159d09a2SMark Phalan 	free_gic_opt_ext_preauth_data(context, opte);
140*159d09a2SMark Phalan     free(opte->opt_private);
141*159d09a2SMark Phalan     opte->opt_private = NULL;
142*159d09a2SMark Phalan     return 0;
143*159d09a2SMark Phalan }
144*159d09a2SMark Phalan 
145*159d09a2SMark Phalan static krb5_gic_opt_ext *
146*159d09a2SMark Phalan krb5int_gic_opte_alloc(krb5_context context)
147*159d09a2SMark Phalan {
148*159d09a2SMark Phalan     krb5_gic_opt_ext *opte;
149*159d09a2SMark Phalan     krb5_error_code code;
150*159d09a2SMark Phalan 
151*159d09a2SMark Phalan     opte = calloc(1, sizeof(*opte));
152*159d09a2SMark Phalan     if (NULL == opte)
153*159d09a2SMark Phalan 	return NULL;
154*159d09a2SMark Phalan     opte->flags = KRB5_GET_INIT_CREDS_OPT_EXTENDED;
155*159d09a2SMark Phalan 
156*159d09a2SMark Phalan     code = krb5int_gic_opte_private_alloc(context, opte);
157*159d09a2SMark Phalan     if (code) {
158*159d09a2SMark Phalan 	krb5int_set_error(&context->err, code,
159*159d09a2SMark Phalan 		"krb5int_gic_opte_alloc: krb5int_gic_opte_private_alloc failed");
160*159d09a2SMark Phalan 	free(opte);
161*159d09a2SMark Phalan 	return NULL;
162*159d09a2SMark Phalan     }
163*159d09a2SMark Phalan     return(opte);
164*159d09a2SMark Phalan }
165*159d09a2SMark Phalan 
166*159d09a2SMark Phalan krb5_error_code KRB5_CALLCONV
167*159d09a2SMark Phalan krb5_get_init_creds_opt_alloc(krb5_context context,
168*159d09a2SMark Phalan 			      krb5_get_init_creds_opt **opt)
169*159d09a2SMark Phalan {
170*159d09a2SMark Phalan     krb5_gic_opt_ext *opte;
171*159d09a2SMark Phalan 
172*159d09a2SMark Phalan     if (NULL == opt)
173*159d09a2SMark Phalan 	return EINVAL;
174*159d09a2SMark Phalan     *opt = NULL;
175*159d09a2SMark Phalan 
176*159d09a2SMark Phalan     /*
177*159d09a2SMark Phalan      * We return a new extended structure cast as a krb5_get_init_creds_opt
178*159d09a2SMark Phalan      */
179*159d09a2SMark Phalan     opte = krb5int_gic_opte_alloc(context);
180*159d09a2SMark Phalan     if (NULL == opte)
181*159d09a2SMark Phalan 	return ENOMEM;
182*159d09a2SMark Phalan 
183*159d09a2SMark Phalan     *opt = (krb5_get_init_creds_opt *) opte;
184*159d09a2SMark Phalan     init_common(*opt);
185*159d09a2SMark Phalan     return 0;
186*159d09a2SMark Phalan }
187*159d09a2SMark Phalan 
188*159d09a2SMark Phalan void KRB5_CALLCONV
189*159d09a2SMark Phalan krb5_get_init_creds_opt_free(krb5_context context,
190*159d09a2SMark Phalan 			     krb5_get_init_creds_opt *opt)
191*159d09a2SMark Phalan {
192*159d09a2SMark Phalan     krb5_gic_opt_ext *opte;
193*159d09a2SMark Phalan 
194*159d09a2SMark Phalan     if (NULL == opt)
195*159d09a2SMark Phalan 	return;
196*159d09a2SMark Phalan 
197*159d09a2SMark Phalan     /* Don't touch it if we didn't allocate it */
198*159d09a2SMark Phalan     if (!krb5_gic_opt_is_extended(opt))
199*159d09a2SMark Phalan 	return;
200*159d09a2SMark Phalan 
201*159d09a2SMark Phalan     opte = (krb5_gic_opt_ext *)opt;
202*159d09a2SMark Phalan     if (opte->opt_private)
203*159d09a2SMark Phalan 	krb5int_gic_opte_private_free(context, opte);
204*159d09a2SMark Phalan 
205*159d09a2SMark Phalan     free(opte);
206*159d09a2SMark Phalan }
207*159d09a2SMark Phalan 
208*159d09a2SMark Phalan static krb5_error_code
209*159d09a2SMark Phalan krb5int_gic_opte_copy(krb5_context context,
210*159d09a2SMark Phalan 		      krb5_get_init_creds_opt *opt,
211*159d09a2SMark Phalan 		      krb5_gic_opt_ext **opte)
212*159d09a2SMark Phalan {
213*159d09a2SMark Phalan     krb5_gic_opt_ext *oe;
214*159d09a2SMark Phalan 
215*159d09a2SMark Phalan     oe = krb5int_gic_opte_alloc(context);
216*159d09a2SMark Phalan     if (NULL == oe)
217*159d09a2SMark Phalan 	return ENOMEM;
218*159d09a2SMark Phalan 
219*159d09a2SMark Phalan     if (opt)
220*159d09a2SMark Phalan         memcpy(oe, opt, sizeof(*opt));
221*159d09a2SMark Phalan 
222*159d09a2SMark Phalan     /*
223*159d09a2SMark Phalan      * Fix the flags -- the EXTENDED flag would have been
224*159d09a2SMark Phalan      * overwritten by the copy if there was one.  The
225*159d09a2SMark Phalan      * SHADOWED flag is necessary to ensure that the
226*159d09a2SMark Phalan      * krb5_gic_opt_ext structure that was allocated
227*159d09a2SMark Phalan      * here will be freed by the library because the
228*159d09a2SMark Phalan      * application is unaware of its existence.
229*159d09a2SMark Phalan      */
230*159d09a2SMark Phalan     oe->flags |= ( KRB5_GET_INIT_CREDS_OPT_EXTENDED |
231*159d09a2SMark Phalan 		   KRB5_GET_INIT_CREDS_OPT_SHADOWED);
232*159d09a2SMark Phalan 
233*159d09a2SMark Phalan     *opte = oe;
234*159d09a2SMark Phalan     return 0;
235*159d09a2SMark Phalan }
236*159d09a2SMark Phalan 
237*159d09a2SMark Phalan /*
238*159d09a2SMark Phalan  * Convert a krb5_get_init_creds_opt pointer to a pointer to
239*159d09a2SMark Phalan  * an extended, krb5_gic_opt_ext pointer.  If the original
240*159d09a2SMark Phalan  * pointer already points to an extended structure, then simply
241*159d09a2SMark Phalan  * return the original pointer.  Otherwise, if 'force' is non-zero,
242*159d09a2SMark Phalan  * allocate an extended structure and copy the original over it.
243*159d09a2SMark Phalan  * If the original pointer did not point to an extended structure
244*159d09a2SMark Phalan  * and 'force' is zero, then return an error.  This is used in
245*159d09a2SMark Phalan  * cases where the original *should* be an extended structure.
246*159d09a2SMark Phalan  */
247*159d09a2SMark Phalan krb5_error_code
248*159d09a2SMark Phalan krb5int_gic_opt_to_opte(krb5_context context,
249*159d09a2SMark Phalan 			krb5_get_init_creds_opt *opt,
250*159d09a2SMark Phalan 			krb5_gic_opt_ext **opte,
251*159d09a2SMark Phalan 			unsigned int force,
252*159d09a2SMark Phalan 			const char *where)
253*159d09a2SMark Phalan {
254*159d09a2SMark Phalan     if (!krb5_gic_opt_is_extended(opt)) {
255*159d09a2SMark Phalan 	if (force) {
256*159d09a2SMark Phalan 	    return krb5int_gic_opte_copy(context, opt, opte);
257*159d09a2SMark Phalan 	} else {
258*159d09a2SMark Phalan 	    krb5int_set_error(&context->err, EINVAL,
259*159d09a2SMark Phalan 		    "%s: attempt to convert non-extended krb5_get_init_creds_opt",
260*159d09a2SMark Phalan 		    where);
261*159d09a2SMark Phalan 	    return EINVAL;
262*159d09a2SMark Phalan 	}
263*159d09a2SMark Phalan     }
264*159d09a2SMark Phalan     /* If it is already extended, just return it */
265*159d09a2SMark Phalan     *opte = (krb5_gic_opt_ext *)opt;
266*159d09a2SMark Phalan     return 0;
267*159d09a2SMark Phalan }
268*159d09a2SMark Phalan 
269*159d09a2SMark Phalan static void
270*159d09a2SMark Phalan free_gic_opt_ext_preauth_data(krb5_context context,
271*159d09a2SMark Phalan 			      krb5_gic_opt_ext *opte)
272*159d09a2SMark Phalan {
273*159d09a2SMark Phalan     int i;
274*159d09a2SMark Phalan 
275*159d09a2SMark Phalan     if (NULL == opte || !krb5_gic_opt_is_extended(opte))
276*159d09a2SMark Phalan 	return;
277*159d09a2SMark Phalan     if (NULL == opte->opt_private || NULL == opte->opt_private->preauth_data)
278*159d09a2SMark Phalan 	return;
279*159d09a2SMark Phalan 
280*159d09a2SMark Phalan     for (i = 0; i < opte->opt_private->num_preauth_data; i++) {
281*159d09a2SMark Phalan 	if (opte->opt_private->preauth_data[i].attr != NULL)
282*159d09a2SMark Phalan 	    free(opte->opt_private->preauth_data[i].attr);
283*159d09a2SMark Phalan 	if (opte->opt_private->preauth_data[i].value != NULL)
284*159d09a2SMark Phalan 	    free(opte->opt_private->preauth_data[i].value);
285*159d09a2SMark Phalan     }
286*159d09a2SMark Phalan     free(opte->opt_private->preauth_data);
287*159d09a2SMark Phalan     opte->opt_private->preauth_data = NULL;
288*159d09a2SMark Phalan     opte->opt_private->num_preauth_data = 0;
289*159d09a2SMark Phalan }
290*159d09a2SMark Phalan 
291*159d09a2SMark Phalan static krb5_error_code
292*159d09a2SMark Phalan add_gic_opt_ext_preauth_data(krb5_context context,
293*159d09a2SMark Phalan 			     krb5_gic_opt_ext *opte,
294*159d09a2SMark Phalan 			     const char *attr,
295*159d09a2SMark Phalan 			     const char *value)
296*159d09a2SMark Phalan {
297*159d09a2SMark Phalan     size_t newsize;
298*159d09a2SMark Phalan     int i;
299*159d09a2SMark Phalan     krb5_gic_opt_pa_data *newpad;
300*159d09a2SMark Phalan 
301*159d09a2SMark Phalan     newsize = opte->opt_private->num_preauth_data + 1;
302*159d09a2SMark Phalan     newsize = newsize * sizeof(*opte->opt_private->preauth_data);
303*159d09a2SMark Phalan     if (opte->opt_private->preauth_data == NULL)
304*159d09a2SMark Phalan 	newpad = malloc(newsize);
305*159d09a2SMark Phalan     else
306*159d09a2SMark Phalan 	newpad = realloc(opte->opt_private->preauth_data, newsize);
307*159d09a2SMark Phalan     if (newpad == NULL)
308*159d09a2SMark Phalan 	return ENOMEM;
309*159d09a2SMark Phalan 
310*159d09a2SMark Phalan     i = opte->opt_private->num_preauth_data;
311*159d09a2SMark Phalan     newpad[i].attr = strdup(attr);
312*159d09a2SMark Phalan     if (newpad[i].attr == NULL)
313*159d09a2SMark Phalan 	return ENOMEM;
314*159d09a2SMark Phalan     newpad[i].value = strdup(value);
315*159d09a2SMark Phalan     if (newpad[i].value == NULL) {
316*159d09a2SMark Phalan 	free(newpad[i].attr);
317*159d09a2SMark Phalan 	return ENOMEM;
318*159d09a2SMark Phalan     }
319*159d09a2SMark Phalan     opte->opt_private->num_preauth_data += 1;
320*159d09a2SMark Phalan     opte->opt_private->preauth_data = newpad;
321*159d09a2SMark Phalan     return 0;
322*159d09a2SMark Phalan }
323*159d09a2SMark Phalan 
324*159d09a2SMark Phalan /*
325*159d09a2SMark Phalan  * This function allows the caller to supply options to preauth
326*159d09a2SMark Phalan  * plugins.  Preauth plugin modules are given a chance to look
327*159d09a2SMark Phalan  * at each option at the time this function is called in ordre
328*159d09a2SMark Phalan  * to check the validity of the option.
329*159d09a2SMark Phalan  * The 'opt' pointer supplied to this function must have been
330*159d09a2SMark Phalan  * obtained using krb5_get_init_creds_opt_alloc()
331*159d09a2SMark Phalan  */
332*159d09a2SMark Phalan krb5_error_code KRB5_CALLCONV
333*159d09a2SMark Phalan krb5_get_init_creds_opt_set_pa(krb5_context context,
334*159d09a2SMark Phalan 			       krb5_get_init_creds_opt *opt,
335*159d09a2SMark Phalan 			       const char *attr,
336*159d09a2SMark Phalan 			       const char *value)
337*159d09a2SMark Phalan {
338*159d09a2SMark Phalan     krb5_error_code retval;
339*159d09a2SMark Phalan     krb5_gic_opt_ext *opte;
340*159d09a2SMark Phalan 
341*159d09a2SMark Phalan     retval = krb5int_gic_opt_to_opte(context, opt, &opte, 0,
342*159d09a2SMark Phalan 				     "krb5_get_init_creds_opt_set_pa");
343*159d09a2SMark Phalan     if (retval)
344*159d09a2SMark Phalan 	return retval;
345*159d09a2SMark Phalan 
346*159d09a2SMark Phalan     /*
347*159d09a2SMark Phalan      * Copy the option into the extended get_init_creds_opt structure
348*159d09a2SMark Phalan      */
349*159d09a2SMark Phalan     retval = add_gic_opt_ext_preauth_data(context, opte, attr, value);
350*159d09a2SMark Phalan     if (retval)
351*159d09a2SMark Phalan 	return retval;
352*159d09a2SMark Phalan 
353*159d09a2SMark Phalan     /*
354*159d09a2SMark Phalan      * Give the plugins a chance to look at the option now.
355*159d09a2SMark Phalan      */
356*159d09a2SMark Phalan     retval = krb5_preauth_supply_preauth_data(context, opte, attr, value);
357*159d09a2SMark Phalan     return retval;
358*159d09a2SMark Phalan }
359*159d09a2SMark Phalan 
360*159d09a2SMark Phalan /*
361*159d09a2SMark Phalan  * This function allows a preauth plugin to obtain preauth
362*159d09a2SMark Phalan  * options.  The preauth_data returned from this function
363*159d09a2SMark Phalan  * should be freed by calling krb5_get_init_creds_opt_free_pa().
364*159d09a2SMark Phalan  *
365*159d09a2SMark Phalan  * The 'opt' pointer supplied to this function must have been
366*159d09a2SMark Phalan  * obtained using krb5_get_init_creds_opt_alloc()
367*159d09a2SMark Phalan  */
368*159d09a2SMark Phalan krb5_error_code KRB5_CALLCONV
369*159d09a2SMark Phalan krb5_get_init_creds_opt_get_pa(krb5_context context,
370*159d09a2SMark Phalan 			       krb5_get_init_creds_opt *opt,
371*159d09a2SMark Phalan 			       int *num_preauth_data,
372*159d09a2SMark Phalan 			       krb5_gic_opt_pa_data **preauth_data)
373*159d09a2SMark Phalan {
374*159d09a2SMark Phalan     krb5_error_code retval;
375*159d09a2SMark Phalan     krb5_gic_opt_ext *opte;
376*159d09a2SMark Phalan     krb5_gic_opt_pa_data *p = NULL;
377*159d09a2SMark Phalan     int i;
378*159d09a2SMark Phalan     size_t allocsize;
379*159d09a2SMark Phalan 
380*159d09a2SMark Phalan     retval = krb5int_gic_opt_to_opte(context, opt, &opte, 0,
381*159d09a2SMark Phalan 				     "krb5_get_init_creds_opt_get_pa");
382*159d09a2SMark Phalan     if (retval)
383*159d09a2SMark Phalan 	return retval;
384*159d09a2SMark Phalan 
385*159d09a2SMark Phalan     if (num_preauth_data == NULL || preauth_data == NULL)
386*159d09a2SMark Phalan 	return EINVAL;
387*159d09a2SMark Phalan 
388*159d09a2SMark Phalan     *num_preauth_data = 0;
389*159d09a2SMark Phalan     *preauth_data = NULL;
390*159d09a2SMark Phalan 
391*159d09a2SMark Phalan     if (opte->opt_private->num_preauth_data == 0)
392*159d09a2SMark Phalan 	return 0;
393*159d09a2SMark Phalan 
394*159d09a2SMark Phalan     allocsize =
395*159d09a2SMark Phalan 	    opte->opt_private->num_preauth_data * sizeof(krb5_gic_opt_pa_data);
396*159d09a2SMark Phalan     p = malloc(allocsize);
397*159d09a2SMark Phalan     if (p == NULL)
398*159d09a2SMark Phalan 	return ENOMEM;
399*159d09a2SMark Phalan 
400*159d09a2SMark Phalan     /* Init these to make cleanup easier */
401*159d09a2SMark Phalan     for (i = 0; i < opte->opt_private->num_preauth_data; i++) {
402*159d09a2SMark Phalan 	p[i].attr = NULL;
403*159d09a2SMark Phalan 	p[i].value = NULL;
404*159d09a2SMark Phalan     }
405*159d09a2SMark Phalan 
406*159d09a2SMark Phalan     for (i = 0; i < opte->opt_private->num_preauth_data; i++) {
407*159d09a2SMark Phalan 	p[i].attr = strdup(opte->opt_private->preauth_data[i].attr);
408*159d09a2SMark Phalan 	p[i].value = strdup(opte->opt_private->preauth_data[i].value);
409*159d09a2SMark Phalan 	if (p[i].attr == NULL || p[i].value == NULL)
410*159d09a2SMark Phalan 	    goto cleanup;
411*159d09a2SMark Phalan     }
412*159d09a2SMark Phalan     *num_preauth_data = i;
413*159d09a2SMark Phalan     *preauth_data = p;
414*159d09a2SMark Phalan     return 0;
415*159d09a2SMark Phalan cleanup:
416*159d09a2SMark Phalan     for (i = 0; i < opte->opt_private->num_preauth_data; i++) {
417*159d09a2SMark Phalan 	if (p[i].attr != NULL)
418*159d09a2SMark Phalan 	    free(p[i].attr);
419*159d09a2SMark Phalan 	if (p[i].value != NULL)
420*159d09a2SMark Phalan 	    free(p[i].value);
421*159d09a2SMark Phalan     }
422*159d09a2SMark Phalan     free(p);
423*159d09a2SMark Phalan     return ENOMEM;
424*159d09a2SMark Phalan }
425*159d09a2SMark Phalan 
426*159d09a2SMark Phalan /*
427*159d09a2SMark Phalan  * This function frees the preauth_data that was returned by
428*159d09a2SMark Phalan  * krb5_get_init_creds_opt_get_pa().
429*159d09a2SMark Phalan  */
430*159d09a2SMark Phalan void KRB5_CALLCONV
431*159d09a2SMark Phalan krb5_get_init_creds_opt_free_pa(krb5_context context,
432*159d09a2SMark Phalan 				int num_preauth_data,
433*159d09a2SMark Phalan 				krb5_gic_opt_pa_data *preauth_data)
434*159d09a2SMark Phalan {
435*159d09a2SMark Phalan     int i;
436*159d09a2SMark Phalan 
437*159d09a2SMark Phalan     if (num_preauth_data <= 0 || preauth_data == NULL)
438*159d09a2SMark Phalan 	return;
439*159d09a2SMark Phalan 
440*159d09a2SMark Phalan     for (i = 0; i < num_preauth_data; i++) {
441*159d09a2SMark Phalan 	if (preauth_data[i].attr != NULL)
442*159d09a2SMark Phalan 	    free(preauth_data[i].attr);
443*159d09a2SMark Phalan 	if (preauth_data[i].value != NULL)
444*159d09a2SMark Phalan 	    free(preauth_data[i].value);
445*159d09a2SMark Phalan     }
446*159d09a2SMark Phalan     free(preauth_data);
447*159d09a2SMark Phalan }
448