nfs-ganesha 1.4

svcgssd_krb5.c

Go to the documentation of this file.
00001 /*
00002  * COPYRIGHT (c) 2011
00003  * The Regents of the University of Michigan
00004  * ALL RIGHTS RESERVED
00005  *
00006  * Permission is granted to use, copy, create derivative works
00007  * and redistribute this software and such derivative works
00008  * for any purpose, so long as the name of The University of
00009  * Michigan is not used in any advertising or publicity
00010  * pertaining to the use of distribution of this software
00011  * without specific, written prior authorization.  If the
00012  * above copyright notice or any other identification of the
00013  * University of Michigan is included in any copy of any
00014  * portion of this software, then the disclaimer below must
00015  * also be included.
00016  *
00017  * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION
00018  * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY
00019  * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF
00020  * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
00021  * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF
00022  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
00023  * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE
00024  * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR
00025  * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING
00026  * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN
00027  * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGES.
00029  */
00030 
00031 #ifdef HAVE_CONFIG_H
00032 #include <config.h>
00033 #endif  /* HAVE_CONFIG_H */
00034 
00035 #ifndef _GNU_SOURCE
00036 #define _GNU_SOURCE
00037 #endif
00038 
00039 #include <stdio.h>
00040 #include <errno.h>
00041 #include <gssapi/gssapi.h>
00042 #include <krb5.h>
00043 
00044 #include "gss_util.h"
00045 #include "gss_oids.h"
00046 #include "err_util.h"
00047 #include "svcgssd_krb5.h"
00048 #include "../mount/version.h"
00049 
00050 #define MYBUFLEN 1024
00051 
00052 char *supported_enctypes_filename = "/proc/fs/nfsd/supported_krb5_enctypes";
00053 int parsed_num_enctypes = 0;
00054 krb5_enctype *parsed_enctypes = NULL;
00055 char *cached_enctypes = NULL;
00056 
00057 /*==========================*/
00058 /*===  Internal routines ===*/
00059 /*==========================*/
00060 
00061 /*
00062  * Parse the supported encryption type information
00063  */
00064 static int
00065 parse_enctypes(char *enctypes)
00066 {
00067         int n = 0;
00068         char *curr, *comma;
00069         int i;
00070 
00071         /* Don't parse the same string over and over... */
00072         if (cached_enctypes && strcmp(cached_enctypes, enctypes) == 0)
00073                 return 0;
00074 
00075         /* Free any existing cached_enctypes */
00076         free(cached_enctypes);
00077 
00078         if (parsed_enctypes != NULL) {
00079                 free(parsed_enctypes);
00080                 parsed_enctypes = NULL;
00081                 parsed_num_enctypes = 0;
00082         }
00083 
00084         /* count the number of commas */
00085         for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) {
00086                 comma = strchr(curr, ',');
00087                 if (comma != NULL)
00088                         n++;
00089                 else
00090                         break;
00091         }
00092 
00093         /* If no more commas and we're not at the end, there's one more value */
00094         if (*curr != '\0')
00095                 n++;
00096 
00097         /* Empty string, return an error */
00098         if (n == 0)
00099                 return ENOENT;
00100 
00101         /* Allocate space for enctypes array */
00102         if ((parsed_enctypes = (int *) calloc(n, sizeof(int))) == NULL) {
00103                 return ENOMEM;
00104         }
00105 
00106         /* Now parse each value into the array */
00107         for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) {
00108                 parsed_enctypes[i++] = atoi(curr);
00109                 comma = strchr(curr, ',');
00110                 if (comma == NULL)
00111                         break;
00112         }
00113 
00114         parsed_num_enctypes = n;
00115         if ((cached_enctypes = malloc(strlen(enctypes)+1)))
00116                 strcpy(cached_enctypes, enctypes);
00117 
00118         return 0;
00119 }
00120 
00121 static void
00122 get_kernel_supported_enctypes(void)
00123 {
00124         FILE *s_e;
00125         int ret;
00126         char buffer[MYBUFLEN + 1];
00127 
00128         memset(buffer, '\0', sizeof(buffer));
00129 
00130         s_e = fopen(supported_enctypes_filename, "r");
00131         if (s_e == NULL)
00132                 goto out_clean_parsed;
00133 
00134         ret = fread(buffer, 1, MYBUFLEN, s_e);
00135         if (ret < 0) {
00136                 fclose(s_e);
00137                 goto out_clean_parsed;
00138         }
00139         fclose(s_e);
00140         if (parse_enctypes(buffer)) {
00141                 goto out_clean_parsed;
00142         }
00143 out:
00144         return;
00145 
00146 out_clean_parsed:
00147         if (parsed_enctypes != NULL) {
00148                 free(parsed_enctypes);
00149                 parsed_num_enctypes = 0;
00150         }
00151         goto out;
00152 }
00153 
00154 /*==========================*/
00155 /*===  External routines ===*/
00156 /*==========================*/
00157 
00158 /*
00159  * Get encryption types supported by the kernel, and then
00160  * call gss_krb5_set_allowable_enctypes() to limit the
00161  * encryption types negotiated.
00162  *
00163  * Returns:
00164  *      0 => all went well
00165  *     -1 => there was an error
00166  */
00167 
00168 int
00169 svcgssd_limit_krb5_enctypes(void)
00170 {
00171 #ifdef HAVE_SET_ALLOWABLE_ENCTYPES
00172         u_int maj_stat, min_stat;
00173         krb5_enctype old_kernel_enctypes[] = {
00174                 ENCTYPE_DES_CBC_CRC,
00175                 ENCTYPE_DES_CBC_MD5,
00176                 ENCTYPE_DES_CBC_MD4 };
00177         krb5_enctype new_kernel_enctypes[] = {
00178                 ENCTYPE_AES256_CTS_HMAC_SHA1_96,
00179                 ENCTYPE_AES128_CTS_HMAC_SHA1_96,
00180                 ENCTYPE_DES3_CBC_SHA1,
00181                 ENCTYPE_ARCFOUR_HMAC,
00182                 ENCTYPE_DES_CBC_CRC,
00183                 ENCTYPE_DES_CBC_MD5,
00184                 ENCTYPE_DES_CBC_MD4 };
00185         krb5_enctype *default_enctypes, *enctypes;
00186         int default_num_enctypes, num_enctypes;
00187 
00188 
00189         if (linux_version_code() < MAKE_VERSION(2, 6, 35)) {
00190                 default_enctypes = old_kernel_enctypes;
00191                 default_num_enctypes =
00192                         sizeof(old_kernel_enctypes) / sizeof(old_kernel_enctypes[0]);
00193         } else {
00194                 default_enctypes = new_kernel_enctypes;
00195                 default_num_enctypes =
00196                         sizeof(new_kernel_enctypes) / sizeof(new_kernel_enctypes[0]);
00197         }
00198 
00199         get_kernel_supported_enctypes();
00200 
00201         if (parsed_enctypes != NULL) {
00202                 enctypes = parsed_enctypes;
00203                 num_enctypes = parsed_num_enctypes;
00204                 printerr(2, "%s: Calling gss_set_allowable_enctypes with %d "
00205                         "enctypes from the kernel\n", __func__, num_enctypes);
00206         } else {
00207                 enctypes = default_enctypes;
00208                 num_enctypes = default_num_enctypes;
00209                 printerr(2, "%s: Calling gss_set_allowable_enctypes with %d "
00210                         "enctypes from defaults\n", __func__, num_enctypes);
00211         }
00212 
00213         maj_stat = gss_set_allowable_enctypes(&min_stat, gssd_creds,
00214                         &krb5oid, num_enctypes, enctypes);
00215         if (maj_stat != GSS_S_COMPLETE) {
00216                 printerr(1, "WARNING: gss_set_allowable_enctypes failed\n");
00217                 pgsserr("svcgssd_limit_krb5_enctypes: gss_set_allowable_enctypes",
00218                         maj_stat, min_stat, &krb5oid);
00219                 return -1;
00220         }
00221 #endif
00222         return 0;
00223 }