ticket: 6793
[idra/krb5.git] / src / lib / gssapi / krb5 / acquire_cred.c
1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /*
3  * Copyright 2000, 2007-2010 by the Massachusetts Institute of Technology.
4  * All Rights Reserved.
5  *
6  * Export of this software from the United States of America may
7  *   require a specific license from the United States Government.
8  *   It is the responsibility of any person or organization contemplating
9  *   export to obtain such a license before exporting.
10  *
11  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
12  * distribute this software and its documentation for any purpose and
13  * without fee is hereby granted, provided that the above copyright
14  * notice appear in all copies and that both that copyright notice and
15  * this permission notice appear in supporting documentation, and that
16  * the name of M.I.T. not be used in advertising or publicity pertaining
17  * to distribution of the software without specific, written prior
18  * permission.  Furthermore if you modify this software you must label
19  * your software as modified software and not distribute it in such a
20  * fashion that it might be confused with the original M.I.T. software.
21  * M.I.T. makes no representations about the suitability of
22  * this software for any purpose.  It is provided "as is" without express
23  * or implied warranty.
24  *
25  */
26 /*
27  * Copyright 1993 by OpenVision Technologies, Inc.
28  *
29  * Permission to use, copy, modify, distribute, and sell this software
30  * and its documentation for any purpose is hereby granted without fee,
31  * provided that the above copyright notice appears in all copies and
32  * that both that copyright notice and this permission notice appear in
33  * supporting documentation, and that the name of OpenVision not be used
34  * in advertising or publicity pertaining to distribution of the software
35  * without specific, written prior permission. OpenVision makes no
36  * representations about the suitability of this software for any
37  * purpose.  It is provided "as is" without express or implied warranty.
38  *
39  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
40  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
41  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
42  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
43  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
44  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
45  * PERFORMANCE OF THIS SOFTWARE.
46  */
47
48 /*
49  * Copyright (C) 1998 by the FundsXpress, INC.
50  *
51  * All rights reserved.
52  *
53  * Export of this software from the United States of America may require
54  * a specific license from the United States Government.  It is the
55  * responsibility of any person or organization contemplating export to
56  * obtain such a license before exporting.
57  *
58  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
59  * distribute this software and its documentation for any purpose and
60  * without fee is hereby granted, provided that the above copyright
61  * notice appear in all copies and that both that copyright notice and
62  * this permission notice appear in supporting documentation, and that
63  * the name of FundsXpress. not be used in advertising or publicity pertaining
64  * to distribution of the software without specific, written prior
65  * permission.  FundsXpress makes no representations about the suitability of
66  * this software for any purpose.  It is provided "as is" without express
67  * or implied warranty.
68  *
69  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
70  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
71  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
72  */
73
74 #include "k5-int.h"
75 #include "gssapiP_krb5.h"
76 #ifdef HAVE_STRING_H
77 #include <string.h>
78 #else
79 #include <strings.h>
80 #endif
81
82 #if defined(USE_KIM)
83 #include <kim/kim.h>
84 #include "kim_library_private.h"
85 #elif defined(USE_LEASH)
86 #ifdef _WIN64
87 #define LEASH_DLL "leashw64.dll"
88 #else
89 #define LEASH_DLL "leashw32.dll"
90 #endif
91 static void (*pLeash_AcquireInitialTicketsIfNeeded)(krb5_context,krb5_principal,char*,int) = NULL;
92 static HANDLE hLeashDLL = INVALID_HANDLE_VALUE;
93 #endif
94
95 #ifndef LEAN_CLIENT
96 k5_mutex_t gssint_krb5_keytab_lock = K5_MUTEX_PARTIAL_INITIALIZER;
97 static char *krb5_gss_keytab = NULL;
98
99 /* Heimdal calls this gsskrb5_register_acceptor_identity. */
100 OM_uint32
101 gss_krb5int_register_acceptor_identity(OM_uint32 *minor_status,
102                                        const gss_OID desired_mech,
103                                        const gss_OID desired_object,
104                                        gss_buffer_t value)
105 {
106     char *new = NULL, *old;
107     int err;
108
109     err = gss_krb5int_initialize_library();
110     if (err != 0)
111         return GSS_S_FAILURE;
112
113     if (value->value != NULL) {
114         new = strdup((char *)value->value);
115         if (new == NULL)
116             return GSS_S_FAILURE;
117     }
118
119     err = k5_mutex_lock(&gssint_krb5_keytab_lock);
120     if (err) {
121         free(new);
122         return GSS_S_FAILURE;
123     }
124     old = krb5_gss_keytab;
125     krb5_gss_keytab = new;
126     k5_mutex_unlock(&gssint_krb5_keytab_lock);
127     free(old);
128     return GSS_S_COMPLETE;
129 }
130
131 /* get credentials corresponding to a key in the krb5 keytab.
132    If successful, set the keytab-specific fields in cred
133 */
134
135 static OM_uint32
136 acquire_accept_cred(krb5_context context,
137                     OM_uint32 *minor_status,
138                     krb5_principal desired_princ,
139                     krb5_keytab req_keytab,
140                     krb5_gss_cred_id_rec *cred)
141 {
142     krb5_error_code code;
143     krb5_keytab kt;
144     krb5_keytab_entry entry;
145
146     assert(cred->keytab == NULL);
147
148     if (req_keytab != NULL) {
149         char ktname[BUFSIZ];
150
151         /* Duplicate keytab handle */
152         code = krb5_kt_get_name(context, req_keytab, ktname, sizeof(ktname));
153         if (code) {
154             *minor_status = code;
155             return GSS_S_CRED_UNAVAIL;
156         }
157         code = krb5_kt_resolve(context, ktname, &kt);
158     } else {
159         code = k5_mutex_lock(&gssint_krb5_keytab_lock);
160         if (code) {
161             *minor_status = code;
162             return GSS_S_FAILURE;
163         }
164         if (krb5_gss_keytab != NULL) {
165             code = krb5_kt_resolve(context, krb5_gss_keytab, &kt);
166             k5_mutex_unlock(&gssint_krb5_keytab_lock);
167         } else {
168             k5_mutex_unlock(&gssint_krb5_keytab_lock);
169             code = krb5_kt_default(context, &kt);
170         }
171     }
172     if (code) {
173         *minor_status = code;
174         return GSS_S_CRED_UNAVAIL;
175     }
176
177     if (desired_princ != NULL) {
178         code = krb5_kt_get_entry(context, kt, desired_princ, 0, 0, &entry);
179         if (code) {
180             krb5_kt_close(context, kt);
181             if (code == KRB5_KT_NOTFOUND) {
182                 char *errstr = (char *)krb5_get_error_message(context, code);
183                 krb5_set_error_message(context, KG_KEYTAB_NOMATCH, "%s", errstr);
184                 krb5_free_error_message(context, errstr);
185                 *minor_status = KG_KEYTAB_NOMATCH;
186             } else
187                 *minor_status = code;
188             return GSS_S_CRED_UNAVAIL;
189         }
190         krb5_kt_free_entry(context, &entry);
191
192         assert(cred->name == NULL);
193         code = kg_init_name(context, desired_princ, NULL, 0, &cred->name);
194         if (code) {
195             *minor_status = code;
196             return GSS_S_FAILURE;
197         }
198
199         /* Open the replay cache for this principal. */
200         code = krb5_get_server_rcache(context,
201                                       krb5_princ_component(context, desired_princ, 0),
202                                       &cred->rcache);
203         if (code) {
204             *minor_status = code;
205             return GSS_S_FAILURE;
206         }
207     }
208
209     cred->keytab = kt;
210
211     return GSS_S_COMPLETE;
212 }
213 #endif /* LEAN_CLIENT */
214
215 /* get credentials corresponding to the default credential cache.
216    If successful, set the ccache-specific fields in cred.
217 */
218
219 static OM_uint32
220 acquire_init_cred(krb5_context context,
221                   OM_uint32 *minor_status,
222                   krb5_ccache req_ccache,
223                   krb5_principal desired_princ,
224                   gss_buffer_t password,
225                   krb5_gss_cred_id_rec *cred)
226 {
227     krb5_error_code code;
228     krb5_ccache ccache;
229     krb5_principal ccache_princ = NULL, tmp_princ;
230     krb5_cc_cursor cur;
231     krb5_creds creds;
232     int got_endtime;
233     int caller_provided_ccache_name = 0;
234     krb5_data password_data, *cred_princ_realm;
235
236     cred->ccache = NULL;
237
238     /* load the GSS ccache name into the kg_context */
239
240     if (GSS_ERROR(kg_sync_ccache_name(context, minor_status)))
241         return GSS_S_FAILURE;
242
243     /* check to see if the caller provided a ccache name if so
244      * we will just use that and not search the cache collection */
245     if (GSS_ERROR(kg_caller_provided_ccache_name (minor_status, &caller_provided_ccache_name))) {
246         return GSS_S_FAILURE;
247     }
248
249 #if defined(USE_KIM) || defined(USE_LEASH)
250     if (desired_princ && !caller_provided_ccache_name && !req_ccache) {
251 #if defined(USE_KIM)
252         kim_error err = KIM_NO_ERROR;
253         kim_ccache kimccache = NULL;
254         kim_identity identity = NULL;
255         kim_credential_state state;
256
257         err = kim_identity_create_from_krb5_principal (&identity,
258                                                        context,
259                                                        desired_princ);
260
261         if (!err) {
262             err = kim_ccache_create_from_client_identity (&kimccache, identity);
263         }
264
265         if (!err) {
266             err = kim_ccache_get_state (kimccache, &state);
267         }
268
269         if (!err && state != kim_credentials_state_valid) {
270             if (state == kim_credentials_state_needs_validation) {
271                 err = kim_ccache_validate (kimccache, KIM_OPTIONS_DEFAULT);
272             } else {
273                 kim_ccache_free (&kimccache);
274                 ccache = NULL;
275             }
276         }
277
278         if (!kimccache && kim_library_allow_automatic_prompting ()) {
279             /* ccache does not already exist, create a new one */
280             err = kim_ccache_create_new (&kimccache, identity,
281                                          KIM_OPTIONS_DEFAULT);
282         }
283
284         if (!err) {
285             err = kim_ccache_get_krb5_ccache (kimccache, context, &ccache);
286         }
287
288         kim_ccache_free (&kimccache);
289         kim_identity_free (&identity);
290
291         if (err) {
292             *minor_status = err;
293             return GSS_S_CRED_UNAVAIL;
294         }
295
296 #elif defined(USE_LEASH)
297         if ( hLeashDLL == INVALID_HANDLE_VALUE ) {
298             hLeashDLL = LoadLibrary(LEASH_DLL);
299             if ( hLeashDLL != INVALID_HANDLE_VALUE ) {
300                 (FARPROC) pLeash_AcquireInitialTicketsIfNeeded =
301                     GetProcAddress(hLeashDLL, "not_an_API_Leash_AcquireInitialTicketsIfNeeded");
302             }
303         }
304
305         if ( pLeash_AcquireInitialTicketsIfNeeded ) {
306             char ccname[256]="";
307             pLeash_AcquireInitialTicketsIfNeeded(context, desired_princ, ccname, sizeof(ccname));
308             if (!ccname[0]) {
309                 *minor_status = KRB5_CC_NOTFOUND;
310                 return GSS_S_CRED_UNAVAIL;
311             }
312
313             if ((code = krb5_cc_resolve (context, ccname, &ccache))) {
314                 *minor_status = code;
315                 return GSS_S_CRED_UNAVAIL;
316             }
317         } else {
318             /* leash dll not available, open the default credential cache */
319
320             if ((code = krb5int_cc_default(context, &ccache))) {
321                 *minor_status = code;
322                 return GSS_S_CRED_UNAVAIL;
323             }
324         }
325 #endif /* USE_LEASH */
326     } else
327 #endif /* USE_KIM || USE_LEASH */
328     {
329         if (req_ccache != NULL) {
330             /* Duplicate ccache handle */
331             code = krb5_cc_dup(context, req_ccache, &ccache);
332         } else {
333             /* Open the default credential cache */
334             code = krb5int_cc_default(context, &ccache);
335         }
336         if (code != 0) {
337             *minor_status = code;
338             return GSS_S_CRED_UNAVAIL;
339         }
340     }
341
342     /* turn off OPENCLOSE mode while extensive frobbing is going on */
343     code = krb5_cc_set_flags(context, ccache, 0);
344     if (code == KRB5_FCC_NOFILE &&
345         password != GSS_C_NO_BUFFER && desired_princ != NULL) {
346         /* We will get initial creds later. */
347         code = krb5_cc_initialize(context, ccache, desired_princ);
348         if (code == 0)
349             code = krb5_cc_set_flags(context, ccache, 0);
350     }
351     if (code != 0) {
352         krb5_cc_close(context, ccache);
353         *minor_status = code;
354         return GSS_S_CRED_UNAVAIL;
355     }
356
357     /*
358      * Credentials cache principal must match either the acceptor principal
359      * name or the desired_princ argument (they may be the same).
360      */
361     if (cred->name != NULL && desired_princ == NULL)
362         desired_princ = cred->name->princ;
363
364     code = krb5_cc_get_principal(context, ccache, &ccache_princ);
365     if (code != 0) {
366         krb5_cc_close(context, ccache);
367         *minor_status = code;
368         return GSS_S_FAILURE;
369     }
370
371     if (desired_princ != NULL) {
372         if (!krb5_principal_compare(context, ccache_princ, desired_princ)) {
373             krb5_free_principal(context, ccache_princ);
374             krb5_cc_close(context, ccache);
375             *minor_status = KG_CCACHE_NOMATCH;
376             return GSS_S_CRED_UNAVAIL;
377         }
378     }
379
380     /*
381      * If we are acquiring initiator-only default credentials, then set
382      * cred->name to the credentials cache principal name.
383      */
384     if (cred->name == NULL) {
385         if ((code = kg_init_name(context, ccache_princ, NULL,
386                                  KG_INIT_NAME_NO_COPY, &cred->name))) {
387             krb5_free_principal(context, ccache_princ);
388             krb5_cc_close(context, ccache);
389             *minor_status = code;
390             return GSS_S_FAILURE;
391         }
392     } else {
393         krb5_free_principal(context, ccache_princ);
394     }
395
396     assert(cred->name->princ != NULL);
397     cred_princ_realm = krb5_princ_realm(context, cred->name->princ);
398
399     if (password != GSS_C_NO_BUFFER) {
400         /* stash the password for later */
401         password_data.length = password->length;
402         password_data.data = (char *)password->value;
403
404         code = krb5int_copy_data_contents_add0(context, &password_data,
405                                                &cred->password);
406         if (code != 0) {
407             krb5_cc_close(context, ccache);
408             *minor_status = code;
409             return GSS_S_FAILURE;
410         }
411
412         /* restore the OPENCLOSE flag */
413         code = krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE);
414         if (code != 0) {
415             krb5_cc_close(context, ccache);
416             *minor_status = code;
417             return GSS_S_FAILURE;
418         }
419
420         cred->ccache = ccache;
421         return GSS_S_COMPLETE;
422     }
423
424     /* iterate over the ccache, find the tgt */
425
426     if ((code = krb5_cc_start_seq_get(context, ccache, &cur))) {
427         krb5_cc_close(context, ccache);
428         *minor_status = code;
429         return GSS_S_FAILURE;
430     }
431
432     /* this is hairy.  If there's a tgt for the principal's local realm
433        in here, that's what we want for the expire time.  But if
434        there's not, then we want to use the first key.  */
435
436     got_endtime = 0;
437
438     code = krb5_build_principal_ext(context, &tmp_princ,
439                                     cred_princ_realm->length,
440                                     cred_princ_realm->data,
441                                     KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME,
442                                     cred_princ_realm->length,
443                                     cred_princ_realm->data,
444                                     0);
445     if (code) {
446         krb5_cc_close(context, ccache);
447         *minor_status = code;
448         return GSS_S_FAILURE;
449     }
450     while (!(code = krb5_cc_next_cred(context, ccache, &cur, &creds))) {
451         if (krb5_principal_compare(context, tmp_princ, creds.server)) {
452             cred->tgt_expire = creds.times.endtime;
453             got_endtime = 1;
454             *minor_status = 0;
455             code = 0;
456             krb5_free_cred_contents(context, &creds);
457             break;
458         }
459         if (got_endtime == 0) {
460             cred->tgt_expire = creds.times.endtime;
461             got_endtime = 1;
462         }
463         krb5_free_cred_contents(context, &creds);
464     }
465     krb5_free_principal(context, tmp_princ);
466
467     if (code && code != KRB5_CC_END) {
468         /* this means some error occurred reading the ccache */
469         krb5_cc_end_seq_get(context, ccache, &cur);
470         krb5_cc_close(context, ccache);
471         *minor_status = code;
472         return GSS_S_FAILURE;
473     } else if (! got_endtime) {
474         /* this means the ccache was entirely empty */
475         krb5_cc_end_seq_get(context, ccache, &cur);
476         krb5_cc_close(context, ccache);
477         *minor_status = KG_EMPTY_CCACHE;
478         return GSS_S_FAILURE;
479     } else {
480         /* this means that we found an endtime to use. */
481         if ((code = krb5_cc_end_seq_get(context, ccache, &cur))) {
482             krb5_cc_close(context, ccache);
483             *minor_status = code;
484             return GSS_S_FAILURE;
485         }
486         if ((code = krb5_cc_set_flags(context, ccache, KRB5_TC_OPENCLOSE))) {
487             krb5_cc_close(context, ccache);
488             *minor_status = code;
489             return GSS_S_FAILURE;
490         }
491     }
492
493     /* the credentials match and are valid */
494
495     cred->ccache = ccache;
496     /* minor_status is set while we are iterating over the ccache */
497     return GSS_S_COMPLETE;
498 }
499
500 struct acquire_cred_args {
501     gss_name_t desired_name;
502     gss_buffer_t password;
503     OM_uint32 time_req;
504     gss_OID_set desired_mechs;
505     gss_cred_usage_t cred_usage;
506     krb5_keytab keytab;
507     krb5_ccache ccache;
508     int iakerb;
509 };
510
511 /*ARGSUSED*/
512 static OM_uint32
513 acquire_cred(OM_uint32 *minor_status,
514              const struct acquire_cred_args *args,
515              gss_cred_id_t *output_cred_handle,
516              OM_uint32 *time_rec)
517 {
518     krb5_context context = NULL;
519     krb5_gss_cred_id_t cred = NULL;
520     OM_uint32 ret;
521     krb5_error_code code = 0;
522     krb5_principal desired_princ = NULL;
523
524     /* make sure all outputs are valid */
525     *output_cred_handle = GSS_C_NO_CREDENTIAL;
526     if (time_rec)
527         *time_rec = 0;
528
529     code = gss_krb5int_initialize_library();
530     if (code)
531         goto krb_error_out;
532
533     code = krb5_gss_init_context(&context);
534     if (code)
535         goto krb_error_out;
536
537     /* create the gss cred structure */
538     cred = k5alloc(sizeof(krb5_gss_cred_id_rec), &code);
539     if (cred == NULL)
540         goto krb_error_out;
541
542     cred->usage = args->cred_usage;
543     cred->name = NULL;
544     cred->iakerb_mech = args->iakerb;
545     cred->default_identity = (args->desired_name == GSS_C_NO_NAME);
546 #ifndef LEAN_CLIENT
547     cred->keytab = NULL;
548 #endif /* LEAN_CLIENT */
549     cred->ccache = NULL;
550
551     code = k5_mutex_init(&cred->lock);
552     if (code)
553         goto krb_error_out;
554
555     switch (args->cred_usage) {
556     case GSS_C_INITIATE:
557     case GSS_C_ACCEPT:
558     case GSS_C_BOTH:
559         break;
560     default:
561         ret = GSS_S_FAILURE;
562         *minor_status = (OM_uint32) G_BAD_USAGE;
563         goto error_out;
564     }
565
566     if (args->desired_name != GSS_C_NO_NAME)
567         desired_princ = ((krb5_gss_name_t)args->desired_name)->princ;
568
569 #ifndef LEAN_CLIENT
570     /*
571      * If requested, acquire credentials for accepting. This will fill
572      * in cred->name if desired_princ is specified.
573      */
574     if (args->cred_usage == GSS_C_ACCEPT || args->cred_usage == GSS_C_BOTH) {
575         ret = acquire_accept_cred(context, minor_status,
576                                   desired_princ,
577                                   args->keytab, cred);
578         if (ret != GSS_S_COMPLETE)
579             goto error_out;
580     }
581 #endif /* LEAN_CLIENT */
582
583     /*
584      * If requested, acquire credentials for initiation. This will fill
585      * in cred->name if it wasn't set above.
586      */
587     if (args->cred_usage == GSS_C_INITIATE || args->cred_usage == GSS_C_BOTH) {
588         ret = acquire_init_cred(context, minor_status, args->ccache,
589                                 desired_princ, args->password, cred);
590         if (ret != GSS_S_COMPLETE)
591             goto error_out;
592     }
593
594     assert(cred->default_identity || cred->name != NULL);
595
596     /*** at this point, the cred structure has been completely created */
597
598     if (args->cred_usage == GSS_C_ACCEPT) {
599         if (time_rec)
600             *time_rec = GSS_C_INDEFINITE;
601     } else {
602         krb5_timestamp now;
603
604         code = krb5_timeofday(context, &now);
605         if (code != 0)
606             goto krb_error_out;
607
608         if (time_rec)
609             *time_rec = (cred->tgt_expire > now) ? (cred->tgt_expire - now) : 0;
610     }
611
612     if (!kg_save_cred_id((gss_cred_id_t)cred)) {
613         ret = GSS_S_FAILURE;
614         goto error_out;
615     }
616
617     *minor_status = 0;
618     *output_cred_handle = (gss_cred_id_t) cred;
619
620     krb5_free_context(context);
621     return GSS_S_COMPLETE;
622
623 krb_error_out:
624     *minor_status = code;
625     ret = GSS_S_FAILURE;
626
627 error_out:
628     if (cred != NULL) {
629         if (cred->ccache)
630             krb5_cc_close(context, cred->ccache);
631 #ifndef LEAN_CLIENT
632         if (cred->keytab)
633             krb5_kt_close(context, cred->keytab);
634 #endif /* LEAN_CLIENT */
635         if (cred->name)
636             kg_release_name(context, 0, &cred->name);
637         k5_mutex_destroy(&cred->lock);
638         xfree(cred);
639     }
640     save_error_info(*minor_status, context);
641     krb5_free_context(context);
642     return ret;
643 }
644
645 OM_uint32
646 gss_krb5int_set_cred_rcache(OM_uint32 *minor_status,
647                             gss_cred_id_t *cred_handle,
648                             const gss_OID desired_oid,
649                             const gss_buffer_t value)
650 {
651     krb5_gss_cred_id_t cred;
652     krb5_error_code code;
653     krb5_context context;
654     krb5_rcache rcache;
655
656     assert(value->length == sizeof(rcache));
657
658     if (value->length != sizeof(rcache))
659         return GSS_S_FAILURE;
660
661     rcache = (krb5_rcache)value->value;
662
663     cred = (krb5_gss_cred_id_t)*cred_handle;
664
665     code = krb5_gss_init_context(&context);
666     if (code) {
667         *minor_status = code;
668         return GSS_S_FAILURE;
669     }
670     if (cred->rcache != NULL) {
671         code = krb5_rc_close(context, cred->rcache);
672         if (code) {
673             *minor_status = code;
674             krb5_free_context(context);
675             return GSS_S_FAILURE;
676         }
677     }
678
679     cred->rcache = rcache;
680
681     krb5_free_context(context);
682
683     *minor_status = 0;
684     return GSS_S_COMPLETE;
685 }
686
687 /*
688  * krb5 and IAKERB mech API functions follow.  The mechglue always passes null
689  * desired_mechs and actual_mechs, so we ignore those parameters.
690  */
691
692 OM_uint32
693 krb5_gss_acquire_cred(minor_status, desired_name, time_req,
694                       desired_mechs, cred_usage, output_cred_handle,
695                       actual_mechs, time_rec)
696     OM_uint32 *minor_status;
697     gss_name_t desired_name;
698     OM_uint32 time_req;
699     gss_OID_set desired_mechs;
700     gss_cred_usage_t cred_usage;
701     gss_cred_id_t *output_cred_handle;
702     gss_OID_set *actual_mechs;
703     OM_uint32 *time_rec;
704 {
705     struct acquire_cred_args args;
706
707     if (desired_name && !kg_validate_name(desired_name)) {
708         *minor_status = G_VALIDATE_FAILED;
709         return GSS_S_FAILURE;
710     }
711
712     memset(&args, 0, sizeof(args));
713     args.desired_name = desired_name;
714     args.time_req = time_req;
715     args.desired_mechs = desired_mechs;
716     args.cred_usage = cred_usage;
717     args.iakerb = 0;
718
719     return acquire_cred(minor_status, &args, output_cred_handle, time_rec);
720 }
721
722 OM_uint32
723 iakerb_gss_acquire_cred(minor_status, desired_name, time_req,
724                         desired_mechs, cred_usage, output_cred_handle,
725                         actual_mechs, time_rec)
726     OM_uint32 *minor_status;
727     gss_name_t desired_name;
728     OM_uint32 time_req;
729     gss_OID_set desired_mechs;
730     gss_cred_usage_t cred_usage;
731     gss_cred_id_t *output_cred_handle;
732     gss_OID_set *actual_mechs;
733     OM_uint32 *time_rec;
734 {
735     struct acquire_cred_args args;
736
737     if (desired_name && !kg_validate_name(desired_name)) {
738         *minor_status = G_VALIDATE_FAILED;
739         return GSS_S_FAILURE;
740     }
741
742     memset(&args, 0, sizeof(args));
743     args.desired_name = desired_name;
744     args.time_req = time_req;
745     args.desired_mechs = desired_mechs;
746     args.cred_usage = cred_usage;
747     args.iakerb = 1;
748
749     return acquire_cred(minor_status, &args, output_cred_handle, time_rec);
750 }
751
752 OM_uint32
753 krb5_gss_acquire_cred_with_password(OM_uint32 *minor_status,
754                                     const gss_name_t desired_name,
755                                     const gss_buffer_t password,
756                                     OM_uint32 time_req,
757                                     const gss_OID_set desired_mechs,
758                                     int cred_usage,
759                                     gss_cred_id_t *output_cred_handle,
760                                     gss_OID_set *actual_mechs,
761                                     OM_uint32 *time_rec)
762 {
763     struct acquire_cred_args args;
764
765     if (desired_name && !kg_validate_name(desired_name)) {
766         *minor_status = G_VALIDATE_FAILED;
767         return GSS_S_FAILURE;
768     }
769
770     memset(&args, 0, sizeof(args));
771     args.desired_name = desired_name;
772     args.password = password;
773     args.time_req = time_req;
774     args.desired_mechs = desired_mechs;
775     args.cred_usage = cred_usage;
776     args.iakerb = 0;
777
778     return acquire_cred(minor_status, &args, output_cred_handle, time_rec);
779 }
780
781 OM_uint32
782 iakerb_gss_acquire_cred_with_password(OM_uint32 *minor_status,
783                                       const gss_name_t desired_name,
784                                       const gss_buffer_t password,
785                                       OM_uint32 time_req,
786                                       const gss_OID_set desired_mechs,
787                                       int cred_usage,
788                                       gss_cred_id_t *output_cred_handle,
789                                       gss_OID_set *actual_mechs,
790                                       OM_uint32 *time_rec)
791 {
792     struct acquire_cred_args args;
793
794     if (desired_name && !kg_validate_name(desired_name)) {
795         *minor_status = G_VALIDATE_FAILED;
796         return GSS_S_FAILURE;
797     }
798
799     memset(&args, 0, sizeof(args));
800     args.desired_name = desired_name;
801     args.password = password;
802     args.time_req = time_req;
803     args.desired_mechs = desired_mechs;
804     args.cred_usage = cred_usage;
805     args.iakerb = 1;
806
807     return acquire_cred(minor_status, &args, output_cred_handle, time_rec);
808 }
809
810 OM_uint32
811 gss_krb5int_import_cred(OM_uint32 *minor_status,
812                         gss_cred_id_t *cred_handle,
813                         const gss_OID desired_oid,
814                         const gss_buffer_t value)
815 {
816     struct krb5_gss_import_cred_req *req;
817     struct acquire_cred_args args;
818     krb5_gss_name_rec name;
819     OM_uint32 time_rec;
820
821     assert(value->length == sizeof(*req));
822
823     if (value->length != sizeof(*req))
824         return GSS_S_FAILURE;
825
826     req = (struct krb5_gss_import_cred_req *)value->value;
827
828     memset(&args, 0, sizeof(args));
829
830     if (req->keytab_principal) {
831         memset(&name, 0, sizeof(name));
832         name.princ = req->keytab_principal;
833         args.desired_name = (gss_name_t)&name;
834     }
835
836     args.ccache = req->id;
837     args.keytab = req->keytab;
838
839     if (req->id && req->keytab)
840         args.cred_usage = GSS_C_BOTH;
841     else if (req->id)
842         args.cred_usage = GSS_C_INITIATE;
843     else if (req->keytab)
844         args.cred_usage = GSS_C_ACCEPT;
845     else {
846         *minor_status = EINVAL;
847         return GSS_S_FAILURE;
848     }
849
850     return acquire_cred(minor_status, &args, cred_handle, &time_rec);
851 }
852