1 /*
2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 #pragma ident "%Z%%M% %I% %E% SMI"
7
8 /*
9 * Copyright 2000 by the Massachusetts Institute of Technology.
10 * All Rights Reserved.
11 *
12 * Export of this software from the United States of America may
13 * require a specific license from the United States Government.
14 * It is the responsibility of any person or organization contemplating
15 * export to obtain such a license before exporting.
16 *
17 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
18 * distribute this software and its documentation for any purpose and
19 * without fee is hereby granted, provided that the above copyright
20 * notice appear in all copies and that both that copyright notice and
21 * this permission notice appear in supporting documentation, and that
22 * the name of M.I.T. not be used in advertising or publicity pertaining
23 * to distribution of the software without specific, written prior
24 * permission. Furthermore if you modify this software you must label
25 * your software as modified software and not distribute it in such a
26 * fashion that it might be confused with the original M.I.T. software.
27 * M.I.T. makes no representations about the suitability of
28 * this software for any purpose. It is provided "as is" without express
29 * or implied warranty.
30 *
31 */
32
33 /*
34 * Copyright 1993 by OpenVision Technologies, Inc.
35 *
36 * Permission to use, copy, modify, distribute, and sell this software
37 * and its documentation for any purpose is hereby granted without fee,
38 * provided that the above copyright notice appears in all copies and
39 * that both that copyright notice and this permission notice appear in
40 * supporting documentation, and that the name of OpenVision not be used
41 * in advertising or publicity pertaining to distribution of the software
42 * without specific, written prior permission. OpenVision makes no
43 * representations about the suitability of this software for any
44 * purpose. It is provided "as is" without express or implied warranty.
45 *
46 * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
47 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
48 * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
49 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
50 * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
51 * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
52 * PERFORMANCE OF THIS SOFTWARE.
53 */
54
55 /*
56 * Copyright (C) 1998 by the FundsXpress, INC.
57 *
58 * All rights reserved.
59 *
60 * Export of this software from the United States of America may require
61 * a specific license from the United States Government. It is the
62 * responsibility of any person or organization contemplating export to
63 * obtain such a license before exporting.
64 *
65 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
66 * distribute this software and its documentation for any purpose and
67 * without fee is hereby granted, provided that the above copyright
68 * notice appear in all copies and that both that copyright notice and
69 * this permission notice appear in supporting documentation, and that
70 * the name of FundsXpress. not be used in advertising or publicity pertaining
71 * to distribution of the software without specific, written prior
72 * permission. FundsXpress makes no representations about the suitability of
73 * this software for any purpose. It is provided "as is" without express
74 * or implied warranty.
75 *
76 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
77 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
78 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
79 */
80
81 #include "gss_libinit.h"
82 #include <gssapiP_krb5.h>
83 #include <k5-int.h>
84
85 #ifdef HAVE_STRING_H
86 #include <string.h>
87 #else
88 #include <strings.h>
89 #endif
90
91 /*
92 * $Id: acquire_cred.c,v 1.25.6.2 2000/05/22 20:41:32 meeroh Exp $
93 */
94
95 /* ARGSUSED */
96 static OM_uint32
acquire_accept_cred_with_pw(context,minor_status,desired_name,password,cred)97 acquire_accept_cred_with_pw(context, minor_status, desired_name, password, cred)
98 krb5_context context;
99 OM_uint32 *minor_status;
100 krb5_principal desired_name;
101 const gss_buffer_t password;
102 krb5_gss_cred_id_rec *cred;
103 {
104 /*
105 * We could add support for this, but we'd need a "memory" based
106 * keytab, which we lack support for.
107 */
108 return (GSS_S_UNAVAILABLE);
109 }
110
111 static OM_uint32
acquire_init_cred_with_pw(context,minor_status,desired_name,password,cred)112 acquire_init_cred_with_pw(context, minor_status, desired_name, password, cred)
113 krb5_context context;
114 OM_uint32 *minor_status;
115 krb5_principal desired_name;
116 const gss_buffer_t password;
117 krb5_gss_cred_id_rec *cred;
118 {
119 krb5_error_code code = 0;
120 krb5_ccache ccache1 = NULL;
121 krb5_ccache ccache2 = NULL;
122 krb5_creds creds;
123 char *pw;
124
125 cred->ccache = NULL;
126
127 if (password == NULL || password->length == NULL ||
128 password->value == NULL)
129 pw = strdup("");
130 else if (*((char *)password->value + (password->length - 1)) == '\0')
131 pw = strdup(password->value);
132 else {
133 pw = malloc(password->length + 1);
134 if (pw == NULL) {
135 code = ENOMEM;
136 goto out;
137 }
138 *pw = '\0';
139 (void) strlcat(pw, password->value, password->length + 1);
140 }
141
142 if (pw == NULL) {
143 code = ENOMEM;
144 goto out;
145 }
146
147 (void) memset(&creds, 0, sizeof (creds));
148
149 code = krb5_get_init_creds_password(context, &creds, desired_name, pw,
150 NULL, /* no prompter callback */
151 NULL, /* no prompter callback data */
152 0, /* start time (now) */
153 NULL, /* target princ; NULL -> TGS */
154 NULL); /* no options; use defaults/config */
155
156 if (code)
157 goto out;
158
159 /* Got a TGT, now make a MEMORY ccache, stuff in the TGT */
160
161 if ((code = krb5_cc_resolve(context, "MEMORY:GSSAPI", &ccache1)))
162 goto out;
163
164 /*
165 * Weirdness: there's no way to gen a new ccache without first
166 * opening another of well-known name. A bug in the krb5 API,
167 * really which will have to be fixed in coordination with MIT.
168 *
169 * So we first krb5_cc_resolve() "MEMORY:GSSAPI", then we
170 * krb5_cc_gen_new(), which is a macro that finds the memory
171 * ccache ops from the first ccache but generates a new one. If
172 * we don't close that first ccache it will leak.
173 */
174 ccache2 = ccache1;
175 if ((code = krb5_cc_gen_new(context, &ccache2)) != 0)
176 goto out;
177
178 (void) krb5_cc_close(context, ccache1); /* avoid leak; see above */
179
180 if ((code = krb5_cc_initialize(context, ccache2, creds.client)) != 0)
181 goto out;
182
183 if ((code = krb5_cc_store_cred(context, ccache2, &creds)) != 0)
184 goto out;
185
186 krb5_free_cred_contents(context, &creds);
187
188 cred->ccache = ccache2;
189
190 out:
191 if (pw)
192 free(pw);
193
194 *minor_status = code;
195
196 if (code == 0)
197 return (GSS_S_COMPLETE);
198
199 if (ccache2 != NULL)
200 (void) krb5_cc_close(context, ccache2);
201
202 return (GSS_S_FAILURE);
203 }
204
205 /*ARGSUSED*/
206 OM_uint32
krb5_gss_acquire_cred_with_password(minor_status,desired_name,password,time_req,desired_mechs,cred_usage,output_cred_handle,actual_mechs,time_rec)207 krb5_gss_acquire_cred_with_password(minor_status,
208 desired_name, password, time_req,
209 desired_mechs, cred_usage,
210 output_cred_handle, actual_mechs,
211 time_rec)
212 OM_uint32 *minor_status;
213 gss_name_t desired_name;
214 const gss_buffer_t password;
215 OM_uint32 time_req;
216 gss_OID_set desired_mechs;
217 gss_cred_usage_t cred_usage;
218 gss_cred_id_t *output_cred_handle;
219 gss_OID_set *actual_mechs;
220 OM_uint32 *time_rec;
221 {
222 krb5_context context;
223 size_t i;
224 krb5_gss_cred_id_t cred;
225 gss_OID_set ret_mechs = GSS_C_NULL_OID_SET;
226 const gss_OID_set_desc * valid_mechs;
227 int req_old, req_new;
228 OM_uint32 ret;
229 krb5_error_code code;
230
231 if (desired_name == GSS_C_NO_NAME)
232 return (GSS_S_BAD_NAME);
233
234 code = gssint_initialize_library();
235 if (code) {
236 *minor_status = code;
237 return (GSS_S_FAILURE);
238 }
239
240 code = krb5_gss_init_context(&context);
241 if (code) {
242 *minor_status = code;
243 return (GSS_S_FAILURE);
244 }
245
246 /* make sure all outputs are valid */
247
248 *output_cred_handle = NULL;
249 if (actual_mechs)
250 *actual_mechs = NULL;
251 if (time_rec)
252 *time_rec = 0;
253
254 /* validate the name */
255 if (!kg_validate_name(desired_name)) {
256 *minor_status = (OM_uint32) G_VALIDATE_FAILED;
257 krb5_free_context(context);
258 return (GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
259 }
260
261 /*
262 * verify that the requested mechanism set is the default, or
263 * contains krb5
264 */
265
266 if (desired_mechs == GSS_C_NULL_OID_SET) {
267 valid_mechs = gss_mech_set_krb5_both;
268 req_old = 1;
269 req_new = 1;
270 } else {
271 req_old = 0;
272 req_new = 0;
273
274 for (i = 0; i < desired_mechs->count; i++) {
275 if (g_OID_equal(gss_mech_krb5_old,
276 &(desired_mechs->elements[i])))
277 req_old++;
278 if (g_OID_equal(gss_mech_krb5,
279 &(desired_mechs->elements[i])))
280 req_new++;
281 }
282
283 if (!req_old && !req_new) {
284 *minor_status = 0;
285 krb5_free_context(context);
286 return (GSS_S_BAD_MECH);
287 }
288 }
289
290 /* create the gss cred structure */
291 if ((cred = (krb5_gss_cred_id_t)
292 xmalloc(sizeof (krb5_gss_cred_id_rec))) == NULL) {
293 *minor_status = ENOMEM;
294 krb5_free_context(context);
295 return (GSS_S_FAILURE);
296 }
297 memset(cred, 0, sizeof (krb5_gss_cred_id_rec));
298
299 cred->usage = cred_usage;
300 cred->princ = NULL;
301 cred->prerfc_mech = req_old;
302 cred->rfc_mech = req_new;
303
304 cred->keytab = NULL;
305 cred->ccache = NULL;
306
307 if ((cred_usage != GSS_C_INITIATE) &&
308 (cred_usage != GSS_C_ACCEPT) &&
309 (cred_usage != GSS_C_BOTH)) {
310 xfree(cred);
311 *minor_status = (OM_uint32) G_BAD_USAGE;
312 krb5_free_context(context);
313 return (GSS_S_FAILURE);
314 }
315
316 /*
317 * If requested, acquire credentials for accepting. This will
318 * fill in cred->princ if the desired_name is not specified.
319 */
320
321 if ((cred_usage == GSS_C_ACCEPT) ||
322 (cred_usage == GSS_C_BOTH))
323 if ((ret = acquire_accept_cred_with_pw(context, minor_status,
324 (krb5_principal) desired_name,
325 password, cred))
326 != GSS_S_COMPLETE) {
327 if (cred->princ)
328 krb5_free_principal(context, cred->princ);
329 xfree(cred);
330 krb5_free_context(context);
331 /* minor_status set by acquire_accept_cred() */
332 return (ret);
333 }
334
335 /*
336 * If requested, acquire credentials for initiation. This will
337 * fill in cred->princ if it wasn't set above, and the
338 * desired_name is not specified.
339 */
340
341 if ((cred_usage == GSS_C_INITIATE) ||
342 (cred_usage == GSS_C_BOTH))
343 if ((ret = acquire_init_cred_with_pw(context, minor_status,
344 cred->princ ? cred->princ : (krb5_principal)
345 desired_name, password, cred))
346 != GSS_S_COMPLETE) {
347 if (cred->keytab)
348 (void) krb5_kt_close(context, cred->keytab);
349 if (cred->princ)
350 krb5_free_principal(context, cred->princ);
351 xfree(cred);
352 krb5_free_context(context);
353 /* minor_status set by acquire_init_cred() */
354 return (ret);
355 }
356
357 /* if the princ wasn't filled in already, fill it in now */
358
359 if (!cred->princ)
360 if ((code = krb5_copy_principal(context, (krb5_principal)
361 desired_name, &(cred->princ)))) {
362 if (cred->ccache)
363 (void) krb5_cc_close(context, cred->ccache);
364 if (cred->keytab)
365 (void) krb5_kt_close(context, cred->keytab);
366 xfree(cred);
367 *minor_status = code;
368 krb5_free_context(context);
369 return (GSS_S_FAILURE);
370 }
371
372 /* at this point, the cred structure has been completely created */
373
374 /* compute time_rec */
375
376 if (cred_usage == GSS_C_ACCEPT) {
377 if (time_rec)
378 *time_rec = GSS_C_INDEFINITE;
379 } else {
380 krb5_timestamp now;
381
382 if ((code = krb5_timeofday(context, &now))) {
383 if (cred->ccache)
384 (void) krb5_cc_close(context, cred->ccache);
385 if (cred->keytab)
386 (void) krb5_kt_close(context, cred->keytab);
387 if (cred->princ)
388 krb5_free_principal(context, cred->princ);
389 xfree(cred);
390 *minor_status = code;
391 krb5_free_context(context);
392 return (GSS_S_FAILURE);
393 }
394
395 if (time_rec)
396 *time_rec = (cred->tgt_expire > now) ?
397 (cred->tgt_expire - now) : 0;
398 }
399
400 /* create mechs */
401
402 if (actual_mechs) {
403 if (GSS_ERROR(ret = gss_create_empty_oid_set(minor_status,
404 &ret_mechs)) ||
405 (cred->prerfc_mech && GSS_ERROR(ret =
406 gss_add_oid_set_member(minor_status,
407 (gss_OID) gss_mech_krb5_old,
408 &ret_mechs))) ||
409 (cred->rfc_mech && GSS_ERROR(ret =
410 gss_add_oid_set_member(minor_status,
411 (gss_OID) gss_mech_krb5,
412 &ret_mechs)))) {
413 if (cred->ccache)
414 (void) krb5_cc_close(context, cred->ccache);
415 if (cred->keytab)
416 (void) krb5_kt_close(context, cred->keytab);
417 if (cred->princ)
418 krb5_free_principal(context, cred->princ);
419 xfree(cred);
420 krb5_free_context(context);
421 /* (*minor_status) set above */
422 return (ret);
423 }
424 }
425
426 /* intern the credential handle */
427
428 if (! kg_save_cred_id((gss_cred_id_t)cred)) {
429 (void) gss_release_oid_set(NULL, &ret_mechs);
430 free(ret_mechs->elements);
431 free(ret_mechs);
432 if (cred->ccache)
433 (void) krb5_cc_close(context, cred->ccache);
434 if (cred->keytab)
435 (void) krb5_kt_close(context, cred->keytab);
436 if (cred->princ)
437 krb5_free_principal(context, cred->princ);
438 xfree(cred);
439 krb5_free_context(context);
440 *minor_status = (OM_uint32) G_VALIDATE_FAILED;
441 return (GSS_S_FAILURE);
442 }
443
444 krb5_free_context(context);
445
446 /* return success */
447 *minor_status = 0;
448 *output_cred_handle = (gss_cred_id_t)cred;
449 if (actual_mechs)
450 *actual_mechs = ret_mechs;
451 return (GSS_S_COMPLETE);
452 }
453
454 /*ARGSUSED*/
455 OM_uint32
gssspi_acquire_cred_with_password(ctx,minor_status,desired_name,password,time_req,desired_mechs,cred_usage,output_cred_handle,actual_mechs,time_rec)456 gssspi_acquire_cred_with_password(ctx, minor_status, desired_name,
457 password, time_req, desired_mechs, cred_usage,
458 output_cred_handle, actual_mechs, time_rec)
459 void *ctx;
460 OM_uint32 *minor_status;
461 gss_name_t desired_name;
462 const gss_buffer_t password;
463 OM_uint32 time_req;
464 gss_OID_set desired_mechs;
465 gss_cred_usage_t cred_usage;
466 gss_cred_id_t *output_cred_handle;
467 gss_OID_set *actual_mechs;
468 OM_uint32 *time_rec;
469 {
470 OM_uint32 ret;
471
472 ret = krb5_gss_acquire_cred_with_password(minor_status,
473 desired_name, password, time_req, desired_mechs,
474 cred_usage, output_cred_handle, actual_mechs, time_rec);
475 return (ret);
476 }
477