/* * Build a tree given a set of profile values retrieved by * walk_rtree_capath_vals(). */ static krb5_error_code rtree_capath_tree( krb5_context context, const krb5_data *client, const krb5_data *server, char **vals, krb5_principal **rettree) { krb5_error_code retval = 0; unsigned int nvals, nlinks, nprincs, i; krb5_data srcrealm, dstrealm; krb5_principal *tree, *pprinc; *rettree = NULL; tree = pprinc = NULL; for (nvals = 0; vals[nvals] != NULL; nvals++) ; if (vals[0] != NULL && *vals[0] == '.') { nlinks = 0; } else { nlinks = nvals; } nprincs = nlinks + 2; tree = calloc(nprincs + 1, sizeof(krb5_principal)); if (tree == NULL) { retval = ENOMEM; goto error; } for (i = 0; i < nprincs + 1; i++) tree[i] = NULL; /* Invariant: PPRINC points one past end of list. */ pprinc = &tree[0]; /* Local TGS name */ retval = krb5_tgtname(context, client, client, pprinc++); if (retval) goto error; srcrealm = *client; for (i = 0; i < nlinks; i++) { dstrealm.data = vals[i]; dstrealm.length = strcspn(vals[i], "\t "); retval = krb5_tgtname(context, &dstrealm, &srcrealm, pprinc++); if (retval) goto error; srcrealm = dstrealm; } retval = krb5_tgtname(context, server, &srcrealm, pprinc++); if (retval) goto error; *rettree = tree; error: profile_free_list(vals); if (retval) { while (pprinc != NULL && pprinc > &tree[0]) { /* krb5_free_principal() correctly handles null input */ krb5_free_principal(context, *--pprinc); *pprinc = NULL; } free(tree); } return retval; }
/* Ensure that a plugin interface is configured. id must be valid. */ static krb5_error_code configure_interface(krb5_context context, int id) { krb5_error_code ret; struct plugin_interface *interface = &context->plugins[id]; char **modstrs = NULL, **enable = NULL, **disable = NULL; if (interface->configured) return 0; /* Detect consistency errors when plugin interfaces are added. */ assert(sizeof(interface_names) / sizeof(*interface_names) == PLUGIN_NUM_INTERFACES); /* Get profile variables for this interface. */ ret = get_profile_var(context, id, KRB5_CONF_MODULE, &modstrs); if (ret) goto cleanup; ret = get_profile_var(context, id, KRB5_CONF_DISABLE, &disable); if (ret) goto cleanup; ret = get_profile_var(context, id, KRB5_CONF_ENABLE_ONLY, &enable); if (ret) goto cleanup; /* Create the full list of dynamic and built-in modules. */ if (modstrs != NULL) { ret = make_full_list(context, modstrs, &interface->modules); if (ret) goto cleanup; } /* Remove disabled modules. */ if (disable != NULL) remove_disabled_modules(interface->modules, disable); /* Filter and re-order the list according to enable-modules. */ if (enable != NULL) filter_enabled_modules(interface->modules, enable); cleanup: profile_free_list(modstrs); profile_free_list(enable); profile_free_list(disable); return ret; }
bool sss_krb5_realm_has_proxy(const char *realm) { krb5_context context = NULL; krb5_error_code kerr; struct _profile_t *profile = NULL; const char *profile_path[4] = {"realms", NULL, "kdc", NULL}; char **list = NULL; bool res = false; size_t c; if (realm == NULL) { return false; } kerr = krb5_init_context(&context); if (kerr != 0) { DEBUG(SSSDBG_OP_FAILURE, "krb5_init_context failed.\n"); return false; } kerr = krb5_get_profile(context, &profile); if (kerr != 0) { DEBUG(SSSDBG_OP_FAILURE, "krb5_get_profile failed.\n"); goto done; } profile_path[1] = realm; kerr = profile_get_values(profile, profile_path, &list); if (kerr == PROF_NO_RELATION || kerr == PROF_NO_SECTION) { kerr = 0; goto done; } else if (kerr != 0) { DEBUG(SSSDBG_OP_FAILURE, "profile_get_values failed.\n"); goto done; } for (c = 0; list[c] != NULL; c++) { if (strncasecmp(KDC_PROXY_INDICATOR, list[c], KDC_PROXY_INDICATOR_LEN) == 0) { DEBUG(SSSDBG_TRACE_ALL, "Found KDC Proxy indicator [%s] in [%s].\n", KDC_PROXY_INDICATOR, list[c]); res = true; break; } } done: profile_free_list(list); profile_release(profile); krb5_free_context(context); return res; }
krb5_error_code pkinit_libdefault_string(krb5_context context, const krb5_data *realm, const char *option, char **ret_value) { krb5_error_code retval; char **values = NULL; retval = pkinit_libdefault_strings(context, realm, option, &values); if (retval) return retval; if (values[0] == NULL) { retval = ENOENT; } else { *ret_value = strdup(values[0]); if (*ret_value == NULL) retval = ENOMEM; } profile_free_list(values); return retval; }
/* Set up conn->http.tls. Return true on success. */ static krb5_boolean setup_tls(krb5_context context, const krb5_data *realm, struct conn_state *conn, struct select_state *selstate) { krb5_error_code ret; krb5_boolean ok = FALSE; char **anchors = NULL, *realmstr = NULL; const char *names[4]; if (init_tls_vtable(context) != 0 || context->tls->setup == NULL) return FALSE; realmstr = k5memdup0(realm->data, realm->length, &ret); if (realmstr == NULL) goto cleanup; /* Load the configured anchors. */ names[0] = KRB5_CONF_REALMS; names[1] = realmstr; names[2] = KRB5_CONF_HTTP_ANCHORS; names[3] = NULL; ret = profile_get_values(context->profile, names, &anchors); if (ret != 0 && ret != PROF_NO_RELATION) goto cleanup; if (context->tls->setup(context, conn->fd, conn->http.servername, anchors, &conn->http.tls) != 0) { TRACE_SENDTO_KDC_HTTPS_ERROR_CONNECT(context, &conn->addr); goto cleanup; } ok = TRUE; cleanup: free(realmstr); profile_free_list(anchors); return ok; }
krb5_error_code krb5int_locate_server (krb5_context context, const krb5_data *realm, struct addrlist *addrlist, enum locate_service_type svc, int socktype, int family) { krb5_error_code code; struct addrlist al = ADDRLIST_INIT; char **hostlist = NULL; struct srv_dns_entry *dns_list_head = NULL; *addrlist = al; /* * Solaris Kerberos (illumos) * Allow main programs to override _locate_server() */ code = override_locate_server(context, realm, &al, svc, socktype, family); if (code != KRB5_PLUGIN_NO_HANDLE) { if (code == 0) *addrlist = al; else if (al.space) free_list (&al); return (code); } /* Solaris Kerberos (illumos) */ code = module_locate_server(context, realm, &al, svc, socktype, family); Tprintf("module_locate_server returns %d\n", code); if (code == KRB5_PLUGIN_NO_HANDLE) { /* * We always try the local file before DNS. Note that there * is no way to indicate "service not available" via the * config file. */ code = prof_locate_server(context, realm, &hostlist, svc); /* * Solaris Kerberos: * If kpasswd_server has not been configured and dns_lookup_kdc - * dns_fallback are not configured then admin_server should * be inferred, per krb5.conf(4). */ if (code && svc == locate_service_kpasswd && !maybe_use_dns(context, "dns_lookup_kdc", 0)) { code = prof_locate_server(context, realm, &hostlist, locate_service_kadmin); } #ifdef KRB5_DNS_LOOKUP /* * Solaris Kerberos: * There is no point in trying to locate the KDC in DNS if "realm" * is empty. */ /* Try DNS for all profile errors? */ if (code && !krb5_is_referral_realm(realm)) { krb5_error_code code2; code2 = dns_locate_server(context, realm, &dns_list_head, svc, socktype, family); if (code2 != KRB5_PLUGIN_NO_HANDLE) code = code2; } #endif /* KRB5_DNS_LOOKUP */ /* We could put more heuristics here, like looking up a hostname of "kerberos."+REALM, etc. */ } if (code != 0) { if (al.space) free_list (&al); if (hostlist) profile_free_list(hostlist); if (dns_list_head) krb5int_free_srv_dns_data(dns_list_head); return code; } /* * At this point we have no errors, let's check to see if we have * any KDC entries from krb5.conf or DNS. */ if (!hostlist && !dns_list_head) { switch(svc) { case locate_service_master_kdc: krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE, dgettext(TEXT_DOMAIN, "Cannot find a master KDC entry in krb5.conf(4) or DNS Service Location records for realm '%.*s'"), realm->length, realm->data); break; case locate_service_kadmin: krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE, dgettext(TEXT_DOMAIN, "Cannot find a kadmin KDC entry in krb5.conf(4) or DNS Service Location records for realm '%.*s'"), realm->length, realm->data); break; case locate_service_kpasswd: krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE, dgettext(TEXT_DOMAIN, "Cannot find a kpasswd KDC entry in krb5.conf(4) or DNS Service Location records for realm '%.*s'"), realm->length, realm->data); break; default: /* locate_service_kdc: */ krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE, dgettext(TEXT_DOMAIN, "Cannot find any KDC entries in krb5.conf(4) or DNS Service Location records for realm '%.*s'"), realm->length, realm->data); } return KRB5_REALM_CANT_RESOLVE; } /* We have KDC entries, let see if we can get their net addrs. */ if (hostlist) code = prof_hostnames2netaddrs(hostlist, svc, socktype, family, &al); else if (dns_list_head) code = dns_hostnames2netaddrs(dns_list_head, svc, socktype, family, &al); if (code) { if (hostlist) profile_free_list(hostlist); if (dns_list_head) krb5int_free_srv_dns_data(dns_list_head); return code; } /* * Solaris Kerberos: * If an entry for _kerberos-master. does not exist (checked for * above) but _kpasswd. does then treat that as an entry for the * master KDC (but use port 88 not the kpasswd port). MS AD creates * kpasswd entries by default in DNS. */ if (!dns_list_head && svc == locate_service_master_kdc && al.naddrs == 0) { /* Look for _kpasswd._tcp|udp */ code = dns_locate_server(context, realm, &dns_list_head, locate_service_kpasswd, socktype, family); if (code == 0 && dns_list_head) { int i; struct addrinfo *a; code = dns_hostnames2netaddrs(dns_list_head, svc, socktype, family, &al); /* Set the port to 88 instead of the kpasswd port */ if (code == 0 && al.naddrs > 0) { for (i = 0; i < al.naddrs; i++) { if (al.addrs[i].ai->ai_family == AF_INET) for (a = al.addrs[i].ai; a != NULL; a = a->ai_next) ((struct sockaddr_in *)a->ai_addr)->sin_port = htons(KRB5_DEFAULT_PORT); if (al.addrs[i].ai->ai_family == AF_INET6) for (a = al.addrs[i].ai; a != NULL; a = a->ai_next) ((struct sockaddr_in6 *)a->ai_addr)->sin6_port = htons(KRB5_DEFAULT_PORT); } } } } /* No errors so far, lets see if we have KDC net addrs */ if (al.naddrs == 0) { char *hostlist_str = NULL, *dnslist_str = NULL; if (al.space) free_list (&al); if (hostlist) { hostlist_str = hostlist2str(hostlist); krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE, dgettext(TEXT_DOMAIN, "Cannot resolve network address for KDCs '%s' specified in krb5.conf(4) for realm %.*s"), hostlist_str ? hostlist_str : "unknown", realm->length, realm->data); if (hostlist_str) free(hostlist_str); } else if (dns_list_head) { dnslist_str = dnslist2str(dns_list_head); krb5_set_error_message(context, KRB5_REALM_CANT_RESOLVE, dgettext(TEXT_DOMAIN, "Cannot resolve network address for KDCs '%s' discovered via DNS Service Location records for realm '%.*s'"), dnslist_str ? dnslist_str : "unknown", realm->length, realm->data); if (dnslist_str) free(dnslist_str); } if (hostlist) profile_free_list(hostlist); if (dns_list_head) krb5int_free_srv_dns_data(dns_list_head); return KRB5_REALM_CANT_RESOLVE; } if (hostlist) profile_free_list(hostlist); if (dns_list_head) krb5int_free_srv_dns_data(dns_list_head); *addrlist = al; return 0; }
static krb5_error_code kdb_load_library(krb5_context kcontext, char *lib_name, db_library * lib) { krb5_error_code status = 0; int ndx; void **vftabl_addrs = NULL; /* N.B.: If this is "const" but not "static", the Solaris 10 native compiler has trouble building the library because of absolute relocations needed in read-only section ".rodata". When it's static, it goes into ".picdata", which is read-write. */ static const char *const dbpath_names[] = { KDB_MODULE_SECTION, "db_module_dir", NULL, }; const char *filebases[2]; char **profpath = NULL; char **path = NULL; filebases[0] = lib_name; filebases[1] = NULL; if (!strcmp(DB2_NAME, lib_name) && (kdb_db2_pol_err_loaded == 0)) { initialize_adb_error_table(); kdb_db2_pol_err_loaded = 1; } *lib = calloc((size_t) 1, sizeof(**lib)); if (*lib == NULL) { status = ENOMEM; goto clean_n_exit; } status = kdb_init_lib_lock(*lib); if (status) { goto clean_n_exit; } strcpy((*lib)->name, lib_name); /* Fetch the list of directories specified in the config file(s) first. */ status = profile_get_values(kcontext->profile, dbpath_names, &profpath); if (status != 0 && status != PROF_NO_RELATION) goto clean_n_exit; ndx = 0; if (profpath) while (profpath[ndx] != NULL) ndx++; path = calloc(ndx + db_dl_n_locations, sizeof (char *)); if (path == NULL) { status = errno; goto clean_n_exit; } if (ndx) memcpy(path, profpath, ndx * sizeof(profpath[0])); memcpy(path + ndx, db_dl_location, db_dl_n_locations * sizeof(char *)); status = 0; if ((status = krb5int_open_plugin_dirs ((const char **) path, filebases, &(*lib)->dl_dir_handle, &kcontext->err))) { char *err_str = krb5_get_error_message(kcontext, status); status = KRB5_KDB_DBTYPE_NOTFOUND; krb5_set_error_message (kcontext, status, "Unable to find requested database type: %s", err_str); krb5_free_error_message (kcontext, err_str); goto clean_n_exit; } if ((status = krb5int_get_plugin_dir_data (&(*lib)->dl_dir_handle, "kdb_function_table", &vftabl_addrs, &kcontext->err))) { char *err_str = krb5_get_error_message(kcontext, status); status = KRB5_KDB_DBTYPE_INIT; krb5_set_error_message (kcontext, status, "plugin symbol 'kdb_function_table' lookup failed: %s", err_str); krb5_free_error_message (kcontext, err_str); goto clean_n_exit; } if (vftabl_addrs[0] == NULL) { /* No plugins! */ status = KRB5_KDB_DBTYPE_NOTFOUND; krb5_set_error_message (kcontext, status, _("Unable to load requested database module '%s': plugin symbol 'kdb_function_table' not found"), lib_name); goto clean_n_exit; } memcpy(&(*lib)->vftabl, vftabl_addrs[0], sizeof(kdb_vftabl)); kdb_setup_opt_functions(*lib); if ((status = (*lib)->vftabl.init_library())) { /* ERROR. library not initialized cleanly */ goto clean_n_exit; } clean_n_exit: if (vftabl_addrs != NULL) { krb5int_free_plugin_dir_data (vftabl_addrs); } /* Both of these DTRT with NULL. */ profile_free_list(profpath); free(path); if (status) { if (*lib) { kdb_destroy_lib_lock(*lib); if (PLUGIN_DIR_OPEN((&(*lib)->dl_dir_handle))) { krb5int_close_plugin_dirs (&(*lib)->dl_dir_handle); } free(*lib); *lib = NULL; } } return status; }
krb5_error_code KRB5_CALLCONV krb5_425_conv_principal(krb5_context context, const char *name, const char *instance, const char *realm, krb5_principal *princ) { const struct krb_convert *p; char buf[256]; /* V4 instances are limited to 40 characters */ krb5_error_code retval; char *domain, *cp; char **full_name = 0; const char *names[5], *names2[2]; void* iterator = NULL; char** v4realms = NULL; char* realm_name = NULL; char* dummy_value = NULL; /* First, convert the realm, since the v4 realm is not necessarily the same as the v5 realm To do that, iterate over all the realms in the config file, looking for a matching v4_realm line */ names2 [0] = "realms"; names2 [1] = NULL; retval = profile_iterator_create (context -> profile, names2, PROFILE_ITER_LIST_SECTION | PROFILE_ITER_SECTIONS_ONLY, &iterator); while (retval == 0) { retval = profile_iterator (&iterator, &realm_name, &dummy_value); if ((retval == 0) && (realm_name != NULL)) { names [0] = "realms"; names [1] = realm_name; names [2] = "v4_realm"; names [3] = NULL; retval = profile_get_values (context -> profile, names, &v4realms); if ((retval == 0) && (v4realms != NULL) && (v4realms [0] != NULL) && (strcmp (v4realms [0], realm) == 0)) { realm = realm_name; break; } else if (retval == PROF_NO_RELATION) { /* If it's not found, just keep going */ retval = 0; } } else if ((retval == 0) && (realm_name == NULL)) { break; } if (v4realms != NULL) { profile_free_list(v4realms); v4realms = NULL; } if (realm_name != NULL) { profile_release_string (realm_name); realm_name = NULL; } if (dummy_value != NULL) { profile_release_string (dummy_value); dummy_value = NULL; } } if (instance) { if (instance[0] == '\0') { instance = 0; goto not_service; } p = sconv_list; while (1) { if (!p->v4_str) goto not_service; if (!strcmp(p->v4_str, name)) break; p++; } name = p->v5_str; if ((p->flags & DO_REALM_CONVERSION) && !strchr(instance, '.')) { names[0] = "realms"; names[1] = realm; names[2] = "v4_instance_convert"; names[3] = instance; names[4] = 0; retval = profile_get_values(context->profile, names, &full_name); if (retval == 0 && full_name && full_name[0]) { instance = full_name[0]; } else { strncpy(buf, instance, sizeof(buf)); buf[sizeof(buf) - 1] = '\0'; retval = krb5_get_realm_domain(context, realm, &domain); if (retval) return retval; if (domain) { for (cp = domain; *cp; cp++) if (isupper((unsigned char) (*cp))) *cp = tolower((unsigned char) *cp); strncat(buf, ".", sizeof(buf) - 1 - strlen(buf)); strncat(buf, domain, sizeof(buf) - 1 - strlen(buf)); krb5_xfree(domain); } instance = buf; } } } not_service: retval = krb5_build_principal(context, princ, strlen(realm), realm, name, instance, NULL); if (iterator) profile_iterator_free (&iterator); if (full_name) profile_free_list(full_name); if (v4realms) profile_free_list(v4realms); if (realm_name) profile_release_string (realm_name); if (dummy_value) profile_release_string (dummy_value); return retval; }
static krb5_error_code locate_srv_conf_1(krb5_context context, const krb5_data *realm, const char * name, struct serverlist *serverlist, int socktype, int udpport, int sec_udpport) { const char *realm_srv_names[4]; char **hostlist, *host, *port, *cp; krb5_error_code code; int i; Tprintf ("looking in krb5.conf for realm %s entry %s; ports %d,%d\n", realm->data, name, ntohs (udpport), ntohs (sec_udpport)); if ((host = malloc(realm->length + 1)) == NULL) return ENOMEM; strncpy(host, realm->data, realm->length); host[realm->length] = '\0'; hostlist = 0; realm_srv_names[0] = KRB5_CONF_REALMS; realm_srv_names[1] = host; realm_srv_names[2] = name; realm_srv_names[3] = 0; code = profile_get_values(context->profile, realm_srv_names, &hostlist); free(host); if (code) { Tprintf ("config file lookup failed: %s\n", error_message(code)); if (code == PROF_NO_SECTION || code == PROF_NO_RELATION) code = 0; return code; } for (i=0; hostlist[i]; i++) { int p1, p2; host = hostlist[i]; Tprintf ("entry %d is '%s'\n", i, host); /* Find port number, and strip off any excess characters. */ if (*host == '[' && (cp = strchr(host, ']'))) cp = cp + 1; else cp = host + strcspn(host, " \t:"); port = (*cp == ':') ? cp + 1 : NULL; *cp = '\0'; if (port) { unsigned long l; #ifdef HAVE_STROUL char *endptr; l = strtoul (port, &endptr, 10); if (endptr == NULL || *endptr != 0) return EINVAL; #else l = atoi (port); #endif /* L is unsigned, don't need to check <0. */ if (l > 65535) return EINVAL; p1 = htons (l); p2 = 0; } else { p1 = udpport; p2 = sec_udpport; } /* If the hostname was in brackets, strip those off now. */ if (*host == '[' && (cp = strchr(host, ']'))) { host++; *cp = '\0'; } code = add_host_to_list(serverlist, host, p1, socktype, AF_UNSPEC); /* Second port is for IPv4 UDP only, and should possibly go away as * it was originally a krb4 compatibility measure. */ if (code == 0 && p2 != 0 && (socktype == 0 || socktype == SOCK_DGRAM)) code = add_host_to_list(serverlist, host, p2, SOCK_DGRAM, AF_INET); if (code) goto cleanup; } cleanup: profile_free_list(hostlist); return code; }
krb5_error_code krb5_get_krbhst(krb5_context context, const krb5_data *realm, char ***hostlist) { char **values, **cpp, *cp; const char *realm_kdc_names[4]; krb5_error_code retval; int i, count; char **rethosts; rethosts = 0; realm_kdc_names[0] = "realms"; realm_kdc_names[1] = realm->data; realm_kdc_names[2] = "kdc"; realm_kdc_names[3] = 0; if (context->profile == 0) return KRB5_CONFIG_CANTOPEN; retval = profile_get_values(context->profile, realm_kdc_names, &values); if (retval == PROF_NO_SECTION) return KRB5_REALM_UNKNOWN; if (retval == PROF_NO_RELATION) return KRB5_CONFIG_BADFORMAT; if (retval) return retval; /* * Do cleanup over the list. We allow for some extra field to be * added to the kdc line later (maybe the port number) */ for (cpp = values; *cpp; cpp++) { cp = strchr(*cpp, ' '); if (cp) *cp = 0; cp = strchr(*cpp, '\t'); if (cp) *cp = 0; cp = strchr(*cpp, ':'); if (cp) *cp = 0; } count = cpp - values; rethosts = malloc(sizeof(char *) * (count + 1)); if (!rethosts) { retval = ENOMEM; goto cleanup; } for (i = 0; i < count; i++) { unsigned int len = strlen (values[i]) + 1; rethosts[i] = malloc(len); if (!rethosts[i]) { retval = ENOMEM; goto cleanup; } memcpy (rethosts[i], values[i], len); } rethosts[count] = 0; cleanup: if (retval && rethosts) { for (cpp = rethosts; *cpp; cpp++) free(*cpp); free(rethosts); rethosts = 0; } profile_free_list(values); *hostlist = rethosts; return retval; }
static krb5_error_code locate_srv_conf_1(krb5_context context, const krb5_data *realm, const char * name, struct serverlist *serverlist, k5_transport transport, int udpport) { const char *realm_srv_names[4]; char **hostlist = NULL, *realmstr = NULL, *host = NULL; const char *hostspec; krb5_error_code code; int i, default_port; Tprintf("looking in krb5.conf for realm %s entry %s; ports %d,%d\n", realm->data, name, udpport); realmstr = k5memdup0(realm->data, realm->length, &code); if (realmstr == NULL) goto cleanup; realm_srv_names[0] = KRB5_CONF_REALMS; realm_srv_names[1] = realmstr; realm_srv_names[2] = name; realm_srv_names[3] = 0; code = profile_get_values(context->profile, realm_srv_names, &hostlist); if (code) { Tprintf("config file lookup failed: %s\n", error_message(code)); if (code == PROF_NO_SECTION || code == PROF_NO_RELATION) code = 0; goto cleanup; } for (i = 0; hostlist[i]; i++) { int port_num; k5_transport this_transport = transport; const char *uri_path = NULL; hostspec = hostlist[i]; Tprintf("entry %d is '%s'\n", i, hostspec); parse_uri_if_https(hostspec, &this_transport, &hostspec, &uri_path); default_port = (this_transport == HTTPS) ? 443 : udpport; code = k5_parse_host_string(hostspec, default_port, &host, &port_num); if (code == 0 && host == NULL) code = EINVAL; if (code) goto cleanup; code = add_host_to_list(serverlist, host, port_num, this_transport, AF_UNSPEC, uri_path, -1); if (code) goto cleanup; free(host); host = NULL; } cleanup: free(realmstr); free(host); profile_free_list(hostlist); return code; }
krb5_error_code pkinit_cert_matching(krb5_context context, pkinit_plg_crypto_context plg_cryptoctx, pkinit_req_crypto_context req_cryptoctx, pkinit_identity_crypto_context id_cryptoctx, krb5_principal princ) { krb5_error_code retval = KRB5KDC_ERR_PREAUTH_FAILED; int x; char **rules = NULL; rule_set *rs = NULL; int match_found = 0; pkinit_cert_matching_data **matchdata = NULL; pkinit_cert_matching_data *the_matching_cert = NULL; /* If no matching rules, select the default cert and we're done */ pkinit_libdefault_strings(context, krb5_princ_realm(context, princ), KRB5_CONF_PKINIT_CERT_MATCH, &rules); if (rules == NULL) { pkiDebug("%s: no matching rules found in config file\n", __FUNCTION__); retval = crypto_cert_select_default(context, plg_cryptoctx, req_cryptoctx, id_cryptoctx); goto cleanup; } /* parse each rule line one at a time and check all the certs against it */ for (x = 0; rules[x] != NULL; x++) { pkiDebug("%s: Processing rule '%s'\n", __FUNCTION__, rules[x]); /* Free rules from previous time through... */ if (rs != NULL) { free_rule_set(context, rs); rs = NULL; } retval = parse_rule_set(context, rules[x], &rs); if (retval) { if (retval == EINVAL) { pkiDebug("%s: Ignoring invalid rule pkinit_cert_match = '%s'\n", __FUNCTION__, rules[x]); continue; } goto cleanup; } /* * Optimize so that we do not get cert info unless we have * valid rules to check. Once obtained, keep it around * until we are done. */ if (matchdata == NULL) { retval = obtain_all_cert_matching_data(context, plg_cryptoctx, req_cryptoctx, id_cryptoctx, &matchdata); if (retval || matchdata == NULL) { pkiDebug("%s: Error %d obtaining certificate information\n", __FUNCTION__, retval); retval = ENOENT; goto cleanup; } } retval = check_all_certs(context, plg_cryptoctx, req_cryptoctx, id_cryptoctx, princ, rs, matchdata, &match_found, &the_matching_cert); if (retval) { pkiDebug("%s: Error %d, checking certs against rule '%s'\n", __FUNCTION__, retval, rules[x]); goto cleanup; } if (match_found) { pkiDebug("%s: We have an exact match with rule '%s'\n", __FUNCTION__, rules[x]); break; } } if (match_found && the_matching_cert != NULL) { pkiDebug("%s: Selecting the matching cert!\n", __FUNCTION__); retval = crypto_cert_select(context, the_matching_cert); if (retval) { pkiDebug("%s: crypto_cert_select error %d, %s\n", __FUNCTION__, retval, error_message(retval)); goto cleanup; } } else { retval = ENOENT; /* XXX */ goto cleanup; } retval = 0; cleanup: if (rules != NULL) profile_free_list(rules); if (rs != NULL) free_rule_set(context, rs); if (matchdata != NULL) free_all_cert_matching_data(context, matchdata); return retval; }