gss_mech_switch.c revision 155287
1153838Sdfr/*- 2153838Sdfr * Copyright (c) 2005 Doug Rabson 3153838Sdfr * All rights reserved. 4153838Sdfr * 5153838Sdfr * Redistribution and use in source and binary forms, with or without 6153838Sdfr * modification, are permitted provided that the following conditions 7153838Sdfr * are met: 8153838Sdfr * 1. Redistributions of source code must retain the above copyright 9153838Sdfr * notice, this list of conditions and the following disclaimer. 10153838Sdfr * 2. Redistributions in binary form must reproduce the above copyright 11153838Sdfr * notice, this list of conditions and the following disclaimer in the 12153838Sdfr * documentation and/or other materials provided with the distribution. 13153838Sdfr * 14153838Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15153838Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16153838Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17153838Sdfr * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18153838Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19153838Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20153838Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21153838Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22153838Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23153838Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24153838Sdfr * SUCH DAMAGE. 25153838Sdfr * 26153838Sdfr * $FreeBSD: head/lib/libgssapi/gss_mech_switch.c 155287 2006-02-04 09:40:21Z dfr $ 27153838Sdfr */ 28153838Sdfr 29153838Sdfr#include <gssapi/gssapi.h> 30153838Sdfr#include <dlfcn.h> 31153838Sdfr#include <errno.h> 32153838Sdfr#include <stdio.h> 33153838Sdfr#include <stdlib.h> 34153838Sdfr#include <string.h> 35153838Sdfr 36153838Sdfr#include "mech_switch.h" 37153838Sdfr#include "utils.h" 38153838Sdfr 39153838Sdfr#ifndef _PATH_GSS_MECH 40153838Sdfr#define _PATH_GSS_MECH "/etc/gss/mech" 41153838Sdfr#endif 42153838Sdfr 43153838Sdfrstruct _gss_mech_switch_list _gss_mechs = 44153838Sdfr SLIST_HEAD_INITIALIZER(&_gss_mechs); 45153838Sdfrgss_OID_set _gss_mech_oids; 46153838Sdfr 47153838Sdfr/* 48153838Sdfr * Convert a string containing an OID in 'dot' form 49153838Sdfr * (e.g. 1.2.840.113554.1.2.2) to a gss_OID. 50153838Sdfr */ 51153838Sdfrstatic int 52153838Sdfr_gss_string_to_oid(const char* s, gss_OID oid) 53153838Sdfr{ 54153838Sdfr int number_count, i, j; 55153838Sdfr int byte_count; 56153838Sdfr const char *p, *q; 57153838Sdfr char *res; 58153838Sdfr 59153838Sdfr /* 60153838Sdfr * First figure out how many numbers in the oid, then 61153838Sdfr * calculate the compiled oid size. 62153838Sdfr */ 63153838Sdfr number_count = 0; 64153838Sdfr for (p = s; p; p = q) { 65153838Sdfr q = strchr(p, '.'); 66153838Sdfr if (q) q = q + 1; 67153838Sdfr number_count++; 68153838Sdfr } 69153838Sdfr 70153838Sdfr /* 71153838Sdfr * The first two numbers are in the first byte and each 72153838Sdfr * subsequent number is encoded in a variable byte sequence. 73153838Sdfr */ 74153838Sdfr if (number_count < 2) 75153838Sdfr return (EINVAL); 76153838Sdfr 77153838Sdfr /* 78153838Sdfr * We do this in two passes. The first pass, we just figure 79153838Sdfr * out the size. Second time around, we actually encode the 80153838Sdfr * number. 81153838Sdfr */ 82153838Sdfr res = 0; 83153838Sdfr for (i = 0; i < 2; i++) { 84153838Sdfr byte_count = 0; 85153838Sdfr for (p = s, j = 0; p; p = q, j++) { 86153838Sdfr unsigned int number = 0; 87153838Sdfr 88153838Sdfr /* 89153838Sdfr * Find the end of this number. 90153838Sdfr */ 91153838Sdfr q = strchr(p, '.'); 92153838Sdfr if (q) q = q + 1; 93153838Sdfr 94153838Sdfr /* 95153838Sdfr * Read the number of of the string. Don't 96153838Sdfr * bother with anything except base ten. 97153838Sdfr */ 98153838Sdfr while (*p && *p != '.') { 99153838Sdfr number = 10 * number + (*p - '0'); 100153838Sdfr p++; 101153838Sdfr } 102153838Sdfr 103153838Sdfr /* 104153838Sdfr * Encode the number. The first two numbers 105153838Sdfr * are packed into the first byte. Subsequent 106153838Sdfr * numbers are encoded in bytes seven bits at 107153838Sdfr * a time with the last byte having the high 108153838Sdfr * bit set. 109153838Sdfr */ 110153838Sdfr if (j == 0) { 111153838Sdfr if (res) 112153838Sdfr *res = number * 40; 113153838Sdfr } else if (j == 1) { 114153838Sdfr if (res) { 115153838Sdfr *res += number; 116153838Sdfr res++; 117153838Sdfr } 118153838Sdfr byte_count++; 119153838Sdfr } else if (j >= 2) { 120153838Sdfr /* 121153838Sdfr * The number is encoded in seven bit chunks. 122153838Sdfr */ 123153838Sdfr unsigned int t; 124153838Sdfr int bytes; 125153838Sdfr 126153838Sdfr bytes = 0; 127153838Sdfr for (t = number; t; t >>= 7) 128153838Sdfr bytes++; 129153838Sdfr if (bytes == 0) bytes = 1; 130153838Sdfr while (bytes) { 131153838Sdfr if (res) { 132153838Sdfr int bit = 7*(bytes-1); 133153838Sdfr 134153838Sdfr *res = (number >> bit) & 0x7f; 135153838Sdfr if (bytes != 1) 136153838Sdfr *res |= 0x80; 137153838Sdfr res++; 138153838Sdfr } 139153838Sdfr byte_count++; 140153838Sdfr bytes--; 141153838Sdfr } 142153838Sdfr } 143153838Sdfr } 144153838Sdfr if (!res) { 145153838Sdfr res = malloc(byte_count); 146153838Sdfr if (!res) 147153838Sdfr return (ENOMEM); 148153838Sdfr oid->length = byte_count; 149153838Sdfr oid->elements = res; 150153838Sdfr } 151153838Sdfr } 152153838Sdfr 153153838Sdfr return (0); 154153838Sdfr} 155153838Sdfr 156153838Sdfr#define SYM(name) \ 157153838Sdfrdo { \ 158153838Sdfr m->gm_ ## name = dlsym(so, "gss_" #name); \ 159153838Sdfr if (!m->gm_ ## name) { \ 160153838Sdfr fprintf(stderr, "can't find symbol gss_" #name "\n"); \ 161153838Sdfr goto bad; \ 162153838Sdfr } \ 163153838Sdfr} while (0) 164153838Sdfr 165153838Sdfr#define OPTSYM(name) \ 166153838Sdfrdo { \ 167153838Sdfr m->gm_ ## name = dlsym(so, "gss_" #name); \ 168153838Sdfr} while (0) 169153838Sdfr 170153838Sdfr#define OPTSYM2(symname, ourname) \ 171153838Sdfrdo { \ 172153838Sdfr m->ourname = dlsym(so, #symname); \ 173153838Sdfr} while (0) 174153838Sdfr 175153838Sdfr/* 176153838Sdfr * Load the mechanisms file (/etc/gss/mech). 177153838Sdfr */ 178153838Sdfrvoid 179153838Sdfr_gss_load_mech(void) 180153838Sdfr{ 181153838Sdfr OM_uint32 major_status, minor_status; 182153838Sdfr FILE *fp; 183153838Sdfr char buf[256]; 184153838Sdfr char *p; 185153838Sdfr char *name, *oid, *lib, *kobj; 186153838Sdfr struct _gss_mech_switch *m; 187153838Sdfr int count; 188153838Sdfr char **pp; 189153838Sdfr void *so; 190153838Sdfr 191153838Sdfr if (SLIST_FIRST(&_gss_mechs)) 192153838Sdfr return; 193153838Sdfr 194153838Sdfr major_status = gss_create_empty_oid_set(&minor_status, 195153838Sdfr &_gss_mech_oids); 196153838Sdfr if (major_status) 197153838Sdfr return; 198153838Sdfr 199153838Sdfr fp = fopen(_PATH_GSS_MECH, "r"); 200153838Sdfr if (!fp) { 201153838Sdfr perror(_PATH_GSS_MECH); 202153838Sdfr return; 203153838Sdfr } 204153838Sdfr 205153838Sdfr count = 0; 206153838Sdfr while (fgets(buf, sizeof(buf), fp)) { 207153838Sdfr if (*buf == '#') 208153838Sdfr continue; 209153838Sdfr p = buf; 210153838Sdfr name = strsep(&p, "\t\n "); 211155287Sdfr if (p) while (isspace(*p)) p++; 212153838Sdfr oid = strsep(&p, "\t\n "); 213155287Sdfr if (p) while (isspace(*p)) p++; 214153838Sdfr lib = strsep(&p, "\t\n "); 215155287Sdfr if (p) while (isspace(*p)) p++; 216153838Sdfr kobj = strsep(&p, "\t\n "); 217153838Sdfr if (!name || !oid || !lib || !kobj) 218153838Sdfr continue; 219153838Sdfr 220153838Sdfr so = dlopen(lib, RTLD_LOCAL); 221153838Sdfr if (!so) { 222153838Sdfr fprintf(stderr, "dlopen: %s\n", dlerror()); 223153838Sdfr continue; 224153838Sdfr } 225153838Sdfr 226153838Sdfr m = malloc(sizeof(struct _gss_mech_switch)); 227153838Sdfr if (!m) 228153838Sdfr break; 229153838Sdfr m->gm_so = so; 230153838Sdfr if (_gss_string_to_oid(oid, &m->gm_mech_oid)) { 231153838Sdfr free(m); 232153838Sdfr continue; 233153838Sdfr } 234153838Sdfr 235153838Sdfr major_status = gss_add_oid_set_member(&minor_status, 236153838Sdfr &m->gm_mech_oid, &_gss_mech_oids); 237153838Sdfr if (major_status) { 238153838Sdfr free(m->gm_mech_oid.elements); 239153838Sdfr free(m); 240153838Sdfr continue; 241153838Sdfr } 242153838Sdfr 243153838Sdfr SYM(acquire_cred); 244153838Sdfr SYM(release_cred); 245153838Sdfr SYM(init_sec_context); 246153838Sdfr SYM(accept_sec_context); 247153838Sdfr SYM(process_context_token); 248153838Sdfr SYM(delete_sec_context); 249153838Sdfr SYM(context_time); 250153838Sdfr SYM(get_mic); 251153838Sdfr SYM(verify_mic); 252153838Sdfr SYM(wrap); 253153838Sdfr SYM(unwrap); 254153838Sdfr SYM(display_status); 255153838Sdfr SYM(indicate_mechs); 256153838Sdfr SYM(compare_name); 257153838Sdfr SYM(display_name); 258153838Sdfr SYM(import_name); 259153838Sdfr SYM(export_name); 260153838Sdfr SYM(release_name); 261153838Sdfr SYM(inquire_cred); 262153838Sdfr SYM(inquire_context); 263153838Sdfr SYM(wrap_size_limit); 264153838Sdfr SYM(add_cred); 265153838Sdfr SYM(inquire_cred_by_mech); 266153838Sdfr SYM(export_sec_context); 267153838Sdfr SYM(import_sec_context); 268153838Sdfr SYM(inquire_names_for_mech); 269153838Sdfr SYM(inquire_mechs_for_name); 270153838Sdfr SYM(canonicalize_name); 271153838Sdfr SYM(duplicate_name); 272153838Sdfr OPTSYM2(gsskrb5_register_acceptor_identity, 273153838Sdfr gm_krb5_register_acceptor_identity); 274153838Sdfr OPTSYM(krb5_copy_ccache); 275153838Sdfr OPTSYM(krb5_compat_des3_mic); 276153838Sdfr 277153838Sdfr SLIST_INSERT_HEAD(&_gss_mechs, m, gm_link); 278153838Sdfr count++; 279153838Sdfr continue; 280153838Sdfr 281153838Sdfr bad: 282153838Sdfr free(m->gm_mech_oid.elements); 283153838Sdfr free(m); 284153838Sdfr dlclose(so); 285153838Sdfr continue; 286153838Sdfr } 287153838Sdfr fclose(fp); 288153838Sdfr} 289153838Sdfr 290153838Sdfrstruct _gss_mech_switch * 291153838Sdfr_gss_find_mech_switch(gss_OID mech) 292153838Sdfr{ 293153838Sdfr struct _gss_mech_switch *m; 294153838Sdfr 295153838Sdfr _gss_load_mech(); 296153838Sdfr SLIST_FOREACH(m, &_gss_mechs, gm_link) { 297153838Sdfr if (_gss_oid_equal(&m->gm_mech_oid, mech)) 298153838Sdfr return m; 299153838Sdfr } 300153838Sdfr return (0); 301153838Sdfr} 302