/* * Allow single attribute values to be retrieved from the dhcp. */ static ssize_t dhcp_options_xlat(UNUSED void *instance, REQUEST *request, char const *fmt, char **out, size_t freespace) { vp_cursor_t cursor, src_cursor; vp_tmpl_t src; VALUE_PAIR *vp, *head = NULL; int decoded = 0; ssize_t slen; while (isspace((int) *fmt)) fmt++; slen = tmpl_from_attr_str(&src, fmt, REQUEST_CURRENT, PAIR_LIST_REQUEST, false, false); if (slen <= 0) { REMARKER(fmt, slen, fr_strerror()); error: return -1; } if (src.type != TMPL_TYPE_ATTR) { REDEBUG("dhcp_options cannot operate on a %s", fr_int2str(tmpl_names, src.type, "<INVALID>")); goto error; } if (src.tmpl_da->type != PW_TYPE_OCTETS) { REDEBUG("dhcp_options got a %s attribute needed octets", fr_int2str(dict_attr_types, src.tmpl_da->type, "<INVALID>")); goto error; } for (vp = tmpl_cursor_init(NULL, &src_cursor, request, &src); vp; vp = tmpl_cursor_next(&src_cursor, &src)) { /* * @fixme: we should pass in a cursor, then decoding multiple * source attributes can be made atomic. */ if ((fr_dhcp_decode_options(request->packet, &head, vp->vp_octets, vp->vp_length) < 0) || (!head)) { RWDEBUG("DHCP option decoding failed: %s", fr_strerror()); goto error; } for (vp = fr_cursor_init(&cursor, &head); vp; vp = fr_cursor_next(&cursor)) { rdebug_pair(L_DBG_LVL_2, request, vp, "dhcp_options: "); decoded++; } fr_pair_list_move(request->packet, &(request->packet->vps), &head); /* Free any unmoved pairs */ fr_pair_list_free(&head); } snprintf(*out, freespace, "%i", decoded); return strlen(*out); }
/* * Xlat for %{attr_by_oid:<oid>} */ static ssize_t xlat_dict_attr_by_oid(TALLOC_CTX *ctx, char **out, UNUSED size_t outlen, UNUSED void const *mod_inst, UNUSED void const *xlat_inst, REQUEST *request, char const *fmt) { unsigned int attr = 0; fr_dict_attr_t const *parent = fr_dict_root(request->dict); fr_dict_attr_t const *da; ssize_t ret; ret = fr_dict_attr_by_oid(NULL, &parent, &attr, fmt); if (ret <= 0) { REMARKER(fmt, -(ret), "%s", fr_strerror()); return ret; } da = fr_dict_attr_child_by_num(parent, attr); *out = talloc_typed_strdup(ctx, da->name); return talloc_array_length(*out) - 1; }
static rlm_rcode_t mod_do_linelog(void *instance, REQUEST *request) { int fd = -1; linelog_conn_t *conn; struct timeval *timeout = NULL; char buff[4096]; char *p = buff; linelog_instance_t *inst = instance; char const *value; vp_tmpl_t empty, *vpt = NULL, *vpt_p = NULL; rlm_rcode_t rcode = RLM_MODULE_OK; ssize_t slen; struct iovec vector_s[2]; struct iovec *vector = NULL, *vector_p; size_t vector_len; bool with_delim; buff[0] = '.'; /* force to be in current section */ buff[1] = '\0'; buff[2] = '\0'; /* * Expand log_ref to a config path, using the module * configuration section as the root. */ if (inst->log_ref) { CONF_ITEM *ci; CONF_PAIR *cp; char const *tmpl_str; if (tmpl_expand(NULL, buff + 1, sizeof(buff) - 1, request, inst->log_ref, linelog_escape_func, NULL) < 0) { return RLM_MODULE_FAIL; } if (buff[1] == '.') p++; /* * Don't go back up. */ if (buff[2] == '.') { REDEBUG("Invalid path \"%s\"", p); return RLM_MODULE_FAIL; } ci = cf_reference_item(NULL, inst->cs, p); if (!ci) { RDEBUG2("Path \"%s\" doesn't exist", p); goto default_msg; } if (!cf_item_is_pair(ci)) { REDEBUG("Path \"%s\" resolves to a section (should be a pair)", p); return RLM_MODULE_FAIL; } cp = cf_item_to_pair(ci); tmpl_str = cf_pair_value(cp); if (!tmpl_str || (tmpl_str[0] == '\0')) { RDEBUG2("Path \"%s\" resolves to an empty config pair", p); vpt_p = tmpl_init(&empty, TMPL_TYPE_LITERAL, "", 0); goto build_vector; } /* * Alloc a template from the value of the CONF_PAIR * using request as the context (which will hopefully avoid a malloc). */ slen = tmpl_afrom_str(request, &vpt, tmpl_str, talloc_array_length(tmpl_str) - 1, cf_pair_value_type(cp), REQUEST_CURRENT, PAIR_LIST_REQUEST, true); if (slen <= 0) { REMARKER(tmpl_str, -slen, fr_strerror()); return RLM_MODULE_FAIL; } vpt_p = vpt; } else { default_msg: /* * Use the default format string */ if (!inst->log_src) { RDEBUG2("No default message configured"); return RLM_MODULE_NOOP; } /* * Use the pre-parsed format template */ RDEBUG2("Using default message"); vpt_p = inst->log_src; } build_vector: with_delim = (inst->log_dst != LINELOG_DST_SYSLOG) && (inst->delimiter_len > 0); /* * Log all the things! */ switch (vpt_p->type) { case TMPL_TYPE_ATTR: case TMPL_TYPE_LIST: { #define VECTOR_INCREMENT 20 vp_cursor_t cursor; VALUE_PAIR *vp; int alloced = VECTOR_INCREMENT, i; MEM(vector = talloc_array(request, struct iovec, alloced)); for (vp = tmpl_cursor_init(NULL, &cursor, request, vpt_p), i = 0; vp; vp = tmpl_cursor_next(&cursor, vpt_p), i++) { /* need extra for line terminator */ if ((with_delim && ((i + 1) >= alloced)) || (i >= alloced)) { alloced += VECTOR_INCREMENT; MEM(vector = talloc_realloc(request, vector, struct iovec, alloced)); } switch (vp->da->type) { case PW_TYPE_OCTETS: case PW_TYPE_STRING: vector[i].iov_base = vp->data.ptr; vector[i].iov_len = vp->vp_length; break; default: p = vp_aprints_value(vector, vp, '\0'); vector[i].iov_base = p; vector[i].iov_len = talloc_array_length(p) - 1; break; } /* * Add the line delimiter string */ if (with_delim) { i++; memcpy(&vector[i].iov_base, &(inst->delimiter), sizeof(vector[i].iov_base)); vector[i].iov_len = inst->delimiter_len; } } vector_p = vector; vector_len = i; } break; /* * Log a single thing. */ default: slen = tmpl_expand(&value, buff, sizeof(buff), request, vpt_p, linelog_escape_func, NULL); if (slen < 0) { rcode = RLM_MODULE_FAIL; goto finish; } /* iov_base is not declared as const *sigh* */ memcpy(&vector_s[0].iov_base, &value, sizeof(vector_s[0].iov_base)); vector_s[0].iov_len = slen; if (!with_delim) { vector_len = 1; } else { memcpy(&vector_s[1].iov_base, &(inst->delimiter), sizeof(vector_s[1].iov_base)); vector_s[1].iov_len = inst->delimiter_len; vector_len = 2; } vector_p = &vector_s[0]; }
int paircmp_pairs(UNUSED REQUEST *request, VALUE_PAIR *check, VALUE_PAIR *vp) #endif { int ret = 0; /* * Check for =* and !* and return appropriately */ if (check->op == T_OP_CMP_TRUE) return 0; if (check->op == T_OP_CMP_FALSE) return 1; if (!vp) { REDEBUG("Non-Unary operations require two operands"); return -2; } #ifdef HAVE_REGEX if ((check->op == T_OP_REG_EQ) || (check->op == T_OP_REG_NE)) { ssize_t slen; regex_t *preg = NULL; uint32_t subcaptures; fr_regmatch_t *regmatch; char *expr = NULL, *value = NULL; char const *expr_p, *value_p; if (check->vp_type == FR_TYPE_STRING) { expr_p = check->vp_strvalue; } else { expr_p = expr = fr_pair_value_asprint(check, check, '\0'); } if (vp->vp_type == FR_TYPE_STRING) { value_p = vp->vp_strvalue; } else { value_p = value = fr_pair_value_asprint(vp, vp, '\0'); } if (!expr_p || !value_p) { REDEBUG("Error stringifying operand for regular expression"); regex_error: talloc_free(preg); talloc_free(expr); talloc_free(value); return -2; } /* * Include substring matches. */ slen = regex_compile(request, &preg, expr_p, talloc_array_length(expr_p) - 1, false, false, true, true); if (slen <= 0) { REMARKER(expr_p, -slen, fr_strerror()); goto regex_error; } subcaptures = regex_subcapture_count(preg); if (!subcaptures) subcaptures = REQUEST_MAX_REGEX + 1; /* +1 for %{0} (whole match) capture group */ MEM(regmatch = regex_match_data_alloc(NULL, subcaptures)); /* * Evaluate the expression */ slen = regex_exec(preg, value_p, talloc_array_length(value_p) - 1, regmatch); if (slen < 0) { RPERROR("Invalid regex"); goto regex_error; } if (check->op == T_OP_REG_EQ) { /* * Add in %{0}. %{1}, etc. */ regex_sub_to_request(request, &preg, ®match); ret = (slen == 1) ? 0 : -1; } else { ret = (slen != 1) ? 0 : -1; } talloc_free(regmatch); talloc_free(preg); talloc_free(expr); talloc_free(value); goto finish; } #endif /* * Attributes must be of the same type. * * FIXME: deal with type mismatch properly if one side contain * ABINARY, OCTETS or STRING by converting the other side to * a string * */ if (vp->vp_type != check->vp_type) return -1; /* * Tagged attributes are equal if and only if both the * tag AND value match. */ if (check->da->flags.has_tag && !TAG_EQ(check->tag, vp->tag)) { ret = ((int) vp->tag) - ((int) check->tag); if (ret != 0) goto finish; } /* * Not a regular expression, compare the types. */ switch (check->vp_type) { #ifdef WITH_ASCEND_BINARY /* * Ascend binary attributes can be treated * as opaque objects, I guess... */ case FR_TYPE_ABINARY: #endif case FR_TYPE_OCTETS: if (vp->vp_length != check->vp_length) { ret = 1; /* NOT equal */ break; } ret = memcmp(vp->vp_strvalue, check->vp_strvalue, vp->vp_length); break; case FR_TYPE_STRING: ret = strcmp(vp->vp_strvalue, check->vp_strvalue); break; case FR_TYPE_UINT8: ret = vp->vp_uint8 - check->vp_uint8; break; case FR_TYPE_UINT16: ret = vp->vp_uint16 - check->vp_uint16; break; case FR_TYPE_UINT32: ret = vp->vp_uint32 - check->vp_uint32; break; case FR_TYPE_UINT64: /* * Don't want integer overflow! */ if (vp->vp_uint64 < check->vp_uint64) { ret = -1; } else if (vp->vp_uint64 > check->vp_uint64) { ret = +1; } else { ret = 0; } break; case FR_TYPE_INT32: if (vp->vp_int32 < check->vp_int32) { ret = -1; } else if (vp->vp_int32 > check->vp_int32) { ret = +1; } else { ret = 0; } break; case FR_TYPE_DATE: ret = vp->vp_date - check->vp_date; break; case FR_TYPE_IPV4_ADDR: ret = ntohl(vp->vp_ipv4addr) - ntohl(check->vp_ipv4addr); break; case FR_TYPE_IPV6_ADDR: ret = memcmp(vp->vp_ip.addr.v6.s6_addr, check->vp_ip.addr.v6.s6_addr, sizeof(vp->vp_ip.addr.v6.s6_addr)); break; case FR_TYPE_IPV4_PREFIX: case FR_TYPE_IPV6_PREFIX: ret = memcmp(&vp->vp_ip, &check->vp_ip, sizeof(vp->vp_ip)); break; case FR_TYPE_IFID: ret = memcmp(vp->vp_ifid, check->vp_ifid, sizeof(vp->vp_ifid)); break; default: break; } finish: if (ret > 0) return 1; if (ret < 0) return -1; return 0; }