Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/lib/gssapi/krb5/acquire_cred.c
34923 views
1
/*
2
* Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan
3
* (Royal Institute of Technology, Stockholm, Sweden).
4
* All rights reserved.
5
*
6
* Redistribution and use in source and binary forms, with or without
7
* modification, are permitted provided that the following conditions
8
* are met:
9
*
10
* 1. Redistributions of source code must retain the above copyright
11
* notice, this list of conditions and the following disclaimer.
12
*
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.
16
*
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.
20
*
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.
32
*/
33
34
#include "gsskrb5_locl.h"
35
36
OM_uint32
37
__gsskrb5_ccache_lifetime(OM_uint32 *minor_status,
38
krb5_context context,
39
krb5_ccache id,
40
krb5_principal principal,
41
OM_uint32 *lifetime)
42
{
43
krb5_creds in_cred, out_cred;
44
krb5_const_realm realm;
45
krb5_error_code kret;
46
47
memset(&in_cred, 0, sizeof(in_cred));
48
in_cred.client = principal;
49
50
realm = krb5_principal_get_realm(context, principal);
51
if (realm == NULL) {
52
_gsskrb5_clear_status ();
53
*minor_status = KRB5_PRINC_NOMATCH; /* XXX */
54
return GSS_S_FAILURE;
55
}
56
57
kret = krb5_make_principal(context, &in_cred.server,
58
realm, KRB5_TGS_NAME, realm, NULL);
59
if (kret) {
60
*minor_status = kret;
61
return GSS_S_FAILURE;
62
}
63
64
kret = krb5_cc_retrieve_cred(context, id, 0, &in_cred, &out_cred);
65
krb5_free_principal(context, in_cred.server);
66
if (kret) {
67
*minor_status = 0;
68
*lifetime = 0;
69
return GSS_S_COMPLETE;
70
}
71
72
*lifetime = out_cred.times.endtime;
73
krb5_free_cred_contents(context, &out_cred);
74
75
return GSS_S_COMPLETE;
76
}
77
78
79
80
81
static krb5_error_code
82
get_keytab(krb5_context context, krb5_keytab *keytab)
83
{
84
krb5_error_code kret;
85
86
HEIMDAL_MUTEX_lock(&gssapi_keytab_mutex);
87
88
if (_gsskrb5_keytab != NULL) {
89
char *name = NULL;
90
91
kret = krb5_kt_get_full_name(context, _gsskrb5_keytab, &name);
92
if (kret == 0) {
93
kret = krb5_kt_resolve(context, name, keytab);
94
krb5_xfree(name);
95
}
96
} else
97
kret = krb5_kt_default(context, keytab);
98
99
HEIMDAL_MUTEX_unlock(&gssapi_keytab_mutex);
100
101
return (kret);
102
}
103
104
static OM_uint32 acquire_initiator_cred
105
(OM_uint32 * minor_status,
106
krb5_context context,
107
gss_const_OID credential_type,
108
const void *credential_data,
109
const gss_name_t desired_name,
110
OM_uint32 time_req,
111
gss_const_OID desired_mech,
112
gss_cred_usage_t cred_usage,
113
gsskrb5_cred handle
114
)
115
{
116
OM_uint32 ret;
117
krb5_creds cred;
118
krb5_principal def_princ;
119
krb5_get_init_creds_opt *opt;
120
krb5_ccache ccache;
121
krb5_keytab keytab;
122
krb5_error_code kret;
123
124
keytab = NULL;
125
ccache = NULL;
126
def_princ = NULL;
127
ret = GSS_S_FAILURE;
128
memset(&cred, 0, sizeof(cred));
129
130
/*
131
* If we have a preferred principal, lets try to find it in all
132
* caches, otherwise, fall back to default cache, ignore all
133
* errors while searching.
134
*/
135
136
if (credential_type != GSS_C_NO_OID &&
137
!gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) {
138
kret = KRB5_NOCREDS_SUPPLIED; /* XXX */
139
goto end;
140
}
141
142
if (handle->principal) {
143
kret = krb5_cc_cache_match (context,
144
handle->principal,
145
&ccache);
146
if (kret == 0) {
147
ret = GSS_S_COMPLETE;
148
goto found;
149
}
150
}
151
152
if (ccache == NULL) {
153
kret = krb5_cc_default(context, &ccache);
154
if (kret)
155
goto end;
156
}
157
kret = krb5_cc_get_principal(context, ccache, &def_princ);
158
if (kret != 0) {
159
/* we'll try to use a keytab below */
160
krb5_cc_close(context, ccache);
161
def_princ = NULL;
162
kret = 0;
163
} else if (handle->principal == NULL) {
164
kret = krb5_copy_principal(context, def_princ, &handle->principal);
165
if (kret)
166
goto end;
167
} else if (handle->principal != NULL &&
168
krb5_principal_compare(context, handle->principal,
169
def_princ) == FALSE) {
170
krb5_free_principal(context, def_princ);
171
def_princ = NULL;
172
krb5_cc_close(context, ccache);
173
ccache = NULL;
174
}
175
if (def_princ == NULL) {
176
/* We have no existing credentials cache,
177
* so attempt to get a TGT using a keytab.
178
*/
179
if (handle->principal == NULL) {
180
kret = krb5_get_default_principal(context, &handle->principal);
181
if (kret)
182
goto end;
183
}
184
kret = krb5_get_init_creds_opt_alloc(context, &opt);
185
if (kret)
186
goto end;
187
if (credential_type != GSS_C_NO_OID &&
188
gss_oid_equal(credential_type, GSS_C_CRED_PASSWORD)) {
189
gss_buffer_t password = (gss_buffer_t)credential_data;
190
191
/* XXX are we requiring password to be NUL terminated? */
192
193
kret = krb5_get_init_creds_password(context, &cred,
194
handle->principal,
195
password->value,
196
NULL, NULL, 0, NULL, opt);
197
} else {
198
kret = get_keytab(context, &keytab);
199
if (kret) {
200
krb5_get_init_creds_opt_free(context, opt);
201
goto end;
202
}
203
kret = krb5_get_init_creds_keytab(context, &cred,
204
handle->principal, keytab,
205
0, NULL, opt);
206
}
207
krb5_get_init_creds_opt_free(context, opt);
208
if (kret)
209
goto end;
210
kret = krb5_cc_new_unique(context, krb5_cc_type_memory,
211
NULL, &ccache);
212
if (kret)
213
goto end;
214
kret = krb5_cc_initialize(context, ccache, cred.client);
215
if (kret) {
216
krb5_cc_destroy(context, ccache);
217
goto end;
218
}
219
kret = krb5_cc_store_cred(context, ccache, &cred);
220
if (kret) {
221
krb5_cc_destroy(context, ccache);
222
goto end;
223
}
224
handle->lifetime = cred.times.endtime;
225
handle->cred_flags |= GSS_CF_DESTROY_CRED_ON_RELEASE;
226
} else {
227
228
ret = __gsskrb5_ccache_lifetime(minor_status,
229
context,
230
ccache,
231
handle->principal,
232
&handle->lifetime);
233
if (ret != GSS_S_COMPLETE) {
234
krb5_cc_close(context, ccache);
235
goto end;
236
}
237
kret = 0;
238
}
239
found:
240
handle->ccache = ccache;
241
ret = GSS_S_COMPLETE;
242
243
end:
244
if (cred.client != NULL)
245
krb5_free_cred_contents(context, &cred);
246
if (def_princ != NULL)
247
krb5_free_principal(context, def_princ);
248
if (keytab != NULL)
249
krb5_kt_close(context, keytab);
250
if (ret != GSS_S_COMPLETE && kret != 0)
251
*minor_status = kret;
252
return (ret);
253
}
254
255
static OM_uint32 acquire_acceptor_cred
256
(OM_uint32 * minor_status,
257
krb5_context context,
258
gss_const_OID credential_type,
259
const void *credential_data,
260
const gss_name_t desired_name,
261
OM_uint32 time_req,
262
gss_const_OID desired_mech,
263
gss_cred_usage_t cred_usage,
264
gsskrb5_cred handle
265
)
266
{
267
OM_uint32 ret;
268
krb5_error_code kret;
269
270
ret = GSS_S_FAILURE;
271
272
if (credential_type != GSS_C_NO_OID) {
273
kret = EINVAL;
274
goto end;
275
}
276
277
kret = get_keytab(context, &handle->keytab);
278
if (kret)
279
goto end;
280
281
/* check that the requested principal exists in the keytab */
282
if (handle->principal) {
283
krb5_keytab_entry entry;
284
285
kret = krb5_kt_get_entry(context, handle->keytab,
286
handle->principal, 0, 0, &entry);
287
if (kret)
288
goto end;
289
krb5_kt_free_entry(context, &entry);
290
ret = GSS_S_COMPLETE;
291
} else {
292
/*
293
* Check if there is at least one entry in the keytab before
294
* declaring it as an useful keytab.
295
*/
296
krb5_keytab_entry tmp;
297
krb5_kt_cursor c;
298
299
kret = krb5_kt_start_seq_get (context, handle->keytab, &c);
300
if (kret)
301
goto end;
302
if (krb5_kt_next_entry(context, handle->keytab, &tmp, &c) == 0) {
303
krb5_kt_free_entry(context, &tmp);
304
ret = GSS_S_COMPLETE; /* ok found one entry */
305
}
306
krb5_kt_end_seq_get (context, handle->keytab, &c);
307
}
308
end:
309
if (ret != GSS_S_COMPLETE) {
310
if (handle->keytab != NULL)
311
krb5_kt_close(context, handle->keytab);
312
if (kret != 0) {
313
*minor_status = kret;
314
}
315
}
316
return (ret);
317
}
318
319
OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred
320
(OM_uint32 * minor_status,
321
const gss_name_t desired_name,
322
OM_uint32 time_req,
323
const gss_OID_set desired_mechs,
324
gss_cred_usage_t cred_usage,
325
gss_cred_id_t * output_cred_handle,
326
gss_OID_set * actual_mechs,
327
OM_uint32 * time_rec
328
)
329
{
330
OM_uint32 ret;
331
332
if (desired_mechs) {
333
int present = 0;
334
335
ret = gss_test_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
336
desired_mechs, &present);
337
if (ret)
338
return ret;
339
if (!present) {
340
*minor_status = 0;
341
return GSS_S_BAD_MECH;
342
}
343
}
344
345
ret = _gsskrb5_acquire_cred_ext(minor_status,
346
desired_name,
347
GSS_C_NO_OID,
348
NULL,
349
time_req,
350
GSS_KRB5_MECHANISM,
351
cred_usage,
352
output_cred_handle);
353
if (ret)
354
return ret;
355
356
357
ret = _gsskrb5_inquire_cred(minor_status, *output_cred_handle,
358
NULL, time_rec, NULL, actual_mechs);
359
if (ret) {
360
OM_uint32 tmp;
361
_gsskrb5_release_cred(&tmp, output_cred_handle);
362
}
363
364
return ret;
365
}
366
367
OM_uint32 GSSAPI_CALLCONV _gsskrb5_acquire_cred_ext
368
(OM_uint32 * minor_status,
369
const gss_name_t desired_name,
370
gss_const_OID credential_type,
371
const void *credential_data,
372
OM_uint32 time_req,
373
gss_const_OID desired_mech,
374
gss_cred_usage_t cred_usage,
375
gss_cred_id_t * output_cred_handle
376
)
377
{
378
krb5_context context;
379
gsskrb5_cred handle;
380
OM_uint32 ret;
381
382
cred_usage &= GSS_C_OPTION_MASK;
383
384
if (cred_usage != GSS_C_ACCEPT && cred_usage != GSS_C_INITIATE && cred_usage != GSS_C_BOTH) {
385
*minor_status = GSS_KRB5_S_G_BAD_USAGE;
386
return GSS_S_FAILURE;
387
}
388
389
GSSAPI_KRB5_INIT(&context);
390
391
*output_cred_handle = NULL;
392
393
handle = calloc(1, sizeof(*handle));
394
if (handle == NULL) {
395
*minor_status = ENOMEM;
396
return (GSS_S_FAILURE);
397
}
398
399
HEIMDAL_MUTEX_init(&handle->cred_id_mutex);
400
401
if (desired_name != GSS_C_NO_NAME) {
402
ret = _gsskrb5_canon_name(minor_status, context, 1, NULL,
403
desired_name, &handle->principal);
404
if (ret) {
405
HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
406
free(handle);
407
return ret;
408
}
409
}
410
if (cred_usage == GSS_C_INITIATE || cred_usage == GSS_C_BOTH) {
411
ret = acquire_initiator_cred(minor_status, context,
412
credential_type, credential_data,
413
desired_name, time_req,
414
desired_mech, cred_usage, handle);
415
if (ret != GSS_S_COMPLETE) {
416
HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
417
krb5_free_principal(context, handle->principal);
418
free(handle);
419
return (ret);
420
}
421
}
422
if (cred_usage == GSS_C_ACCEPT || cred_usage == GSS_C_BOTH) {
423
ret = acquire_acceptor_cred(minor_status, context,
424
credential_type, credential_data,
425
desired_name, time_req,
426
desired_mech, cred_usage, handle);
427
if (ret != GSS_S_COMPLETE) {
428
HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
429
krb5_free_principal(context, handle->principal);
430
free(handle);
431
return (ret);
432
}
433
}
434
ret = gss_create_empty_oid_set(minor_status, &handle->mechanisms);
435
if (ret == GSS_S_COMPLETE)
436
ret = gss_add_oid_set_member(minor_status, GSS_KRB5_MECHANISM,
437
&handle->mechanisms);
438
if (ret != GSS_S_COMPLETE) {
439
if (handle->mechanisms != NULL)
440
gss_release_oid_set(NULL, &handle->mechanisms);
441
HEIMDAL_MUTEX_destroy(&handle->cred_id_mutex);
442
krb5_free_principal(context, handle->principal);
443
free(handle);
444
return (ret);
445
}
446
handle->usage = cred_usage;
447
*minor_status = 0;
448
*output_cred_handle = (gss_cred_id_t)handle;
449
return (GSS_S_COMPLETE);
450
}
451
452