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$ 27153838Sdfr */ 28153838Sdfr 29153838Sdfr#include <gssapi/gssapi.h> 30178828Sdfr#include <ctype.h> 31153838Sdfr#include <dlfcn.h> 32153838Sdfr#include <errno.h> 33153838Sdfr#include <stdio.h> 34153838Sdfr#include <stdlib.h> 35153838Sdfr#include <string.h> 36153838Sdfr 37153838Sdfr#include "mech_switch.h" 38153838Sdfr#include "utils.h" 39153838Sdfr 40153838Sdfr#ifndef _PATH_GSS_MECH 41153838Sdfr#define _PATH_GSS_MECH "/etc/gss/mech" 42153838Sdfr#endif 43153838Sdfr 44153838Sdfrstruct _gss_mech_switch_list _gss_mechs = 45201145Santoine SLIST_HEAD_INITIALIZER(_gss_mechs); 46153838Sdfrgss_OID_set _gss_mech_oids; 47153838Sdfr 48153838Sdfr/* 49153838Sdfr * Convert a string containing an OID in 'dot' form 50153838Sdfr * (e.g. 1.2.840.113554.1.2.2) to a gss_OID. 51153838Sdfr */ 52153838Sdfrstatic int 53153838Sdfr_gss_string_to_oid(const char* s, gss_OID oid) 54153838Sdfr{ 55153838Sdfr int number_count, i, j; 56153838Sdfr int byte_count; 57153838Sdfr const char *p, *q; 58153838Sdfr char *res; 59153838Sdfr 60178828Sdfr oid->length = 0; 61178828Sdfr oid->elements = NULL; 62178828Sdfr 63153838Sdfr /* 64153838Sdfr * First figure out how many numbers in the oid, then 65153838Sdfr * calculate the compiled oid size. 66153838Sdfr */ 67153838Sdfr number_count = 0; 68153838Sdfr for (p = s; p; p = q) { 69153838Sdfr q = strchr(p, '.'); 70153838Sdfr if (q) q = q + 1; 71153838Sdfr number_count++; 72153838Sdfr } 73153838Sdfr 74153838Sdfr /* 75153838Sdfr * The first two numbers are in the first byte and each 76153838Sdfr * subsequent number is encoded in a variable byte sequence. 77153838Sdfr */ 78153838Sdfr if (number_count < 2) 79153838Sdfr return (EINVAL); 80153838Sdfr 81153838Sdfr /* 82153838Sdfr * We do this in two passes. The first pass, we just figure 83153838Sdfr * out the size. Second time around, we actually encode the 84153838Sdfr * number. 85153838Sdfr */ 86153838Sdfr res = 0; 87153838Sdfr for (i = 0; i < 2; i++) { 88153838Sdfr byte_count = 0; 89153838Sdfr for (p = s, j = 0; p; p = q, j++) { 90153838Sdfr unsigned int number = 0; 91153838Sdfr 92153838Sdfr /* 93153838Sdfr * Find the end of this number. 94153838Sdfr */ 95153838Sdfr q = strchr(p, '.'); 96153838Sdfr if (q) q = q + 1; 97153838Sdfr 98153838Sdfr /* 99153838Sdfr * Read the number of of the string. Don't 100153838Sdfr * bother with anything except base ten. 101153838Sdfr */ 102153838Sdfr while (*p && *p != '.') { 103153838Sdfr number = 10 * number + (*p - '0'); 104153838Sdfr p++; 105153838Sdfr } 106153838Sdfr 107153838Sdfr /* 108153838Sdfr * Encode the number. The first two numbers 109153838Sdfr * are packed into the first byte. Subsequent 110153838Sdfr * numbers are encoded in bytes seven bits at 111153838Sdfr * a time with the last byte having the high 112153838Sdfr * bit set. 113153838Sdfr */ 114153838Sdfr if (j == 0) { 115153838Sdfr if (res) 116153838Sdfr *res = number * 40; 117153838Sdfr } else if (j == 1) { 118153838Sdfr if (res) { 119153838Sdfr *res += number; 120153838Sdfr res++; 121153838Sdfr } 122153838Sdfr byte_count++; 123153838Sdfr } else if (j >= 2) { 124153838Sdfr /* 125153838Sdfr * The number is encoded in seven bit chunks. 126153838Sdfr */ 127153838Sdfr unsigned int t; 128153838Sdfr int bytes; 129153838Sdfr 130153838Sdfr bytes = 0; 131153838Sdfr for (t = number; t; t >>= 7) 132153838Sdfr bytes++; 133153838Sdfr if (bytes == 0) bytes = 1; 134153838Sdfr while (bytes) { 135153838Sdfr if (res) { 136153838Sdfr int bit = 7*(bytes-1); 137153838Sdfr 138153838Sdfr *res = (number >> bit) & 0x7f; 139153838Sdfr if (bytes != 1) 140153838Sdfr *res |= 0x80; 141153838Sdfr res++; 142153838Sdfr } 143153838Sdfr byte_count++; 144153838Sdfr bytes--; 145153838Sdfr } 146153838Sdfr } 147153838Sdfr } 148153838Sdfr if (!res) { 149153838Sdfr res = malloc(byte_count); 150153838Sdfr if (!res) 151153838Sdfr return (ENOMEM); 152153838Sdfr oid->length = byte_count; 153153838Sdfr oid->elements = res; 154153838Sdfr } 155153838Sdfr } 156153838Sdfr 157153838Sdfr return (0); 158153838Sdfr} 159153838Sdfr 160153838Sdfr 161178828Sdfr#define SYM(name) \ 162178828Sdfrdo { \ 163178828Sdfr snprintf(buf, sizeof(buf), "%s_%s", \ 164178828Sdfr m->gm_name_prefix, #name); \ 165178828Sdfr m->gm_ ## name = dlsym(so, buf); \ 166178828Sdfr if (!m->gm_ ## name) { \ 167178828Sdfr fprintf(stderr, "can't find symbol %s\n", buf); \ 168178828Sdfr goto bad; \ 169178828Sdfr } \ 170153838Sdfr} while (0) 171153838Sdfr 172178828Sdfr#define OPTSYM(name) \ 173178828Sdfrdo { \ 174178828Sdfr snprintf(buf, sizeof(buf), "%s_%s", \ 175178828Sdfr m->gm_name_prefix, #name); \ 176178828Sdfr m->gm_ ## name = dlsym(so, buf); \ 177153838Sdfr} while (0) 178153838Sdfr 179153838Sdfr/* 180153838Sdfr * Load the mechanisms file (/etc/gss/mech). 181153838Sdfr */ 182153838Sdfrvoid 183153838Sdfr_gss_load_mech(void) 184153838Sdfr{ 185153838Sdfr OM_uint32 major_status, minor_status; 186153838Sdfr FILE *fp; 187153838Sdfr char buf[256]; 188153838Sdfr char *p; 189153838Sdfr char *name, *oid, *lib, *kobj; 190153838Sdfr struct _gss_mech_switch *m; 191153838Sdfr int count; 192153838Sdfr void *so; 193178828Sdfr const char *(*prefix_fn)(void); 194153838Sdfr 195153838Sdfr if (SLIST_FIRST(&_gss_mechs)) 196153838Sdfr return; 197153838Sdfr 198153838Sdfr major_status = gss_create_empty_oid_set(&minor_status, 199153838Sdfr &_gss_mech_oids); 200153838Sdfr if (major_status) 201153838Sdfr return; 202153838Sdfr 203153838Sdfr fp = fopen(_PATH_GSS_MECH, "r"); 204153838Sdfr if (!fp) { 205153838Sdfr perror(_PATH_GSS_MECH); 206153838Sdfr return; 207153838Sdfr } 208153838Sdfr 209153838Sdfr count = 0; 210153838Sdfr while (fgets(buf, sizeof(buf), fp)) { 211153838Sdfr if (*buf == '#') 212153838Sdfr continue; 213153838Sdfr p = buf; 214153838Sdfr name = strsep(&p, "\t\n "); 215155287Sdfr if (p) while (isspace(*p)) p++; 216153838Sdfr oid = strsep(&p, "\t\n "); 217155287Sdfr if (p) while (isspace(*p)) p++; 218153838Sdfr lib = strsep(&p, "\t\n "); 219155287Sdfr if (p) while (isspace(*p)) p++; 220153838Sdfr kobj = strsep(&p, "\t\n "); 221153838Sdfr if (!name || !oid || !lib || !kobj) 222153838Sdfr continue; 223153838Sdfr 224153838Sdfr so = dlopen(lib, RTLD_LOCAL); 225153838Sdfr if (!so) { 226153838Sdfr fprintf(stderr, "dlopen: %s\n", dlerror()); 227153838Sdfr continue; 228153838Sdfr } 229153838Sdfr 230153838Sdfr m = malloc(sizeof(struct _gss_mech_switch)); 231153838Sdfr if (!m) 232153838Sdfr break; 233153838Sdfr m->gm_so = so; 234153838Sdfr if (_gss_string_to_oid(oid, &m->gm_mech_oid)) { 235153838Sdfr free(m); 236153838Sdfr continue; 237153838Sdfr } 238153838Sdfr 239178828Sdfr prefix_fn = (const char *(*)(void)) 240178828Sdfr dlsym(so, "_gss_name_prefix"); 241178828Sdfr if (prefix_fn) 242178828Sdfr m->gm_name_prefix = prefix_fn(); 243178828Sdfr else 244178828Sdfr m->gm_name_prefix = "gss"; 245178828Sdfr 246153838Sdfr major_status = gss_add_oid_set_member(&minor_status, 247153838Sdfr &m->gm_mech_oid, &_gss_mech_oids); 248153838Sdfr if (major_status) { 249153838Sdfr free(m->gm_mech_oid.elements); 250153838Sdfr free(m); 251153838Sdfr continue; 252153838Sdfr } 253153838Sdfr 254153838Sdfr SYM(acquire_cred); 255153838Sdfr SYM(release_cred); 256153838Sdfr SYM(init_sec_context); 257153838Sdfr SYM(accept_sec_context); 258153838Sdfr SYM(process_context_token); 259153838Sdfr SYM(delete_sec_context); 260153838Sdfr SYM(context_time); 261153838Sdfr SYM(get_mic); 262153838Sdfr SYM(verify_mic); 263153838Sdfr SYM(wrap); 264153838Sdfr SYM(unwrap); 265153838Sdfr SYM(display_status); 266178828Sdfr OPTSYM(indicate_mechs); 267153838Sdfr SYM(compare_name); 268153838Sdfr SYM(display_name); 269153838Sdfr SYM(import_name); 270153838Sdfr SYM(export_name); 271153838Sdfr SYM(release_name); 272153838Sdfr SYM(inquire_cred); 273153838Sdfr SYM(inquire_context); 274153838Sdfr SYM(wrap_size_limit); 275153838Sdfr SYM(add_cred); 276153838Sdfr SYM(inquire_cred_by_mech); 277153838Sdfr SYM(export_sec_context); 278153838Sdfr SYM(import_sec_context); 279153838Sdfr SYM(inquire_names_for_mech); 280153838Sdfr SYM(inquire_mechs_for_name); 281153838Sdfr SYM(canonicalize_name); 282153838Sdfr SYM(duplicate_name); 283178828Sdfr OPTSYM(inquire_sec_context_by_oid); 284178828Sdfr OPTSYM(inquire_cred_by_oid); 285178828Sdfr OPTSYM(set_sec_context_option); 286178828Sdfr OPTSYM(set_cred_option); 287178828Sdfr OPTSYM(pseudo_random); 288181344Sdfr OPTSYM(pname_to_uid); 289153838Sdfr 290153838Sdfr SLIST_INSERT_HEAD(&_gss_mechs, m, gm_link); 291153838Sdfr count++; 292153838Sdfr continue; 293153838Sdfr 294153838Sdfr bad: 295153838Sdfr free(m->gm_mech_oid.elements); 296153838Sdfr free(m); 297153838Sdfr dlclose(so); 298153838Sdfr continue; 299153838Sdfr } 300153838Sdfr fclose(fp); 301153838Sdfr} 302153838Sdfr 303153838Sdfrstruct _gss_mech_switch * 304153838Sdfr_gss_find_mech_switch(gss_OID mech) 305153838Sdfr{ 306153838Sdfr struct _gss_mech_switch *m; 307153838Sdfr 308153838Sdfr _gss_load_mech(); 309153838Sdfr SLIST_FOREACH(m, &_gss_mechs, gm_link) { 310178828Sdfr if (gss_oid_equal(&m->gm_mech_oid, mech)) 311153838Sdfr return m; 312153838Sdfr } 313153838Sdfr return (0); 314153838Sdfr} 315