X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fgssd%2Fkrb5_util.c;h=bf8690e3fbd325ca12ac6e7c608d82f91f197a62;hp=5d433b121ee26b96f2319fec04eda6eca638dc18;hb=4cfb608c949d3f38d9d5bc2c3c8aef268b88a697;hpb=3a09fc138b1347ec5b20351674d3d901bc961937 diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c index 5d433b1..bf8690e 100644 --- a/utils/gssd/krb5_util.c +++ b/utils/gssd/krb5_util.c @@ -134,9 +134,6 @@ static int select_krb5_ccache(const struct dirent *d); static int gssd_find_existing_krb5_ccache(uid_t uid, struct dirent **d); static int gssd_get_single_krb5_cred(krb5_context context, krb5_keytab kt, struct gssd_k5_kt_princ *ple); -static int gssd_have_realm_ple(void *realm); -static int gssd_process_krb5_keytab(krb5_context context, krb5_keytab kt, - char *kt_name); /* @@ -326,7 +323,12 @@ gssd_get_single_krb5_cred(krb5_context context, krb5_keytab kt, struct gssd_k5_kt_princ *ple) { +#if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS + krb5_get_init_creds_opt *init_opts = NULL; +#else krb5_get_init_creds_opt options; +#endif + krb5_get_init_creds_opt *opts; krb5_creds my_creds; krb5_ccache ccache = NULL; char kt_name[BUFSIZ]; @@ -354,19 +356,40 @@ gssd_get_single_krb5_cred(krb5_context context, if ((krb5_unparse_name(context, ple->princ, &pname))) pname = NULL; +#if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS + code = krb5_get_init_creds_opt_alloc(context, &init_opts); + if (code) { + printerr(0, "ERROR: %s allocating gic options\n", + gssd_k5_err_msg(context, code)); + goto out; + } + if (krb5_get_init_creds_opt_set_addressless(context, init_opts, 1)) + printerr(0, "WARNING: Unable to set option for addressless " + "tickets. May have problems behind a NAT.\n"); +#ifdef TEST_SHORT_LIFETIME + /* set a short lifetime (for debugging only!) */ + printerr(0, "WARNING: Using (debug) short machine cred lifetime!\n"); + krb5_get_init_creds_opt_set_tkt_life(init_opts, 5*60); +#endif + opts = init_opts; + +#else /* HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS */ + krb5_get_init_creds_opt_init(&options); krb5_get_init_creds_opt_set_address_list(&options, NULL); - #ifdef TEST_SHORT_LIFETIME /* set a short lifetime (for debugging only!) */ printerr(0, "WARNING: Using (debug) short machine cred lifetime!\n"); krb5_get_init_creds_opt_set_tkt_life(&options, 5*60); #endif + opts = &options; +#endif + if ((code = krb5_get_init_creds_keytab(context, &my_creds, ple->princ, - kt, 0, NULL, &options))) { + kt, 0, NULL, opts))) { printerr(0, "WARNING: %s while getting initial ticket for " "principal '%s' using keytab '%s'\n", - error_message(code), + gssd_k5_err_msg(context, code), pname ? pname : "", kt_name); goto out; } @@ -395,17 +418,18 @@ gssd_get_single_krb5_cred(krb5_context context, } if ((code = krb5_cc_resolve(context, cc_name, &ccache))) { printerr(0, "ERROR: %s while opening credential cache '%s'\n", - error_message(code), cc_name); + gssd_k5_err_msg(context, code), cc_name); goto out; } if ((code = krb5_cc_initialize(context, ccache, ple->princ))) { printerr(0, "ERROR: %s while initializing credential " - "cache '%s'\n", error_message(code), cc_name); + "cache '%s'\n", gssd_k5_err_msg(context, code), + cc_name); goto out; } if ((code = krb5_cc_store_cred(context, ccache, &my_creds))) { printerr(0, "ERROR: %s while storing credentials in '%s'\n", - error_message(code), cc_name); + gssd_k5_err_msg(context, code), cc_name); goto out; } @@ -413,6 +437,10 @@ gssd_get_single_krb5_cred(krb5_context context, printerr(2, "Successfully obtained machine credentials for " "principal '%s' stored in ccache '%s'\n", pname, cc_name); out: +#if HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS + if (init_opts) + krb5_get_init_creds_opt_free(context, init_opts); +#endif if (pname) k5_free_unparsed_name(context, pname); if (ccache) @@ -421,147 +449,6 @@ gssd_get_single_krb5_cred(krb5_context context, return (code); } -/* - * Determine if we already have a ple for the given realm - * - * Returns: - * 0 => no ple found for given realm - * 1 => found ple for given realm - */ -static int -gssd_have_realm_ple(void *r) -{ - struct gssd_k5_kt_princ *ple; -#ifdef HAVE_KRB5 - krb5_data *realm = (krb5_data *)r; -#else - char *realm = (char *)r; -#endif - - for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) { -#ifdef HAVE_KRB5 - if ((realm->length == strlen(ple->realm)) && - (strncmp(realm->data, ple->realm, realm->length) == 0)) { -#else - if (strcmp(realm, ple->realm) == 0) { -#endif - return 1; - } - } - return 0; -} - -/* - * Process the given keytab file and create a list of principals we - * might use as machine credentials. - * - * Returns: - * 0 => Sucess - * nonzero => Error - */ -static int -gssd_process_krb5_keytab(krb5_context context, krb5_keytab kt, char *kt_name) -{ - krb5_kt_cursor cursor; - krb5_keytab_entry kte; - krb5_error_code code; - struct gssd_k5_kt_princ *ple; - int retval = -1; - - /* - * Look through each entry in the keytab file and determine - * if we might want to use it as machine credentials. If so, - * save info in the global principal list (gssd_k5_kt_princ_list). - * Note: (ple == principal list entry) - */ - if ((code = krb5_kt_start_seq_get(context, kt, &cursor))) { - printerr(0, "ERROR: %s while beginning keytab scan " - "for keytab '%s'\n", - error_message(code), kt_name); - retval = code; - goto out; - } - - while ((code = krb5_kt_next_entry(context, kt, &kte, &cursor)) == 0) { - char *pname; - if ((code = krb5_unparse_name(context, kte.principal, - &pname))) { - printerr(0, "WARNING: Skipping keytab entry because " - "we failed to unparse principal name: %s\n", - error_message(code)); - krb5_kt_free_entry(context, &kte); - continue; - } - printerr(2, "Processing keytab entry for principal '%s'\n", - pname); - /* Just use the first keytab entry found for each realm */ - if ((!gssd_have_realm_ple((void *)&kte.principal->realm)) ) { - printerr(2, "We WILL use this entry (%s)\n", pname); - ple = malloc(sizeof(struct gssd_k5_kt_princ)); - if (ple == NULL) { - printerr(0, "ERROR: could not allocate storage " - "for principal list entry\n"); - k5_free_unparsed_name(context, pname); - krb5_kt_free_entry(context, &kte); - retval = ENOMEM; - goto out; - } - /* These will be filled in later */ - ple->next = NULL; - ple->ccname = NULL; - ple->endtime = 0; - if ((ple->realm = -#ifdef HAVE_KRB5 - strndup(kte.principal->realm.data, - kte.principal->realm.length)) -#else - strdup(kte.principal->realm)) -#endif - == NULL) { - printerr(0, "ERROR: %s while copying realm to " - "principal list entry\n", - "not enough memory"); - k5_free_unparsed_name(context, pname); - krb5_kt_free_entry(context, &kte); - retval = ENOMEM; - goto out; - } - if ((code = krb5_copy_principal(context, - kte.principal, &ple->princ))) { - printerr(0, "ERROR: %s while copying principal " - "to principal list entry\n", - error_message(code)); - k5_free_unparsed_name(context, pname); - krb5_kt_free_entry(context, &kte); - retval = code; - goto out; - } - if (gssd_k5_kt_princ_list == NULL) - gssd_k5_kt_princ_list = ple; - else { - ple->next = gssd_k5_kt_princ_list; - gssd_k5_kt_princ_list = ple; - } - } - else { - printerr(2, "We will NOT use this entry (%s)\n", - pname); - } - k5_free_unparsed_name(context, pname); - krb5_kt_free_entry(context, &kte); - } - - if ((code = krb5_kt_end_seq_get(context, kt, &cursor))) { - printerr(0, "WARNING: %s while ending keytab scan for " - "keytab '%s'\n", - error_message(code), kt_name); - } - - retval = 0; - out: - return retval; -} - /* * Depending on the version of Kerberos, we either need to use * a private function, or simply set the environment variable. @@ -796,14 +683,14 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt, */ if ((code = krb5_kt_get_name(context, kt, kt_name, BUFSIZ))) { printerr(0, "ERROR: %s attempting to get keytab name\n", - error_message(code)); + gssd_k5_err_msg(context, code)); retval = code; goto out; } if ((code = krb5_kt_start_seq_get(context, kt, &cursor))) { printerr(0, "ERROR: %s while beginning keytab scan " "for keytab '%s'\n", - error_message(code), kt_name); + gssd_k5_err_msg(context, code), kt_name); retval = code; goto out; } @@ -813,7 +700,7 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt, &pname))) { printerr(0, "WARNING: Skipping keytab entry because " "we failed to unparse principal name: %s\n", - error_message(code)); + gssd_k5_err_msg(context, code)); k5_free_kt_entry(context, kte); continue; } @@ -849,7 +736,7 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt, if ((code = krb5_kt_end_seq_get(context, kt, &cursor))) { printerr(0, "WARNING: %s while ending keytab scan for " "keytab '%s'\n", - error_message(code), kt_name); + gssd_k5_err_msg(context, code), kt_name); } retval = 0; @@ -887,7 +774,7 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname, retval = gethostname(myhostname, sizeof(myhostname)); if (retval) { printerr(1, "%s while getting local hostname\n", - error_message(retval)); + gssd_k5_err_msg(context, retval)); goto out; } retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname)); @@ -898,7 +785,7 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname, if (code) { retval = code; printerr(1, "%s while getting default realm name\n", - error_message(code)); + gssd_k5_err_msg(context, code)); goto out; } @@ -911,7 +798,7 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname, code = krb5_get_host_realm(context, targethostname, &realmnames); if (code) { printerr(0, "ERROR: %s while getting realm(s) for host '%s'\n", - error_message(code), targethostname); + gssd_k5_err_msg(context, code), targethostname); retval = code; goto out; } @@ -943,7 +830,8 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname, NULL); if (code) { printerr(1, "%s while building principal for " - "'%s/%s@%s'\n", error_message(code), + "'%s/%s@%s'\n", + gssd_k5_err_msg(context, code), svcnames[j], myhostname, realm); continue; } @@ -951,7 +839,8 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname, krb5_free_principal(context, princ); if (code) { printerr(3, "%s while getting keytab entry for " - "'%s/%s@%s'\n", error_message(code), + "'%s/%s@%s'\n", + gssd_k5_err_msg(context, code), svcnames[j], myhostname, realm); } else { printerr(3, "Success getting keytab entry for " @@ -1038,96 +927,6 @@ gssd_setup_krb5_machine_gss_ccache(char *ccname) gssd_set_krb5_ccache_name(ccname); } -/* - * The first time through this routine, go through the keytab and - * determine which keys we will try to use as machine credentials. - * Every time through this routine, try to obtain credentials using - * the keytab entries selected the first time through. - * - * Returns: - * 0 => obtained one or more credentials - * nonzero => error - * - */ - -int -gssd_refresh_krb5_machine_creds(void) -{ - krb5_context context = NULL; - krb5_keytab kt = NULL;; - krb5_error_code code; - int retval = -1; - struct gssd_k5_kt_princ *ple; - int gotone = 0; - static int processed_keytab = 0; - - - code = krb5_init_context(&context); - if (code) { - printerr(0, "ERROR: %s while initializing krb5 in " - "gssd_refresh_krb5_machine_creds\n", - error_message(code)); - retval = code; - goto out; - } - - printerr(1, "Using keytab file '%s'\n", keytabfile); - - if ((code = krb5_kt_resolve(context, keytabfile, &kt))) { - printerr(0, "ERROR: %s while resolving keytab '%s'\n", - error_message(code), keytabfile); - goto out; - } - - /* Only go through the keytab file once. Only print messages once. */ - if (gssd_k5_kt_princ_list == NULL && !processed_keytab) { - processed_keytab = 1; - gssd_process_krb5_keytab(context, kt, keytabfile); - if (gssd_k5_kt_princ_list == NULL) { - printerr(0, "ERROR: No usable keytab entries found in " - "keytab '%s'\n", keytabfile); - printerr(0, "Do you have a valid keytab entry for " - "%s/@ in " - "keytab file %s ?\n", - GSSD_SERVICE_NAME, keytabfile); - printerr(0, "Continuing without (machine) credentials " - "- nfs4 mounts with Kerberos will fail\n"); - } - } - - /* - * If we don't have any keytab entries we liked, then we have a problem - */ - if (gssd_k5_kt_princ_list == NULL) { - retval = ENOENT; - goto out; - } - - /* - * Now go through the list of saved entries and get initial - * credentials for them (We can't do this while making the - * list because it messes up the keytab iteration cursor - * when we use the keytab to get credentials.) - */ - for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) { - if ((gssd_get_single_krb5_cred(context, kt, ple)) == 0) { - gotone++; - } - } - if (!gotone) { - printerr(0, "ERROR: No usable machine credentials obtained\n"); - goto out; - } - - retval = 0; - out: - if (kt) krb5_kt_close(context, kt); - krb5_free_context(context); - - return retval; -} - - /* * Return an array of pointers to names of credential cache files * which can be used to try to create gss contexts with a server. @@ -1218,7 +1017,7 @@ gssd_destroy_krb5_machine_creds(void) code = krb5_init_context(&context); if (code) { printerr(0, "ERROR: %s while initializing krb5\n", - error_message(code)); + gssd_k5_err_msg(NULL, code)); goto out; } @@ -1228,14 +1027,14 @@ gssd_destroy_krb5_machine_creds(void) if ((code = krb5_cc_resolve(context, ple->ccname, &ccache))) { printerr(0, "WARNING: %s while resolving credential " "cache '%s' for destruction\n", - error_message(code), ple->ccname); + gssd_k5_err_msg(context, code), ple->ccname); continue; } if ((code = krb5_cc_destroy(context, ccache))) { printerr(0, "WARNING: %s while destroying credential " "cache '%s'\n", - error_message(code), ple->ccname); + gssd_k5_err_msg(context, code), ple->ccname); } } out: @@ -1260,14 +1059,15 @@ gssd_refresh_krb5_machine_credential(char *hostname, code = krb5_init_context(&context); if (code) { printerr(0, "ERROR: %s: %s while initializing krb5 context\n", - __FUNCTION__, error_message(code)); + __FUNCTION__, gssd_k5_err_msg(NULL, code)); retval = code; goto out; } if ((code = krb5_kt_resolve(context, keytabfile, &kt))) { printerr(0, "ERROR: %s: %s while resolving keytab '%s'\n", - __FUNCTION__, error_message(code), keytabfile); + __FUNCTION__, gssd_k5_err_msg(context, code), + keytabfile); goto out; } @@ -1307,3 +1107,25 @@ out: return retval; } +/* + * A common routine for getting the Kerberos error message + */ +const char * +gssd_k5_err_msg(krb5_context context, krb5_error_code code) +{ + const char *msg = NULL; +#if HAVE_KRB5_GET_ERROR_MESSAGE + if (context != NULL) + msg = krb5_get_error_message(context, code); +#endif + if (msg != NULL) + return msg; +#if HAVE_KRB5 + return error_message(code); +#else + if (context != NULL) + return krb5_get_err_text(context, code); + else + return error_message(code); +#endif +}