3be44d5cd756a7c71d14191e7c2d0d282a736109
[platform/upstream/krb5.git] / src / lib / krb5 / krb / gic_opt.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 #include "k5-int.h"
3 #include "int-proto.h"
4 #include <krb5/clpreauth_plugin.h>
5
6 #define GIC_OPT_EXTENDED      0x80000000
7 #define GIC_OPT_SHALLOW_COPY  0x40000000
8
9 #define DEFAULT_FLAGS KRB5_GET_INIT_CREDS_OPT_CHG_PWD_PRMPT
10
11 #if defined(__MACH__) && defined(__APPLE__)
12 #include <TargetConditionals.h>
13 #endif
14
15 /* Match struct packing of krb5_get_init_creds_opt on MacOS X. */
16 #if TARGET_OS_MAC
17 #pragma pack(push,2)
18 #endif
19 struct extended_options {
20     krb5_get_init_creds_opt opt;
21     int num_preauth_data;
22     krb5_gic_opt_pa_data *preauth_data;
23     char *fast_ccache_name;
24     krb5_ccache in_ccache;
25     krb5_ccache out_ccache;
26     krb5_flags fast_flags;
27     krb5_expire_callback_func expire_cb;
28     void *expire_data;
29     krb5_responder_fn responder;
30     void *responder_data;
31     int pac_request;            /* -1 unset, 0 false, 1 true */
32 };
33 #if TARGET_OS_MAC
34 #pragma pack(pop)
35 #endif
36
37 void KRB5_CALLCONV
38 krb5_get_init_creds_opt_init(krb5_get_init_creds_opt *opt)
39 {
40     opt->flags = DEFAULT_FLAGS;
41 }
42
43 void KRB5_CALLCONV
44 krb5_get_init_creds_opt_set_tkt_life(krb5_get_init_creds_opt *opt,
45                                      krb5_deltat tkt_life)
46 {
47     opt->flags |= KRB5_GET_INIT_CREDS_OPT_TKT_LIFE;
48     opt->tkt_life = tkt_life;
49 }
50
51 void KRB5_CALLCONV
52 krb5_get_init_creds_opt_set_renew_life(krb5_get_init_creds_opt *opt,
53                                        krb5_deltat renew_life)
54 {
55     opt->flags |= KRB5_GET_INIT_CREDS_OPT_RENEW_LIFE;
56     opt->renew_life = renew_life;
57 }
58
59 void KRB5_CALLCONV
60 krb5_get_init_creds_opt_set_forwardable(krb5_get_init_creds_opt *opt,
61                                         int forwardable)
62 {
63     opt->flags |= KRB5_GET_INIT_CREDS_OPT_FORWARDABLE;
64     opt->forwardable = forwardable;
65 }
66
67 void KRB5_CALLCONV
68 krb5_get_init_creds_opt_set_proxiable(krb5_get_init_creds_opt *opt,
69                                       int proxiable)
70 {
71     opt->flags |= KRB5_GET_INIT_CREDS_OPT_PROXIABLE;
72     opt->proxiable = proxiable;
73 }
74
75 void KRB5_CALLCONV
76 krb5_get_init_creds_opt_set_canonicalize(krb5_get_init_creds_opt *opt,
77                                          int canonicalize)
78 {
79     if (canonicalize)
80         opt->flags |= KRB5_GET_INIT_CREDS_OPT_CANONICALIZE;
81     else
82         opt->flags &= ~(KRB5_GET_INIT_CREDS_OPT_CANONICALIZE);
83 }
84
85 void KRB5_CALLCONV
86 krb5_get_init_creds_opt_set_anonymous (krb5_get_init_creds_opt *opt,
87                                        int anonymous)
88 {
89     if (anonymous)
90         opt->flags |= KRB5_GET_INIT_CREDS_OPT_ANONYMOUS;
91     else opt->flags &= ~KRB5_GET_INIT_CREDS_OPT_ANONYMOUS;
92 }
93
94 void KRB5_CALLCONV
95 krb5_get_init_creds_opt_set_etype_list(krb5_get_init_creds_opt *opt, krb5_enctype *etype_list, int etype_list_length)
96 {
97     opt->flags |= KRB5_GET_INIT_CREDS_OPT_ETYPE_LIST;
98     opt->etype_list = etype_list;
99     opt->etype_list_length = etype_list_length;
100 }
101
102 void KRB5_CALLCONV
103 krb5_get_init_creds_opt_set_address_list(krb5_get_init_creds_opt *opt,
104                                          krb5_address **addresses)
105 {
106     opt->flags |= KRB5_GET_INIT_CREDS_OPT_ADDRESS_LIST;
107     opt->address_list = addresses;
108 }
109
110 void KRB5_CALLCONV
111 krb5_get_init_creds_opt_set_preauth_list(krb5_get_init_creds_opt *opt,
112                                          krb5_preauthtype *preauth_list,
113                                          int preauth_list_length)
114 {
115     opt->flags |= KRB5_GET_INIT_CREDS_OPT_PREAUTH_LIST;
116     opt->preauth_list = preauth_list;
117     opt->preauth_list_length = preauth_list_length;
118 }
119
120 void KRB5_CALLCONV
121 krb5_get_init_creds_opt_set_salt(krb5_get_init_creds_opt *opt, krb5_data *salt)
122 {
123     opt->flags |= KRB5_GET_INIT_CREDS_OPT_SALT;
124     opt->salt = salt;
125 }
126
127 void KRB5_CALLCONV
128 krb5_get_init_creds_opt_set_change_password_prompt(
129     krb5_get_init_creds_opt *opt, int prompt)
130 {
131     if (prompt)
132         opt->flags |= KRB5_GET_INIT_CREDS_OPT_CHG_PWD_PRMPT;
133     else
134         opt->flags &= ~KRB5_GET_INIT_CREDS_OPT_CHG_PWD_PRMPT;
135 }
136
137 krb5_error_code KRB5_CALLCONV
138 krb5_get_init_creds_opt_alloc(krb5_context context,
139                               krb5_get_init_creds_opt **opt)
140 {
141     struct extended_options *opte;
142
143     if (opt == NULL)
144         return EINVAL;
145     *opt = NULL;
146
147     /* Return an extended structure cast as a krb5_get_init_creds_opt. */
148     opte = calloc(1, sizeof(*opte));
149     if (opte == NULL)
150         return ENOMEM;
151     opte->opt.flags = DEFAULT_FLAGS | GIC_OPT_EXTENDED;
152     opte->pac_request = -1;
153     *opt = (krb5_get_init_creds_opt *)opte;
154     return 0;
155 }
156
157 void KRB5_CALLCONV
158 krb5_get_init_creds_opt_free(krb5_context context,
159                              krb5_get_init_creds_opt *opt)
160 {
161     struct extended_options *opte = (struct extended_options *)opt;
162     int i;
163
164     if (opt == NULL || !(opt->flags & GIC_OPT_EXTENDED))
165         return;
166     assert(!(opt->flags & GIC_OPT_SHALLOW_COPY));
167     for (i = 0; i < opte->num_preauth_data; i++) {
168         free(opte->preauth_data[i].attr);
169         free(opte->preauth_data[i].value);
170     }
171     free(opte->preauth_data);
172     free(opte->fast_ccache_name);
173     free(opte);
174 }
175
176 krb5_error_code KRB5_CALLCONV
177 krb5_get_init_creds_opt_set_pa(krb5_context context,
178                                krb5_get_init_creds_opt *opt,
179                                const char *attr,
180                                const char *value)
181 {
182     struct extended_options *opte = (struct extended_options *)opt;
183     krb5_gic_opt_pa_data *t, *pa;
184
185     if (opt == NULL || !(opt->flags & GIC_OPT_EXTENDED))
186         return EINVAL;
187     assert(!(opt->flags & GIC_OPT_SHALLOW_COPY));
188
189     /* Allocate space for another option. */
190     t = realloc(opte->preauth_data, (opte->num_preauth_data + 1) * sizeof(*t));
191     if (t == NULL)
192         return ENOMEM;
193     opte->preauth_data = t;
194
195     /* Copy the option into the new slot. */
196     pa = &opte->preauth_data[opte->num_preauth_data];
197     pa->attr = strdup(attr);
198     if (pa->attr == NULL)
199         return ENOMEM;
200     pa->value = strdup(value);
201     if (pa->value == NULL) {
202         free(pa->attr);
203         return ENOMEM;
204     }
205     opte->num_preauth_data++;
206
207     /* Give preauth modules a chance to look at the option now. */
208     return krb5_preauth_supply_preauth_data(context, opt, attr, value);
209 }
210
211 /*
212  * This function allows a preauth plugin to obtain preauth
213  * options.  The preauth_data returned from this function
214  * should be freed by calling krb5_get_init_creds_opt_free_pa().
215  *
216  * The 'opt' pointer supplied to this function must have been
217  * obtained using krb5_get_init_creds_opt_alloc()
218  */
219 krb5_error_code KRB5_CALLCONV
220 krb5_get_init_creds_opt_get_pa(krb5_context context,
221                                krb5_get_init_creds_opt *opt,
222                                int *num_preauth_data,
223                                krb5_gic_opt_pa_data **preauth_data)
224 {
225     struct extended_options *opte = (struct extended_options *)opt;
226     krb5_gic_opt_pa_data *p = NULL;
227     int i;
228
229     if (num_preauth_data == NULL || preauth_data == NULL)
230         return EINVAL;
231     *num_preauth_data = 0;
232     *preauth_data = NULL;
233     if (opt == NULL || !(opt->flags & GIC_OPT_EXTENDED))
234         return EINVAL;
235
236     if (opte->num_preauth_data == 0)
237         return 0;
238
239     p = calloc(opte->num_preauth_data, sizeof(*p));
240     if (p == NULL)
241         return ENOMEM;
242
243     for (i = 0; i < opte->num_preauth_data; i++) {
244         p[i].attr = strdup(opte->preauth_data[i].attr);
245         p[i].value = strdup(opte->preauth_data[i].value);
246         if (p[i].attr == NULL || p[i].value == NULL)
247             goto cleanup;
248     }
249     *num_preauth_data = i;
250     *preauth_data = p;
251     return 0;
252
253 cleanup:
254     krb5_get_init_creds_opt_free_pa(context, opte->num_preauth_data, p);
255     return ENOMEM;
256 }
257
258 /*
259  * This function frees the preauth_data that was returned by
260  * krb5_get_init_creds_opt_get_pa().
261  */
262 void KRB5_CALLCONV
263 krb5_get_init_creds_opt_free_pa(krb5_context context, int num_preauth_data,
264                                 krb5_gic_opt_pa_data *preauth_data)
265 {
266     int i;
267
268     if (num_preauth_data <= 0 || preauth_data == NULL)
269         return;
270
271     for (i = 0; i < num_preauth_data; i++) {
272         free(preauth_data[i].attr);
273         free(preauth_data[i].value);
274     }
275     free(preauth_data);
276 }
277
278 krb5_error_code KRB5_CALLCONV
279 krb5_get_init_creds_opt_set_fast_ccache_name(krb5_context context,
280                                              krb5_get_init_creds_opt *opt,
281                                              const char *ccache_name)
282 {
283     struct extended_options *opte = (struct extended_options *)opt;
284
285     if (opt == NULL || !(opt->flags & GIC_OPT_EXTENDED))
286         return EINVAL;
287     assert(!(opt->flags & GIC_OPT_SHALLOW_COPY));
288     free(opte->fast_ccache_name);
289     opte->fast_ccache_name = strdup(ccache_name);
290     if (opte->fast_ccache_name == NULL)
291         return ENOMEM;
292     return 0;
293 }
294
295 krb5_error_code KRB5_CALLCONV
296 krb5_get_init_creds_opt_set_fast_ccache(krb5_context context,
297                                         krb5_get_init_creds_opt *opt,
298                                         krb5_ccache ccache)
299 {
300     krb5_error_code ret;
301     char *name;
302
303     ret = krb5_cc_get_full_name(context, ccache, &name);
304     if (ret)
305         return ret;
306     ret = krb5_get_init_creds_opt_set_fast_ccache_name(context, opt, name);
307     free(name);
308     return ret;
309 }
310
311 const char *
312 k5_gic_opt_get_fast_ccache_name(krb5_get_init_creds_opt *opt)
313 {
314     struct extended_options *opte = (struct extended_options *)opt;
315
316     if (opt == NULL || !(opt->flags & GIC_OPT_EXTENDED))
317         return NULL;
318     return opte->fast_ccache_name;
319 }
320
321 krb5_error_code KRB5_CALLCONV
322 krb5_get_init_creds_opt_set_in_ccache(krb5_context context,
323                                       krb5_get_init_creds_opt *opt,
324                                       krb5_ccache ccache)
325 {
326     struct extended_options *opte = (struct extended_options *)opt;
327
328     if (opt == NULL || !(opt->flags & GIC_OPT_EXTENDED))
329         return EINVAL;
330     opte->in_ccache = ccache;
331     return 0;
332 }
333
334 krb5_ccache
335 k5_gic_opt_get_in_ccache(krb5_get_init_creds_opt *opt)
336 {
337     struct extended_options *opte = (struct extended_options *)opt;
338
339     if (opt == NULL || !(opt->flags & GIC_OPT_EXTENDED))
340         return NULL;
341     return opte->in_ccache;
342 }
343
344 krb5_error_code KRB5_CALLCONV
345 krb5_get_init_creds_opt_set_out_ccache(krb5_context context,
346                                        krb5_get_init_creds_opt *opt,
347                                        krb5_ccache ccache)
348 {
349     struct extended_options *opte = (struct extended_options *)opt;
350
351     if (opt == NULL || !(opt->flags & GIC_OPT_EXTENDED))
352         return EINVAL;
353     opte->out_ccache = ccache;
354     return 0;
355 }
356
357 krb5_ccache
358 k5_gic_opt_get_out_ccache(krb5_get_init_creds_opt *opt)
359 {
360     struct extended_options *opte = (struct extended_options *)opt;
361
362     if (opt == NULL || !(opt->flags & GIC_OPT_EXTENDED))
363         return NULL;
364     return opte->out_ccache;
365 }
366
367 krb5_error_code KRB5_CALLCONV
368 krb5_get_init_creds_opt_set_fast_flags(krb5_context context,
369                                        krb5_get_init_creds_opt *opt,
370                                        krb5_flags flags)
371 {
372     struct extended_options *opte = (struct extended_options *)opt;
373
374     if (opt == NULL || !(opt->flags & GIC_OPT_EXTENDED))
375         return EINVAL;
376     opte->fast_flags = flags;
377     return 0;
378 }
379
380 krb5_error_code KRB5_CALLCONV
381 krb5_get_init_creds_opt_get_fast_flags(krb5_context context,
382                                        krb5_get_init_creds_opt *opt,
383                                        krb5_flags *out_flags)
384 {
385     struct extended_options *opte = (struct extended_options *)opt;
386
387     if (out_flags == NULL)
388         return EINVAL;
389     *out_flags = 0;
390     if (opt == NULL || !(opt->flags & GIC_OPT_EXTENDED))
391         return EINVAL;
392     *out_flags = opte->fast_flags;
393     return 0;
394 }
395
396 krb5_flags
397 k5_gic_opt_get_fast_flags(krb5_get_init_creds_opt *opt)
398 {
399     struct extended_options *opte = (struct extended_options *)opt;
400
401     if (opt == NULL || !(opt->flags & GIC_OPT_EXTENDED))
402         return 0;
403     return opte->fast_flags;
404 }
405
406 krb5_error_code KRB5_CALLCONV
407 krb5_get_init_creds_opt_set_expire_callback(krb5_context context,
408                                             krb5_get_init_creds_opt *opt,
409                                             krb5_expire_callback_func cb,
410                                             void *data)
411 {
412     struct extended_options *opte = (struct extended_options *)opt;
413
414     if (opt == NULL || !(opt->flags & GIC_OPT_EXTENDED))
415         return EINVAL;
416     opte->expire_cb = cb;
417     opte->expire_data = data;
418     return 0;
419 }
420
421 void
422 k5_gic_opt_get_expire_cb(krb5_get_init_creds_opt *opt,
423                          krb5_expire_callback_func *cb_out, void **data_out)
424 {
425     struct extended_options *opte = (struct extended_options *)opt;
426
427     *cb_out = NULL;
428     *data_out = NULL;
429     if (opt == NULL || !(opt->flags & GIC_OPT_EXTENDED))
430         return;
431     *cb_out = opte->expire_cb;
432     *data_out = opte->expire_data;
433 }
434
435 krb5_error_code KRB5_CALLCONV
436 krb5_get_init_creds_opt_set_responder(krb5_context context,
437                                       krb5_get_init_creds_opt *opt,
438                                       krb5_responder_fn responder, void *data)
439 {
440     struct extended_options *opte = (struct extended_options *)opt;
441
442     if (opt == NULL || !(opt->flags & GIC_OPT_EXTENDED))
443         return EINVAL;
444     opte->responder = responder;
445     opte->responder_data = data;
446     return 0;
447 }
448
449 void
450 k5_gic_opt_get_responder(krb5_get_init_creds_opt *opt,
451                          krb5_responder_fn *responder_out, void **data_out)
452 {
453     struct extended_options *opte = (struct extended_options *)opt;
454
455     *responder_out = NULL;
456     *data_out = NULL;
457     if (opt == NULL || !(opt->flags & GIC_OPT_EXTENDED))
458         return;
459     *responder_out = opte->responder;
460     *data_out = opte->responder_data;
461 }
462
463 krb5_get_init_creds_opt *
464 k5_gic_opt_shallow_copy(krb5_get_init_creds_opt *opt)
465 {
466     struct extended_options *opte;
467
468     opte = calloc(1, sizeof(*opte));
469     if (opt == NULL)
470         opte->opt.flags = DEFAULT_FLAGS;
471     else if (opt->flags & GIC_OPT_EXTENDED)
472         *opte = *(struct extended_options *)opt;
473     else
474         opte->opt = *opt;
475     opte->opt.flags |= GIC_OPT_SHALLOW_COPY;
476     return (krb5_get_init_creds_opt *)opte;
477 }
478
479 krb5_error_code KRB5_CALLCONV
480 krb5_get_init_creds_opt_set_pac_request(krb5_context context,
481                                         krb5_get_init_creds_opt *opt,
482                                         krb5_boolean req_pac)
483 {
484     struct extended_options *opte = (struct extended_options *)opt;
485
486     if (opt == NULL || !(opt->flags & GIC_OPT_EXTENDED))
487         return EINVAL;
488     opte->pac_request = !!req_pac;
489     return 0;
490 }
491
492 int
493 k5_gic_opt_pac_request(krb5_get_init_creds_opt *opt)
494 {
495     struct extended_options *opte = (struct extended_options *)opt;
496
497     if (opt == NULL || !(opt->flags & GIC_OPT_EXTENDED))
498         return -1;
499     return opte->pac_request;
500 }