* gic_keytab.c (krb5_get_in_tkt_with_keytab): Pass (void*)keytab,
[krb5.git] / src / lib / krb5 / krb / gic_keytab.c
1 /*
2  * lib/krb5/krb/gic_keytab.c
3  *
4  * Copyright (C) 2002, 2003 by the Massachusetts Institute of Technology.
5  * All rights reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  * 
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  Furthermore if you modify this software you must label
20  * your software as modified software and not distribute it in such a
21  * fashion that it might be confused with the original M.I.T. software.
22  * M.I.T. makes no representations about the suitability of
23  * this software for any purpose.  It is provided "as is" without express
24  * or implied warranty.
25  */
26
27 #include "k5-int.h"
28
29 static krb5_error_code
30 krb5_get_as_key_keytab(
31     krb5_context context,
32     krb5_principal client,
33     krb5_enctype etype,
34     krb5_prompter_fct prompter,
35     void *prompter_data,
36     krb5_data *salt,
37     krb5_data *params,
38     krb5_keyblock *as_key,
39     void *gak_data)
40 {
41     krb5_keytab keytab = (krb5_keytab) gak_data;
42     krb5_error_code ret;
43     krb5_keytab_entry kt_ent;
44     krb5_keyblock *kt_key;
45
46     /* if there's already a key of the correct etype, we're done.
47        if the etype is wrong, free the existing key, and make
48        a new one. */
49
50     if (as_key->length) {
51         if (as_key->enctype == etype)
52             return(0);
53
54         krb5_free_keyblock_contents(context, as_key);
55         as_key->length = 0;
56     }
57
58     if (!krb5_c_valid_enctype(etype))
59         return(KRB5_PROG_ETYPE_NOSUPP);
60
61     if ((ret = krb5_kt_get_entry(context, keytab, client,
62                                  0, /* don't have vno available */
63                                  etype, &kt_ent)))
64         return(ret);
65
66     ret = krb5_copy_keyblock(context, &kt_ent.key, &kt_key);
67
68     /* again, krb5's memory management is lame... */
69
70     *as_key = *kt_key;
71     krb5_xfree(kt_key);
72
73     (void) krb5_kt_free_entry(context, &kt_ent);
74
75     return(ret);
76 }
77
78 krb5_error_code KRB5_CALLCONV
79 krb5_get_init_creds_keytab(krb5_context context, krb5_creds *creds, krb5_principal client, krb5_keytab arg_keytab, krb5_deltat start_time, char *in_tkt_service, krb5_get_init_creds_opt *options)
80 {
81    krb5_error_code ret, ret2;
82    int use_master;
83    krb5_keytab keytab;
84
85    if (arg_keytab == NULL) {
86        if ((ret = krb5_kt_default(context, &keytab)))
87             return ret;
88    } else {
89        keytab = arg_keytab;
90    }
91
92    use_master = 0;
93
94    /* first try: get the requested tkt from any kdc */
95
96    ret = krb5_get_init_creds(context, creds, client, NULL, NULL,
97                              start_time, in_tkt_service, options,
98                              krb5_get_as_key_keytab, (void *) keytab,
99                              use_master,NULL);
100
101    /* check for success */
102
103    if (ret == 0)
104       goto cleanup;
105
106    /* If all the kdc's are unavailable fail */
107
108    if ((ret == KRB5_KDC_UNREACH) || (ret == KRB5_REALM_CANT_RESOLVE))
109       goto cleanup;
110
111    /* if the reply did not come from the master kdc, try again with
112       the master kdc */
113
114    if (!use_master) {
115       use_master = 1;
116
117       ret2 = krb5_get_init_creds(context, creds, client, NULL, NULL,
118                                  start_time, in_tkt_service, options,
119                                  krb5_get_as_key_keytab, (void *) keytab,
120                                  use_master, NULL);
121       
122       if (ret2 == 0) {
123          ret = 0;
124          goto cleanup;
125       }
126
127       /* if the master is unreachable, return the error from the
128          slave we were able to contact */
129
130       if ((ret2 == KRB5_KDC_UNREACH) || (ret2 == KRB5_REALM_CANT_RESOLVE))
131          goto cleanup;
132
133       ret = ret2;
134    }
135
136    /* at this point, we have a response from the master.  Since we don't
137       do any prompting or changing for keytabs, that's it. */
138
139 cleanup:
140    if (arg_keytab == NULL)
141        krb5_kt_close(context, keytab);
142
143    return(ret);
144 }
145 krb5_error_code KRB5_CALLCONV
146 krb5_get_in_tkt_with_keytab(krb5_context context, krb5_flags options,
147                               krb5_address *const *addrs, krb5_enctype *ktypes,
148                               krb5_preauthtype *pre_auth_types,
149                               krb5_keytab arg_keytab, krb5_ccache ccache,
150                               krb5_creds *creds, krb5_kdc_rep **ret_as_reply)
151 {
152     krb5_error_code retval;
153     krb5_get_init_creds_opt opt;
154     char * server = NULL;
155     krb5_keytab keytab;
156     krb5_principal client_princ, server_princ;
157     
158     krb5int_populate_gic_opt(context, &opt,
159                              options, addrs, ktypes,
160                              pre_auth_types);
161     if (arg_keytab == NULL) {
162         retval = krb5_kt_default(context, &keytab);
163         if (retval)
164             return retval;
165     }
166     else keytab = arg_keytab;
167     
168     retval = krb5_unparse_name( context, creds->server, &server);
169     if (retval)
170         goto cleanup;
171     server_princ = creds->server;
172     client_princ = creds->client;
173     retval = krb5_get_init_creds (context,
174                                   creds, creds->client,  
175                                   krb5_prompter_posix,  NULL,
176                                   0, server, &opt,
177                                   krb5_get_as_key_keytab, (void *)keytab,
178                                   0, ret_as_reply);
179     krb5_free_unparsed_name( context, server);
180     if (retval) {
181         goto cleanup;
182     }
183         if (creds->server)
184             krb5_free_principal( context, creds->server);
185         if (creds->client)
186             krb5_free_principal( context, creds->client);
187         creds->client = client_princ;
188         creds->server = server_princ;
189         
190     /* store it in the ccache! */
191     if (ccache)
192         if ((retval = krb5_cc_store_cred(context, ccache, creds)))
193             goto cleanup;
194  cleanup:    if (arg_keytab == NULL)
195      krb5_kt_close(context, keytab);
196     return retval;
197 }
198