/* * Copy data from src to dst, where the attributes are of * different type. */ static int do_cast_copy(VALUE_PAIR *dst, VALUE_PAIR const *src) { rad_assert(dst->da->type != src->da->type); if (dst->da->type == PW_TYPE_STRING) { dst->vp_strvalue = vp_aprint_value(dst, src, false); dst->length = strlen(dst->vp_strvalue); return 0; } if (dst->da->type == PW_TYPE_OCTETS) { if (src->da->type == PW_TYPE_STRING) { pairmemcpy(dst, src->vp_octets, src->length); /* Copy embedded NULLs */ } else { pairmemcpy(dst, (uint8_t const *) &src->data, src->length); } return 0; } if (src->da->type == PW_TYPE_STRING) { return pairparsevalue(dst, src->vp_strvalue, 0); } if ((src->da->type == PW_TYPE_INTEGER64) && (dst->da->type == PW_TYPE_ETHERNET)) { uint8_t array[8]; uint64_t i; i = htonll(src->vp_integer64); memcpy(array, &i, 8); /* * For OUIs in the DB. */ if ((array[0] != 0) || (array[1] != 0)) return -1; memcpy(&dst->vp_ether, &array[2], 6); dst->length = 6; return 0; } /* * For integers, we allow the casting of a SMALL type to * a larger type, but not vice-versa. */ if (dst->da->type == PW_TYPE_INTEGER64) { switch (src->da->type) { case PW_TYPE_BYTE: dst->vp_integer64 = src->vp_byte; break; case PW_TYPE_SHORT: dst->vp_integer64 = src->vp_short; break; case PW_TYPE_INTEGER: dst->vp_integer64 = src->vp_integer; break; case PW_TYPE_OCTETS: goto do_octets; default: EVAL_DEBUG("Invalid cast to integer64"); return -1; } return 0; } /* * We can compare LONG integers to SHORTER ones, so long * as the long one is on the LHS. */ if (dst->da->type == PW_TYPE_INTEGER) { switch (src->da->type) { case PW_TYPE_BYTE: dst->vp_integer = src->vp_byte; break; case PW_TYPE_SHORT: dst->vp_integer = src->vp_short; break; case PW_TYPE_OCTETS: goto do_octets; default: EVAL_DEBUG("Invalid cast to integer"); return -1; } return 0; } if (dst->da->type == PW_TYPE_SHORT) { switch (src->da->type) { case PW_TYPE_BYTE: dst->vp_short = src->vp_byte; break; case PW_TYPE_OCTETS: goto do_octets; default: EVAL_DEBUG("Invalid cast to short"); return -1; } return 0; } /* * The attribute we've found has to have a size which is * compatible with the type of the destination cast. */ if ((src->length < dict_attr_sizes[dst->da->type][0]) || (src->length > dict_attr_sizes[dst->da->type][1])) { EVAL_DEBUG("Casted attribute is wrong size (%u)", (unsigned int) src->length); return -1; } if (src->da->type == PW_TYPE_OCTETS) { do_octets: switch (dst->da->type) { case PW_TYPE_INTEGER64: dst->vp_integer = ntohll(*(uint64_t const *) src->vp_octets); break; case PW_TYPE_INTEGER: case PW_TYPE_DATE: case PW_TYPE_SIGNED: dst->vp_integer = ntohl(*(uint32_t const *) src->vp_octets); break; case PW_TYPE_SHORT: dst->vp_integer = ntohs(*(uint16_t const *) src->vp_octets); break; case PW_TYPE_BYTE: dst->vp_integer = src->vp_octets[0]; break; default: memcpy(&dst->data, src->vp_octets, src->length); break; } dst->length = src->length; return 0; } /* * Convert host order to network byte order. */ if ((dst->da->type == PW_TYPE_IPV4_ADDR) && ((src->da->type == PW_TYPE_INTEGER) || (src->da->type == PW_TYPE_DATE) || (src->da->type == PW_TYPE_SIGNED))) { dst->vp_ipaddr = htonl(src->vp_integer); } else if ((src->da->type == PW_TYPE_IPV4_ADDR) && ((dst->da->type == PW_TYPE_INTEGER) || (dst->da->type == PW_TYPE_DATE) || (dst->da->type == PW_TYPE_SIGNED))) { dst->vp_integer = htonl(src->vp_ipaddr); } else { /* they're of the same byte order */ memcpy(&dst->data, &src->data, src->length); } dst->length = src->length; return 0; }
/** Expand the RHS of a template * * @note Length of expanded string can be found with talloc_array_length(*out) - 1 * * @param out where to write a pointer to the newly allocated buffer. * @param request Current request. * @param vpt to evaluate. * @return -1 on error, else 0. */ int radius_expand_tmpl(char **out, REQUEST *request, value_pair_tmpl_t const *vpt) { VALUE_PAIR *vp; *out = NULL; rad_assert(vpt->type != TMPL_TYPE_LIST); switch (vpt->type) { case TMPL_TYPE_LITERAL: EVAL_DEBUG("TMPL LITERAL"); *out = talloc_typed_strdup(request, vpt->name); break; case TMPL_TYPE_EXEC: EVAL_DEBUG("TMPL EXEC"); *out = talloc_array(request, char, 1024); if (radius_exec_program(request, vpt->name, true, false, *out, 1024, EXEC_TIMEOUT, NULL, NULL) != 0) { TALLOC_FREE(*out); return -1; } break; case TMPL_TYPE_REGEX: EVAL_DEBUG("TMPL REGEX"); /* Error in expansion, this is distinct from zero length expansion */ if (radius_axlat(out, request, vpt->name, NULL, NULL) < 0) { rad_assert(!*out); return -1; } break; case TMPL_TYPE_XLAT: EVAL_DEBUG("TMPL XLAT"); /* Error in expansion, this is distinct from zero length expansion */ if (radius_axlat(out, request, vpt->name, NULL, NULL) < 0) { rad_assert(!*out); return -1; } break; case TMPL_TYPE_XLAT_STRUCT: EVAL_DEBUG("TMPL XLAT_STRUCT"); /* Error in expansion, this is distinct from zero length expansion */ if (radius_axlat_struct(out, request, vpt->tmpl_xlat, NULL, NULL) < 0) { rad_assert(!*out); return -1; } RDEBUG2("EXPAND %s", vpt->name); /* xlat_struct doesn't do this */ RDEBUG2(" --> %s", *out); break; case TMPL_TYPE_ATTR: { int ret; EVAL_DEBUG("TMPL ATTR"); ret = tmpl_find_vp(&vp, request, vpt); if (ret < 0) return -2; *out = vp_aprint_value(request, vp, false); if (!*out) return -1; } break; case TMPL_TYPE_DATA: case TMPL_TYPE_REGEX_STRUCT: rad_assert(0 == 1); /* FALL-THROUGH */ default: break; } EVAL_DEBUG("Expand tmpl --> %s", *out); return 0; }
/** Print a template to a string * * @param[out] buffer for the output string * @param[in] bufsize of the buffer * @param[in] vpt to print * @return the size of the string printed */ size_t radius_tmpl2str(char *buffer, size_t bufsize, value_pair_tmpl_t const *vpt) { size_t len; char c; char const *p; char *q = buffer; char *end; if (!vpt) { *buffer = '\0'; return 0; } switch (vpt->type) { default: return 0; case VPT_TYPE_REGEX: case VPT_TYPE_REGEX_STRUCT: c = '/'; break; case VPT_TYPE_XLAT: case VPT_TYPE_XLAT_STRUCT: c = '"'; break; case VPT_TYPE_LIST: case VPT_TYPE_LITERAL: /* single-quoted or bare word */ /* * Hack */ for (p = vpt->name; *p != '\0'; p++) { if (*p == ' ') break; if (*p == '\'') break; if (!dict_attr_allowed_chars[(int) *p]) break; } if (!*p) { strlcpy(buffer, vpt->name, bufsize); return strlen(buffer); } c = '\''; break; case VPT_TYPE_EXEC: c = '`'; break; case VPT_TYPE_ATTR: buffer[0] = '&'; if (vpt->vpt_request == REQUEST_CURRENT) { if (vpt->vpt_list == PAIR_LIST_REQUEST) { strlcpy(buffer + 1, vpt->vpt_da->name, bufsize - 1); } else { snprintf(buffer + 1, bufsize - 1, "%s:%s", fr_int2str(pair_lists, vpt->vpt_list, ""), vpt->vpt_da->name); } } else { snprintf(buffer + 1, bufsize - 1, "%s.%s:%s", fr_int2str(request_refs, vpt->vpt_request, ""), fr_int2str(pair_lists, vpt->vpt_list, ""), vpt->vpt_da->name); } len = strlen(buffer); if ((vpt->vpt_tag == TAG_ANY) && (vpt->vpt_num == NUM_ANY)) { return len; } q = buffer + len; bufsize -= len; if (vpt->vpt_tag != TAG_ANY) { snprintf(q, bufsize, ":%d", vpt->vpt_tag); len = strlen(q); q += len; bufsize -= len; } if (vpt->vpt_num != NUM_ANY) { snprintf(q, bufsize, "[%u]", vpt->vpt_num); len = strlen(q); q += len; } return (q - buffer); case VPT_TYPE_DATA: if (vpt->vpt_value) { VALUE_PAIR *vp; TALLOC_CTX *ctx; memcpy(&ctx, &vpt, sizeof(ctx)); /* hack */ MEM(vp = pairalloc(ctx, vpt->vpt_da)); memcpy(&vp->data, vpt->vpt_value, sizeof(vp->data)); vp->length = vpt->vpt_length; q = vp_aprint_value(vp, vp); if ((vpt->vpt_da->type != PW_TYPE_STRING) && (vpt->vpt_da->type != PW_TYPE_DATE)) { strlcpy(buffer, q, bufsize); } else { /* * FIXME: properly escape the string... */ snprintf(buffer, bufsize, "\"%s\"", q); } talloc_free(q); pairfree(&vp); return strlen(buffer); } else { *buffer = '\0'; return 0; } } if (bufsize <= 3) { no_room: *buffer = '\0'; return 0; } p = vpt->name; *(q++) = c; end = buffer + bufsize - 3; /* quotes + EOS */ while (*p && (q < end)) { if (*p == c) { if ((end - q) < 4) goto no_room; /* escape, char, quote, EOS */ *(q++) = '\\'; *(q++) = *(p++); continue; } switch (*p) { case '\\': if ((end - q) < 4) goto no_room; *(q++) = '\\'; *(q++) = *(p++); break; case '\r': if ((end - q) < 4) goto no_room; *(q++) = '\\'; *(q++) = 'r'; p++; break; case '\n': if ((end - q) < 4) goto no_room; *(q++) = '\\'; *(q++) = 'r'; p++; break; case '\t': if ((end - q) < 4) goto no_room; *(q++) = '\\'; *(q++) = 't'; p++; break; default: *(q++) = *(p++); break; } } *(q++) = c; *q = '\0'; return q - buffer; }