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