x
[heimdal.git] / lib / gssapi / krb5 / acquire_cred.c
blob7f7e90f35d9c2999f153fbeabdea885159de6f7b
1 /*
2 * Copyright (c) 1997 - 2004 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
34 #include "gssapi_locl.h"
36 RCSID("$Id$");
38 static krb5_error_code
39 get_keytab(krb5_keytab *keytab)
41 char kt_name[256];
42 krb5_error_code kret;
44 HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
46 if (gssapi_krb5_keytab != NULL) {
47 kret = krb5_kt_get_name(gssapi_krb5_context,
48 gssapi_krb5_keytab,
49 kt_name, sizeof(kt_name));
50 if (kret == 0)
51 kret = krb5_kt_resolve(gssapi_krb5_context, kt_name, keytab);
52 } else
53 kret = krb5_kt_default(gssapi_krb5_context, keytab);
55 HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
57 return (kret);
60 static OM_uint32 acquire_initiator_cred
61 (OM_uint32 * minor_status,
62 const gss_name_t desired_name,
63 OM_uint32 time_req,
64 const gss_OID_set desired_mechs,
65 gss_cred_usage_t cred_usage,
66 gss_cred_id_t handle,
67 gss_OID_set * actual_mechs,
68 OM_uint32 * time_rec
71 OM_uint32 ret;
72 krb5_creds cred;
73 krb5_principal def_princ;
74 krb5_get_init_creds_opt *opt;
75 krb5_ccache ccache;
76 krb5_keytab keytab;
77 krb5_error_code kret;
79 keytab = NULL;
80 ccache = NULL;
81 def_princ = NULL;
82 ret = GSS_S_FAILURE;
83 memset(&cred, 0, sizeof(cred));
85 kret = krb5_cc_default(gssapi_krb5_context, &ccache);
86 if (kret)
87 goto end;
88 kret = krb5_cc_get_principal(gssapi_krb5_context, ccache,
89 &def_princ);
90 if (kret != 0) {
91 /* we'll try to use a keytab below */
92 krb5_cc_destroy(gssapi_krb5_context, ccache);
93 ccache = NULL;
94 kret = 0;
95 } else if (handle->principal == NULL) {
96 kret = krb5_copy_principal(gssapi_krb5_context, def_princ,
97 &handle->principal);
98 if (kret)
99 goto end;
100 } else if (handle->principal != NULL &&
101 krb5_principal_compare(gssapi_krb5_context, handle->principal,
102 def_princ) == FALSE) {
103 /* Before failing, lets check the keytab */
104 krb5_free_principal(gssapi_krb5_context, def_princ);
105 def_princ = NULL;
107 if (def_princ == NULL) {
108 /* We have no existing credentials cache,
109 * so attempt to get a TGT using a keytab.
111 if (handle->principal == NULL) {
112 kret = krb5_get_default_principal(gssapi_krb5_context,
113 &handle->principal);
114 if (kret)
115 goto end;
117 kret = get_keytab(&keytab);
118 if (kret)
119 goto end;
120 kret = krb5_get_init_creds_opt_alloc(gssapi_krb5_context, &opt);
121 if (kret)
122 goto end;
123 kret = krb5_get_init_creds_keytab(gssapi_krb5_context, &cred,
124 handle->principal, keytab, 0, NULL, opt);
125 krb5_get_init_creds_opt_free(opt);
126 if (kret)
127 goto end;
128 kret = krb5_cc_gen_new(gssapi_krb5_context, &krb5_mcc_ops,
129 &ccache);
130 if (kret)
131 goto end;
132 kret = krb5_cc_initialize(gssapi_krb5_context, ccache, cred.client);
133 if (kret)
134 goto end;
135 kret = krb5_cc_store_cred(gssapi_krb5_context, ccache, &cred);
136 if (kret)
137 goto end;
138 handle->lifetime = cred.times.endtime;
139 } else {
140 krb5_creds in_cred, *out_cred;
141 krb5_const_realm realm;
143 memset(&in_cred, 0, sizeof(in_cred));
144 in_cred.client = handle->principal;
146 realm = krb5_principal_get_realm(gssapi_krb5_context,
147 handle->principal);
148 if (realm == NULL) {
149 kret = KRB5_PRINC_NOMATCH; /* XXX */
150 goto end;
153 kret = krb5_make_principal(gssapi_krb5_context, &in_cred.server,
154 realm, KRB5_TGS_NAME, realm, NULL);
155 if (kret)
156 goto end;
158 kret = krb5_get_credentials(gssapi_krb5_context, 0,
159 ccache, &in_cred, &out_cred);
160 krb5_free_principal(gssapi_krb5_context, in_cred.server);
161 if (kret)
162 goto end;
164 handle->lifetime = out_cred->times.endtime;
165 krb5_free_creds(gssapi_krb5_context, out_cred);
168 handle->ccache = ccache;
169 ret = GSS_S_COMPLETE;
171 end:
172 if (cred.client != NULL)
173 krb5_free_cred_contents(gssapi_krb5_context, &cred);
174 if (def_princ != NULL)
175 krb5_free_principal(gssapi_krb5_context, def_princ);
176 if (keytab != NULL)
177 krb5_kt_close(gssapi_krb5_context, keytab);
178 if (ret != GSS_S_COMPLETE) {
179 if (ccache != NULL)
180 krb5_cc_close(gssapi_krb5_context, ccache);
181 if (kret != 0) {
182 *minor_status = kret;
183 gssapi_krb5_set_error_string ();
186 return (ret);
189 static OM_uint32 acquire_acceptor_cred
190 (OM_uint32 * minor_status,
191 const gss_name_t desired_name,
192 OM_uint32 time_req,
193 const gss_OID_set desired_mechs,
194 gss_cred_usage_t cred_usage,
195 gss_cred_id_t handle,
196 gss_OID_set * actual_mechs,
197 OM_uint32 * time_rec
200 OM_uint32 ret;
201 krb5_error_code kret;
203 kret = 0;
204 ret = GSS_S_FAILURE;
205 kret = get_keytab(&handle->keytab);
206 if (kret)
207 goto end;
208 ret = GSS_S_COMPLETE;
210 end:
211 if (ret != GSS_S_COMPLETE) {
212 if (handle->keytab != NULL)
213 krb5_kt_close(gssapi_krb5_context, handle->keytab);
214 if (kret != 0) {
215 *minor_status = kret;
216 gssapi_krb5_set_error_string ();
219 return (ret);
222 OM_uint32 gss_acquire_cred
223 (OM_uint32 * minor_status,
224 const gss_name_t desired_name,
225 OM_uint32 time_req,
226 const gss_OID_set desired_mechs,
227 gss_cred_usage_t cred_usage,
228 gss_cred_id_t * output_cred_handle,
229 gss_OID_set * actual_mechs,
230 OM_uint32 * time_rec
233 gss_cred_id_t handle;
234 OM_uint32 ret;
236 if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) {
237 *minor_status = GSS_KRB5_S_G_BAD_USAGE;
238 return GSS_S_FAILURE;
241 GSSAPI_KRB5_INIT ();
243 *output_cred_handle = NULL;
244 if (time_rec)
245 *time_rec = 0;
246 if (actual_mechs)
247 *actual_mechs = GSS_C_NO_OID_SET;
249 if (desired_mechs) {
250 int present = 0;
252 ret = gss_test_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
253 desired_mechs, &present);
254 if (ret)
255 return ret;
256 if (!present) {
257 *minor_status = 0;
258 return GSS_S_BAD_MECH;
262 handle = (gss_cred_id_t)malloc(sizeof(*handle));
263 if (handle == GSS_C_NO_CREDENTIAL) {
264 *minor_status = ENOMEM;
265 return (GSS_S_FAILURE);
268 memset(handle, 0, sizeof (*handle));
269 HEIMDAL_MUTEX_init(&handle->cred_id_mutex);
271 if (desired_name != GSS_C_NO_NAME) {
272 ret = gss_duplicate_name(minor_status, desired_name,
273 &handle->principal);
274 if (ret != GSS_S_COMPLETE) {
275 HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
276 free(handle);
277 return (ret);
280 if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) {
281 ret = acquire_initiator_cred(minor_status, desired_name, time_req,
282 desired_mechs, cred_usage, handle, actual_mechs, time_rec);
283 if (ret != GSS_S_COMPLETE) {
284 HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
285 krb5_free_principal(gssapi_krb5_context, handle->principal);
286 free(handle);
287 return (ret);
290 if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) {
291 ret = acquire_acceptor_cred(minor_status, desired_name, time_req,
292 desired_mechs, cred_usage, handle, actual_mechs, time_rec);
293 if (ret != GSS_S_COMPLETE) {
294 HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
295 krb5_free_principal(gssapi_krb5_context, handle->principal);
296 free(handle);
297 return (ret);
300 ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms);
301 if (ret == GSS_S_COMPLETE)
302 ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
303 &handle->mechanisms);
304 if (ret == GSS_S_COMPLETE)
305 ret = gss_inquire_cred(minor_status, handle, NULL, time_rec, NULL,
306 actual_mechs);
307 if (ret != GSS_S_COMPLETE) {
308 if (handle->mechanisms != NULL)
309 gss_release_oid_set(NULL, &handle->mechanisms);
310 HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
311 krb5_free_principal(gssapi_krb5_context, handle->principal);
312 free(handle);
313 return (ret);
315 *minor_status = 0;
316 if (time_rec) {
317 ret = gssapi_lifetime_left(minor_status,
318 handle->lifetime,
319 time_rec);
321 if (ret)
322 return ret;
324 handle->usage = cred_usage;
325 *output_cred_handle = handle;
326 return (GSS_S_COMPLETE);