]> git.decadent.org.uk Git - nfs-utils.git/blob - support/gssapi/oid_ops.c
2005-08-26 Kevin Coffman <kwc@citi.umich.edu>
[nfs-utils.git] / support / gssapi / oid_ops.c
1 /*
2  * lib/gssapi/generic/oid_ops.c
3  *
4  * Copyright 1995 by the Massachusetts Institute of Technology.
5  * All Rights Reserved.
6  *
7  * Export of this software from the United States of America may
8  *   require a specific license from the United States Government.
9  *   It is the responsibility of any person or organization contemplating
10  *   export to obtain such a license before exporting.
11  *
12  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13  * distribute this software and its documentation for any purpose and
14  * without fee is hereby granted, provided that the above copyright
15  * notice appear in all copies and that both that copyright notice and
16  * this permission notice appear in supporting documentation, and that
17  * the name of M.I.T. not be used in advertising or publicity pertaining
18  * to distribution of the software without specific, written prior
19  * permission.  Furthermore if you modify this software you must label
20  * your software as modified software and not distribute it in such a
21  * fashion that it might be confused with the original M.I.T. software.
22  * M.I.T. makes no representations about the suitability of
23  * this software for any purpose.  It is provided "as is" without express
24  * or implied warranty.
25  *
26  */
27
28 /*
29  * oid_ops.c - GSS-API V2 interfaces to manipulate OIDs
30  */
31
32 #include "mglueP.h"
33 #ifdef HAVE_UNISTD_H
34 #include <unistd.h>
35 #endif
36 #include <stdlib.h>
37 #include <string.h>
38 #include <stdio.h>
39 #include <errno.h>
40 #include <ctype.h>
41
42 OM_uint32
43 generic_gss_release_oid(minor_status, oid)
44     OM_uint32   *minor_status;
45     gss_OID     *oid;
46 {
47     *minor_status = 0;
48 #ifdef DEBUG
49     static int printed = 0;
50
51     if (!printed++)
52         fprintf(stderr, "gss_generic_release_oid (glue):\n"
53                 "  GSS_C_NT_USER_NAME           %p\n"
54                 "  GSS_C_NT_MACHINE_UID_NAME    %p\n"
55                 "  GSS_C_NT_STRING_UID_NAME     %p\n"
56                 "  GSS_C_NT_HOSTBASED_SERVICE   %p\n"
57                 "  GSS_C_NT_ANONYMOUS           %p\n"
58                 "  GSS_C_NT_EXPORT_NAME         %p\n",
59         GSS_C_NT_USER_NAME, GSS_C_NT_MACHINE_UID_NAME,
60         GSS_C_NT_STRING_UID_NAME, GSS_C_NT_HOSTBASED_SERVICE,
61         GSS_C_NT_ANONYMOUS, GSS_C_NT_EXPORT_NAME);
62 #endif
63
64     if (*oid == GSS_C_NO_OID)
65         return(GSS_S_COMPLETE);
66
67     /*
68      * The V2 API says the following!
69      *
70      * gss_release_oid[()] will recognize any of the GSSAPI's own OID values,
71      * and will silently ignore attempts to free these OIDs; for other OIDs
72      * it will call the C free() routine for both the OID data and the
73      * descriptor.  This allows applications to freely mix their own heap-
74      * allocated OID values with OIDs returned by GSS-API.
75      */
76     if ((*oid != GSS_C_NT_USER_NAME) &&
77         (*oid != GSS_C_NT_MACHINE_UID_NAME) &&
78         (*oid != GSS_C_NT_STRING_UID_NAME) &&
79         (*oid != GSS_C_NT_HOSTBASED_SERVICE) &&
80         (*oid != GSS_C_NT_ANONYMOUS) &&
81         (*oid != GSS_C_NT_EXPORT_NAME)) {
82 #ifdef DEBUG
83         fprintf(stderr, "generic_gss_release_oid (glue): freeing *oid at %p\n",
84                 *oid);
85 #endif
86         free((*oid)->elements);
87         free(*oid);
88     }
89     *oid = GSS_C_NO_OID;
90     return(GSS_S_COMPLETE);
91 }
92
93 OM_uint32
94 mech_gss_release_oid(minor_status, oid, gss_mech)
95     OM_uint32   *minor_status;
96     gss_OID     *oid;
97     gss_mechanism       gss_mech;
98 {
99     *minor_status = 0;
100
101 #ifdef DEBUG
102         fprintf(stderr, "mech_gss_release_oid: *oid %p, gss_mech %p\n",
103                 *oid, gss_mech);
104 #endif
105     if (*oid == GSS_C_NO_OID)
106         return (GSS_S_COMPLETE);
107
108     if (gss_mech == NULL) {
109 #ifdef DEBUG
110         fprintf(stderr, "mech_gss_release_oid: no gss_mech!\n");
111 #endif
112         return (generic_gss_release_oid(minor_status, oid));
113     }
114
115     if (!gss_mech->gss_internal_release_oid) {
116 #ifdef DEBUG
117         fprintf(stderr, "mech_gss_release_oid: mechanism has "
118                         "no gss_internal_release_oid function! using "
119                         "generic_gss_release_oid\n");
120 #endif
121         return (generic_gss_release_oid(minor_status, oid));
122     }
123
124 #ifdef DEBUG
125     fprintf(stderr, "mech_gss_release_oid: calling mechanism's "
126                         "gss_internal_release_oid\n");
127 #endif
128     return (gss_mech->gss_internal_release_oid(minor_status, oid));
129 }
130
131 OM_uint32
132 generic_gss_copy_oid(minor_status, oid, new_oid)
133         OM_uint32       *minor_status;
134         gss_OID         oid, *new_oid;
135 {
136         gss_OID         p;
137
138         if (oid == GSS_C_NO_OID) {
139                 *new_oid = GSS_C_NO_OID;
140                 return (GSS_S_COMPLETE);
141         }
142
143         p = (gss_OID) malloc(sizeof(gss_OID_desc));
144         if (!p) {
145                 *minor_status = ENOMEM;
146                 return GSS_S_FAILURE;
147         }
148         p->length = oid->length;
149         p->elements = malloc(p->length);
150         if (!p->elements) {
151                 free(p);
152                 *minor_status = ENOMEM;
153                 return GSS_S_FAILURE;
154         }
155         memcpy(p->elements, oid->elements, p->length);
156         *new_oid = p;
157         return (GSS_S_COMPLETE);
158 }
159
160
161 OM_uint32
162 generic_gss_create_empty_oid_set(minor_status, oid_set)
163     OM_uint32   *minor_status;
164     gss_OID_set *oid_set;
165 {
166     if ((*oid_set = (gss_OID_set) malloc(sizeof(gss_OID_set_desc)))) {
167         memset(*oid_set, 0, sizeof(gss_OID_set_desc));
168         *minor_status = 0;
169         return(GSS_S_COMPLETE);
170     }
171     else {
172         *minor_status = ENOMEM;
173         return(GSS_S_FAILURE);
174     }
175 }
176
177 OM_uint32
178 generic_gss_add_oid_set_member(minor_status, member_oid, oid_set)
179     OM_uint32   *minor_status;
180     gss_OID     member_oid;
181     gss_OID_set *oid_set;
182 {
183     gss_OID     elist;
184     gss_OID     lastel;
185
186     elist = (*oid_set)->elements;
187     /* Get an enlarged copy of the array */
188     if (((*oid_set)->elements = (gss_OID) malloc(((*oid_set)->count+1) *
189                                                   sizeof(gss_OID_desc)))) {
190         /* Copy in the old junk */
191         if (elist)
192             memcpy((*oid_set)->elements,
193                    elist,
194                    ((*oid_set)->count * sizeof(gss_OID_desc)));
195
196         /* Duplicate the input element */
197         lastel = &(*oid_set)->elements[(*oid_set)->count];
198         if ((lastel->elements =
199              (void *) malloc((size_t) member_oid->length))) {
200             /* Success - copy elements */
201             memcpy(lastel->elements, member_oid->elements,
202                    (size_t) member_oid->length);
203             /* Set length */
204             lastel->length = member_oid->length;
205
206             /* Update count */
207             (*oid_set)->count++;
208             if (elist)
209                 free(elist);
210             *minor_status = 0;
211             return(GSS_S_COMPLETE);
212         }
213         else
214             free((*oid_set)->elements);
215     }
216     /* Failure - restore old contents of list */
217     (*oid_set)->elements = elist;
218     *minor_status = ENOMEM;
219     return(GSS_S_FAILURE);
220 }
221
222 OM_uint32
223 generic_gss_test_oid_set_member(minor_status, member, set, present)
224     OM_uint32   *minor_status;
225     gss_OID     member;
226     gss_OID_set set;
227     int         *present;
228 {
229     size_t      i;
230     int         result;
231
232     result = 0;
233     for (i=0; i<set->count; i++) {
234         if ((set->elements[i].length == member->length) &&
235             !memcmp(set->elements[i].elements,
236                     member->elements,
237                     (size_t) member->length)) {
238             result = 1;
239             break;
240         }
241     }
242     *present = result;
243     *minor_status = 0;
244     return(GSS_S_COMPLETE);
245 }
246
247 /*
248  * OID<->string routines.  These are uuuuugly.
249  */
250 OM_uint32
251 generic_gss_oid_to_str(minor_status, oid, oid_str)
252     OM_uint32           *minor_status;
253     gss_OID             oid;
254     gss_buffer_t        oid_str;
255 {
256     char                numstr[128];
257     unsigned long       number;
258     int                 numshift;
259     size_t              string_length;
260     size_t              i;
261     unsigned char       *cp;
262     char                *bp;
263
264     /* Decoded according to krb5/gssapi_krb5.c */
265
266     /* First determine the size of the string */
267     string_length = 0;
268     number = 0;
269     numshift = 0;
270     cp = (unsigned char *) oid->elements;
271     number = (unsigned long) cp[0];
272     sprintf(numstr, "%ld ", number/40);
273     string_length += strlen(numstr);
274     sprintf(numstr, "%ld ", number%40);
275     string_length += strlen(numstr);
276     for (i=1; i<oid->length; i++) {
277         if ( (size_t) (numshift+7) < (sizeof(unsigned long)*8)) {
278             number = (number << 7) | (cp[i] & 0x7f);
279             numshift += 7;
280         }
281         else {
282             *minor_status = EINVAL;
283             return(GSS_S_FAILURE);
284         }
285         if ((cp[i] & 0x80) == 0) {
286             sprintf(numstr, "%ld ", number);
287             string_length += strlen(numstr);
288             number = 0;
289             numshift = 0;
290         }
291     }
292     /*
293      * If we get here, we've calculated the length of "n n n ... n ".  Add 4
294      * here for "{ " and "}\0".
295      */
296     string_length += 4;
297     if ((bp = (char *) malloc(string_length))) {
298         strcpy(bp, "{ ");
299         number = (unsigned long) cp[0];
300         sprintf(numstr, "%ld ", number/40);
301         strcat(bp, numstr);
302         sprintf(numstr, "%ld ", number%40);
303         strcat(bp, numstr);
304         number = 0;
305         cp = (unsigned char *) oid->elements;
306         for (i=1; i<oid->length; i++) {
307             number = (number << 7) | (cp[i] & 0x7f);
308             if ((cp[i] & 0x80) == 0) {
309                 sprintf(numstr, "%ld ", number);
310                 strcat(bp, numstr);
311                 number = 0;
312             }
313         }
314         strcat(bp, "}");
315         oid_str->length = strlen(bp)+1;
316         oid_str->value = (void *) bp;
317         *minor_status = 0;
318         return(GSS_S_COMPLETE);
319     }
320     *minor_status = ENOMEM;
321     return(GSS_S_FAILURE);
322 }
323
324 OM_uint32
325 generic_gss_str_to_oid(minor_status, oid_str, oid)
326     OM_uint32           *minor_status;
327     gss_buffer_t        oid_str;
328     gss_OID             *oid;
329 {
330     char        *cp, *bp, *startp;
331     int         brace;
332     long        numbuf;
333     long        onumbuf;
334     OM_uint32   nbytes;
335     int         index;
336     unsigned char *op;
337
338     brace = 0;
339     bp = (char *) oid_str->value;
340     cp = bp;
341     /* Skip over leading space */
342     while ((bp < &cp[oid_str->length]) && isspace(*bp))
343         bp++;
344     if (*bp == '{') {
345         brace = 1;
346         bp++;
347     }
348     while ((bp < &cp[oid_str->length]) && isspace(*bp))
349         bp++;
350     startp = bp;
351     nbytes = 0;
352
353     /*
354      * The first two numbers are chewed up by the first octet.
355      */
356     if (sscanf(bp, "%ld", &numbuf) != 1) {
357         *minor_status = EINVAL;
358         return(GSS_S_FAILURE);
359     }
360     while ((bp < &cp[oid_str->length]) && isdigit(*bp))
361         bp++;
362     while ((bp < &cp[oid_str->length]) && isspace(*bp))
363         bp++;
364     if (sscanf(bp, "%ld", &numbuf) != 1) {
365         *minor_status = EINVAL;
366         return(GSS_S_FAILURE);
367     }
368     while ((bp < &cp[oid_str->length]) && isdigit(*bp))
369         bp++;
370     while ((bp < &cp[oid_str->length]) && isspace(*bp))
371         bp++;
372     nbytes++;
373     while (isdigit(*bp)) {
374         if (sscanf(bp, "%ld", &numbuf) != 1) {
375             *minor_status = EINVAL;
376             return(GSS_S_FAILURE);
377         }
378         while (numbuf) {
379             nbytes++;
380             numbuf >>= 7;
381         }
382         while ((bp < &cp[oid_str->length]) && isdigit(*bp))
383             bp++;
384         while ((bp < &cp[oid_str->length]) && isspace(*bp))
385             bp++;
386     }
387     if (brace && (*bp != '}')) {
388         *minor_status = EINVAL;
389         return(GSS_S_FAILURE);
390     }
391
392     /*
393      * Phew!  We've come this far, so the syntax is good.
394      */
395     if ((*oid = (gss_OID) malloc(sizeof(gss_OID_desc)))) {
396         if (((*oid)->elements = (void *) malloc((size_t) nbytes))) {
397             (*oid)->length = nbytes;
398             op = (unsigned char *) (*oid)->elements;
399             bp = startp;
400             sscanf(bp, "%ld", &numbuf);
401             while (isdigit(*bp))
402                 bp++;
403             while (isspace(*bp))
404                 bp++;
405             onumbuf = 40*numbuf;
406             sscanf(bp, "%ld", &numbuf);
407             onumbuf += numbuf;
408             *op = (unsigned char) onumbuf;
409             op++;
410             while (isdigit(*bp))
411                 bp++;
412             while (isspace(*bp))
413                 bp++;
414             while (isdigit(*bp)) {
415                 sscanf(bp, "%ld", &numbuf);
416                 nbytes = 0;
417                 /* Have to fill in the bytes msb-first */
418                 onumbuf = numbuf;
419                 while (numbuf) {
420                     nbytes++;
421                     numbuf >>= 7;
422                 }
423                 numbuf = onumbuf;
424                 op += nbytes;
425                 index = -1;
426                 while (numbuf) {
427                     op[index] = (unsigned char) numbuf & 0x7f;
428                     if (index != -1)
429                         op[index] |= 0x80;
430                     index--;
431                     numbuf >>= 7;
432                 }
433                 while (isdigit(*bp))
434                     bp++;
435                 while (isspace(*bp))
436                     bp++;
437             }
438             *minor_status = 0;
439             return(GSS_S_COMPLETE);
440         }
441         else {
442             free(*oid);
443             *oid = GSS_C_NO_OID;
444         }
445     }
446     *minor_status = ENOMEM;
447     return(GSS_S_FAILURE);
448 }
449