Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/heimdal/lib/gssapi/mech/gss_mech_switch.c
34907 views
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>
31
32
#ifndef _PATH_GSS_MECH
33
#define _PATH_GSS_MECH "/etc/gss/mech"
34
#endif
35
36
struct _gss_mech_switch_list _gss_mechs = { NULL } ;
37
gss_OID_set _gss_mech_oids;
38
static HEIMDAL_MUTEX _gss_mech_mutex = HEIMDAL_MUTEX_INITIALIZER;
39
40
/*
41
* Convert a string containing an OID in 'dot' form
42
* (e.g. 1.2.840.113554.1.2.2) to a gss_OID.
43
*/
44
static int
45
_gss_string_to_oid(const char* s, gss_OID oid)
46
{
47
int number_count, i, j;
48
size_t byte_count;
49
const char *p, *q;
50
char *res;
51
52
oid->length = 0;
53
oid->elements = NULL;
54
55
/*
56
* First figure out how many numbers in the oid, then
57
* calculate the compiled oid size.
58
*/
59
number_count = 0;
60
for (p = s; p; p = q) {
61
q = strchr(p, '.');
62
if (q) q = q + 1;
63
number_count++;
64
}
65
66
/*
67
* The first two numbers are in the first byte and each
68
* subsequent number is encoded in a variable byte sequence.
69
*/
70
if (number_count < 2)
71
return (EINVAL);
72
73
/*
74
* We do this in two passes. The first pass, we just figure
75
* out the size. Second time around, we actually encode the
76
* number.
77
*/
78
res = 0;
79
for (i = 0; i < 2; i++) {
80
byte_count = 0;
81
for (p = s, j = 0; p; p = q, j++) {
82
unsigned int number = 0;
83
84
/*
85
* Find the end of this number.
86
*/
87
q = strchr(p, '.');
88
if (q) q = q + 1;
89
90
/*
91
* Read the number of of the string. Don't
92
* bother with anything except base ten.
93
*/
94
while (*p && *p != '.') {
95
number = 10 * number + (*p - '0');
96
p++;
97
}
98
99
/*
100
* Encode the number. The first two numbers
101
* are packed into the first byte. Subsequent
102
* numbers are encoded in bytes seven bits at
103
* a time with the last byte having the high
104
* bit set.
105
*/
106
if (j == 0) {
107
if (res)
108
*res = number * 40;
109
} else if (j == 1) {
110
if (res) {
111
*res += number;
112
res++;
113
}
114
byte_count++;
115
} else if (j >= 2) {
116
/*
117
* The number is encoded in seven bit chunks.
118
*/
119
unsigned int t;
120
unsigned int bytes;
121
122
bytes = 0;
123
for (t = number; t; t >>= 7)
124
bytes++;
125
if (bytes == 0) bytes = 1;
126
while (bytes) {
127
if (res) {
128
int bit = 7*(bytes-1);
129
130
*res = (number >> bit) & 0x7f;
131
if (bytes != 1)
132
*res |= 0x80;
133
res++;
134
}
135
byte_count++;
136
bytes--;
137
}
138
}
139
}
140
if (byte_count == 0)
141
return EINVAL;
142
if (!res) {
143
res = malloc(byte_count);
144
if (!res)
145
return (ENOMEM);
146
oid->length = byte_count;
147
oid->elements = res;
148
}
149
}
150
151
return (0);
152
}
153
154
#define SYM(name) \
155
do { \
156
m->gm_mech.gm_ ## name = dlsym(so, "gss_" #name); \
157
if (!m->gm_mech.gm_ ## name || \
158
m->gm_mech.gm_ ##name == gss_ ## name) { \
159
fprintf(stderr, "can't find symbol gss_" #name "\n"); \
160
goto bad; \
161
} \
162
} while (0)
163
164
#define OPTSYM(name) \
165
do { \
166
m->gm_mech.gm_ ## name = dlsym(so, "gss_" #name); \
167
if (m->gm_mech.gm_ ## name == gss_ ## name) \
168
m->gm_mech.gm_ ## name = NULL; \
169
} while (0)
170
171
#define OPTSPISYM(name) \
172
do { \
173
m->gm_mech.gm_ ## name = dlsym(so, "gssspi_" #name); \
174
} while (0)
175
176
#define COMPATSYM(name) \
177
do { \
178
m->gm_mech.gm_compat->gmc_ ## name = dlsym(so, "gss_" #name); \
179
if (m->gm_mech.gm_compat->gmc_ ## name == gss_ ## name) \
180
m->gm_mech.gm_compat->gmc_ ## name = NULL; \
181
} while (0)
182
183
#define COMPATSPISYM(name) \
184
do { \
185
m->gm_mech.gm_compat->gmc_ ## name = dlsym(so, "gssspi_" #name);\
186
if (m->gm_mech.gm_compat->gmc_ ## name == gss_ ## name) \
187
m->gm_mech.gm_compat->gmc_ ## name = NULL; \
188
} while (0)
189
190
/*
191
*
192
*/
193
static int
194
add_builtin(gssapi_mech_interface mech)
195
{
196
struct _gss_mech_switch *m;
197
OM_uint32 minor_status;
198
199
/* not registering any mech is ok */
200
if (mech == NULL)
201
return 0;
202
203
m = calloc(1, sizeof(*m));
204
if (m == NULL)
205
return ENOMEM;
206
m->gm_so = NULL;
207
m->gm_mech = *mech;
208
m->gm_mech_oid = mech->gm_mech_oid; /* XXX */
209
gss_add_oid_set_member(&minor_status,
210
&m->gm_mech.gm_mech_oid, &_gss_mech_oids);
211
212
/* pick up the oid sets of names */
213
214
if (m->gm_mech.gm_inquire_names_for_mech)
215
(*m->gm_mech.gm_inquire_names_for_mech)(&minor_status,
216
&m->gm_mech.gm_mech_oid, &m->gm_name_types);
217
218
if (m->gm_name_types == NULL)
219
gss_create_empty_oid_set(&minor_status, &m->gm_name_types);
220
221
HEIM_SLIST_INSERT_HEAD(&_gss_mechs, m, gm_link);
222
return 0;
223
}
224
225
/*
226
* Load the mechanisms file (/etc/gss/mech).
227
*/
228
void
229
_gss_load_mech(void)
230
{
231
OM_uint32 major_status, minor_status;
232
FILE *fp;
233
char buf[256];
234
char *p;
235
char *name, *oid, *lib, *kobj;
236
struct _gss_mech_switch *m;
237
void *so;
238
gss_OID_desc mech_oid;
239
int found;
240
241
242
HEIMDAL_MUTEX_lock(&_gss_mech_mutex);
243
244
if (HEIM_SLIST_FIRST(&_gss_mechs)) {
245
HEIMDAL_MUTEX_unlock(&_gss_mech_mutex);
246
return;
247
}
248
249
major_status = gss_create_empty_oid_set(&minor_status,
250
&_gss_mech_oids);
251
if (major_status) {
252
HEIMDAL_MUTEX_unlock(&_gss_mech_mutex);
253
return;
254
}
255
256
add_builtin(__gss_krb5_initialize());
257
add_builtin(__gss_spnego_initialize());
258
add_builtin(__gss_ntlm_initialize());
259
260
#ifdef HAVE_DLOPEN
261
fp = fopen(_PATH_GSS_MECH, "r");
262
if (!fp) {
263
HEIMDAL_MUTEX_unlock(&_gss_mech_mutex);
264
return;
265
}
266
rk_cloexec_file(fp);
267
268
while (fgets(buf, sizeof(buf), fp)) {
269
_gss_mo_init *mi;
270
271
if (*buf == '#')
272
continue;
273
p = buf;
274
name = strsep(&p, "\t\n ");
275
if (p) while (isspace((unsigned char)*p)) p++;
276
oid = strsep(&p, "\t\n ");
277
if (p) while (isspace((unsigned char)*p)) p++;
278
lib = strsep(&p, "\t\n ");
279
if (p) while (isspace((unsigned char)*p)) p++;
280
kobj = strsep(&p, "\t\n ");
281
if (!name || !oid || !lib || !kobj)
282
continue;
283
284
if (_gss_string_to_oid(oid, &mech_oid))
285
continue;
286
287
/*
288
* Check for duplicates, already loaded mechs.
289
*/
290
found = 0;
291
HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) {
292
if (gss_oid_equal(&m->gm_mech.gm_mech_oid, &mech_oid)) {
293
found = 1;
294
free(mech_oid.elements);
295
break;
296
}
297
}
298
if (found)
299
continue;
300
301
#ifndef RTLD_LOCAL
302
#define RTLD_LOCAL 0
303
#endif
304
305
#ifndef RTLD_GROUP
306
#define RTLD_GROUP 0
307
#endif
308
309
so = dlopen(lib, RTLD_LAZY | RTLD_LOCAL | RTLD_GROUP);
310
if (so == NULL) {
311
/* fprintf(stderr, "dlopen: %s\n", dlerror()); */
312
goto bad;
313
}
314
315
m = calloc(1, sizeof(*m));
316
if (m == NULL)
317
goto bad;
318
319
m->gm_so = so;
320
m->gm_mech.gm_mech_oid = mech_oid;
321
m->gm_mech.gm_flags = 0;
322
m->gm_mech.gm_compat = calloc(1, sizeof(struct gss_mech_compat_desc_struct));
323
if (m->gm_mech.gm_compat == NULL)
324
goto bad;
325
326
major_status = gss_add_oid_set_member(&minor_status,
327
&m->gm_mech.gm_mech_oid, &_gss_mech_oids);
328
if (GSS_ERROR(major_status))
329
goto bad;
330
331
SYM(acquire_cred);
332
SYM(release_cred);
333
SYM(init_sec_context);
334
SYM(accept_sec_context);
335
SYM(process_context_token);
336
SYM(delete_sec_context);
337
SYM(context_time);
338
SYM(get_mic);
339
SYM(verify_mic);
340
SYM(wrap);
341
SYM(unwrap);
342
SYM(display_status);
343
SYM(indicate_mechs);
344
SYM(compare_name);
345
SYM(display_name);
346
SYM(import_name);
347
SYM(export_name);
348
SYM(release_name);
349
SYM(inquire_cred);
350
SYM(inquire_context);
351
SYM(wrap_size_limit);
352
SYM(add_cred);
353
SYM(inquire_cred_by_mech);
354
SYM(export_sec_context);
355
SYM(import_sec_context);
356
SYM(inquire_names_for_mech);
357
SYM(inquire_mechs_for_name);
358
SYM(canonicalize_name);
359
SYM(duplicate_name);
360
OPTSYM(inquire_cred_by_oid);
361
OPTSYM(inquire_sec_context_by_oid);
362
OPTSYM(set_sec_context_option);
363
OPTSPISYM(set_cred_option);
364
OPTSYM(pseudo_random);
365
OPTSYM(wrap_iov);
366
OPTSYM(unwrap_iov);
367
OPTSYM(wrap_iov_length);
368
OPTSYM(store_cred);
369
OPTSYM(export_cred);
370
OPTSYM(import_cred);
371
#if 0
372
OPTSYM(acquire_cred_ext);
373
OPTSYM(iter_creds);
374
OPTSYM(destroy_cred);
375
OPTSYM(cred_hold);
376
OPTSYM(cred_unhold);
377
OPTSYM(cred_label_get);
378
OPTSYM(cred_label_set);
379
#endif
380
OPTSYM(display_name_ext);
381
OPTSYM(inquire_name);
382
OPTSYM(get_name_attribute);
383
OPTSYM(set_name_attribute);
384
OPTSYM(delete_name_attribute);
385
OPTSYM(export_name_composite);
386
OPTSYM(pname_to_uid);
387
OPTSPISYM(authorize_localname);
388
389
mi = dlsym(so, "gss_mo_init");
390
if (mi != NULL) {
391
major_status = mi(&minor_status, &mech_oid,
392
&m->gm_mech.gm_mo, &m->gm_mech.gm_mo_num);
393
if (GSS_ERROR(major_status))
394
goto bad;
395
} else {
396
/* API-as-SPI compatibility */
397
COMPATSYM(inquire_saslname_for_mech);
398
COMPATSYM(inquire_mech_for_saslname);
399
COMPATSYM(inquire_attrs_for_mech);
400
COMPATSPISYM(acquire_cred_with_password);
401
}
402
403
/* pick up the oid sets of names */
404
405
if (m->gm_mech.gm_inquire_names_for_mech)
406
(*m->gm_mech.gm_inquire_names_for_mech)(&minor_status,
407
&m->gm_mech.gm_mech_oid, &m->gm_name_types);
408
409
if (m->gm_name_types == NULL)
410
gss_create_empty_oid_set(&minor_status, &m->gm_name_types);
411
412
HEIM_SLIST_INSERT_HEAD(&_gss_mechs, m, gm_link);
413
continue;
414
415
bad:
416
if (m != NULL) {
417
free(m->gm_mech.gm_compat);
418
free(m->gm_mech.gm_mech_oid.elements);
419
free(m);
420
}
421
dlclose(so);
422
continue;
423
}
424
fclose(fp);
425
#endif
426
HEIMDAL_MUTEX_unlock(&_gss_mech_mutex);
427
}
428
429
gssapi_mech_interface
430
__gss_get_mechanism(gss_const_OID mech)
431
{
432
struct _gss_mech_switch *m;
433
434
_gss_load_mech();
435
HEIM_SLIST_FOREACH(m, &_gss_mechs, gm_link) {
436
if (gss_oid_equal(&m->gm_mech.gm_mech_oid, mech))
437
return &m->gm_mech;
438
}
439
return NULL;
440
}
441
442