static krb5_error_code set_etypes (krb5_context context, const char *name, krb5_enctype **ret_enctypes) { char **etypes_str; krb5_enctype *etypes = NULL; etypes_str = krb5_config_get_strings(context, NULL, "libdefaults", name, NULL); if(etypes_str){ int i, j, k; for(i = 0; etypes_str[i]; i++); etypes = malloc((i+1) * sizeof(*etypes)); if (etypes == NULL) { krb5_config_free_strings (etypes_str); return krb5_enomem(context); } for(j = 0, k = 0; j < i; j++) { krb5_enctype e; if(krb5_string_to_enctype(context, etypes_str[j], &e) != 0) continue; if (krb5_enctype_valid(context, e) != 0) continue; etypes[k++] = e; } etypes[k] = ETYPE_NULL; krb5_config_free_strings(etypes_str); } *ret_enctypes = etypes; return 0; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_check_transited_realms(krb5_context context, const char *const *realms, unsigned int num_realms, int *bad_realm) { size_t i; int ret = 0; char **bad_realms = krb5_config_get_strings(context, NULL, "libdefaults", "transited_realms_reject", NULL); if(bad_realms == NULL) return 0; for(i = 0; i < num_realms; i++) { char **p; for(p = bad_realms; *p; p++) if(strcmp(*p, realms[i]) == 0) { ret = KRB5KRB_AP_ERR_ILL_CR_TKT; krb5_set_error_message (context, ret, N_("no transit allowed " "through realm %s", ""), *p); if(bad_realm) *bad_realm = (int)i; break; } } krb5_config_free_strings(bad_realms); return ret; }
krb5_error_code KRB5_LIB_FUNCTION krb5_check_transited_realms(krb5_context context, const char *const *realms, int num_realms, int *bad_realm) { int i; int ret = 0; char **bad_realms = krb5_config_get_strings(context, NULL, "libdefaults", "transited_realms_reject", NULL); if(bad_realms == NULL) return 0; for(i = 0; i < num_realms; i++) { char **p; for(p = bad_realms; *p; p++) if(strcmp(*p, realms[i]) == 0) { krb5_set_error_string (context, "no transit through realm %s", *p); ret = KRB5KRB_AP_ERR_ILL_CR_TKT; if(bad_realm) *bad_realm = i; break; } } krb5_config_free_strings(bad_realms); return ret; }
const char * kadm5_check_password_quality (krb5_context context, krb5_principal principal, krb5_data *pwd_data) { const struct kadm5_pw_policy_check_func *proc; static char error_msg[1024]; const char *msg; char **v, **vp; int ret; /* * Check if we should use the old version of policy function. */ v = krb5_config_get_strings(context, NULL, "password_quality", "policies", NULL); if (v == NULL) { msg = (*passwd_quality_check) (context, principal, pwd_data); if (msg) krb5_set_error_message(context, 0, "password policy failed: %s", msg); return msg; } error_msg[0] = '\0'; msg = NULL; for(vp = v; *vp; vp++) { proc = find_func(context, *vp); if (proc == NULL) { msg = "failed to find password verifier function"; krb5_set_error_message(context, 0, "Failed to find password policy " "function: %s", *vp); break; } ret = (proc->func)(context, principal, pwd_data, NULL, error_msg, sizeof(error_msg)); if (ret) { krb5_set_error_message(context, 0, "Password policy " "%s failed with %s", proc->name, error_msg); msg = error_msg; break; } } krb5_config_free_strings(v); /* If the default quality check isn't used, lets check that the * old quality function the user have set too */ if (msg == NULL && passwd_quality_check != min_length_passwd_quality_v0) { msg = (*passwd_quality_check) (context, principal, pwd_data); if (msg) krb5_set_error_message(context, 0, "(old) password policy " "failed with %s", msg); } return msg; }
krb5_error_code kadm5_add_passwd_quality_verifier(krb5_context context, const char *check_library) { #ifdef HAVE_DLOPEN if(check_library == NULL) { krb5_error_code ret = 0; char **strs; char **tmp; strs = krb5_config_get_strings(context, NULL, "password_quality", "policy_libraries", NULL); if (strs == NULL) return 0; for (tmp = strs; *tmp; tmp++) { ret = add_verifier(context, *tmp); if (ret) break; } krb5_config_free_strings(strs); return ret; } else { return add_verifier(context, check_library); } #else return 0; #endif /* HAVE_DLOPEN */ }
static int dns_find_realm(krb5_context context, const char *domain, krb5_realm **realms) { static const char *default_labels[] = { "_kerberos", NULL }; char dom[MAXHOSTNAMELEN]; struct rk_dns_reply *r; const char **labels; char **config_labels; int i, ret; config_labels = krb5_config_get_strings(context, NULL, "libdefaults", "dns_lookup_realm_labels", NULL); if(config_labels != NULL) labels = (const char **)config_labels; else labels = default_labels; if(*domain == '.') domain++; for (i = 0; labels[i] != NULL; i++) { ret = snprintf(dom, sizeof(dom), "%s.%s.", labels[i], domain); if(ret < 0 || (size_t)ret >= sizeof(dom)) { if (config_labels) krb5_config_free_strings(config_labels); return -1; } r = rk_dns_lookup(dom, "TXT"); if(r != NULL) { ret = copy_txt_to_realms (r->head, realms); rk_dns_free_data(r); if(ret == 0) { if (config_labels) krb5_config_free_strings(config_labels); return 0; } } } if (config_labels) krb5_config_free_strings(config_labels); return -1; }
KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_check_transited(krb5_context context, krb5_const_realm client_realm, krb5_const_realm server_realm, krb5_realm *realms, unsigned int num_realms, int *bad_realm) { char **tr_realms; char **p; size_t i; if(num_realms == 0) return 0; tr_realms = krb5_config_get_strings(context, NULL, "capaths", client_realm, server_realm, NULL); for(i = 0; i < num_realms; i++) { for(p = tr_realms; p && *p; p++) { if(strcmp(*p, realms[i]) == 0) break; } if(p == NULL || *p == NULL) { krb5_config_free_strings(tr_realms); krb5_set_error_message (context, KRB5KRB_AP_ERR_ILL_CR_TKT, N_("no transit allowed " "through realm %s", ""), realms[i]); if(bad_realm) *bad_realm = i; return KRB5KRB_AP_ERR_ILL_CR_TKT; } } krb5_config_free_strings(tr_realms); return 0; }
static void check_escaped_strings(void) { krb5_context context; krb5_config_section *c = NULL; krb5_error_code ret; int i; ret = krb5_init_context(&context); if (ret) errx(1, "krb5_init_context %d", ret); ret = krb5_config_parse_file(context, "test_config_strings.out", &c); if (ret) krb5_errx(context, 1, "krb5_config_parse_file()"); for (i=0; i < sizeof(config_strings_tests)/sizeof(config_strings_tests[0]); i++) { char **ps; const char **s; const char **e; ps = krb5_config_get_strings(context, c, "escapes", config_strings_tests[i].name, NULL); if (ps == NULL) errx(1, "Failed to read string value %s", config_strings_tests[i].name); e = config_strings_tests[i].expected; for (s = (const char **)ps; *s && *e; s++, e++) { if (strcmp(*s, *e)) errx(1, "Unexpected configuration string at value [%s].\n" "Actual=[%s]\n" "Expected=[%s]\n", config_strings_tests[i].name, *s, *e); } if (*s || *e) errx(1, "Configuation string list for value [%s] has incorrect length.", config_strings_tests[i].name); krb5_config_free_strings(ps); } ret = krb5_config_file_free(context, c); if (ret) krb5_errx(context, 1, "krb5_config_file_free()"); krb5_free_context(context); }
void kcm_openlog(void) { char **s = NULL, **p; krb5_initlog(kcm_context, "kcm", &logf); s = krb5_config_get_strings(kcm_context, NULL, "kcm", "logging", NULL); if(s == NULL) s = krb5_config_get_strings(kcm_context, NULL, "logging", "kcm", NULL); if(s) { for(p = s; *p; p++) krb5_addlog_dest(kcm_context, logf, *p); krb5_config_free_strings(s); } else krb5_addlog_dest(kcm_context, logf, DEFAULT_LOG_DEST); krb5_set_warn_dest(kcm_context, logf); }
void kdc_openlog(krb5_context context, krb5_kdc_configuration *config) { char **s = NULL, **p; krb5_initlog(context, "kdc", &config->logf); s = krb5_config_get_strings(context, NULL, "kdc", "logging", NULL); if(s == NULL) s = krb5_config_get_strings(context, NULL, "logging", "kdc", NULL); if(s){ for(p = s; *p; p++) krb5_addlog_dest(context, config->logf, *p); krb5_config_free_strings(s); }else krb5_addlog_dest(context, config->logf, DEFAULT_LOG_DEST); krb5_set_warn_dest(context, config->logf); }
static void init_context_once(void *ctx) { krb5_context context = ctx; char **dirs; dirs = krb5_config_get_strings(context, NULL, "libdefaults", "plugin_dir", NULL); if (dirs == NULL) dirs = rk_UNCONST(sysplugin_dirs); _krb5_load_plugins(context, "krb5", (const char **)dirs); if (dirs != rk_UNCONST(sysplugin_dirs)) krb5_config_free_strings(dirs); bindtextdomain(HEIMDAL_TEXTDOMAIN, HEIMDAL_LOCALEDIR); }
static void config_get_hosts(krb5_context context, struct krb5_krbhst_data *kd, const char *conf_string) { int i; char **hostlist; hostlist = krb5_config_get_strings(context, NULL, "realms", kd->realm, conf_string, NULL); if(hostlist == NULL) return; kd->flags |= KD_CONFIG_EXISTS; for(i = 0; hostlist && hostlist[i] != NULL; i++) append_host_string(context, kd, hostlist[i], kd->def_port, kd->port); krb5_config_free_strings(hostlist); }
static krb5_error_code check_compat(OM_uint32 *minor_status, krb5_context context, krb5_const_principal name, const char *option, krb5_boolean *compat, krb5_boolean match_val) { krb5_error_code ret = 0; char **p, **q; krb5_principal match; p = krb5_config_get_strings(context, NULL, "gssapi", option, NULL); if(p == NULL) return 0; match = NULL; for(q = p; *q; q++) { ret = krb5_parse_name(context, *q, &match); if (ret) break; if (krb5_principal_match(context, name, match)) { *compat = match_val; break; } krb5_free_principal(context, match); match = NULL; } if (match) krb5_free_principal(context, match); krb5_config_free_strings(p); if (ret) { if (minor_status) *minor_status = ret; return GSS_S_FAILURE; } return 0; }
/* * This function implements MIT's auth_to_local_names configuration for * configuration compatibility. Specifically: * * [realms] * <realm-name> = { * auth_to_local_names = { * <unparsed-principal-name> = <username> * } * } * * If multiple usernames are configured then the last one is taken. * * The configuration can only be expected to hold a relatively small * number of mappings. For lots of mappings use a DB. */ static krb5_error_code an2ln_local_names(krb5_context context, krb5_const_principal aname, size_t lnsize, char *lname) { krb5_error_code ret; char *unparsed; char **values; char *res; size_t i; if (!princ_realm_is_default(context, aname)) return KRB5_PLUGIN_NO_HANDLE; ret = krb5_unparse_name_flags(context, aname, KRB5_PRINCIPAL_UNPARSE_NO_REALM, &unparsed); if (ret) return ret; ret = KRB5_PLUGIN_NO_HANDLE; values = krb5_config_get_strings(context, NULL, "realms", aname->realm, "auth_to_local_names", unparsed, NULL); free(unparsed); if (!values) return ret; /* Take the last value, just like MIT */ for (res = NULL, i = 0; values[i]; i++) res = values[i]; if (res) { ret = 0; if (strlcpy(lname, res, lnsize) >= lnsize) ret = KRB5_CONFIG_NOTENUFSPACE; if (!*res || strcmp(res, ":") == 0) ret = KRB5_NO_LOCALNAME; } krb5_config_free_strings(values); return ret; }
void kdc_openlog(krb5_context context, krb5_kdc_configuration *config) { char **s = NULL, **p; krb5_initlog(context, "kdc", &config->logf); s = krb5_config_get_strings(context, NULL, "kdc", "logging", NULL); if(s == NULL) s = krb5_config_get_strings(context, NULL, "logging", "kdc", NULL); if(s){ for(p = s; *p; p++) krb5_addlog_dest(context, config->logf, *p); krb5_config_free_strings(s); }else { char *s; asprintf(&s, "0-1/FILE:%s/%s", hdb_db_dir(context), KDC_LOG_FILE); krb5_addlog_dest(context, config->logf, s); free(s); } krb5_set_warn_dest(context, config->logf); }
krb5_error_code KRB5_LIB_FUNCTION krb5_openlog(krb5_context context, const char *program, krb5_log_facility **fac) { krb5_error_code ret; char **p, **q; ret = krb5_initlog(context, program, fac); if(ret) return ret; p = krb5_config_get_strings(context, NULL, "logging", program, NULL); if(p == NULL) p = krb5_config_get_strings(context, NULL, "logging", "default", NULL); if(p){ for(q = p; *q && ret == 0; q++) ret = krb5_addlog_dest(context, *fac, *q); krb5_config_free_strings(p); }else ret = krb5_addlog_dest(context, *fac, "SYSLOG"); return ret; }
static krb5_error_code init_context_from_config_file(krb5_context context) { krb5_error_code ret; const char * tmp; char **s; krb5_enctype *tmptypes; INIT_FIELD(context, time, max_skew, 5 * 60, "clockskew"); INIT_FIELD(context, time, kdc_timeout, 30, "kdc_timeout"); INIT_FIELD(context, time, host_timeout, 3, "host_timeout"); INIT_FIELD(context, int, max_retries, 3, "max_retries"); INIT_FIELD(context, string, http_proxy, NULL, "http_proxy"); ret = krb5_config_get_bool_default(context, NULL, FALSE, "libdefaults", "allow_weak_crypto", NULL); if (ret) { krb5_enctype_enable(context, ETYPE_DES_CBC_CRC); krb5_enctype_enable(context, ETYPE_DES_CBC_MD4); krb5_enctype_enable(context, ETYPE_DES_CBC_MD5); krb5_enctype_enable(context, ETYPE_DES_CBC_NONE); krb5_enctype_enable(context, ETYPE_DES_CFB64_NONE); krb5_enctype_enable(context, ETYPE_DES_PCBC_NONE); } ret = set_etypes (context, "default_etypes", &tmptypes); if(ret) return ret; free(context->etypes); context->etypes = tmptypes; ret = set_etypes (context, "default_etypes_des", &tmptypes); if(ret) return ret; free(context->etypes_des); context->etypes_des = tmptypes; ret = set_etypes (context, "default_as_etypes", &tmptypes); if(ret) return ret; free(context->as_etypes); context->as_etypes = tmptypes; ret = set_etypes (context, "default_tgs_etypes", &tmptypes); if(ret) return ret; free(context->tgs_etypes); context->tgs_etypes = tmptypes; ret = set_etypes (context, "permitted_enctypes", &tmptypes); if(ret) return ret; free(context->permitted_enctypes); context->permitted_enctypes = tmptypes; /* default keytab name */ tmp = NULL; if(!issuid()) tmp = getenv("KRB5_KTNAME"); if(tmp != NULL) context->default_keytab = tmp; else INIT_FIELD(context, string, default_keytab, KEYTAB_DEFAULT, "default_keytab_name"); INIT_FIELD(context, string, default_keytab_modify, NULL, "default_keytab_modify_name"); INIT_FIELD(context, string, time_fmt, "%Y-%m-%dT%H:%M:%S", "time_format"); INIT_FIELD(context, string, date_fmt, "%Y-%m-%d", "date_format"); INIT_FIELD(context, bool, log_utc, FALSE, "log_utc"); /* init dns-proxy slime */ tmp = krb5_config_get_string(context, NULL, "libdefaults", "dns_proxy", NULL); if(tmp) roken_gethostby_setup(context->http_proxy, tmp); krb5_free_host_realm (context, context->default_realms); context->default_realms = NULL; { krb5_addresses addresses; char **adr, **a; krb5_set_extra_addresses(context, NULL); adr = krb5_config_get_strings(context, NULL, "libdefaults", "extra_addresses", NULL); memset(&addresses, 0, sizeof(addresses)); for(a = adr; a && *a; a++) { ret = krb5_parse_address(context, *a, &addresses); if (ret == 0) { krb5_add_extra_addresses(context, &addresses); krb5_free_addresses(context, &addresses); } } krb5_config_free_strings(adr); krb5_set_ignore_addresses(context, NULL); adr = krb5_config_get_strings(context, NULL, "libdefaults", "ignore_addresses", NULL); memset(&addresses, 0, sizeof(addresses)); for(a = adr; a && *a; a++) { ret = krb5_parse_address(context, *a, &addresses); if (ret == 0) { krb5_add_ignore_addresses(context, &addresses); krb5_free_addresses(context, &addresses); } } krb5_config_free_strings(adr); } INIT_FIELD(context, bool, scan_interfaces, TRUE, "scan_interfaces"); INIT_FIELD(context, int, fcache_vno, 0, "fcache_version"); /* prefer dns_lookup_kdc over srv_lookup. */ INIT_FIELD(context, bool, srv_lookup, TRUE, "srv_lookup"); INIT_FIELD(context, bool, srv_lookup, context->srv_lookup, "dns_lookup_kdc"); INIT_FIELD(context, int, large_msg_size, 1400, "large_message_size"); INIT_FIELD(context, int, max_msg_size, 1000 * 1024, "maximum_message_size"); INIT_FLAG(context, flags, KRB5_CTX_F_DNS_CANONICALIZE_HOSTNAME, TRUE, "dns_canonicalize_hostname"); INIT_FLAG(context, flags, KRB5_CTX_F_CHECK_PAC, TRUE, "check_pac"); if (context->default_cc_name) free(context->default_cc_name); context->default_cc_name = NULL; context->default_cc_name_set = 0; s = krb5_config_get_strings(context, NULL, "logging", "krb5", NULL); if(s) { char **p; if (context->debug_dest) krb5_closelog(context, context->debug_dest); krb5_initlog(context, "libkrb5", &context->debug_dest); for(p = s; *p; p++) krb5_addlog_dest(context, context->debug_dest, *p); krb5_config_free_strings(s); } tmp = krb5_config_get_string(context, NULL, "libdefaults", "check-rd-req-server", NULL); if (tmp == NULL && !issuid()) tmp = getenv("KRB5_CHECK_RD_REQ_SERVER"); if(tmp) { if (strcasecmp(tmp, "ignore") == 0) context->flags |= KRB5_CTX_F_RD_REQ_IGNORE; } ret = krb5_config_get_bool_default(context, NULL, TRUE, "libdefaults", "fcache_strict_checking", NULL); if (ret) context->flags |= KRB5_CTX_F_FCACHE_STRICT_CHECKING; return 0; }
static krb5_error_code change_pw_and_update_keytab(krb5_context context, kcm_ccache ccache) { char newpw[121]; krb5_error_code ret; unsigned kvno; krb5_salt salt; krb5_enctype *etypes = NULL; int i; char *cpn = NULL; char **spns = NULL; krb5_data_zero(&salt.saltvalue); ret = krb5_unparse_name(context, ccache->client, &cpn); if (ret) { kcm_log(0, "Failed to unparse name: %s", krb5_get_err_text(context, ret)); goto out; } ret = krb5_get_default_in_tkt_etypes(context, &etypes); if (ret) { kcm_log(0, "Failed to determine default encryption types: %s", krb5_get_err_text(context, ret)); goto out; } /* Generate a random password (there is no set keys protocol) */ generate_random_pw(context, newpw, sizeof(newpw)); /* Change it */ ret = change_pw(context, ccache, cpn, newpw); if (ret) goto out; /* Do an AS-REQ to determine salt and key version number */ ret = get_salt_and_kvno(context, ccache, etypes, cpn, newpw, &salt, &kvno); if (ret) { kcm_log(0, "Failed to determine salting principal for principal %s: %s", cpn, krb5_get_err_text(context, ret)); goto out; } /* Add canonical name */ ret = update_keytab_entries(context, ccache, etypes, cpn, NULL, newpw, salt, kvno); if (ret) goto out; /* Add SPN aliases, if any */ spns = krb5_config_get_strings(context, NULL, "kcm", "system_ccache", "spn_aliases", NULL); if (spns != NULL) { for (i = 0; spns[i] != NULL; i++) { ret = update_keytab_entries(context, ccache, etypes, cpn, spns[i], newpw, salt, kvno); if (ret) goto out; } } kcm_log(0, "Changed expired password for principal %s in cache %s", cpn, ccache->name); out: if (cpn != NULL) free(cpn); if (spns != NULL) krb5_config_free_strings(spns); if (etypes != NULL) free(etypes); krb5_free_salt(context, salt); memset(newpw, 0, sizeof(newpw)); return ret; }
krb5_error_code KRB5_LIB_FUNCTION krb5_425_conv_principal_ext2(krb5_context context, const char *name, const char *instance, const char *realm, krb5_boolean (*func)(krb5_context, void *, krb5_principal), void *funcctx, krb5_boolean resolve, krb5_principal *princ) { const char *p; krb5_error_code ret; krb5_principal pr; char host[MAXHOSTNAMELEN]; char local_hostname[MAXHOSTNAMELEN]; /* do the following: if the name is found in the `v4_name_convert:host' part, is is assumed to be a `host' type principal, and the instance is looked up in the `v4_instance_convert' part. if not found there the name is (optionally) looked up as a hostname, and if that doesn't yield anything, the `default_domain' is appended to the instance */ if(instance == NULL) goto no_host; if(instance[0] == 0){ instance = NULL; goto no_host; } p = get_name_conversion(context, realm, name); if(p == NULL) goto no_host; name = p; p = krb5_config_get_string(context, NULL, "realms", realm, "v4_instance_convert", instance, NULL); if(p){ instance = p; ret = krb5_make_principal(context, &pr, realm, name, instance, NULL); if(func == NULL || (*func)(context, funcctx, pr)){ *princ = pr; return 0; } krb5_free_principal(context, pr); *princ = NULL; krb5_clear_error_string (context); return HEIM_ERR_V4_PRINC_NO_CONV; } if(resolve){ krb5_boolean passed = FALSE; char *inst = NULL; #ifdef USE_RESOLVER struct dns_reply *r; r = dns_lookup(instance, "aaaa"); if (r) { if (r->head && r->head->type == T_AAAA) { inst = strdup(r->head->domain); passed = TRUE; } dns_free_data(r); } else { r = dns_lookup(instance, "a"); if (r) { if(r->head && r->head->type == T_A) { inst = strdup(r->head->domain); passed = TRUE; } dns_free_data(r); } } #else struct addrinfo hints, *ai; memset (&hints, 0, sizeof(hints)); hints.ai_flags = AI_CANONNAME; ret = getaddrinfo(instance, NULL, &hints, &ai); if (ret == 0) { const struct addrinfo *a; for (a = ai; a != NULL; a = a->ai_next) { if (a->ai_canonname != NULL) { inst = strdup (a->ai_canonname); passed = TRUE; break; } } freeaddrinfo (ai); } #endif if (passed) { if (inst == NULL) { krb5_set_error_string (context, "malloc: out of memory"); return ENOMEM; } strlwr(inst); ret = krb5_make_principal(context, &pr, realm, name, inst, NULL); free (inst); if(ret == 0) { if(func == NULL || (*func)(context, funcctx, pr)){ *princ = pr; return 0; } krb5_free_principal(context, pr); } } } if(func != NULL) { snprintf(host, sizeof(host), "%s.%s", instance, realm); strlwr(host); ret = krb5_make_principal(context, &pr, realm, name, host, NULL); if((*func)(context, funcctx, pr)){ *princ = pr; return 0; } krb5_free_principal(context, pr); } /* * if the instance is the first component of the local hostname, * the converted host should be the long hostname. */ if (func == NULL && gethostname (local_hostname, sizeof(local_hostname)) == 0 && strncmp(instance, local_hostname, strlen(instance)) == 0 && local_hostname[strlen(instance)] == '.') { strlcpy(host, local_hostname, sizeof(host)); goto local_host; } { char **domains, **d; domains = krb5_config_get_strings(context, NULL, "realms", realm, "v4_domains", NULL); for(d = domains; d && *d; d++){ snprintf(host, sizeof(host), "%s.%s", instance, *d); ret = krb5_make_principal(context, &pr, realm, name, host, NULL); if(func == NULL || (*func)(context, funcctx, pr)){ *princ = pr; krb5_config_free_strings(domains); return 0; } krb5_free_principal(context, pr); } krb5_config_free_strings(domains); } p = krb5_config_get_string(context, NULL, "realms", realm, "default_domain", NULL); if(p == NULL){ /* this should be an error, just faking a name is not good */ krb5_clear_error_string (context); return HEIM_ERR_V4_PRINC_NO_CONV; } if (*p == '.') ++p; snprintf(host, sizeof(host), "%s.%s", instance, p); local_host: ret = krb5_make_principal(context, &pr, realm, name, host, NULL); if(func == NULL || (*func)(context, funcctx, pr)){ *princ = pr; return 0; } krb5_free_principal(context, pr); krb5_clear_error_string (context); return HEIM_ERR_V4_PRINC_NO_CONV; no_host: p = krb5_config_get_string(context, NULL, "realms", realm, "v4_name_convert", "plain", name, NULL); if(p == NULL) p = krb5_config_get_string(context, NULL, "libdefaults", "v4_name_convert", "plain", name, NULL); if(p) name = p; ret = krb5_make_principal(context, &pr, realm, name, instance, NULL); if(func == NULL || (*func)(context, funcctx, pr)){ *princ = pr; return 0; } krb5_free_principal(context, pr); krb5_clear_error_string (context); return HEIM_ERR_V4_PRINC_NO_CONV; }
KRB5_LIB_FUNCTION krb5_boolean KRB5_LIB_CALL _krb5_kuserok(krb5_context context, krb5_principal principal, const char *luser, krb5_boolean an2ln_ok) { static heim_base_once_t reg_def_plugins = HEIM_BASE_ONCE_INIT; krb5_error_code ret; struct plctx ctx; char **rules; /* * XXX we should have a struct with a krb5_context field and a * krb5_error_code fied and pass the address of that as the ctx * argument of heim_base_once_f(). For now we use a static to * communicate failures. Actually, we ignore failures anyways, * since we can't return them. */ heim_base_once_f(®_def_plugins, context, reg_def_plugins_once); ctx.flags = 0; ctx.luser = luser; ctx.principal = principal; ctx.result = FALSE; ctx.k5login_dir = krb5_config_get_string(context, NULL, "libdefaults", "k5login_directory", NULL); if (an2ln_ok) ctx.flags |= KUSEROK_ANAME_TO_LNAME_OK; if (krb5_config_get_bool_default(context, NULL, FALSE, "libdefaults", "k5login_authoritative", NULL)) ctx.flags |= KUSEROK_K5LOGIN_IS_AUTHORITATIVE; if ((ctx.flags & KUSEROK_K5LOGIN_IS_AUTHORITATIVE) && plugin_reg_ret) return plugin_reg_ret; /* fail safe */ rules = krb5_config_get_strings(context, NULL, "libdefaults", "kuserok", NULL); if (rules == NULL) { /* Default: check ~/.k5login */ ctx.rule = "USER-K5LOGIN"; ret = plcallback(context, &kuserok_user_k5login_plug, NULL, &ctx); if (ret == 0) goto out; ctx.rule = "SIMPLE"; ret = plcallback(context, &kuserok_simple_plug, NULL, &ctx); if (ret == 0) goto out; ctx.result = FALSE; } else { size_t n; for (n = 0; rules[n]; n++) { ctx.rule = rules[n]; ret = _krb5_plugin_run_f(context, "krb5", KRB5_PLUGIN_KUSEROK, KRB5_PLUGIN_KUSEROK_VERSION_0, 0, &ctx, plcallback); if (ret != KRB5_PLUGIN_NO_HANDLE) goto out; } } out: krb5_config_free_strings(rules); return ctx.result; }
krb5_error_code hdb_generate_key_set(krb5_context context, krb5_principal principal, Key **ret_key_set, size_t *nkeyset, int no_salt) { char **ktypes, **kp; krb5_error_code ret; Key *k, *key_set; size_t i, j; static const char *default_keytypes[] = { "aes256-cts-hmac-sha1-96:pw-salt", "des3-cbc-sha1:pw-salt", "arcfour-hmac-md5:pw-salt", NULL }; ktypes = krb5_config_get_strings(context, NULL, "kadmin", "default_keys", NULL); if (ktypes == NULL) ktypes = (char **)(intptr_t)default_keytypes; *ret_key_set = key_set = NULL; *nkeyset = 0; ret = 0; for(kp = ktypes; kp && *kp; kp++) { const char *p; krb5_salt salt; krb5_enctype *enctypes; size_t num_enctypes; p = *kp; /* check alias */ if(strcmp(p, "v5") == 0) p = "pw-salt"; else if(strcmp(p, "v4") == 0) p = "des:pw-salt:"; else if(strcmp(p, "afs") == 0 || strcmp(p, "afs3") == 0) p = "des:afs3-salt"; else if (strcmp(p, "arcfour-hmac-md5") == 0) p = "arcfour-hmac-md5:pw-salt"; memset(&salt, 0, sizeof(salt)); ret = parse_key_set(context, p, &enctypes, &num_enctypes, &salt, principal); if (ret) { krb5_warn(context, ret, "bad value for default_keys `%s'", *kp); ret = 0; continue; } for (i = 0; i < num_enctypes; i++) { /* find duplicates */ for (j = 0; j < *nkeyset; j++) { k = &key_set[j]; if (k->key.keytype == enctypes[i]) { if (no_salt) break; if (k->salt == NULL && salt.salttype == KRB5_PW_SALT) break; if (k->salt->type == salt.salttype && k->salt->salt.length == salt.saltvalue.length && memcmp(k->salt->salt.data, salt.saltvalue.data, salt.saltvalue.length) == 0) break; } } /* not a duplicate, lets add it */ if (j == *nkeyset) { ret = add_enctype_to_key_set(&key_set, nkeyset, enctypes[i], no_salt ? NULL : &salt); if (ret) { free(enctypes); krb5_free_salt(context, salt); goto out; } } } free(enctypes); krb5_free_salt(context, salt); } *ret_key_set = key_set; out: if (ktypes != (char **)(intptr_t)default_keytypes) krb5_config_free_strings(ktypes); if (ret) { krb5_warn(context, ret, "failed to parse the [kadmin]default_keys values"); for (i = 0; i < *nkeyset; i++) free_Key(&key_set[i]); free(key_set); } else if (*nkeyset == 0) { krb5_warnx(context, "failed to parse any of the [kadmin]default_keys values"); ret = EINVAL; /* XXX */ } return ret; }
static krb5_error_code load_plugins(krb5_context context) { struct plugin *e; krb5_error_code ret; char **dirs = NULL, **di; struct dirent *entry; char *path; DIR *d = NULL; if (!plugins_needs_scan) return 0; plugins_needs_scan = 0; #ifdef HAVE_DLOPEN dirs = krb5_config_get_strings(context, NULL, "libdefaults", "plugin_dir", NULL); if (dirs == NULL) dirs = rk_UNCONST(sysplugin_dirs); for (di = dirs; *di != NULL; di++) { char * dir = *di; #ifdef KRB5_USE_PATH_TOKENS if (_krb5_expand_path_tokens(context, *di, &dir)) goto next_dir; #endif trim_trailing_slash(dir); d = opendir(dir); if (d == NULL) goto next_dir; rk_cloexec_dir(d); while ((entry = readdir(d)) != NULL) { char *n = entry->d_name; /* skip . and .. */ if (!is_valid_plugin_filename(n)) continue; path = NULL; ret = 0; #ifdef __APPLE__ { /* support loading bundles on MacOS */ size_t len = strlen(n); if (len > 7 && strcmp(&n[len - 7], ".bundle") == 0) ret = asprintf(&path, "%s/%s/Contents/MacOS/%.*s", dir, n, (int)(len - 7), n); } #endif if (ret < 0 || path == NULL) ret = asprintf(&path, "%s/%s", dir, n); if (ret < 0 || path == NULL) { ret = ENOMEM; krb5_set_error_message(context, ret, "malloc: out of memory"); return ret; } /* check if already tried */ for (e = registered; e != NULL; e = e->next) if (e->type == DSO && strcmp(e->u.dso.path, path) == 0) break; if (e) { free(path); } else { loadlib(context, path); /* store or frees path */ } } closedir(d); next_dir: if (dir != *di) free(dir); } if (dirs != rk_UNCONST(sysplugin_dirs)) krb5_config_free_strings(dirs); #endif /* HAVE_DLOPEN */ return 0; }
/** * Map a principal name to a local username. * * Returns 0 on success, KRB5_NO_LOCALNAME if no mapping was found, or * some Kerberos or system error. * * Inputs: * * @param context A krb5_context * @param aname A principal name * @param lnsize The size of the buffer into which the username will be written * @param lname The buffer into which the username will be written * * @ingroup krb5_support */ KRB5_LIB_FUNCTION krb5_error_code KRB5_LIB_CALL krb5_aname_to_localname(krb5_context context, krb5_const_principal aname, size_t lnsize, char *lname) { static heim_base_once_t reg_def_plugins = HEIM_BASE_ONCE_INIT; krb5_error_code ret; size_t i; char **rules = NULL; char *rule; if (lnsize) lname[0] = '\0'; heim_base_once_f(®_def_plugins, context, reg_def_plugins_once); /* Try MIT's auth_to_local_names config first */ ret = an2ln_local_names(context, aname, lnsize, lname); if (ret != KRB5_PLUGIN_NO_HANDLE) return ret; rules = krb5_config_get_strings(context, NULL, "realms", aname->realm, "auth_to_local", NULL); if (!rules) { /* Heimdal's default rule */ ret = an2ln_default(context, "HEIMDAL_DEFAULT", aname, lnsize, lname); if (ret == KRB5_PLUGIN_NO_HANDLE) return KRB5_NO_LOCALNAME; return ret; } /* * MIT rules. * * Note that RULEs and DBs only have white-list functionality, * thus RULEs and DBs that we don't understand we simply ignore. * * This means that plugins that implement black-lists are * dangerous: if a black-list plugin isn't found, the black-list * won't be enforced. But black-lists are dangerous anyways. */ for (ret = KRB5_PLUGIN_NO_HANDLE, i = 0; rules[i]; i++) { rule = rules[i]; /* Try NONE, DEFAULT, and HEIMDAL_DEFAULT rules */ ret = an2ln_default(context, rule, aname, lnsize, lname); if (ret == KRB5_PLUGIN_NO_HANDLE) /* Try DB, RULE, ... plugins */ ret = an2ln_plugin(context, rule, aname, lnsize, lname); if (ret == 0 && lnsize && !lname[0]) continue; /* Success but no lname?! lies! */ else if (ret != KRB5_PLUGIN_NO_HANDLE) break; } if (ret == KRB5_PLUGIN_NO_HANDLE) { if (lnsize) lname[0] = '\0'; ret = KRB5_NO_LOCALNAME; } krb5_config_free_strings(rules); return ret; }