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 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 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 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 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