commit f8160472fe0b4b217c173e2ce4fe9a0603c1288a From: Kevin Coffman Try to use kernel function to determine supported Kerberos enctypes. Signed-off-by: Kevin Coffman This patch replaces a hard-coded list with a function to obtain the Kerberos encryption types that the kernel's rpcsec_gss code can support. Defaults to old behavior if kernel does not supply information. --- utils/gssd/gssd.c | 3 + utils/gssd/krb5_util.c | 136 +++++++++++++++++++++++++++++++++++++++++++++++- utils/gssd/krb5_util.h | 2 + 3 files changed, 139 insertions(+), 2 deletions(-) diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c index e8612a5..3e15cbb 100644 --- a/utils/gssd/gssd.c +++ b/utils/gssd/gssd.c @@ -175,6 +175,9 @@ main(int argc, char *argv[]) signal(SIGTERM, sig_die); signal(SIGHUP, sig_hup); + /* Determine Kerberos information from the kernel */ + gssd_obtain_kernel_krb5_info(); + gssd_run(); printerr(0, "gssd_run returned!\n"); abort(); diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c index 18d5571..e3866e4 100644 --- a/utils/gssd/krb5_util.c +++ b/utils/gssd/krb5_util.c @@ -97,6 +97,7 @@ #include "config.h" #include #include +#include #include #include #include @@ -108,6 +109,7 @@ #include #include #include +#include #include #include #include @@ -126,6 +128,10 @@ /* Global list of principals/cache file names for machine credentials */ struct gssd_k5_kt_princ *gssd_k5_kt_princ_list = NULL; +/* Encryption types supported by the kernel rpcsec_gss code */ +int num_krb5_enctypes = 0; +krb5_enctype *krb5_enctypes = NULL; + /*==========================*/ /*=== Internal routines ===*/ /*==========================*/ @@ -829,6 +835,56 @@ out: return retval; } +/* + * Parse the supported encryption type information + */ +static int +parse_enctypes(char *enctypes) +{ + int n = 0; + char *curr, *comma; + int i; + + /* Just in case this ever gets called more than once */ + if (krb5_enctypes != NULL) { + free(krb5_enctypes); + krb5_enctypes = NULL; + num_krb5_enctypes = 0; + } + + /* count the number of commas */ + for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) { + comma = strchr(curr, ','); + if (comma != NULL) + n++; + else + break; + } + /* If no more commas and we're not at the end, there's one more value */ + if (*curr != '\0') + n++; + + /* Empty string, return an error */ + if (n == 0) + return ENOENT; + + /* Allocate space for enctypes array */ + if ((krb5_enctypes = (int *) calloc(n, sizeof(int))) == NULL) { + return ENOMEM; + } + + /* Now parse each value into the array */ + for (curr = enctypes, i = 0; curr && *curr != '\0'; curr = ++comma) { + krb5_enctypes[i++] = atoi(curr); + comma = strchr(curr, ','); + if (comma == NULL) + break; + } + + num_krb5_enctypes = n; + return 0; +} + /*==========================*/ /*=== External routines ===*/ /*==========================*/ @@ -1119,8 +1175,17 @@ limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid) return -1; } - maj_stat = gss_set_allowable_enctypes(&min_stat, credh, &krb5oid, - num_enctypes, &enctypes); + /* + * If we failed for any reason to produce global + * list of supported enctypes, use local default here. + */ + if (krb5_enctypes == NULL) + maj_stat = gss_set_allowable_enctypes(&min_stat, credh, + &krb5oid, num_enctypes, &enctypes); + else + maj_stat = gss_set_allowable_enctypes(&min_stat, credh, + &krb5oid, num_krb5_enctypes, + krb5_enctypes); if (maj_stat != GSS_S_COMPLETE) { pgsserr("gss_set_allowable_enctypes", maj_stat, min_stat, &krb5oid); @@ -1132,3 +1197,70 @@ limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid) return 0; } #endif /* HAVE_SET_ALLOWABLE_ENCTYPES */ + +/* + * Obtain supported enctypes from kernel. + * Set defaults if info is not available. + */ +void +gssd_obtain_kernel_krb5_info(void) +{ + char enctype_file_name[128]; + char buf[1024]; + char enctypes[128]; + int nscanned; + int fd; + int use_default_enctypes = 0; + int nbytes, numfields; + char default_enctypes[] = "1,3,2"; + int code; + + snprintf(enctype_file_name, sizeof(enctype_file_name), + "%s/%s", pipefs_dir, "krb5_info"); + + if ((fd = open(enctype_file_name, O_RDONLY)) == -1) { + printerr(1, "WARNING: gssd_obtain_kernel_krb5_info: " + "Unable to open '%s'. Unable to determine " + "Kerberos encryption types supported by the " + "kernel; using defaults (%s).\n", + enctype_file_name, default_enctypes); + use_default_enctypes = 1; + goto do_the_parse; + } + memset(buf, 0, sizeof(buf)); + if ((nbytes = read(fd, buf, sizeof(buf)-1)) == -1) { + printerr(0, "WARNING: gssd_obtain_kernel_krb5_info: " + "Error reading Kerberos encryption type " + "information file '%s'; using defaults (%s).\n", + enctype_file_name, default_enctypes); + use_default_enctypes = 1; + close(fd); + goto do_the_parse; + } + close(fd); + numfields = sscanf(buf, "enctypes: %s\n%n", enctypes, &nscanned); + if (numfields < 1) { + printerr(0, "WARNING: gssd_obtain_kernel_krb5_info: " + "error parsing Kerberos encryption type " + "information from file '%s'; using defaults (%s).\n", + enctype_file_name, default_enctypes); + use_default_enctypes = 1; + goto do_the_parse; + } + if (nbytes > nscanned) { + printerr(2, "gssd_obtain_kernel_krb5_info: " + "Ignoring extra information, '%s', from '%s'\n", + buf+nscanned, enctype_file_name); + goto do_the_parse; + } + do_the_parse: + if (use_default_enctypes) + strcpy(enctypes, default_enctypes); + + if ((code = parse_enctypes(enctypes)) != 0) { + printerr(0, "ERROR: gssd_obtain_kernel_krb5_info: " + "parse_enctypes%s failed with code %d\n", + use_default_enctypes ? " (with default enctypes)" : "", + code); + } +} diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h index 431fdaf..b68bd55 100644 --- a/utils/gssd/krb5_util.h +++ b/utils/gssd/krb5_util.h @@ -27,6 +27,8 @@ int gssd_refresh_krb5_machine_credential(char *hostname, struct gssd_k5_kt_princ *ple); const char * gssd_k5_err_msg(krb5_context context, krb5_error_code code); +void gssd_obtain_kernel_krb5_info(void); + #ifdef HAVE_SET_ALLOWABLE_ENCTYPES int limit_krb5_enctypes(struct rpc_gss_sec *sec, uid_t uid);