/** Convert module specific attribute id to value_pair_tmpl_t. * * @param[in] name string to convert. * @param[in] type Type of quoting around value. * @return pointer to new VPT. */ value_pair_tmpl_t *radius_str2tmpl(const char *name, FR_TOKEN type) { value_pair_tmpl_t *vpt; vpt = rad_calloc(sizeof(value_pair_tmpl_t)); vpt->name = strdup(name); switch (type) { case T_BARE_WORD: case T_SINGLE_QUOTED_STRING: vpt->type = VPT_TYPE_LITERAL; break; case T_DOUBLE_QUOTED_STRING: vpt->type = VPT_TYPE_XLAT; break; case T_BACK_QUOTED_STRING: vpt->type = VPT_TYPE_EXEC; break; default: rad_assert(0); return NULL; } return vpt; }
/** Parse qualifiers to convert attrname into a value_pair_tmpl_t. * * VPTs are used in various places where we need to pre-parse configuration * sections into attribute mappings. * * @param[in] name attribute name including qualifiers. * @param[in] request_def The default request to insert unqualified * attributes into. * @param[in] list_def The default list to insert unqualified attributes into. * @return pointer to a value_pair_tmpl_t struct (must be freed with * radius_tmplfree) or NULL on error. */ value_pair_tmpl_t *radius_attr2tmpl(const char *name, request_refs_t request_def, pair_lists_t list_def) { value_pair_tmpl_t *vpt; const char *copy = strdup(name); vpt = rad_calloc(sizeof(value_pair_tmpl_t)); if (radius_parse_attr(copy, vpt, request_def, list_def) < 0) { radius_tmplfree(&vpt); return NULL; } return vpt; }
/** Convert CONFIG_PAIR (which may contain refs) to value_pair_map_t. * * Treats the left operand as an attribute reference * @verbatim<request>.<list>.<attribute>@endverbatim * * Treatment of left operand depends on quotation, barewords are treated as * attribute references, double quoted values are treated as expandable strings, * single quoted values are treated as literal strings. * * Return must be freed with radius_mapfree. * * @param[in] cp to convert to map. * @param[in] dst_request_def The default request to insert unqualified * attributes into. * @param[in] dst_list_def The default list to insert unqualified attributes * into. * @param[in] src_request_def The default request to resolve attribute * references in. * @param[in] src_list_def The default list to resolve unqualified attributes * in. * @return value_pair_map_t if successful or NULL on error. */ value_pair_map_t *radius_cp2map(CONF_PAIR *cp, request_refs_t dst_request_def, pair_lists_t dst_list_def, request_refs_t src_request_def, pair_lists_t src_list_def) { value_pair_map_t *map; const char *attr; const char *value; FR_TOKEN type; CONF_ITEM *ci = cf_pairtoitem(cp); if (!cp) return NULL; map = rad_calloc(sizeof(value_pair_map_t)); attr = cf_pair_attr(cp); value = cf_pair_value(cp); if (!value) { cf_log_err(ci, "Missing attribute value"); goto error; } map->dst = radius_attr2tmpl(attr, dst_request_def, dst_list_def); if (!map->dst){ goto error; } /* * Bare words always mean attribute references. */ type = cf_pair_value_type(cp); map->src = type == T_BARE_WORD ? radius_attr2tmpl(value, src_request_def, src_list_def) : radius_str2tmpl(value, type); if (!map->src) { goto error; } map->op = cf_pair_operator(cp); map->ci = ci; /* * Lots of sanity checks for insane people... */ /* * We don't support implicit type conversion */ if (map->dst->da && map->src->da && (map->src->da->type != map->dst->da->type)) { cf_log_err(ci, "Attribute type mismatch"); goto error; } /* * What exactly where you expecting to happen here? */ if ((map->dst->type == VPT_TYPE_ATTR) && (map->src->type == VPT_TYPE_LIST)) { cf_log_err(ci, "Can't copy list into an attribute"); goto error; } switch (map->src->type) { /* * Only += and -= operators are supported for list copy. */ case VPT_TYPE_LIST: switch (map->op) { case T_OP_SUB: case T_OP_ADD: break; default: cf_log_err(ci, "Operator \"%s\" not allowed " "for list copy", fr_int2str(fr_tokens, map->op, "¿unknown?")); goto error; } break; /* * @todo add support for exec expansion. */ case VPT_TYPE_EXEC: cf_log_err(ci, "Exec values are not allowed"); break; default: break; } return map; error: radius_mapfree(&map); return NULL; }
static int krb5_instantiate(CONF_SECTION *conf, void **instance) { rlm_krb5_t *inst; krb5_error_code ret; krb5_context *context; char *princ_name; #ifndef HEIMDAL_KRB5 radlog(L_ERR, "rlm_krb5 (*): Using MIT Kerberos library"); #else radlog(L_ERR, "rlm_krb5 (*): Using Heimdal Kerberos library"); #endif /* * @todo Update configure script to call krb5_is_thread_safe, * this should really be a warning. */ if (!krb5_is_thread_safe()) { radlog(L_ERR, "rlm_krb5 (*): krb5 library is not threadsafe, " "please recompile it with thread support enabled"); return -1; } inst = rad_calloc(sizeof(*inst)); if (cf_section_parse(conf, inst, module_config) < 0) { free(inst); return -1; } inst->xlat_name = cf_section_name2(conf); if (!inst->xlat_name) { inst->xlat_name = cf_section_name1(conf); } rad_assert(inst->xlat_name); context = inst->context = rad_calloc(sizeof(*context)); ret = krb5_init_context(context); if (ret) { radlog(L_ERR, "rlm_krb5 (%s): Context initialisation " "failed: %s", inst->xlat_name, error_message(ret)); goto error; } else { radlog(L_DBG, "rlm_krb5 (%s): Context initialised " "successfully", inst->xlat_name); } /* * Split service principal into service and host components * they're needed to build the server principal in MIT, * and to set the validation service in Heimdal. */ if (inst->service_princ) { size_t len; /* Service principal appears to contain a host component */ inst->hostname = strchr(inst->service_princ, '/'); if (inst->hostname) { len = (inst->hostname - inst->service_princ); inst->hostname++; } else { len = SERVICE_NAME_LEN; } if (len) { inst->service = rad_malloc(len + 1); strlcpy(inst->service, inst->service_princ, len); } } #ifndef HEIMDAL_KRB5 /* * Convert the service principal string to a krb5 principal. */ ret = krb5_sname_to_principal(*context, inst->hostname, inst->service, KRB5_NT_SRV_HST, &(inst->server)); if (ret) { radlog(L_ERR, "rlm_krb5 (%s): Failed parsing service " "principal: %s", inst->xlat_name, error_message(ret)); goto error; } ret = krb5_unparse_name(*context, inst->server, &princ_name); if (ret) { /* Uh? */ radlog(L_ERR, "rlm_krb5 (%s): Failed constructing service " "principal string: %s", inst->xlat_name, error_message(ret)); goto error; } /* * Not necessarily the same as the config item */ radlog(L_DBG, "rlm_krb5 (%s): Using service principal \"%s\"", inst->xlat_name, princ_name); krb5_free_unparsed_name(*context, princ_name); /* * Setup options for getting credentials and verifying them */ /* For some reason the 'init' version of this function is deprecated */ ret = krb5_get_init_creds_opt_alloc(*context, &(inst->gic_options)); if (ret) { radlog(L_ERR, "rlm_krb5 (%s): Couldn't allocated inital " "credential options: %s", inst->xlat_name, error_message(ret)); goto error; } inst->vic_options = rad_calloc(sizeof(*(inst->vic_options))); if (!inst->vic_options) goto error; krb5_verify_init_creds_opt_init(inst->vic_options); krb5_verify_init_creds_opt_set_ap_req_nofail(inst->vic_options, TRUE); #else if (inst->hostname) { radlog(L_DBG, "rlm_krb5 (%s): Ignoring hostname component of " "service principal \"%s\", not needed/supported by " "Heimdal", inst->xlat_name, hostname); } #endif *instance = inst; return 0; error: krb5_detach(inst); return -1; }