1 /* 2 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. 3 */ 4 /* 5 * Copyright 2000 by the Massachusetts Institute of Technology. 6 * All Rights Reserved. 7 * 8 * Export of this software from the United States of America may 9 * require a specific license from the United States Government. 10 * It is the responsibility of any person or organization contemplating 11 * export to obtain such a license before exporting. 12 * 13 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 14 * distribute this software and its documentation for any purpose and 15 * without fee is hereby granted, provided that the above copyright 16 * notice appear in all copies and that both that copyright notice and 17 * this permission notice appear in supporting documentation, and that 18 * the name of M.I.T. not be used in advertising or publicity pertaining 19 * to distribution of the software without specific, written prior 20 * permission. Furthermore if you modify this software you must label 21 * your software as modified software and not distribute it in such a 22 * fashion that it might be confused with the original M.I.T. software. 23 * M.I.T. makes no representations about the suitability of 24 * this software for any purpose. It is provided "as is" without express 25 * or implied warranty. 26 * 27 */ 28 /* 29 * Copyright (C) 1998 by the FundsXpress, INC. 30 * 31 * All rights reserved. 32 * 33 * Export of this software from the United States of America may require 34 * a specific license from the United States Government. It is the 35 * responsibility of any person or organization contemplating export to 36 * obtain such a license before exporting. 37 * 38 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 39 * distribute this software and its documentation for any purpose and 40 * without fee is hereby granted, provided that the above copyright 41 * notice appear in all copies and that both that copyright notice and 42 * this permission notice appear in supporting documentation, and that 43 * the name of FundsXpress. not be used in advertising or publicity pertaining 44 * to distribution of the software without specific, written prior 45 * permission. FundsXpress makes no representations about the suitability of 46 * this software for any purpose. It is provided "as is" without express 47 * or implied warranty. 48 * 49 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 50 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 51 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. 52 */ 53 54 #include "gssapiP_krb5.h" 55 #ifdef HAVE_STRING_H 56 #include <string.h> 57 #else 58 #include <strings.h> 59 #endif 60 #include <locale.h> /* Solaris Kerberos */ 61 62 /* 63 * $Id: add_cred.c 18396 2006-07-25 20:29:43Z lxs $ 64 */ 65 66 /* V2 interface */ 67 OM_uint32 68 krb5_gss_add_cred(minor_status, input_cred_handle, 69 desired_name, desired_mech, cred_usage, 70 initiator_time_req, acceptor_time_req, 71 output_cred_handle, actual_mechs, 72 initiator_time_rec, acceptor_time_rec) 73 OM_uint32 *minor_status; 74 gss_cred_id_t input_cred_handle; 75 gss_name_t desired_name; 76 gss_OID desired_mech; 77 gss_cred_usage_t cred_usage; 78 OM_uint32 initiator_time_req; 79 OM_uint32 acceptor_time_req; 80 gss_cred_id_t *output_cred_handle; 81 gss_OID_set *actual_mechs; 82 OM_uint32 *initiator_time_rec; 83 OM_uint32 *acceptor_time_rec; 84 { 85 krb5_context context; 86 OM_uint32 major_status, lifetime; 87 krb5_gss_cred_id_t cred; 88 krb5_error_code code; 89 90 /* this is pretty simple, since there's not really any difference 91 between the underlying mechanisms. The main hair is in copying 92 a mechanism if requested. */ 93 94 /* check if the desired_mech is bogus */ 95 96 if (!g_OID_equal(desired_mech, gss_mech_krb5) && 97 !g_OID_equal(desired_mech, gss_mech_krb5_old)) { 98 *minor_status = 0; 99 return(GSS_S_BAD_MECH); 100 } 101 102 /* check if the desired_mech is bogus */ 103 104 if ((cred_usage != GSS_C_INITIATE) && 105 (cred_usage != GSS_C_ACCEPT) && 106 (cred_usage != GSS_C_BOTH)) { 107 *minor_status = (OM_uint32) G_BAD_USAGE; 108 return(GSS_S_FAILURE); 109 } 110 111 /* since the default credential includes all the mechanisms, 112 return an error for that case. */ 113 114 /*SUPPRESS 29*/ 115 if (input_cred_handle == GSS_C_NO_CREDENTIAL) { 116 *minor_status = 0; 117 return(GSS_S_DUPLICATE_ELEMENT); 118 } 119 120 code = krb5_gss_init_context(&context); 121 if (code) { 122 *minor_status = code; 123 return GSS_S_FAILURE; 124 } 125 126 major_status = krb5_gss_validate_cred_1(minor_status, input_cred_handle, 127 context); 128 if (GSS_ERROR(major_status)) { 129 save_error_info(*minor_status, context); 130 krb5_free_context(context); 131 return major_status; 132 } 133 134 cred = (krb5_gss_cred_id_t) input_cred_handle; 135 k5_mutex_assert_locked(&cred->lock); 136 137 /* check if the cred_usage is equal or "less" than the passed-in cred 138 if copying */ 139 140 if (!((cred->usage == cred_usage) || 141 ((cred->usage == GSS_C_BOTH) && 142 (output_cred_handle != NULL)))) { 143 *minor_status = (OM_uint32) G_BAD_USAGE; 144 krb5_free_context(context); 145 return(GSS_S_FAILURE); 146 } 147 148 /* check that desired_mech isn't already in the credential */ 149 150 if ((g_OID_equal(desired_mech, gss_mech_krb5_old) && cred->prerfc_mech) || 151 (g_OID_equal(desired_mech, gss_mech_krb5) && cred->rfc_mech)) { 152 *minor_status = 0; 153 krb5_free_context(context); 154 return(GSS_S_DUPLICATE_ELEMENT); 155 } 156 157 if (GSS_ERROR(kg_sync_ccache_name(context, minor_status))) { 158 save_error_info(*minor_status, context); 159 krb5_free_context(context); 160 return GSS_S_FAILURE; 161 } 162 163 /* verify the desired_name */ 164 165 /*SUPPRESS 29*/ 166 if ((desired_name != (gss_name_t) NULL) && 167 (! kg_validate_name(desired_name))) { 168 *minor_status = (OM_uint32) G_VALIDATE_FAILED; 169 krb5_free_context(context); 170 return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME); 171 } 172 173 /* make sure the desired_name is the same as the existing one */ 174 175 if (desired_name && 176 !krb5_principal_compare(context, (krb5_principal) desired_name, 177 cred->princ)) { 178 /* Solaris Kerberos: spruce-up the err msg */ 179 krb5_principal dname = (krb5_principal) desired_name; 180 char *s_name = NULL, *s_princ= NULL; 181 int kret = krb5_unparse_name(context, dname, &s_name); 182 int kret1 = krb5_unparse_name(context, cred->princ, &s_princ); 183 *minor_status = (OM_uint32) G_BAD_USAGE; 184 if (kret == 0 && kret1 == 0) { 185 krb5_set_error_message(context, *minor_status, 186 dgettext(TEXT_DOMAIN, 187 "Desired name principal '%s' does not match '%s'"), 188 s_name, s_princ); 189 save_error_info(*minor_status, context); 190 } 191 if (s_name) 192 krb5_free_unparsed_name(context, s_name); 193 if (s_princ) 194 krb5_free_unparsed_name(context, s_princ); 195 196 krb5_free_context(context); 197 return(GSS_S_BAD_NAME); 198 } 199 200 /* copy the cred if necessary */ 201 202 if (output_cred_handle) { 203 /* make a copy */ 204 krb5_gss_cred_id_t new_cred; 205 char *kttype, ktboth[1024]; 206 const char *cctype, *ccname; 207 char ccboth[1024]; 208 209 if ((new_cred = 210 (krb5_gss_cred_id_t) xmalloc(sizeof(krb5_gss_cred_id_rec))) 211 == NULL) { 212 *minor_status = ENOMEM; 213 krb5_free_context(context); 214 return(GSS_S_FAILURE); 215 } 216 memset(new_cred, 0, sizeof(krb5_gss_cred_id_rec)); 217 218 new_cred->usage = cred_usage; 219 new_cred->prerfc_mech = cred->prerfc_mech; 220 new_cred->rfc_mech = cred->rfc_mech; 221 new_cred->tgt_expire = cred->tgt_expire; 222 223 if (cred->princ) 224 code = krb5_copy_principal(context, cred->princ, &new_cred->princ); 225 if (code) { 226 xfree(new_cred); 227 228 *minor_status = code; 229 save_error_info(*minor_status, context); 230 krb5_free_context(context); 231 return(GSS_S_FAILURE); 232 } 233 234 if (cred->keytab) { 235 kttype = krb5_kt_get_type(context, cred->keytab); 236 if ((strlen(kttype)+2) > sizeof(ktboth)) { 237 if (new_cred->princ) 238 krb5_free_principal(context, new_cred->princ); 239 xfree(new_cred); 240 241 *minor_status = ENOMEM; 242 krb5_free_context(context); 243 return(GSS_S_FAILURE); 244 } 245 246 strncpy(ktboth, kttype, sizeof(ktboth) - 1); 247 ktboth[sizeof(ktboth) - 1] = '\0'; 248 strncat(ktboth, ":", sizeof(ktboth) - 1 - strlen(ktboth)); 249 250 code = krb5_kt_get_name(context, cred->keytab, 251 ktboth+strlen(ktboth), 252 sizeof(ktboth)-strlen(ktboth)); 253 if (code) { 254 if(new_cred->princ) 255 krb5_free_principal(context, new_cred->princ); 256 xfree(new_cred); 257 258 *minor_status = code; 259 save_error_info(*minor_status, context); 260 krb5_free_context(context); 261 return(GSS_S_FAILURE); 262 } 263 264 code = krb5_kt_resolve(context, ktboth, &new_cred->keytab); 265 if (code) { 266 if (new_cred->princ) 267 krb5_free_principal(context, new_cred->princ); 268 xfree(new_cred); 269 270 *minor_status = code; 271 save_error_info(*minor_status, context); 272 krb5_free_context(context); 273 return(GSS_S_FAILURE); 274 } 275 } else { 276 new_cred->keytab = NULL; 277 } 278 279 if (cred->rcache) { 280 /* Open the replay cache for this principal. */ 281 if ((code = krb5_get_server_rcache(context, 282 krb5_princ_component(context, cred->princ, 0), 283 &new_cred->rcache))) { 284 if (new_cred->keytab) 285 krb5_kt_close(context, new_cred->keytab); 286 if (new_cred->princ) 287 krb5_free_principal(context, new_cred->princ); 288 xfree(new_cred); 289 290 *minor_status = code; 291 save_error_info(*minor_status, context); 292 krb5_free_context(context); 293 return(GSS_S_FAILURE); 294 } 295 } else { 296 new_cred->rcache = NULL; 297 } 298 299 if (cred->ccache) { 300 cctype = krb5_cc_get_type(context, cred->ccache); 301 ccname = krb5_cc_get_name(context, cred->ccache); 302 303 if ((strlen(cctype)+strlen(ccname)+2) > sizeof(ccboth)) { 304 if (new_cred->rcache) 305 krb5_rc_close(context, new_cred->rcache); 306 if (new_cred->keytab) 307 krb5_kt_close(context, new_cred->keytab); 308 if (new_cred->princ) 309 krb5_free_principal(context, new_cred->princ); 310 xfree(new_cred); 311 312 krb5_free_context(context); 313 *minor_status = ENOMEM; 314 return(GSS_S_FAILURE); 315 } 316 317 strncpy(ccboth, cctype, sizeof(ccboth) - 1); 318 ccboth[sizeof(ccboth) - 1] = '\0'; 319 strncat(ccboth, ":", sizeof(ccboth) - 1 - strlen(ccboth)); 320 strncat(ccboth, ccname, sizeof(ccboth) - 1 - strlen(ccboth)); 321 322 code = krb5_cc_resolve(context, ccboth, &new_cred->ccache); 323 if (code) { 324 if (new_cred->rcache) 325 krb5_rc_close(context, new_cred->rcache); 326 if (new_cred->keytab) 327 krb5_kt_close(context, new_cred->keytab); 328 if (new_cred->princ) 329 krb5_free_principal(context, new_cred->princ); 330 xfree(new_cred); 331 *minor_status = code; 332 save_error_info(*minor_status, context); 333 krb5_free_context(context); 334 return(GSS_S_FAILURE); 335 } 336 } else { 337 new_cred->ccache = NULL; 338 } 339 340 /* intern the credential handle */ 341 342 if (! kg_save_cred_id((gss_cred_id_t) new_cred)) { 343 if (new_cred->ccache) 344 krb5_cc_close(context, new_cred->ccache); 345 if (new_cred->rcache) 346 krb5_rc_close(context, new_cred->rcache); 347 if (new_cred->keytab) 348 krb5_kt_close(context, new_cred->keytab); 349 if (new_cred->princ) 350 krb5_free_principal(context, new_cred->princ); 351 xfree(new_cred); 352 krb5_free_context(context); 353 354 *minor_status = (OM_uint32) G_VALIDATE_FAILED; 355 return(GSS_S_FAILURE); 356 } 357 358 /* modify new_cred */ 359 360 cred = new_cred; 361 } 362 363 /* set the flag for the new mechanism */ 364 365 if (g_OID_equal(desired_mech, gss_mech_krb5_old)) 366 cred->prerfc_mech = 1; 367 else if (g_OID_equal(desired_mech, gss_mech_krb5)) 368 cred->rfc_mech = 1; 369 370 /* set the outputs */ 371 372 if (GSS_ERROR(major_status = krb5_gss_inquire_cred(minor_status, 373 (gss_cred_id_t)cred, 374 NULL, &lifetime, 375 NULL, actual_mechs))) { 376 OM_uint32 dummy; 377 378 if (output_cred_handle) 379 (void) krb5_gss_release_cred(&dummy, (gss_cred_id_t *) &cred); 380 krb5_free_context(context); 381 382 return(major_status); 383 } 384 385 if (initiator_time_rec) 386 *initiator_time_rec = lifetime; 387 if (acceptor_time_rec) 388 *acceptor_time_rec = lifetime; 389 390 if (output_cred_handle) 391 *output_cred_handle = (gss_cred_id_t)cred; 392 393 krb5_free_context(context); 394 *minor_status = 0; 395 return(GSS_S_COMPLETE); 396 } 397