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$ 27 */ 28 29 #include <gssapi/gssapi.h> 30 #include <dlfcn.h> 31 #include <errno.h> 32 #include <stdio.h> 33 #include <stdlib.h> 34 #include <string.h> 35 36 #include "mech_switch.h" 37 #include "utils.h" 38 39 #ifndef _PATH_GSS_MECH 40 #define _PATH_GSS_MECH "/etc/gss/mech" 41 #endif 42 43 struct _gss_mech_switch_list _gss_mechs = 44 SLIST_HEAD_INITIALIZER(&_gss_mechs); 45 gss_OID_set _gss_mech_oids; 46 47 /* 48 * Convert a string containing an OID in 'dot' form 49 * (e.g. 1.2.840.113554.1.2.2) to a gss_OID. 50 */ 51 static int 52 _gss_string_to_oid(const char* s, gss_OID oid) 53 { 54 int number_count, i, j; 55 int byte_count; 56 const char *p, *q; 57 char *res; 58 59 /* 60 * First figure out how many numbers in the oid, then 61 * calculate the compiled oid size. 62 */ 63 number_count = 0; 64 for (p = s; p; p = q) { 65 q = strchr(p, '.'); 66 if (q) q = q + 1; 67 number_count++; 68 } 69 70 /* 71 * The first two numbers are in the first byte and each 72 * subsequent number is encoded in a variable byte sequence. 73 */ 74 if (number_count < 2) 75 return (EINVAL); 76 77 /* 78 * We do this in two passes. The first pass, we just figure 79 * out the size. Second time around, we actually encode the 80 * number. 81 */ 82 res = 0; 83 for (i = 0; i < 2; i++) { 84 byte_count = 0; 85 for (p = s, j = 0; p; p = q, j++) { 86 unsigned int number = 0; 87 88 /* 89 * Find the end of this number. 90 */ 91 q = strchr(p, '.'); 92 if (q) q = q + 1; 93 94 /* 95 * Read the number of of the string. Don't 96 * bother with anything except base ten. 97 */ 98 while (*p && *p != '.') { 99 number = 10 * number + (*p - '0'); 100 p++; 101 } 102 103 /* 104 * Encode the number. The first two numbers 105 * are packed into the first byte. Subsequent 106 * numbers are encoded in bytes seven bits at 107 * a time with the last byte having the high 108 * bit set. 109 */ 110 if (j == 0) { 111 if (res) 112 *res = number * 40; 113 } else if (j == 1) { 114 if (res) { 115 *res += number; 116 res++; 117 } 118 byte_count++; 119 } else if (j >= 2) { 120 /* 121 * The number is encoded in seven bit chunks. 122 */ 123 unsigned int t; 124 int bytes; 125 126 bytes = 0; 127 for (t = number; t; t >>= 7) 128 bytes++; 129 if (bytes == 0) bytes = 1; 130 while (bytes) { 131 if (res) { 132 int bit = 7*(bytes-1); 133 134 *res = (number >> bit) & 0x7f; 135 if (bytes != 1) 136 *res |= 0x80; 137 res++; 138 } 139 byte_count++; 140 bytes--; 141 } 142 } 143 } 144 if (!res) { 145 res = malloc(byte_count); 146 if (!res) 147 return (ENOMEM); 148 oid->length = byte_count; 149 oid->elements = res; 150 } 151 } 152 153 return (0); 154 } 155 156 #define SYM(name) \ 157 do { \ 158 m->gm_ ## name = dlsym(so, "gss_" #name); \ 159 if (!m->gm_ ## name) { \ 160 fprintf(stderr, "can't find symbol gss_" #name "\n"); \ 161 goto bad; \ 162 } \ 163 } while (0) 164 165 #define OPTSYM(name) \ 166 do { \ 167 m->gm_ ## name = dlsym(so, "gss_" #name); \ 168 } while (0) 169 170 #define OPTSYM2(symname, ourname) \ 171 do { \ 172 m->ourname = dlsym(so, #symname); \ 173 } while (0) 174 175 /* 176 * Load the mechanisms file (/etc/gss/mech). 177 */ 178 void 179 _gss_load_mech(void) 180 { 181 OM_uint32 major_status, minor_status; 182 FILE *fp; 183 char buf[256]; 184 char *p; 185 char *name, *oid, *lib, *kobj; 186 struct _gss_mech_switch *m; 187 int count; 188 char **pp; 189 void *so; 190 191 if (SLIST_FIRST(&_gss_mechs)) 192 return; 193 194 major_status = gss_create_empty_oid_set(&minor_status, 195 &_gss_mech_oids); 196 if (major_status) 197 return; 198 199 fp = fopen(_PATH_GSS_MECH, "r"); 200 if (!fp) { 201 perror(_PATH_GSS_MECH); 202 return; 203 } 204 205 count = 0; 206 while (fgets(buf, sizeof(buf), fp)) { 207 if (*buf == '#') 208 continue; 209 p = buf; 210 name = strsep(&p, "\t\n "); 211 if (p) while (isspace(*p)) p++; 212 oid = strsep(&p, "\t\n "); 213 if (p) while (isspace(*p)) p++; 214 lib = strsep(&p, "\t\n "); 215 if (p) while (isspace(*p)) p++; 216 kobj = strsep(&p, "\t\n "); 217 if (!name || !oid || !lib || !kobj) 218 continue; 219 220 so = dlopen(lib, RTLD_LOCAL); 221 if (!so) { 222 fprintf(stderr, "dlopen: %s\n", dlerror()); 223 continue; 224 } 225 226 m = malloc(sizeof(struct _gss_mech_switch)); 227 if (!m) 228 break; 229 m->gm_so = so; 230 if (_gss_string_to_oid(oid, &m->gm_mech_oid)) { 231 free(m); 232 continue; 233 } 234 235 major_status = gss_add_oid_set_member(&minor_status, 236 &m->gm_mech_oid, &_gss_mech_oids); 237 if (major_status) { 238 free(m->gm_mech_oid.elements); 239 free(m); 240 continue; 241 } 242 243 SYM(acquire_cred); 244 SYM(release_cred); 245 SYM(init_sec_context); 246 SYM(accept_sec_context); 247 SYM(process_context_token); 248 SYM(delete_sec_context); 249 SYM(context_time); 250 SYM(get_mic); 251 SYM(verify_mic); 252 SYM(wrap); 253 SYM(unwrap); 254 SYM(display_status); 255 SYM(indicate_mechs); 256 SYM(compare_name); 257 SYM(display_name); 258 SYM(import_name); 259 SYM(export_name); 260 SYM(release_name); 261 SYM(inquire_cred); 262 SYM(inquire_context); 263 SYM(wrap_size_limit); 264 SYM(add_cred); 265 SYM(inquire_cred_by_mech); 266 SYM(export_sec_context); 267 SYM(import_sec_context); 268 SYM(inquire_names_for_mech); 269 SYM(inquire_mechs_for_name); 270 SYM(canonicalize_name); 271 SYM(duplicate_name); 272 OPTSYM2(gsskrb5_register_acceptor_identity, 273 gm_krb5_register_acceptor_identity); 274 OPTSYM(krb5_copy_ccache); 275 OPTSYM(krb5_compat_des3_mic); 276 277 SLIST_INSERT_HEAD(&_gss_mechs, m, gm_link); 278 count++; 279 continue; 280 281 bad: 282 free(m->gm_mech_oid.elements); 283 free(m); 284 dlclose(so); 285 continue; 286 } 287 fclose(fp); 288 } 289 290 struct _gss_mech_switch * 291 _gss_find_mech_switch(gss_OID mech) 292 { 293 struct _gss_mech_switch *m; 294 295 _gss_load_mech(); 296 SLIST_FOREACH(m, &_gss_mechs, gm_link) { 297 if (_gss_oid_equal(&m->gm_mech_oid, mech)) 298 return m; 299 } 300 return (0); 301 } 302