]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/gssd/svcgssd_krb5.c
Imported upstream 1.2.8
[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 <ctype.h>
42 #include <gssapi/gssapi.h>
43 #include <krb5.h>
44
45 #include "gss_util.h"
46 #include "gss_oids.h"
47 #include "err_util.h"
48 #include "svcgssd_krb5.h"
49 #include "../mount/version.h"
50
51 #define MYBUFLEN 1024
52
53 char *supported_enctypes_filename = "/proc/fs/nfsd/supported_krb5_enctypes";
54 int parsed_num_enctypes = 0;
55 krb5_enctype *parsed_enctypes = NULL;
56 char *cached_enctypes = NULL;
57
58 /*==========================*/
59 /*===  Internal routines ===*/
60 /*==========================*/
61
62 /*
63  * Parse the supported encryption type information
64  */
65 static int
66 parse_enctypes(char *enctypes)
67 {
68         int n = 0;
69         char *curr, *comma;
70         int i;
71
72         /* Don't parse the same string over and over... */
73         if (cached_enctypes && strcmp(cached_enctypes, enctypes) == 0)
74                 return 0;
75
76         /* Free any existing cached_enctypes */
77         free(cached_enctypes);
78
79         if (parsed_enctypes != NULL) {
80                 free(parsed_enctypes);
81                 parsed_enctypes = NULL;
82                 parsed_num_enctypes = 0;
83         }
84
85         /* count the number of commas */
86         for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) {
87                 comma = strchr(curr, ',');
88                 if (comma != NULL)
89                         n++;
90                 else
91                         break;
92         }
93
94         /* If no more commas and we're not at the end, there's one more value */
95         if (*curr != '\0')
96                 n++;
97
98         /* Empty string, return an error */
99         if (n == 0)
100                 return ENOENT;
101
102         /* Skip pass any non digits */
103         while (*enctypes && isdigit(*enctypes) == 0)
104                 enctypes++;
105         if (*enctypes == '\0')
106                 return EINVAL;
107
108         /* Allocate space for enctypes array */
109         if ((parsed_enctypes = (int *) calloc(n, sizeof(int))) == NULL) {
110                 return ENOMEM;
111         }
112
113         /* Now parse each value into the array */
114         for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) {
115                 parsed_enctypes[i++] = atoi(curr);
116                 comma = strchr(curr, ',');
117                 if (comma == NULL)
118                         break;
119         }
120
121         parsed_num_enctypes = n;
122         if ((cached_enctypes = malloc(strlen(enctypes)+1)))
123                 strcpy(cached_enctypes, enctypes);
124
125         return 0;
126 }
127
128 static void
129 get_kernel_supported_enctypes(void)
130 {
131         FILE *s_e;
132         int ret;
133         char buffer[MYBUFLEN + 1];
134
135         memset(buffer, '\0', sizeof(buffer));
136
137         s_e = fopen(supported_enctypes_filename, "r");
138         if (s_e == NULL)
139                 goto out_clean_parsed;
140
141         ret = fread(buffer, 1, MYBUFLEN, s_e);
142         if (ret < 0) {
143                 fclose(s_e);
144                 goto out_clean_parsed;
145         }
146         fclose(s_e);
147         if (parse_enctypes(buffer)) {
148                 goto out_clean_parsed;
149         }
150 out:
151         return;
152
153 out_clean_parsed:
154         if (parsed_enctypes != NULL) {
155                 free(parsed_enctypes);
156                 parsed_num_enctypes = 0;
157         }
158         goto out;
159 }
160
161 /*==========================*/
162 /*===  External routines ===*/
163 /*==========================*/
164
165 /*
166  * Get encryption types supported by the kernel, and then
167  * call gss_krb5_set_allowable_enctypes() to limit the
168  * encryption types negotiated.
169  *
170  * Returns:
171  *      0 => all went well
172  *     -1 => there was an error
173  */
174
175 int
176 svcgssd_limit_krb5_enctypes(void)
177 {
178 #ifdef HAVE_SET_ALLOWABLE_ENCTYPES
179         u_int maj_stat, min_stat;
180         krb5_enctype old_kernel_enctypes[] = {
181                 ENCTYPE_DES_CBC_CRC,
182                 ENCTYPE_DES_CBC_MD5,
183                 ENCTYPE_DES_CBC_MD4 };
184         krb5_enctype new_kernel_enctypes[] = {
185                 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
186                 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
187                 ENCTYPE_DES3_CBC_SHA1,
188                 ENCTYPE_ARCFOUR_HMAC,
189                 ENCTYPE_DES_CBC_CRC,
190                 ENCTYPE_DES_CBC_MD5,
191                 ENCTYPE_DES_CBC_MD4 };
192         krb5_enctype *default_enctypes, *enctypes;
193         int default_num_enctypes, num_enctypes;
194
195
196         if (linux_version_code() < MAKE_VERSION(2, 6, 35)) {
197                 default_enctypes = old_kernel_enctypes;
198                 default_num_enctypes =
199                         sizeof(old_kernel_enctypes) / sizeof(old_kernel_enctypes[0]);
200         } else {
201                 default_enctypes = new_kernel_enctypes;
202                 default_num_enctypes =
203                         sizeof(new_kernel_enctypes) / sizeof(new_kernel_enctypes[0]);
204         }
205
206         get_kernel_supported_enctypes();
207
208         if (parsed_enctypes != NULL) {
209                 enctypes = parsed_enctypes;
210                 num_enctypes = parsed_num_enctypes;
211                 printerr(2, "%s: Calling gss_set_allowable_enctypes with %d "
212                         "enctypes from the kernel\n", __func__, num_enctypes);
213         } else {
214                 enctypes = default_enctypes;
215                 num_enctypes = default_num_enctypes;
216                 printerr(2, "%s: Calling gss_set_allowable_enctypes with %d "
217                         "enctypes from defaults\n", __func__, num_enctypes);
218         }
219
220         maj_stat = gss_set_allowable_enctypes(&min_stat, gssd_creds,
221                         &krb5oid, num_enctypes, enctypes);
222         if (maj_stat != GSS_S_COMPLETE) {
223                 printerr(1, "WARNING: gss_set_allowable_enctypes failed\n");
224                 pgsserr("svcgssd_limit_krb5_enctypes: gss_set_allowable_enctypes",
225                         maj_stat, min_stat, &krb5oid);
226                 return -1;
227         }
228 #endif
229         return 0;
230 }