/* * Search the given keytab file looking for an entry with the given * service name and realm, ignoring hostname (instance). * * Returns: * 0 => No error * non-zero => An error occurred * * If a keytab entry is found, "found" is set to one, and the keytab * entry is returned in "kte". Otherwise, "found" is zero, and the * value of "kte" is unpredictable. */ static int gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt, const char *realm, const char *service, int *found, krb5_keytab_entry *kte) { krb5_kt_cursor cursor; krb5_error_code code; struct gssd_k5_kt_princ *ple; int retval = -1, status; char kt_name[BUFSIZ]; char *pname; char *k5err = NULL; if (found == NULL) { retval = EINVAL; goto out; } *found = 0; /* * 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). */ code = krb5_kt_get_name(context, kt, kt_name, BUFSIZ); if (code != 0) { k5err = gssd_k5_err_msg(context, code); printerr(0, "ERROR: %s attempting to get keytab name\n", k5err); gsh_free(k5err); retval = code; goto out; } code = krb5_kt_start_seq_get(context, kt, &cursor); if (code != 0) { k5err = gssd_k5_err_msg(context, code); printerr(0, "ERROR: %s while beginning keytab scan " "for keytab '%s'\n", k5err, kt_name); gsh_free(k5err); retval = code; goto out; } while ((code = krb5_kt_next_entry(context, kt, kte, &cursor)) == 0) { code = krb5_unparse_name(context, kte->principal, &pname); if (code != 0) { k5err = gssd_k5_err_msg(context, code); printerr(0, "WARNING: Skipping keytab entry because " "we failed to unparse principal name: %s\n", k5err); k5_free_kt_entry(context, kte); gsh_free(k5err); continue; } printerr(4, "Processing keytab entry for principal '%s'\n", pname); /* Use the first matching keytab entry found */ #ifdef HAVE_KRB5 status = realm_and_service_match(kte->principal, realm, service); #else status = realm_and_service_match(context, kte->principal, realm, service); #endif if (status) { printerr(4, "We WILL use this entry (%s)\n", pname); ple = get_ple_by_princ(context, kte->principal); /* * Return, don't free, keytab entry if * we were successful! */ if (ple == NULL) { retval = ENOMEM; k5_free_kt_entry(context, kte); } else { retval = 0; *found = 1; } k5_free_unparsed_name(context, pname); break; } else { printerr(4, "We will NOT use this entry (%s)\n", pname); } k5_free_unparsed_name(context, pname); k5_free_kt_entry(context, kte); } code = krb5_kt_end_seq_get(context, kt, &cursor); if (code != 0) { k5err = gssd_k5_err_msg(context, code); printerr(0, "WARNING: %s while ending keytab scan for " "keytab '%s'\n", k5err, kt_name); gsh_free(k5err); } retval = 0; out: return retval; }
/* * Obtain (or refresh if necessary) Kerberos machine credentials */ int gssd_refresh_krb5_machine_credential(char *hostname, struct gssd_k5_kt_princ *ple, char *service) { krb5_error_code code = 0; krb5_context context; krb5_keytab kt = NULL; int retval = 0; char *k5err = NULL; const char *svcnames[5] = { "$", "root", "nfs", "host", NULL }; /* * If a specific service name was specified, use it. * Otherwise, use the default list. */ if (service != NULL && strcmp(service, "*") != 0) { svcnames[0] = service; svcnames[1] = NULL; } if (hostname == NULL && ple == NULL) return EINVAL; code = krb5_init_context(&context); if (code) { k5err = gssd_k5_err_msg(NULL, code); printerr(0, "ERROR: %s: %s while initializing krb5 context\n", __func__, k5err); retval = code; gsh_free(k5err); goto out_wo_context; } code = krb5_kt_resolve(context, keytabfile, &kt); if (code != 0) { k5err = gssd_k5_err_msg(context, code); printerr(0, "ERROR: %s: %s while resolving keytab '%s'\n", __func__, k5err, keytabfile); gsh_free(k5err); goto out; } if (ple == NULL) { krb5_keytab_entry kte; code = find_keytab_entry(context, kt, hostname, &kte, svcnames); if (code) { printerr(0, "ERROR: %s: no usable keytab entry found " "in keytab %s for connection with host %s\n", __func__, keytabfile, hostname); retval = code; goto out; } ple = get_ple_by_princ(context, kte.principal); k5_free_kt_entry(context, &kte); if (ple == NULL) { char *pname; if ((krb5_unparse_name(context, kte.principal, &pname))) { pname = NULL; } printerr(0, "ERROR: %s: Could not locate or create ple struct for principal %s for connection with host %s\n", __func__, pname ? pname : "<unparsable>", hostname); if (pname) k5_free_unparsed_name(context, pname); goto out; } } retval = gssd_get_single_krb5_cred(context, kt, ple, 0); out: if (kt) krb5_kt_close(context, kt); krb5_free_context(context); out_wo_context: return retval; }
/* * Obtain (or refresh if necessary) Kerberos machine credentials */ int gssd_refresh_krb5_machine_credential(char *hostname, struct gssd_k5_kt_princ *ple) { krb5_error_code code = 0; krb5_context context; krb5_keytab kt = NULL;; int retval = 0; char *k5err = NULL; if (hostname == NULL && ple == NULL) return EINVAL; code = krb5_init_context(&context); if (code) { k5err = gssd_k5_err_msg(NULL, code); printerr(0, "ERROR: %s: %s while initializing krb5 context\n", __func__, k5err); retval = code; goto out; } if ((code = krb5_kt_resolve(context, keytabfile, &kt))) { k5err = gssd_k5_err_msg(context, code); printerr(0, "ERROR: %s: %s while resolving keytab '%s'\n", __func__, k5err, keytabfile); goto out; } if (ple == NULL) { krb5_keytab_entry kte; code = find_keytab_entry(context, kt, hostname, &kte); if (code) { printerr(0, "ERROR: %s: no usable keytab entry found " "in keytab %s for connection with host %s\n", __FUNCTION__, keytabfile, hostname); retval = code; goto out; } ple = get_ple_by_princ(context, kte.principal); k5_free_kt_entry(context, &kte); if (ple == NULL) { char *pname; if ((krb5_unparse_name(context, kte.principal, &pname))) { pname = NULL; } printerr(0, "ERROR: %s: Could not locate or create " "ple struct for principal %s for connection " "with host %s\n", __FUNCTION__, pname ? pname : "<unparsable>", hostname); if (pname) k5_free_unparsed_name(context, pname); goto out; } } retval = gssd_get_single_krb5_cred(context, kt, ple); out: if (kt) krb5_kt_close(context, kt); krb5_free_context(context); free(k5err); return retval; }