1 /* $NetBSD: gss_mo.c,v 1.1.1.1 2011/04/13 18:14:46 elric Exp $ */ 2 3 /* 4 * Copyright (c) 2010 Kungliga Tekniska Högskolan 5 * (Royal Institute of Technology, Stockholm, Sweden). 6 * All rights reserved. 7 * 8 * Portions Copyright (c) 2010 Apple Inc. All rights reserved. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * 3. Neither the name of the Institute nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 */ 37 38 #include "mech_locl.h" 39 40 static int 41 get_option_def(int def, gss_const_OID mech, gss_mo_desc *mo, gss_buffer_t value) 42 { 43 return def; 44 } 45 46 47 int 48 _gss_mo_get_option_1(gss_const_OID mech, gss_mo_desc *mo, gss_buffer_t value) 49 { 50 return get_option_def(1, mech, mo, value); 51 } 52 53 int 54 _gss_mo_get_option_0(gss_const_OID mech, gss_mo_desc *mo, gss_buffer_t value) 55 { 56 return get_option_def(0, mech, mo, value); 57 } 58 59 int 60 _gss_mo_get_ctx_as_string(gss_const_OID mech, gss_mo_desc *mo, gss_buffer_t value) 61 { 62 if (value) { 63 value->value = strdup((char *)mo->ctx); 64 if (value->value == NULL) 65 return 1; 66 value->length = strlen((char *)mo->ctx); 67 } 68 return 0; 69 } 70 71 GSSAPI_LIB_FUNCTION int GSSAPI_LIB_CALL 72 gss_mo_set(gss_const_OID mech, gss_const_OID option, 73 int enable, gss_buffer_t value) 74 { 75 gssapi_mech_interface m; 76 size_t n; 77 78 if ((m = __gss_get_mechanism(mech)) == NULL) 79 return GSS_S_BAD_MECH; 80 81 for (n = 0; n < m->gm_mo_num; n++) 82 if (gss_oid_equal(option, m->gm_mo[n].option) && m->gm_mo[n].set) 83 return m->gm_mo[n].set(mech, &m->gm_mo[n], enable, value); 84 return 0; 85 } 86 87 GSSAPI_LIB_FUNCTION int GSSAPI_LIB_CALL 88 gss_mo_get(gss_const_OID mech, gss_const_OID option, gss_buffer_t value) 89 { 90 gssapi_mech_interface m; 91 size_t n; 92 93 _mg_buffer_zero(value); 94 95 if ((m = __gss_get_mechanism(mech)) == NULL) 96 return 0; 97 98 for (n = 0; n < m->gm_mo_num; n++) 99 if (gss_oid_equal(option, m->gm_mo[n].option) && m->gm_mo[n].get) 100 return m->gm_mo[n].get(mech, &m->gm_mo[n], value); 101 102 return 0; 103 } 104 105 static void 106 add_all_mo(gssapi_mech_interface m, gss_OID_set *options, OM_uint32 mask) 107 { 108 OM_uint32 minor; 109 size_t n; 110 111 for (n = 0; n < m->gm_mo_num; n++) 112 if ((m->gm_mo[n].flags & mask) == mask) 113 gss_add_oid_set_member(&minor, m->gm_mo[n].option, options); 114 } 115 116 GSSAPI_LIB_FUNCTION void GSSAPI_LIB_CALL 117 gss_mo_list(gss_const_OID mech, gss_OID_set *options) 118 { 119 gssapi_mech_interface m; 120 OM_uint32 major, minor; 121 122 if (options == NULL) 123 return; 124 125 *options = GSS_C_NO_OID_SET; 126 127 if ((m = __gss_get_mechanism(mech)) == NULL) 128 return; 129 130 major = gss_create_empty_oid_set(&minor, options); 131 if (major != GSS_S_COMPLETE) 132 return; 133 134 add_all_mo(m, options, 0); 135 } 136 137 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 138 gss_mo_name(gss_const_OID mech, gss_const_OID option, gss_buffer_t name) 139 { 140 gssapi_mech_interface m; 141 size_t n; 142 143 if (name == NULL) 144 return GSS_S_BAD_NAME; 145 146 if ((m = __gss_get_mechanism(mech)) == NULL) 147 return GSS_S_BAD_MECH; 148 149 for (n = 0; n < m->gm_mo_num; n++) { 150 if (gss_oid_equal(option, m->gm_mo[n].option)) { 151 /* 152 * If ther is no name, its because its a GSS_C_MA and there is already a table for that. 153 */ 154 if (m->gm_mo[n].name) { 155 name->value = strdup(m->gm_mo[n].name); 156 if (name->value == NULL) 157 return GSS_S_BAD_NAME; 158 name->length = strlen(m->gm_mo[n].name); 159 return GSS_S_COMPLETE; 160 } else { 161 OM_uint32 junk; 162 return gss_display_mech_attr(&junk, option, 163 NULL, name, NULL); 164 } 165 } 166 } 167 return GSS_S_BAD_NAME; 168 } 169 170 /* 171 * Helper function to allow NULL name 172 */ 173 174 static OM_uint32 175 mo_value(const gss_const_OID mech, gss_const_OID option, gss_buffer_t name) 176 { 177 if (name == NULL) 178 return GSS_S_COMPLETE; 179 180 if (gss_mo_get(mech, option, name) != 0 && name->length == 0) 181 return GSS_S_FAILURE; 182 183 return GSS_S_COMPLETE; 184 } 185 186 /** 187 * Returns differnt protocol names and description of the mechanism. 188 * 189 * @param minor_status minor status code 190 * @param desired_mech mech list query 191 * @param sasl_mech_name SASL GS2 protocol name 192 * @param mech_name gssapi protocol name 193 * @param mech_description description of gssapi mech 194 * 195 * @return returns GSS_S_COMPLETE or a error code. 196 * 197 * @ingroup gssapi 198 */ 199 200 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 201 gss_inquire_saslname_for_mech(OM_uint32 *minor_status, 202 const gss_OID desired_mech, 203 gss_buffer_t sasl_mech_name, 204 gss_buffer_t mech_name, 205 gss_buffer_t mech_description) 206 { 207 OM_uint32 major; 208 209 _mg_buffer_zero(sasl_mech_name); 210 _mg_buffer_zero(mech_name); 211 _mg_buffer_zero(mech_description); 212 213 if (minor_status) 214 *minor_status = 0; 215 216 if (desired_mech == NULL) 217 return GSS_S_BAD_MECH; 218 219 major = mo_value(desired_mech, GSS_C_MA_SASL_MECH_NAME, sasl_mech_name); 220 if (major) return major; 221 222 major = mo_value(desired_mech, GSS_C_MA_MECH_NAME, mech_name); 223 if (major) return major; 224 225 major = mo_value(desired_mech, GSS_C_MA_MECH_DESCRIPTION, mech_description); 226 if (major) return major; 227 228 return GSS_S_COMPLETE; 229 } 230 231 /** 232 * Find a mech for a sasl name 233 * 234 * @param minor_status minor status code 235 * @param sasl_mech_name 236 * @param mech_type 237 * 238 * @return returns GSS_S_COMPLETE or an error code. 239 */ 240 241 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 242 gss_inquire_mech_for_saslname(OM_uint32 *minor_status, 243 const gss_buffer_t sasl_mech_name, 244 gss_OID *mech_type) 245 { 246 struct _gss_mech_switch *m; 247 gss_buffer_desc name; 248 OM_uint32 major; 249 250 _gss_load_mech(); 251 252 *mech_type = NULL; 253 254 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) { 255 256 major = mo_value(&m->gm_mech_oid, GSS_C_MA_SASL_MECH_NAME, &name); 257 if (major) 258 continue; 259 if (name.length == sasl_mech_name->length && 260 memcmp(name.value, sasl_mech_name->value, name.length) == 0) { 261 gss_release_buffer(&major, &name); 262 *mech_type = &m->gm_mech_oid; 263 return 0; 264 } 265 gss_release_buffer(&major, &name); 266 } 267 268 return GSS_S_BAD_MECH; 269 } 270 271 /** 272 * Return set of mechanism that fullfill the criteria 273 * 274 * @param minor_status minor status code 275 * @param desired_mech_attrs 276 * @param except_mech_attrs 277 * @param critical_mech_attrs 278 * @param mechs returned mechs, free with gss_release_oid_set(). 279 * 280 * @return returns GSS_S_COMPLETE or an error code. 281 */ 282 283 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 284 gss_indicate_mechs_by_attrs(OM_uint32 * minor_status, 285 gss_const_OID_set desired_mech_attrs, 286 gss_const_OID_set except_mech_attrs, 287 gss_const_OID_set critical_mech_attrs, 288 gss_OID_set *mechs) 289 { 290 struct _gss_mech_switch *ms; 291 OM_uint32 major; 292 size_t n, m; 293 294 major = gss_create_empty_oid_set(minor_status, mechs); 295 if (major) 296 return major; 297 298 _gss_load_mech(); 299 300 HEIM_SLIST_FOREACH(ms, &_gss_mechs, gm_link) { 301 gssapi_mech_interface mi = &ms->gm_mech; 302 303 if (desired_mech_attrs) { 304 for (n = 0; n < desired_mech_attrs->count; n++) { 305 for (m = 0; m < mi->gm_mo_num; m++) 306 if (gss_oid_equal(mi->gm_mo[m].option, &desired_mech_attrs->elements[n])) 307 break; 308 if (m == mi->gm_mo_num) 309 goto next; 310 } 311 } 312 313 if (except_mech_attrs) { 314 for (n = 0; n < desired_mech_attrs->count; n++) { 315 for (m = 0; m < mi->gm_mo_num; m++) { 316 if (gss_oid_equal(mi->gm_mo[m].option, &desired_mech_attrs->elements[n])) 317 goto next; 318 } 319 } 320 } 321 322 if (critical_mech_attrs) { 323 for (n = 0; n < desired_mech_attrs->count; n++) { 324 for (m = 0; m < mi->gm_mo_num; m++) { 325 if (mi->gm_mo[m].flags & GSS_MO_MA_CRITICAL) 326 continue; 327 if (gss_oid_equal(mi->gm_mo[m].option, &desired_mech_attrs->elements[n])) 328 break; 329 } 330 if (m == mi->gm_mo_num) 331 goto next; 332 } 333 } 334 335 336 next: 337 do { } while(0); 338 } 339 340 341 return GSS_S_FAILURE; 342 } 343 344 /** 345 * List support attributes for a mech and/or all mechanisms. 346 * 347 * @param minor_status minor status code 348 * @param mech given together with mech_attr will return the list of 349 * attributes for mechanism, can optionally be GSS_C_NO_OID. 350 * @param mech_attr see mech parameter, can optionally be NULL, 351 * release with gss_release_oid_set(). 352 * @param known_mech_attrs all attributes for mechanisms supported, 353 * release with gss_release_oid_set(). 354 * 355 * @ingroup gssapi 356 */ 357 358 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 359 gss_inquire_attrs_for_mech(OM_uint32 * minor_status, 360 gss_const_OID mech, 361 gss_OID_set *mech_attr, 362 gss_OID_set *known_mech_attrs) 363 { 364 OM_uint32 major, junk; 365 366 if (mech_attr && mech) { 367 gssapi_mech_interface m; 368 369 if ((m = __gss_get_mechanism(mech)) == NULL) { 370 *minor_status = 0; 371 return GSS_S_BAD_MECH; 372 } 373 374 major = gss_create_empty_oid_set(minor_status, mech_attr); 375 if (major != GSS_S_COMPLETE) 376 return major; 377 378 add_all_mo(m, mech_attr, GSS_MO_MA); 379 } 380 381 if (known_mech_attrs) { 382 struct _gss_mech_switch *m; 383 384 major = gss_create_empty_oid_set(minor_status, known_mech_attrs); 385 if (major) { 386 if (mech_attr) 387 gss_release_oid_set(&junk, mech_attr); 388 return major; 389 } 390 391 _gss_load_mech(); 392 393 HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) 394 add_all_mo(&m->gm_mech, known_mech_attrs, GSS_MO_MA); 395 } 396 397 398 return GSS_S_COMPLETE; 399 } 400 401 /** 402 * Return names and descriptions of mech attributes 403 * 404 * @param minor_status minor status code 405 * @param mech_attr 406 * @param name 407 * @param short_desc 408 * @param long_desc 409 * 410 * @return returns GSS_S_COMPLETE or an error code. 411 */ 412 413 GSSAPI_LIB_FUNCTION OM_uint32 GSSAPI_LIB_CALL 414 gss_display_mech_attr(OM_uint32 * minor_status, 415 gss_const_OID mech_attr, 416 gss_buffer_t name, 417 gss_buffer_t short_desc, 418 gss_buffer_t long_desc) 419 { 420 struct _gss_oid_name_table *ma = NULL; 421 OM_uint32 major; 422 size_t n; 423 424 _mg_buffer_zero(name); 425 _mg_buffer_zero(short_desc); 426 _mg_buffer_zero(long_desc); 427 428 if (minor_status) 429 *minor_status = 0; 430 431 for (n = 0; ma == NULL && _gss_ont_ma[n].oid; n++) 432 if (gss_oid_equal(mech_attr, _gss_ont_ma[n].oid)) 433 ma = &_gss_ont_ma[n]; 434 435 if (ma == NULL) 436 return GSS_S_BAD_MECH_ATTR; 437 438 if (name) { 439 gss_buffer_desc n; 440 n.value = rk_UNCONST(ma->name); 441 n.length = strlen(ma->name); 442 major = _gss_copy_buffer(minor_status, &n, name); 443 if (major != GSS_S_COMPLETE) 444 return major; 445 } 446 447 if (short_desc) { 448 gss_buffer_desc n; 449 n.value = rk_UNCONST(ma->short_desc); 450 n.length = strlen(ma->short_desc); 451 major = _gss_copy_buffer(minor_status, &n, short_desc); 452 if (major != GSS_S_COMPLETE) 453 return major; 454 } 455 456 if (long_desc) { 457 gss_buffer_desc n; 458 n.value = rk_UNCONST(ma->long_desc); 459 n.length = strlen(ma->long_desc); 460 major = _gss_copy_buffer(minor_status, &n, long_desc); 461 if (major != GSS_S_COMPLETE) 462 return major; 463 } 464 465 return GSS_S_COMPLETE; 466 } 467