]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/gssd/svcgssd_krb5.c
fc67a6f1363ded05217725cf1fec415aac094a17
[nfs-utils.git] / utils / gssd / svcgssd_krb5.c
1 /*
2  * COPYRIGHT (c) 2011
3  * The Regents of the University of Michigan
4  * ALL RIGHTS RESERVED
5  *
6  * Permission is granted to use, copy, create derivative works
7  * and redistribute this software and such derivative works
8  * for any purpose, so long as the name of The University of
9  * Michigan is not used in any advertising or publicity
10  * pertaining to the use of distribution of this software
11  * without specific, written prior authorization.  If the
12  * above copyright notice or any other identification of the
13  * University of Michigan is included in any copy of any
14  * portion of this software, then the disclaimer below must
15  * also be included.
16  *
17  * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
18  * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
19  * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
20  * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
21  * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
22  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
23  * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
24  * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
25  * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
26  * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
27  * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGES.
29  */
30
31 #ifdef HAVE_CONFIG_H
32 #include <config.h>
33 #endif  /* HAVE_CONFIG_H */
34
35 #ifndef _GNU_SOURCE
36 #define _GNU_SOURCE
37 #endif
38
39 #include <stdio.h>
40 #include <errno.h>
41 #include <gssapi/gssapi.h>
42 #include <krb5.h>
43
44 #include "gss_util.h"
45 #include "gss_oids.h"
46 #include "err_util.h"
47 #include "svcgssd_krb5.h"
48
49 #define MYBUFLEN 1024
50
51 char *supported_enctypes_filename = "/proc/fs/nfsd/supported_krb5_enctypes";
52 int parsed_num_enctypes = 0;
53 krb5_enctype *parsed_enctypes = NULL;
54 char *cached_enctypes = NULL;
55
56 /*==========================*/
57 /*===  Internal routines ===*/
58 /*==========================*/
59
60 /*
61  * Parse the supported encryption type information
62  */
63 static int
64 parse_enctypes(char *enctypes)
65 {
66         int n = 0;
67         char *curr, *comma;
68         int i;
69
70         /* Don't parse the same string over and over... */
71         if (cached_enctypes && strcmp(cached_enctypes, enctypes) == 0)
72                 return 0;
73
74         /* Free any existing cached_enctypes */
75         free(cached_enctypes);
76
77         if (parsed_enctypes != NULL) {
78                 free(parsed_enctypes);
79                 parsed_enctypes = NULL;
80                 parsed_num_enctypes = 0;
81         }
82
83         /* count the number of commas */
84         for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) {
85                 comma = strchr(curr, ',');
86                 if (comma != NULL)
87                         n++;
88                 else
89                         break;
90         }
91
92         /* If no more commas and we're not at the end, there's one more value */
93         if (*curr != '\0')
94                 n++;
95
96         /* Empty string, return an error */
97         if (n == 0)
98                 return ENOENT;
99
100         /* Allocate space for enctypes array */
101         if ((parsed_enctypes = (int *) calloc(n, sizeof(int))) == NULL) {
102                 return ENOMEM;
103         }
104
105         /* Now parse each value into the array */
106         for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) {
107                 parsed_enctypes[i++] = atoi(curr);
108                 comma = strchr(curr, ',');
109                 if (comma == NULL)
110                         break;
111         }
112
113         parsed_num_enctypes = n;
114         if ((cached_enctypes = malloc(strlen(enctypes)+1)))
115                 strcpy(cached_enctypes, enctypes);
116
117         return 0;
118 }
119
120 static void
121 get_kernel_supported_enctypes(void)
122 {
123         FILE *s_e;
124         int ret;
125         char buffer[MYBUFLEN + 1];
126
127         memset(buffer, '\0', sizeof(buffer));
128
129         s_e = fopen(supported_enctypes_filename, "r");
130         if (s_e == NULL)
131                 goto out_clean_parsed;
132
133         ret = fread(buffer, 1, MYBUFLEN, s_e);
134         if (ret < 0) {
135                 fclose(s_e);
136                 goto out_clean_parsed;
137         }
138         fclose(s_e);
139         if (parse_enctypes(buffer)) {
140                 goto out_clean_parsed;
141         }
142 out:
143         return;
144
145 out_clean_parsed:
146         if (parsed_enctypes != NULL) {
147                 free(parsed_enctypes);
148                 parsed_num_enctypes = 0;
149         }
150         goto out;
151 }
152
153 /*==========================*/
154 /*===  External routines ===*/
155 /*==========================*/
156
157 /*
158  * Get encryption types supported by the kernel, and then
159  * call gss_krb5_set_allowable_enctypes() to limit the
160  * encryption types negotiated.
161  *
162  * Returns:
163  *      0 => all went well
164  *     -1 => there was an error
165  */
166
167 int
168 svcgssd_limit_krb5_enctypes(void)
169 {
170 #ifdef HAVE_SET_ALLOWABLE_ENCTYPES
171         u_int maj_stat, min_stat;
172         krb5_enctype default_enctypes[] = { ENCTYPE_DES_CBC_CRC,
173                                             ENCTYPE_DES_CBC_MD5,
174                                             ENCTYPE_DES_CBC_MD4 };
175         int default_num_enctypes =
176                 sizeof(default_enctypes) / sizeof(default_enctypes[0]);
177         krb5_enctype *enctypes;
178         int num_enctypes;
179
180         get_kernel_supported_enctypes();
181
182         if (parsed_enctypes != NULL) {
183                 enctypes = parsed_enctypes;
184                 num_enctypes = parsed_num_enctypes;
185         } else {
186                 enctypes = default_enctypes;
187                 num_enctypes = default_num_enctypes;
188         }
189
190         maj_stat = gss_set_allowable_enctypes(&min_stat, gssd_creds,
191                         &krb5oid, num_enctypes, enctypes);
192         if (maj_stat != GSS_S_COMPLETE) {
193                 printerr(1, "WARNING: gss_set_allowable_enctypes failed\n");
194                 pgsserr("svcgssd_limit_krb5_enctypes: gss_set_allowable_enctypes",
195                         maj_stat, min_stat, &krb5oid);
196                 return -1;
197         }
198 #endif
199         return 0;
200 }