/** Convert module specific attribute id to value_pair_tmpl_t. * * @param[in] ctx for talloc * @param[in] name string to convert. * @param[in] type Type of quoting around value. * @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 new VPT. */ value_pair_tmpl_t *tmpl_afrom_str(TALLOC_CTX *ctx, char const *name, FR_TOKEN type, request_refs_t request_def, pair_lists_t list_def) { int rcode; char const *p; value_pair_tmpl_t *vpt; char buffer[1024]; vpt = talloc_zero(ctx, value_pair_tmpl_t); vpt->name = talloc_typed_strdup(vpt, name); switch (type) { case T_BARE_WORD: /* * If we can parse it as an attribute, it's an attribute. * Otherwise, treat it as a literal. */ rcode = tmpl_from_attr_str(vpt, vpt->name, request_def, list_def); if (rcode == -2) { talloc_free(vpt); return NULL; } if (rcode == 0) { break; } /* FALL-THROUGH */ case T_SINGLE_QUOTED_STRING: vpt->type = TMPL_TYPE_LITERAL; break; case T_DOUBLE_QUOTED_STRING: p = name; while (*p) { if (*p == '\\') { if (!p[1]) break; p += 2; continue; } if (*p == '%') break; p++; } /* * If the double quoted string needs to be * expanded at run time, make it an xlat * expansion. Otherwise, convert it to be a * literal. */ if (*p) { vpt->type = TMPL_TYPE_XLAT; } else { vpt->type = TMPL_TYPE_LITERAL; } break; case T_BACK_QUOTED_STRING: vpt->type = TMPL_TYPE_EXEC; break; case T_OP_REG_EQ: /* hack */ vpt->type = TMPL_TYPE_REGEX; break; default: rad_assert(0); return NULL; } tmpl_prints(buffer, sizeof(buffer), vpt); return vpt; }
/** Create and insert a cache entry. * * @return * - #RLM_MODULE_OK on success. * - #RLM_MODULE_UPDATED if we merged the cache entry. * - #RLM_MODULE_FAIL on failure. */ static rlm_rcode_t cache_insert(rlm_cache_t *inst, REQUEST *request, rlm_cache_handle_t **handle, char const *key, int ttl) { vp_map_t const *map; vp_map_t **last, *c_map; VALUE_PAIR *vp; bool merge = false; rlm_cache_entry_t *c; TALLOC_CTX *pool; if ((inst->max_entries > 0) && inst->module->count && (inst->module->count(inst, request, handle) > inst->max_entries)) { RWDEBUG("Cache is full: %d entries", inst->max_entries); return RLM_MODULE_FAIL; } c = cache_alloc(inst, request); if (!c) return RLM_MODULE_FAIL; c->key = talloc_typed_strdup(c, key); c->created = c->expires = request->timestamp; c->expires += ttl; last = &c->maps; RDEBUG("Creating new cache entry"); /* * Alloc a pool so we don't have excessive mallocs when * gathering VALUE_PAIRs to cache. */ pool = talloc_pool(NULL, 1024); for (map = inst->maps; map != NULL; map = map->next) { VALUE_PAIR *to_cache = NULL; vp_cursor_t cursor; rad_assert(map->lhs && map->rhs); /* * Calling map_to_vp gives us exactly the same result, * as if this were an update section. */ if (map_to_vp(pool, &to_cache, request, map, NULL) < 0) { RDEBUG("Skipping %s", map->rhs->name); continue; } for (vp = fr_cursor_init(&cursor, &to_cache); vp; vp = fr_cursor_next(&cursor)) { /* * Prevent people from accidentally caching * cache control attributes. */ if (map->rhs->type == TMPL_TYPE_LIST) switch (vp->da->attr) { case PW_CACHE_TTL: case PW_CACHE_STATUS_ONLY: case PW_CACHE_READ_ONLY: case PW_CACHE_MERGE: case PW_CACHE_ENTRY_HITS: RDEBUG2("Skipping %s", vp->da->name); continue; default: break; } RINDENT(); if (RDEBUG_ENABLED2) map_debug_log(request, map, vp); REXDENT(); MEM(c_map = talloc_zero(c, vp_map_t)); c_map->op = map->op; /* * Now we turn the VALUE_PAIRs into maps. */ switch (map->lhs->type) { /* * Attributes are easy, reuse the LHS, and create a new * RHS with the value_data_t from the VALUE_PAIR. */ case TMPL_TYPE_ATTR: c_map->lhs = map->lhs; /* lhs shouldn't be touched, so this is ok */ do_rhs: MEM(c_map->rhs = tmpl_init(talloc(c_map, vp_tmpl_t), TMPL_TYPE_DATA, map->rhs->name, map->rhs->len)); if (value_data_copy(c_map->rhs, &c_map->rhs->tmpl_data_value, vp->da->type, &vp->data) < 0) { REDEBUG("Failed copying attribute value"); talloc_free(pool); talloc_free(c); return RLM_MODULE_FAIL; } c_map->rhs->tmpl_data_type = vp->da->type; break; /* * Lists are weird... We need to fudge a new LHS template, * which is a combination of the LHS list and the attribute. */ case TMPL_TYPE_LIST: { char attr[256]; MEM(c_map->lhs = tmpl_init(talloc(c_map, vp_tmpl_t), TMPL_TYPE_ATTR, map->lhs->name, map->lhs->len)); c_map->lhs->tmpl_da = vp->da; c_map->lhs->tmpl_tag = vp->tag; c_map->lhs->tmpl_list = map->lhs->tmpl_list; c_map->lhs->tmpl_num = map->lhs->tmpl_num; c_map->lhs->tmpl_request = map->lhs->tmpl_request; /* * We need to rebuild the attribute name, to be the * one we copied from the source list. */ c_map->lhs->len = tmpl_prints(attr, sizeof(attr), c_map->lhs, NULL); c_map->lhs->name = talloc_strdup(map->lhs, attr); } goto do_rhs; default: rad_assert(0); } *last = c_map; last = &(*last)->next; } talloc_free_children(pool); /* reset pool state */ } talloc_free(pool); /* * Check to see if we need to merge the entry into the request */ vp = pairfind(request->config, PW_CACHE_MERGE, 0, TAG_ANY); if (vp && (vp->vp_integer > 0)) merge = true; if (merge) cache_merge(inst, request, c); for (;;) { cache_status_t ret; ret = inst->module->insert(inst, request, handle, c); switch (ret) { case CACHE_RECONNECT: if (cache_reconnect(inst, request, handle) == 0) continue; return RLM_MODULE_FAIL; case CACHE_OK: RDEBUG("Commited entry, TTL %d seconds", ttl); cache_free(inst, &c); return merge ? RLM_MODULE_UPDATED : RLM_MODULE_OK; default: talloc_free(c); /* Failed insertion - use talloc_free not the driver free */ return RLM_MODULE_FAIL; } } }