2 * Copyright (c) 2008 Doug Rabson
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
34 #include <sys/queue.h>
36 #include <rpc/rpcsec_gss.h>
38 #include "rpcsec_gss_int.h"
40 #ifndef _PATH_GSS_MECH
41 #define _PATH_GSS_MECH "/etc/gss/mech"
45 #define _PATH_GSS_QOP "/etc/gss/qop"
49 SLIST_ENTRY(mech_info) link;
56 SLIST_HEAD(mech_info_list, mech_info);
58 static struct mech_info_list mechs = SLIST_HEAD_INITIALIZER(mechs);
59 static const char **mech_names;
62 SLIST_ENTRY(qop_info) link;
67 SLIST_HEAD(qop_info_list, qop_info);
69 static struct qop_info_list qops = SLIST_HEAD_INITIALIZER(qops);
72 _rpc_gss_string_to_oid(const char* s, gss_OID oid)
74 int number_count, i, j;
80 * First figure out how many numbers in the oid, then
81 * calculate the compiled oid size.
84 for (p = s; p; p = q) {
91 * The first two numbers are in the first byte and each
92 * subsequent number is encoded in a variable byte sequence.
98 * We do this in two passes. The first pass, we just figure
99 * out the size. Second time around, we actually encode the
103 for (i = 0; i < 2; i++) {
105 for (p = s, j = 0; p; p = q, j++) {
109 * Find the end of this number.
115 * Read the number of of the string. Don't
116 * bother with anything except base ten.
118 while (*p && *p != '.') {
119 number = 10 * number + (*p - '0');
124 * Encode the number. The first two numbers
125 * are packed into the first byte. Subsequent
126 * numbers are encoded in bytes seven bits at
127 * a time with the last byte having the high
141 * The number is encoded in seven bit chunks.
147 for (t = number; t; t >>= 7)
149 if (bytes == 0) bytes = 1;
152 int bit = 7*(bytes-1);
154 *res = (number >> bit) & 0x7f;
165 res = malloc(byte_count);
168 oid->length = byte_count;
177 _rpc_gss_load_mech(void)
182 char *name, *oid, *lib, *kobj;
183 struct mech_info *info;
187 if (SLIST_FIRST(&mechs))
190 fp = fopen(_PATH_GSS_MECH, "r");
195 while (fgets(buf, sizeof(buf), fp)) {
199 name = strsep(&p, "\t\n ");
200 if (p) while (isspace(*p)) p++;
201 oid = strsep(&p, "\t\n ");
202 if (p) while (isspace(*p)) p++;
203 lib = strsep(&p, "\t\n ");
204 if (p) while (isspace(*p)) p++;
205 kobj = strsep(&p, "\t\n ");
206 if (!name || !oid || !lib || !kobj)
209 info = malloc(sizeof(struct mech_info));
212 if (_rpc_gss_string_to_oid(oid, &info->oid)) {
216 info->name = strdup(name);
218 info->lib = strdup(lib);
219 info->kobj = strdup(kobj);
220 SLIST_INSERT_HEAD(&mechs, info, link);
225 mech_names = malloc((count + 1) * sizeof(char*));
227 SLIST_FOREACH(info, &mechs, link) {
234 _rpc_gss_load_qop(void)
239 char *name, *num, *mech;
240 struct mech_info *minfo;
241 struct qop_info *info;
243 const char **mech_qops;
246 if (SLIST_FIRST(&qops))
249 fp = fopen(_PATH_GSS_QOP, "r");
253 while (fgets(buf, sizeof(buf), fp)) {
257 name = strsep(&p, "\t\n ");
258 if (p) while (isspace(*p)) p++;
259 num = strsep(&p, "\t\n ");
260 if (p) while (isspace(*p)) p++;
261 mech = strsep(&p, "\t\n ");
262 if (!name || !num || !mech)
265 info = malloc(sizeof(struct qop_info));
268 info->name = strdup(name);
269 info->qop = strtoul(name, 0, 0);
270 info->mech = strdup(mech);
271 SLIST_INSERT_HEAD(&qops, info, link);
276 * Compile lists of qops for each mechanism.
278 SLIST_FOREACH(minfo, &mechs, link) {
280 SLIST_FOREACH(info, &qops, link) {
281 if (strcmp(info->mech, minfo->name) == 0)
284 mech_qops = malloc((count + 1) * sizeof(char*));
286 SLIST_FOREACH(info, &qops, link) {
287 if (strcmp(info->mech, minfo->name) == 0)
291 minfo->qops = mech_qops;
296 rpc_gss_mech_to_oid(const char *mech, gss_OID *oid_ret)
298 struct mech_info *info;
300 _rpc_gss_load_mech();
301 SLIST_FOREACH(info, &mechs, link) {
302 if (!strcmp(info->name, mech)) {
303 *oid_ret = &info->oid;
307 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOENT);
312 rpc_gss_oid_to_mech(gss_OID oid, const char **mech_ret)
314 struct mech_info *info;
316 _rpc_gss_load_mech();
317 SLIST_FOREACH(info, &mechs, link) {
318 if (oid->length == info->oid.length
319 && !memcmp(oid->elements, info->oid.elements,
321 *mech_ret = info->name;
325 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOENT);
330 rpc_gss_qop_to_num(const char *qop, const char *mech, u_int *num_ret)
332 struct qop_info *info;
335 SLIST_FOREACH(info, &qops, link) {
336 if (strcmp(info->name, qop) == 0
337 && strcmp(info->mech, mech) == 0) {
338 *num_ret = info->qop;
342 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOENT);
347 _rpc_gss_num_to_qop(const char *mech, u_int num)
349 struct qop_info *info;
351 if (num == GSS_C_QOP_DEFAULT)
355 SLIST_FOREACH(info, &qops, link) {
356 if (info->qop == num && strcmp(info->mech, mech) == 0) {
364 rpc_gss_get_mechanisms(void)
367 _rpc_gss_load_mech();
372 rpc_gss_get_mech_info(const char *mech, rpc_gss_service_t *service)
374 struct mech_info *info;
376 _rpc_gss_load_mech();
378 SLIST_FOREACH(info, &mechs, link) {
379 if (!strcmp(mech, info->name)) {
381 * I'm not sure what to do with service
382 * here. The Solaris manpages are not clear on
383 * the subject and the OpenSolaris code just
384 * sets it to rpc_gss_svc_privacy
385 * unconditionally with a comment noting that
388 *service = rpc_gss_svc_privacy;
393 _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOENT);
398 rpc_gss_get_versions(u_int *vers_hi, u_int *vers_lo)
407 rpc_gss_is_installed(const char *mech)
409 struct mech_info *info;
411 _rpc_gss_load_mech();
412 SLIST_FOREACH(info, &mechs, link)
413 if (!strcmp(mech, info->name))