1/*- 2 * Copyright (c) 2005 Doug Rabson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * $FreeBSD: src/lib/libgssapi/gss_mech_switch.c,v 1.2 2006/02/04 09:40:21 dfr Exp $ 27 */ 28 29#include "mech_locl.h" 30#include <heim_threads.h> 31RCSID("$Id: gss_mech_switch.c,v 1.1.1.1 2011/06/10 09:34:42 andrew Exp $"); 32 33#ifndef _PATH_GSS_MECH 34#define _PATH_GSS_MECH "/etc/gss/mech" 35#endif 36 37struct _gss_mech_switch_list _gss_mechs = { NULL } ; 38gss_OID_set _gss_mech_oids; 39static HEIMDAL_MUTEX _gss_mech_mutex = HEIMDAL_MUTEX_INITIALIZER; 40 41/* 42 * Convert a string containing an OID in 'dot' form 43 * (e.g. 1.2.840.113554.1.2.2) to a gss_OID. 44 */ 45static int 46_gss_string_to_oid(const char* s, gss_OID oid) 47{ 48 int number_count, i, j; 49 size_t byte_count; 50 const char *p, *q; 51 char *res; 52 53 oid->length = 0; 54 oid->elements = NULL; 55 56 /* 57 * First figure out how many numbers in the oid, then 58 * calculate the compiled oid size. 59 */ 60 number_count = 0; 61 for (p = s; p; p = q) { 62 q = strchr(p, '.'); 63 if (q) q = q + 1; 64 number_count++; 65 } 66 67 /* 68 * The first two numbers are in the first byte and each 69 * subsequent number is encoded in a variable byte sequence. 70 */ 71 if (number_count < 2) 72 return (EINVAL); 73 74 /* 75 * We do this in two passes. The first pass, we just figure 76 * out the size. Second time around, we actually encode the 77 * number. 78 */ 79 res = 0; 80 for (i = 0; i < 2; i++) { 81 byte_count = 0; 82 for (p = s, j = 0; p; p = q, j++) { 83 unsigned int number = 0; 84 85 /* 86 * Find the end of this number. 87 */ 88 q = strchr(p, '.'); 89 if (q) q = q + 1; 90 91 /* 92 * Read the number of of the string. Don't 93 * bother with anything except base ten. 94 */ 95 while (*p && *p != '.') { 96 number = 10 * number + (*p - '0'); 97 p++; 98 } 99 100 /* 101 * Encode the number. The first two numbers 102 * are packed into the first byte. Subsequent 103 * numbers are encoded in bytes seven bits at 104 * a time with the last byte having the high 105 * bit set. 106 */ 107 if (j == 0) { 108 if (res) 109 *res = number * 40; 110 } else if (j == 1) { 111 if (res) { 112 *res += number; 113 res++; 114 } 115 byte_count++; 116 } else if (j >= 2) { 117 /* 118 * The number is encoded in seven bit chunks. 119 */ 120 unsigned int t; 121 unsigned int bytes; 122 123 bytes = 0; 124 for (t = number; t; t >>= 7) 125 bytes++; 126 if (bytes == 0) bytes = 1; 127 while (bytes) { 128 if (res) { 129 int bit = 7*(bytes-1); 130 131 *res = (number >> bit) & 0x7f; 132 if (bytes != 1) 133 *res |= 0x80; 134 res++; 135 } 136 byte_count++; 137 bytes--; 138 } 139 } 140 } 141 if (!res) { 142 res = malloc(byte_count); 143 if (!res) 144 return (ENOMEM); 145 oid->length = byte_count; 146 oid->elements = res; 147 } 148 } 149 150 return (0); 151} 152 153#define SYM(name) \ 154do { \ 155 m->gm_mech.gm_ ## name = dlsym(so, "gss_" #name); \ 156 if (!m->gm_mech.gm_ ## name) { \ 157 fprintf(stderr, "can't find symbol gss_" #name "\n"); \ 158 goto bad; \ 159 } \ 160} while (0) 161 162#define OPTSYM(name) \ 163do { \ 164 m->gm_mech.gm_ ## name = dlsym(so, "gss_" #name); \ 165} while (0) 166 167/* 168 * 169 */ 170static int 171add_builtin(gssapi_mech_interface mech) 172{ 173 struct _gss_mech_switch *m; 174 OM_uint32 minor_status; 175 176 /* not registering any mech is ok */ 177 if (mech == NULL) 178 return 0; 179 180 m = malloc(sizeof(*m)); 181 if (m == NULL) 182 return 1; 183 m->gm_so = NULL; 184 m->gm_mech = *mech; 185 m->gm_mech_oid = mech->gm_mech_oid; /* XXX */ 186 gss_add_oid_set_member(&minor_status, 187 &m->gm_mech.gm_mech_oid, &_gss_mech_oids); 188 189 /* pick up the oid sets of names */ 190 191 if (m->gm_mech.gm_inquire_names_for_mech) { 192 (*m->gm_mech.gm_inquire_names_for_mech)(&minor_status, 193 &m->gm_mech.gm_mech_oid, &m->gm_name_types); 194 } else { 195 gss_create_empty_oid_set(&minor_status, &m->gm_name_types); 196 } 197 198 SLIST_INSERT_HEAD(&_gss_mechs, m, gm_link); 199 return 0; 200} 201 202/* 203 * Load the mechanisms file (/etc/gss/mech). 204 */ 205void 206_gss_load_mech(void) 207{ 208 OM_uint32 major_status, minor_status; 209 FILE *fp; 210 char buf[256]; 211 char *p; 212 char *name, *oid, *lib, *kobj; 213 struct _gss_mech_switch *m; 214 void *so; 215 216 217 HEIMDAL_MUTEX_lock(&_gss_mech_mutex); 218 219 if (SLIST_FIRST(&_gss_mechs)) { 220 HEIMDAL_MUTEX_unlock(&_gss_mech_mutex); 221 return; 222 } 223 224 major_status = gss_create_empty_oid_set(&minor_status, 225 &_gss_mech_oids); 226 if (major_status) { 227 HEIMDAL_MUTEX_unlock(&_gss_mech_mutex); 228 return; 229 } 230 231 add_builtin(__gss_krb5_initialize()); 232 add_builtin(__gss_spnego_initialize()); 233 add_builtin(__gss_ntlm_initialize()); 234 235#ifdef HAVE_DLOPEN 236 fp = fopen(_PATH_GSS_MECH, "r"); 237 if (!fp) { 238 HEIMDAL_MUTEX_unlock(&_gss_mech_mutex); 239 return; 240 } 241 rk_cloexec_file(fp); 242 243 while (fgets(buf, sizeof(buf), fp)) { 244 if (*buf == '#') 245 continue; 246 p = buf; 247 name = strsep(&p, "\t\n "); 248 if (p) while (isspace((unsigned char)*p)) p++; 249 oid = strsep(&p, "\t\n "); 250 if (p) while (isspace((unsigned char)*p)) p++; 251 lib = strsep(&p, "\t\n "); 252 if (p) while (isspace((unsigned char)*p)) p++; 253 kobj = strsep(&p, "\t\n "); 254 if (!name || !oid || !lib || !kobj) 255 continue; 256 257#ifndef RTLD_LOCAL 258#define RTLD_LOCAL 0 259#endif 260 261 so = dlopen(lib, RTLD_LAZY | RTLD_LOCAL); 262 if (!so) { 263/* fprintf(stderr, "dlopen: %s\n", dlerror()); */ 264 continue; 265 } 266 267 m = malloc(sizeof(*m)); 268 if (!m) 269 break; 270 m->gm_so = so; 271 if (_gss_string_to_oid(oid, &m->gm_mech.gm_mech_oid)) { 272 free(m); 273 continue; 274 } 275 276 major_status = gss_add_oid_set_member(&minor_status, 277 &m->gm_mech.gm_mech_oid, &_gss_mech_oids); 278 if (major_status) { 279 free(m->gm_mech.gm_mech_oid.elements); 280 free(m); 281 continue; 282 } 283 284 SYM(acquire_cred); 285 SYM(release_cred); 286 SYM(init_sec_context); 287 SYM(accept_sec_context); 288 SYM(process_context_token); 289 SYM(delete_sec_context); 290 SYM(context_time); 291 SYM(get_mic); 292 SYM(verify_mic); 293 SYM(wrap); 294 SYM(unwrap); 295 SYM(display_status); 296 SYM(indicate_mechs); 297 SYM(compare_name); 298 SYM(display_name); 299 SYM(import_name); 300 SYM(export_name); 301 SYM(release_name); 302 SYM(inquire_cred); 303 SYM(inquire_context); 304 SYM(wrap_size_limit); 305 SYM(add_cred); 306 SYM(inquire_cred_by_mech); 307 SYM(export_sec_context); 308 SYM(import_sec_context); 309 SYM(inquire_names_for_mech); 310 SYM(inquire_mechs_for_name); 311 SYM(canonicalize_name); 312 SYM(duplicate_name); 313 OPTSYM(inquire_cred_by_oid); 314 OPTSYM(inquire_sec_context_by_oid); 315 OPTSYM(set_sec_context_option); 316 OPTSYM(set_cred_option); 317 OPTSYM(pseudo_random); 318 OPTSYM(wrap_iov); 319 OPTSYM(unwrap_iov); 320 OPTSYM(wrap_iov_length); 321 322 SLIST_INSERT_HEAD(&_gss_mechs, m, gm_link); 323 continue; 324 325 bad: 326 free(m->gm_mech.gm_mech_oid.elements); 327 free(m); 328 dlclose(so); 329 continue; 330 } 331 fclose(fp); 332#endif 333 HEIMDAL_MUTEX_unlock(&_gss_mech_mutex); 334} 335 336gssapi_mech_interface 337__gss_get_mechanism(gss_OID mech) 338{ 339 struct _gss_mech_switch *m; 340 341 _gss_load_mech(); 342 SLIST_FOREACH(m, &_gss_mechs, gm_link) { 343 if (gss_oid_equal(&m->gm_mech.gm_mech_oid, mech)) 344 return &m->gm_mech; 345 } 346 return NULL; 347} 348