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