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