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);
/*
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];
int code;
time_t now = time(0);
char *cache_type;
+ char *pname = NULL;
memset(&my_creds, 0, sizeof(my_creds));
goto out;
}
+ 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))) {
- char *pname;
- if ((krb5_unparse_name(context, ple->princ, &pname))) {
- pname = NULL;
- }
+ kt, 0, NULL, opts))) {
printerr(0, "WARNING: %s while getting initial ticket for "
- "principal '%s' from keytab '%s'\n",
- error_message(code),
+ "principal '%s' using keytab '%s'\n",
+ gssd_k5_err_msg(context, code),
pname ? pname : "<unparsable>", kt_name);
- if (pname) k5_free_unparsed_name(context, pname);
goto out;
}
GSSD_DEFAULT_CRED_DIR, GSSD_DEFAULT_CRED_PREFIX,
GSSD_DEFAULT_MACHINE_CRED_SUFFIX, ple->realm);
ple->endtime = my_creds.times.endtime;
+ if (ple->ccname != NULL)
+ free(ple->ccname);
ple->ccname = strdup(cc_name);
if (ple->ccname == NULL) {
printerr(0, "ERROR: no storage to duplicate credentials "
- "cache name\n");
+ "cache name '%s'\n", cc_name);
code = ENOMEM;
goto out;
}
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;
}
code = 0;
- printerr(1, "Using (machine) credentials cache: '%s'\n", cc_name);
+ 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)
krb5_cc_close(context, ccache);
krb5_free_cred_contents(context, &my_creds);
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.
*/
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;
}
&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;
}
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;
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));
if (code) {
retval = code;
printerr(1, "%s while getting default realm name\n",
- error_message(code));
+ gssd_k5_err_msg(context, code));
goto out;
}
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;
}
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;
}
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 "
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/<your.host>@<YOUR.REALM> 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.
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;
}
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:
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;
}
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
+}