]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - lib/librpcsec_gss/rpcsec_gss_conf.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / lib / librpcsec_gss / rpcsec_gss_conf.c
1 /*-
2  * Copyright (c) 2008 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 <ctype.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <stdlib.h>
33 #include <errno.h>
34 #include <sys/queue.h>
35 #include <rpc/rpc.h>
36 #include <rpc/rpcsec_gss.h>
37
38 #include "rpcsec_gss_int.h"
39
40 #ifndef _PATH_GSS_MECH
41 #define _PATH_GSS_MECH  "/etc/gss/mech"
42 #endif
43
44 #ifndef _PATH_GSS_QOP
45 #define _PATH_GSS_QOP   "/etc/gss/qop"
46 #endif
47
48 struct mech_info {
49         SLIST_ENTRY(mech_info) link;
50         char            *name;
51         gss_OID_desc    oid;
52         const char      **qops;
53         char            *lib;
54         char            *kobj;
55 };
56 SLIST_HEAD(mech_info_list, mech_info);
57
58 static struct mech_info_list mechs = SLIST_HEAD_INITIALIZER(mechs);
59 static const char **mech_names;
60
61 struct qop_info {
62         SLIST_ENTRY(qop_info) link;
63         char            *name;
64         char*           mech;
65         u_int           qop;
66 };
67 SLIST_HEAD(qop_info_list, qop_info);
68
69 static struct qop_info_list qops = SLIST_HEAD_INITIALIZER(qops);
70
71 static int
72 _rpc_gss_string_to_oid(const char* s, gss_OID oid)
73 {
74         int                     number_count, i, j;
75         int                     byte_count;
76         const char              *p, *q;
77         char                    *res;
78
79         /*
80          * First figure out how many numbers in the oid, then
81          * calculate the compiled oid size.
82          */
83         number_count = 0;
84         for (p = s; p; p = q) {
85                 q = strchr(p, '.');
86                 if (q) q = q + 1;
87                 number_count++;
88         }
89         
90         /*
91          * The first two numbers are in the first byte and each
92          * subsequent number is encoded in a variable byte sequence.
93          */
94         if (number_count < 2)
95                 return (EINVAL);
96
97         /*
98          * We do this in two passes. The first pass, we just figure
99          * out the size. Second time around, we actually encode the
100          * number.
101          */
102         res = 0;
103         for (i = 0; i < 2; i++) {
104                 byte_count = 0;
105                 for (p = s, j = 0; p; p = q, j++) {
106                         u_int number = 0;
107
108                         /*
109                          * Find the end of this number.
110                          */
111                         q = strchr(p, '.');
112                         if (q) q = q + 1;
113
114                         /*
115                          * Read the number of of the string. Don't
116                          * bother with anything except base ten.
117                          */
118                         while (*p && *p != '.') {
119                                 number = 10 * number + (*p - '0');
120                                 p++;
121                         }
122
123                         /*
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
128                          * bit set.
129                          */
130                         if (j == 0) {
131                                 if (res)
132                                         *res = number * 40;
133                         } else if (j == 1) {
134                                 if (res) {
135                                         *res += number;
136                                         res++;
137                                 }
138                                 byte_count++;
139                         } else if (j >= 2) {
140                                 /*
141                                  * The number is encoded in seven bit chunks.
142                                  */
143                                 u_int t;
144                                 int bytes;
145
146                                 bytes = 0;
147                                 for (t = number; t; t >>= 7)
148                                         bytes++;
149                                 if (bytes == 0) bytes = 1;
150                                 while (bytes) {
151                                         if (res) {
152                                                 int bit = 7*(bytes-1);
153                                                 
154                                                 *res = (number >> bit) & 0x7f;
155                                                 if (bytes != 1)
156                                                         *res |= 0x80;
157                                                 res++;
158                                         }
159                                         byte_count++;
160                                         bytes--;
161                                 }
162                         }
163                 }
164                 if (!res) {
165                         res = malloc(byte_count);
166                         if (!res)
167                                 return (ENOMEM);
168                         oid->length = byte_count;
169                         oid->elements = res;
170                 }
171         }
172
173         return (0);
174 }
175
176 static void
177 _rpc_gss_load_mech(void)
178 {
179         FILE            *fp;
180         char            buf[256];
181         char            *p;
182         char            *name, *oid, *lib, *kobj;
183         struct mech_info *info;
184         int             count;
185         const char      **pp;
186
187         if (SLIST_FIRST(&mechs))
188                 return;
189
190         fp = fopen(_PATH_GSS_MECH, "r");
191         if (!fp)
192                 return;
193
194         count = 0;
195         while (fgets(buf, sizeof(buf), fp)) {
196                 if (*buf == '#')
197                         continue;
198                 p = buf;
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)
207                         continue;
208
209                 info = malloc(sizeof(struct mech_info));
210                 if (!info)
211                         break;
212                 if (_rpc_gss_string_to_oid(oid, &info->oid)) {
213                         free(info);
214                         continue;
215                 }
216                 info->name = strdup(name);
217                 info->qops = NULL;
218                 info->lib = strdup(lib);
219                 info->kobj = strdup(kobj);
220                 SLIST_INSERT_HEAD(&mechs, info, link);
221                 count++;
222         }
223         fclose(fp);
224
225         mech_names = malloc((count + 1) * sizeof(char*));
226         pp = mech_names;
227         SLIST_FOREACH(info, &mechs, link) {
228                 *pp++ = info->name;
229         }
230         *pp = NULL;
231 }
232
233 static void
234 _rpc_gss_load_qop(void)
235 {
236         FILE            *fp;
237         char            buf[256];
238         char            *p;
239         char            *name, *num, *mech;
240         struct mech_info *minfo;
241         struct qop_info *info;
242         int             count;
243         const char      **mech_qops;
244         const char      **pp;
245
246         if (SLIST_FIRST(&qops))
247                 return;
248
249         fp = fopen(_PATH_GSS_QOP, "r");
250         if (!fp)
251                 return;
252
253         while (fgets(buf, sizeof(buf), fp)) {
254                 if (*buf == '#')
255                         continue;
256                 p = buf;
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)
263                         continue;
264
265                 info = malloc(sizeof(struct qop_info));
266                 if (!info)
267                         break;
268                 info->name = strdup(name);
269                 info->qop = strtoul(name, 0, 0);
270                 info->mech = strdup(mech);
271                 SLIST_INSERT_HEAD(&qops, info, link);
272         }
273         fclose(fp);
274
275         /*
276          * Compile lists of qops for each mechanism.
277          */
278         SLIST_FOREACH(minfo, &mechs, link) {
279                 count = 0;
280                 SLIST_FOREACH(info, &qops, link) {
281                         if (strcmp(info->mech, minfo->name) == 0)
282                                 count++;
283                 }
284                 mech_qops = malloc((count + 1) * sizeof(char*));
285                 pp = mech_qops;
286                 SLIST_FOREACH(info, &qops, link) {
287                         if (strcmp(info->mech, minfo->name) == 0)
288                                 *pp++ = info->name;
289                 }
290                 *pp = NULL;
291                 minfo->qops = mech_qops;
292         }
293 }
294
295 bool_t
296 rpc_gss_mech_to_oid(const char *mech, gss_OID *oid_ret)
297 {
298         struct mech_info *info;
299
300         _rpc_gss_load_mech();
301         SLIST_FOREACH(info, &mechs, link) {
302                 if (!strcmp(info->name, mech)) {
303                         *oid_ret = &info->oid;
304                         return (TRUE);
305                 }
306         }
307         _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOENT);
308         return (FALSE);
309 }
310
311 bool_t
312 rpc_gss_oid_to_mech(gss_OID oid, const char **mech_ret)
313 {
314         struct mech_info *info;
315
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,
320                         oid->length)) {
321                         *mech_ret = info->name;
322                         return (TRUE);
323                 }
324         }
325         _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOENT);
326         return (FALSE);
327 }
328
329 bool_t
330 rpc_gss_qop_to_num(const char *qop, const char *mech, u_int *num_ret)
331 {
332         struct qop_info *info;
333
334         _rpc_gss_load_qop();
335         SLIST_FOREACH(info, &qops, link) {
336                 if (strcmp(info->name, qop) == 0
337                     && strcmp(info->mech, mech) == 0) {
338                         *num_ret = info->qop;
339                         return (TRUE);
340                 }
341         }
342         _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOENT);
343         return (FALSE);
344 }
345
346 const char *
347 _rpc_gss_num_to_qop(const char *mech, u_int num)
348 {
349         struct qop_info *info;
350
351         if (num == GSS_C_QOP_DEFAULT)
352                 return "default";
353
354         _rpc_gss_load_qop();
355         SLIST_FOREACH(info, &qops, link) {
356                 if (info->qop == num && strcmp(info->mech, mech) == 0) {
357                         return (info->name);
358                 }
359         }
360         return (NULL);
361 }
362
363 const char **
364 rpc_gss_get_mechanisms(void)
365 {
366
367         _rpc_gss_load_mech();
368         return (mech_names);
369 }
370
371 const char **
372 rpc_gss_get_mech_info(const char *mech, rpc_gss_service_t *service)
373 {
374         struct mech_info *info;
375
376         _rpc_gss_load_mech();
377         _rpc_gss_load_qop();
378         SLIST_FOREACH(info, &mechs, link) {
379                 if (!strcmp(mech, info->name)) {
380                         /*
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
386                          * it is bogus.
387                          */
388                         *service = rpc_gss_svc_privacy;
389                         return info->qops;
390                 }
391         }
392
393         _rpc_gss_set_error(RPC_GSS_ER_SYSTEMERROR, ENOENT);
394         return (NULL);
395 }
396
397 bool_t
398 rpc_gss_get_versions(u_int *vers_hi, u_int *vers_lo)
399 {
400
401         *vers_hi = 1;
402         *vers_lo = 1;
403         return (TRUE);
404 }
405
406 bool_t
407 rpc_gss_is_installed(const char *mech)
408 {
409         struct mech_info *info;
410
411         _rpc_gss_load_mech();
412         SLIST_FOREACH(info, &mechs, link)
413                 if (!strcmp(mech, info->name))
414                         return (TRUE);
415         return (FALSE);
416 }
417