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