X-Git-Url: http://www.project-moonshot.org/gitweb/?a=blobdiff_plain;f=src%2Fmain%2Fxlat.c;h=9c32288d326fc055dee1e3d0b7737befc397679b;hb=df2f776b9dcbf90e264634fa5aa7f65695cc4686;hp=f4aec035f8d4ffaf706f42320985c1a4774afea5;hpb=a6bb1680f926b47c0b3b4f8ac4654c87f050a03a;p=freeradius.git diff --git a/src/main/xlat.c b/src/main/xlat.c index f4aec03..9c32288 100644 --- a/src/main/xlat.c +++ b/src/main/xlat.c @@ -25,17 +25,12 @@ #include RCSID("$Id$") -#include - -#include -#include -#include -#include - #include - +#include #include +#include + typedef struct xlat_t { char module[MAX_STRING_LEN]; int length; @@ -54,6 +49,8 @@ static const char * const internal_xlat[] = {"check", "reply", "proxy-request", "proxy-reply", + "outer.request", + "outer.reply", NULL}; #if REQUEST_MAX_REGEX > 8 @@ -77,22 +74,22 @@ static int valuepair2str(char * out,int outlen,VALUE_PAIR * pair, switch (type) { case PW_TYPE_STRING : - strNcpy(out,"_",outlen); + strlcpy(out,"_",outlen); break; case PW_TYPE_INTEGER : - strNcpy(out,"0",outlen); + strlcpy(out,"0",outlen); break; case PW_TYPE_IPADDR : - strNcpy(out,"?.?.?.?",outlen); + strlcpy(out,"?.?.?.?",outlen); break; case PW_TYPE_IPV6ADDR : - strNcpy(out,":?:",outlen); + strlcpy(out,":?:",outlen); break; case PW_TYPE_DATE : - strNcpy(out,"0",outlen); + strlcpy(out,"0",outlen); break; default : - strNcpy(out,"unknown_type",outlen); + strlcpy(out,"unknown_type",outlen); } return strlen(out); } @@ -101,9 +98,9 @@ static int valuepair2str(char * out,int outlen,VALUE_PAIR * pair, /* * Dynamically translate for check:, request:, reply:, etc. */ -static int xlat_packet(void *instance, REQUEST *request, - char *fmt, char *out, size_t outlen, - RADIUS_ESCAPE_STRING func) +static size_t xlat_packet(void *instance, REQUEST *request, + char *fmt, char *out, size_t outlen, + RADIUS_ESCAPE_STRING func) { DICT_ATTR *da; VALUE_PAIR *vp; @@ -126,15 +123,33 @@ static int xlat_packet(void *instance, REQUEST *request, break; case 3: +#ifdef WITH_PROXY if (request->proxy) vps = request->proxy->vps; packet = request->proxy; +#endif break; case 4: +#ifdef WITH_PROXY if (request->proxy_reply) vps = request->proxy_reply->vps; packet = request->proxy_reply; +#endif break; + case 5: + if (request->parent) { + vps = request->parent->packet->vps; + packet = request->parent->packet; + } + break; + + case 6: + if (request->parent && request->parent->reply) { + vps = request->parent->reply->vps; + packet = request->parent->reply; + } + break; + default: /* WTF? */ return 0; } @@ -144,18 +159,44 @@ static int xlat_packet(void *instance, REQUEST *request, */ da = dict_attrbyname(fmt); if (!da) { - int count; - const char *p = strchr(fmt, '['); + int do_number = FALSE; + size_t count; + const char *p; char buffer[256]; - if (!p) return 0; if (strlen(fmt) > sizeof(buffer)) return 0; - strNcpy(buffer, fmt, p - fmt + 1); + p = strchr(fmt, '['); + if (!p) { + p = strchr(fmt, '#'); + if (!p) return 0; + do_number = TRUE; + } + + strlcpy(buffer, fmt, p - fmt + 1); da = dict_attrbyname(buffer); if (!da) return 0; + if (do_number) { + vp = pairfind(vps, da->attr, 0); + if (!vp) return 0; + + switch (da->type) { + default: + break; + + case PW_TYPE_INTEGER: + case PW_TYPE_DATE: + case PW_TYPE_SHORT: + case PW_TYPE_BYTE: + snprintf(out, outlen, "%u", vp->lvalue); + return strlen(out); + } + + goto just_print; + } + /* * %{Attribute-Name[#]} returns the count of * attributes of that name in the list. @@ -163,31 +204,31 @@ static int xlat_packet(void *instance, REQUEST *request, if ((p[1] == '#') && (p[2] == ']')) { count = 0; - for (vp = pairfind(vps, da->attr); + for (vp = pairfind(vps, da->attr, da->vendor); vp != NULL; - vp = pairfind(vp->next, da->attr)) { + vp = pairfind(vp->next, da->attr, da->vendor)) { count++; } - snprintf(out, outlen, "%d", count); + snprintf(out, outlen, "%d", (int) count); return strlen(out); } /* * %{Attribute-Name[*]} returns ALL of the * the attributes, separated by a newline. - */ + */ if ((p[1] == '*') && (p[2] == ']')) { int total = 0; - for (vp = pairfind(vps, da->attr); + for (vp = pairfind(vps, da->attr, da->vendor); vp != NULL; - vp = pairfind(vp->next, da->attr)) { + vp = pairfind(vp->next, da->attr, da->vendor)) { count = valuepair2str(out, outlen - 1, vp, da->type, func); rad_assert(count <= outlen); total += count + 1; outlen -= (count + 1); out += count; - + *(out++) = '\n'; if (outlen == 0) break; @@ -195,7 +236,7 @@ static int xlat_packet(void *instance, REQUEST *request, return total; } - + count = atoi(p + 1); /* @@ -203,7 +244,7 @@ static int xlat_packet(void *instance, REQUEST *request, */ p += 1 + strspn(p + 1, "0123456789"); if (*p != ']') { - DEBUG2("xlat: Invalid array reference in string at %s %s", + RDEBUG2("xlat: Invalid array reference in string at %s %s", fmt, p); return 0; } @@ -211,9 +252,9 @@ static int xlat_packet(void *instance, REQUEST *request, /* * Find the N'th value. */ - for (vp = pairfind(vps, da->attr); + for (vp = pairfind(vps, da->attr, da->vendor); vp != NULL; - vp = pairfind(vp->next, da->attr)) { + vp = pairfind(vp->next, da->attr, da->vendor)) { if (count == 0) break; count--; } @@ -222,11 +263,11 @@ static int xlat_packet(void *instance, REQUEST *request, * Non-existent array reference. */ if (!vp) return 0; - + just_print: return valuepair2str(out, outlen, vp, da->type, func); } - vp = pairfind(vps, da->attr); + vp = pairfind(vps, da->attr, da->vendor); if (!vp) { /* * Some "magic" handlers, which are never in VP's, but @@ -238,14 +279,14 @@ static int xlat_packet(void *instance, REQUEST *request, if (packet) { VALUE_PAIR localvp; - localvp.vp_strvalue[0] = 0; + memset(&localvp, 0, sizeof(localvp)); switch (da->attr) { case PW_PACKET_TYPE: { DICT_VALUE *dval; - - dval = dict_valbyattr(da->attr, packet->code); + + dval = dict_valbyattr(da->attr, da->vendor, packet->code); if (dval) { snprintf(out, outlen, "%s", dval->name); } else { @@ -255,31 +296,39 @@ static int xlat_packet(void *instance, REQUEST *request, } break; + case PW_CLIENT_SHORTNAME: + if (request->client && request->client->shortname) { + strlcpy(out, request->client->shortname, outlen); + } else { + strlcpy(out, "", outlen); + } + return strlen(out); + case PW_CLIENT_IP_ADDRESS: /* the same as below */ case PW_PACKET_SRC_IP_ADDRESS: if (packet->src_ipaddr.af != AF_INET) { return 0; } localvp.attribute = da->attr; - localvp.lvalue = packet->src_ipaddr.ipaddr.ip4addr.s_addr; + localvp.vp_ipaddr = packet->src_ipaddr.ipaddr.ip4addr.s_addr; break; - + case PW_PACKET_DST_IP_ADDRESS: if (packet->dst_ipaddr.af != AF_INET) { return 0; } localvp.attribute = da->attr; - localvp.lvalue = packet->dst_ipaddr.ipaddr.ip4addr.s_addr; + localvp.vp_ipaddr = packet->dst_ipaddr.ipaddr.ip4addr.s_addr; break; - + case PW_PACKET_SRC_PORT: localvp.attribute = da->attr; - localvp.lvalue = packet->src_port; + localvp.vp_integer = packet->src_port; break; - + case PW_PACKET_DST_PORT: localvp.attribute = da->attr; - localvp.lvalue = packet->dst_port; + localvp.vp_integer = packet->dst_port; break; case PW_PACKET_AUTHENTICATION_VECTOR: @@ -294,12 +343,12 @@ static int xlat_packet(void *instance, REQUEST *request, */ case PW_REQUEST_PROCESSING_STAGE: if (request->component) { - strNcpy(out, request->component, outlen); + strlcpy(out, request->component, outlen); } else { - strNcpy(out, "server_core", outlen); + strlcpy(out, "server_core", outlen); } return strlen(out); - + case PW_PACKET_SRC_IPV6_ADDRESS: if (packet->src_ipaddr.af != AF_INET6) { return 0; @@ -309,7 +358,7 @@ static int xlat_packet(void *instance, REQUEST *request, &packet->src_ipaddr.ipaddr.ip6addr, sizeof(packet->src_ipaddr.ipaddr.ip6addr)); break; - + case PW_PACKET_DST_IPV6_ADDRESS: if (packet->dst_ipaddr.af != AF_INET6) { return 0; @@ -319,14 +368,23 @@ static int xlat_packet(void *instance, REQUEST *request, &packet->dst_ipaddr.ipaddr.ip6addr, sizeof(packet->dst_ipaddr.ipaddr.ip6addr)); break; - - case PW_SERVER_IDENTITY: - if (!request->listener || !request->listener->identity) return 0; - snprintf(out, outlen, "%s", request->listener->identity); + case PW_VIRTUAL_SERVER: + if (!request->server) return 0; + + snprintf(out, outlen, "%s", request->server); return strlen(out); break; - + + case PW_MODULE_RETURN_CODE: + localvp.attribute = da->attr; + + /* + * See modcall.c for a bit of a hack. + */ + localvp.vp_integer = request->simul_max; + break; + default: return 0; /* not found */ break; @@ -355,9 +413,9 @@ static int xlat_packet(void *instance, REQUEST *request, /* * Pull %{0} to %{8} out of the packet. */ -static int xlat_regex(void *instance, REQUEST *request, - char *fmt, char *out, size_t outlen, - RADIUS_ESCAPE_STRING func) +static size_t xlat_regex(void *instance, REQUEST *request, + char *fmt, char *out, size_t outlen, + RADIUS_ESCAPE_STRING func) { char *regex; @@ -367,7 +425,7 @@ static int xlat_regex(void *instance, REQUEST *request, */ fmt = fmt; /* -Wunused */ func = func; /* -Wunused FIXME: do escaping? */ - + regex = request_data_reference(request, request, REQUEST_DATA_REGEX | *(int *)instance); if (!regex) return 0; @@ -376,11 +434,100 @@ static int xlat_regex(void *instance, REQUEST *request, * Copy UP TO "freespace" bytes, including * a zero byte. */ - strNcpy(out, regex, outlen); + strlcpy(out, regex, outlen); return strlen(out); } #endif /* HAVE_REGEX_H */ + +/* + * Change the debugging level. + */ +static size_t xlat_debug(UNUSED void *instance, REQUEST *request, + char *fmt, char *out, size_t outlen, + UNUSED RADIUS_ESCAPE_STRING func) +{ + int level = 0; + + if (*fmt) level = atoi(fmt); + + if (level == 0) { + request->options = RAD_REQUEST_OPTION_NONE; + request->radlog = NULL; + } else { + if (level > 4) level = 4; + + request->options = level; + request->radlog = radlog_request; + } + + snprintf(out, outlen, "%d", level); + return strlen(out); +} + + +/* + * Calculate the MD5 hash of a string. + */ +static size_t xlat_md5(UNUSED void *instance, REQUEST *request, + char *fmt, char *out, size_t outlen, + UNUSED RADIUS_ESCAPE_STRING func) +{ + int i; + uint8_t digest[16]; + FR_MD5_CTX ctx; + char buffer[1024]; + + if (!radius_xlat(buffer, sizeof(buffer), fmt, request, func)) { + *out = '\0'; + return 0; + } + + fr_MD5Init(&ctx); + fr_MD5Update(&ctx, (void *) buffer, strlen(buffer)); + fr_MD5Final(digest, &ctx); + + if (outlen < 33) { + snprintf(out, outlen, "md5_overflow"); + return strlen(out); + } + + for (i = 0; i < 16; i++) { + snprintf(out + i * 2, 3, "%02x", digest[i]); + } + + return strlen(out); +} + + +/* + * Convert a string to lowercase + */ +static size_t xlat_lc(UNUSED void *instance, REQUEST *request, + char *fmt, char *out, size_t outlen, + UNUSED RADIUS_ESCAPE_STRING func) +{ + char *p, *q; + char buffer[1024]; + + if (!radius_xlat(buffer, sizeof(buffer), fmt, request, func)) { + *out = '\0'; + return 0; + } + + for (p = buffer, q = out; *p != '\0'; p++, outlen--) { + if (outlen <= 1) break; + + *(q++) = tolower((int) *p); + } + + *q = '\0'; + + return strlen(out); +} + + + /* * Compare two xlat_t structs, based ONLY on the module name. */ @@ -395,11 +542,10 @@ static int xlat_cmp(const void *a, const void *b) ((const xlat_t *)a)->length); } - /* * find the appropriate registered xlat function. */ -static const xlat_t *xlat_find(const char *module) +static xlat_t *xlat_find(const char *module) { xlat_t my_xlat; @@ -407,19 +553,12 @@ static const xlat_t *xlat_find(const char *module) * Look for dictionary attributes first. */ if ((dict_attrbyname(module) != NULL) || - (strchr(module, '[') != NULL)) { - static const xlat_t dict_xlat = { - "request", - 7, - &xlat_inst[1], - xlat_packet, - TRUE - }; - - return &dict_xlat; + (strchr(module, '[') != NULL) || + (strchr(module, '#') != NULL)) { + module = "request"; } - strNcpy(my_xlat.module, module, sizeof(my_xlat.module)); + strlcpy(my_xlat.module, module, sizeof(my_xlat.module)); my_xlat.length = strlen(my_xlat.module); return rbtree_finddata(xlat_root, &my_xlat); @@ -467,6 +606,14 @@ int xlat_register(const char *module, RAD_XLAT_FUNC func, void *instance) c->internal = TRUE; } + /* + * New name: "control" + */ + xlat_register("control", xlat_packet, &xlat_inst[0]); + c = xlat_find("control"); + rad_assert(c != NULL); + c->internal = TRUE; + #ifdef HAVE_REGEX_H /* * Register xlat's for regexes. @@ -480,12 +627,28 @@ int xlat_register(const char *module, RAD_XLAT_FUNC func, void *instance) c->internal = TRUE; } #endif /* HAVE_REGEX_H */ + + + xlat_register("debug", xlat_debug, &xlat_inst[0]); + c = xlat_find("debug"); + rad_assert(c != NULL); + c->internal = TRUE; + + xlat_register("md5", xlat_md5, &xlat_inst[0]); + c = xlat_find("md5"); + rad_assert(c != NULL); + c->internal = TRUE; + + xlat_register("tolower", xlat_lc, &xlat_inst[0]); + c = xlat_find("tolower"); + rad_assert(c != NULL); + c->internal = TRUE; } /* * If it already exists, replace the instance. */ - strNcpy(my_xlat.module, module, sizeof(my_xlat.module)); + strlcpy(my_xlat.module, module, sizeof(my_xlat.module)); my_xlat.length = strlen(my_xlat.module); c = rbtree_finddata(xlat_root, &my_xlat); if (c) { @@ -502,11 +665,11 @@ int xlat_register(const char *module, RAD_XLAT_FUNC func, void *instance) /* * Doesn't exist. Create it. */ - c = rad_malloc(sizeof(xlat_t)); + c = rad_malloc(sizeof(*c)); memset(c, 0, sizeof(*c)); c->do_xlat = func; - strNcpy(c->module, module, sizeof(c->module)); + strlcpy(c->module, module, sizeof(c->module)); c->length = strlen(c->module); c->instance = instance; @@ -530,7 +693,7 @@ void xlat_unregister(const char *module, RAD_XLAT_FUNC func) if (!module) return; - strNcpy(my_xlat.module, module, sizeof(my_xlat.module)); + strlcpy(my_xlat.module, module, sizeof(my_xlat.module)); my_xlat.length = strlen(my_xlat.module); node = rbtree_find(xlat_root, &my_xlat); @@ -552,222 +715,220 @@ void xlat_free(void) /* * Decode an attribute name into a string. */ -static void decode_attribute(const char **from, char **to, int freespace, - int *open, REQUEST *request, +static int decode_attribute(const char **from, char **to, int freespace, + REQUEST *request, RADIUS_ESCAPE_STRING func) { int do_length = 0; - char xlat_name[128]; - char *xlat_string = NULL; /* can be large */ - int free_xlat_string = FALSE; - const char *p; - char *q, *pa; - int found=0, retlen=0; - int openbraces = *open; + char *xlat_name, *xlat_string; + char *p, *q, *l, *next = NULL; + int retlen=0; const xlat_t *c; + int varlen; + char buffer[8192]; - p = *from; q = *to; - pa = &xlat_name[0]; *q = '\0'; /* - * Skip the '{' at the front of 'p' - * Increment open braces + * Copy the input string to an intermediate buffer where + * we can mangle it. */ - p++; - openbraces++; + varlen = rad_copy_variable(buffer, *from); + if (varlen < 0) { + RDEBUG2("Badly formatted variable: %s", *from); + return -1; + } + *from += varlen; + /* + * Kill the %{} around the data we are looking for. + */ + p = buffer; + p[varlen - 1] = '\0'; /* */ + p += 2; if (*p == '#') { p++; do_length = 1; } /* - * First, copy the xlat key name to one buffer + * Handle %{%{foo}:-%{bar}}, which is useful, too. + * + * Did I mention that this parser is garbage? */ - while (*p && (*p != '}') && (*p != ':')) { - *pa++ = *p++; + if ((p[0] == '%') && (p[1] == '{')) { + int len1, len2; + int expand2 = FALSE; - if (pa >= (xlat_name + sizeof(xlat_name) - 1)) { - /* - * Skip to the end of the input - */ - p += strlen(p); - DEBUG("xlat: Module name is too long in string %%%s", - *from); - goto done; + /* + * 'p' is after the start of 'buffer', so we can + * safely do this. + */ + len1 = rad_copy_variable(buffer, p); + if (len1 < 0) { + RDEBUG2("Badly formatted variable: %s", p); + return -1; } - } - *pa = '\0'; - - if (!*p) { - DEBUG("xlat: Invalid syntax in %s", *from); /* - * %{name} is a simple attribute reference, - * or regex reference. + * They did %{%{foo}}, which is stupid, but allowed. */ - } else if (*p == '}') { - openbraces--; - rad_assert(openbraces == *open); - - p++; - xlat_string = xlat_name; - goto do_xlat; - - } else if (p[1] == '-') { /* handle ':- */ - p += 2; - xlat_string = xlat_name; - goto do_xlat; - - } else { /* module name, followed by per-module string */ - int stop = 0; - int delimitbrace = *open; - - rad_assert(*p == ':'); - p++; /* skip the ':' */ + if (!p[len1]) { + RDEBUG2("Improperly nested variable; %%{%s}", p); + return -1; + } /* - * If there's a brace immediately following the colon, - * then we've chosen to delimite the per-module string, - * so keep track of that. + * It SHOULD be %{%{foo}:-%{bar}}. If not, it's + * an error. */ - if (*p == '{') { - delimitbrace = openbraces; - openbraces++; - p++; + if ((p[len1] != ':') || (p[len1 + 1] != '-')) { + RDEBUG2("No trailing :- after variable at %s", p); + return -1; } - - xlat_string = rad_malloc(strlen(p) + 1); /* always returns */ - free_xlat_string = TRUE; - pa = xlat_string; - + /* - * Copy over the rest of the string, which is per-module - * data. + * Parse the second bit. The second bit can be + * either %{foo}, or a string "foo", or a string + * 'foo', or just a bare word: foo */ - while (*p && !stop) { - switch(*p) { - /* - * What the heck is this supposed - * to be doing? - */ - case '\\': - p++; /* skip it */ - *pa++ = *p++; - break; + p += len1 + 2; + l = buffer + len1 + 1; - /* - * This is pretty hokey... we - * should use the functions in - * util.c - */ - case '{': - openbraces++; - *pa++ = *p++; - break; + if ((p[0] == '%') && (p[1] == '{')) { + len2 = rad_copy_variable(l, p); - case '}': - openbraces--; - if (openbraces == delimitbrace) { - p++; - stop=1; - } else { - *pa++ = *p++; - } - break; - - default: - *pa++ = *p++; - break; + if (len2 < 0) { + RDEBUG2("Invalid text after :- at %s", p); + return -1; } - } + p += len2; + expand2 = TRUE; - *pa = '\0'; + } else if ((p[0] == '"') || p[0] == '\'') { + getstring(&p, l, strlen(l)); + + } else { + l = p; + } /* - * Now check to see if we're at the end of the string - * we were sent. If we're not, check for :- + * Expand the first one. If we did, exit the + * conditional. */ - if (openbraces == delimitbrace) { - if (p[0] == ':' && p[1] == '-') { - p += 2; - } + retlen = radius_xlat(q, freespace, buffer, request, func); + if (retlen) { + q += retlen; + goto done; } - + + RDEBUG2("\t... expanding second conditional"); /* - * Look up almost everything in the new tree of xlat - * functions. This makes it a little quicker... + * Expand / copy the second string if required. */ - do_xlat: - if ((c = xlat_find(xlat_name)) != NULL) { - if (!c->internal) DEBUG("radius_xlat: Running registered xlat function of module %s for string \'%s\'", - c->module, xlat_string); - retlen = c->do_xlat(c->instance, request, xlat_string, - q, freespace, func); - /* If retlen is 0, treat it as not found */ - if (retlen > 0) found = 1; -#ifndef NDEBUG + if (expand2) { + retlen = radius_xlat(q, freespace, l, + request, func); + if (retlen) { + q += retlen; + } } else { - /* - * No attribute by that name, return an error. - */ - DEBUG2("WARNING: Unknown module \"%s\" in string expansion \"%%%s\"", xlat_name, *from); -#endif + strlcpy(q, l, freespace); + q += strlen(q); } + + /* + * Else the output is an empty string. + */ + goto done; } /* - * Skip to last '}' if attr is found - * The rest of the stuff within the braces is - * useless if we found what we need + * See if we're supposed to expand a module name. */ - if (found) { - if (do_length) { - snprintf(q, freespace, "%d", retlen); - retlen = strlen(q); + xlat_name = NULL; + for (l = p; *l != '\0'; l++) { + if (*l == '\\') { + l++; + continue; } - q += retlen; + if (*l == ':') { + xlat_name = p; /* start of name */ + *l = '\0'; + p = l + 1; + break; + } - while((*p != '\0') && (openbraces > *open)) { - /* - * Handle escapes outside of the loop. - */ - if (*p == '\\') { - p++; - if (!*p) break; - p++; /* get & ignore next character */ - continue; - } + /* + * Module names can't have spaces. + */ + if ((*l == ' ') || (*l == '\t')) break; + } - switch (*p) { - default: - break; + /* + * %{name} is a simple attribute reference, + * or regex reference. + */ + if (!xlat_name) { + xlat_name = xlat_string = p; + goto do_xlat; + } - /* - * Bare brace - */ - case '{': - openbraces++; - break; + /* + * Maybe it's the old-style %{foo:-bar} + */ + if (*p == '-') { + RDEBUG2("WARNING: Deprecated conditional expansion \":-\". See \"man unlang\" for details"); + p++; - case '}': - openbraces--; - break; + xlat_string = xlat_name; + next = p; + goto do_xlat; + } + + /* + * FIXME: For backwards "WTF" compatibility, check for + * {...}, (after the :), and copy that, too. + */ + + /* module name, followed by (possibly) per-module string */ + xlat_string = p; + +do_xlat: + if ((c = xlat_find(xlat_name)) != NULL) { + if (!c->internal) RDEBUG3("radius_xlat: Running registered xlat function of module %s for string \'%s\'", + c->module, xlat_string); + retlen = c->do_xlat(c->instance, request, xlat_string, + q, freespace, func); + if (retlen > 0) { + if (do_length) { + snprintf(q, freespace, "%d", retlen); + retlen = strlen(q); } - p++; /* skip the character */ + + } else if (next) { + /* + * Expand the second bit. + */ + RDEBUG2("\t... expanding second conditional"); + retlen = radius_xlat(q, freespace, next, request, func); } + q += retlen; + + } else { + /* + * No attribute by that name, return an error. + */ + RDEBUG2("WARNING: Unknown module \"%s\" in string expansion \"%%%s\"", xlat_name, *from); + return -1; } - - done: - if (free_xlat_string) free(xlat_string); - *open = openbraces; - *from = p; +done: *to = q; + return 0; } /* @@ -775,7 +936,7 @@ static void decode_attribute(const char **from, char **to, int freespace, * we use this one. It simplifies the coding, as the check for * func == NULL only happens once. */ -static int xlat_copy(char *out, int outlen, const char *in) +static size_t xlat_copy(char *out, size_t outlen, const char *in) { int freespace = outlen; @@ -877,58 +1038,44 @@ int radius_xlat(char *out, int outlen, const char *fmt, } p++; - /* - * Hmmm... ${User-Name} is a synonym for - * %{User-Name}. - * - * Why, exactly? - */ - } else if (c == '$') switch(*p) { - case '{': /* Attribute by Name */ - decode_attribute(&p, &q, freespace, &openbraces, request, func); - break; - default: - *q++ = c; - *q++ = *p++; - break; - } else if (c == '%') switch(*p) { case '{': - decode_attribute(&p, &q, freespace, &openbraces, request, func); + p--; + if (decode_attribute(&p, &q, freespace, request, func) < 0) return 0; break; case '%': *q++ = *p++; break; case 'a': /* Protocol: */ - q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_FRAMED_PROTOCOL),PW_TYPE_INTEGER, func); + q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_FRAMED_PROTOCOL, 0),PW_TYPE_INTEGER, func); p++; break; case 'c': /* Callback-Number */ - q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_CALLBACK_NUMBER),PW_TYPE_STRING, func); + q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_CALLBACK_NUMBER, 0),PW_TYPE_STRING, func); p++; break; case 'd': /* request day */ TM = localtime_r(&request->timestamp, &s_TM); len = strftime(tmpdt, sizeof(tmpdt), "%d", TM); if (len > 0) { - strNcpy(q, tmpdt, freespace); + strlcpy(q, tmpdt, freespace); q += strlen(q); } p++; break; case 'f': /* Framed IP address */ - q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_FRAMED_IP_ADDRESS),PW_TYPE_IPADDR, func); + q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_FRAMED_IP_ADDRESS, 0),PW_TYPE_IPADDR, func); p++; break; case 'i': /* Calling station ID */ - q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_CALLING_STATION_ID),PW_TYPE_STRING, func); + q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_CALLING_STATION_ID, 0),PW_TYPE_STRING, func); p++; break; case 'l': /* request timestamp */ snprintf(tmpdt, sizeof(tmpdt), "%lu", (unsigned long) request->timestamp); - strNcpy(q,tmpdt,freespace); + strlcpy(q,tmpdt,freespace); q += strlen(q); p++; break; @@ -936,42 +1083,42 @@ int radius_xlat(char *out, int outlen, const char *fmt, TM = localtime_r(&request->timestamp, &s_TM); len = strftime(tmpdt, sizeof(tmpdt), "%m", TM); if (len > 0) { - strNcpy(q, tmpdt, freespace); + strlcpy(q, tmpdt, freespace); q += strlen(q); } p++; break; case 'n': /* NAS IP address */ - q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_NAS_IP_ADDRESS),PW_TYPE_IPADDR, func); + q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_NAS_IP_ADDRESS, 0),PW_TYPE_IPADDR, func); p++; break; case 'p': /* Port number */ - q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_NAS_PORT),PW_TYPE_INTEGER, func); + q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_NAS_PORT, 0),PW_TYPE_INTEGER, func); p++; break; case 's': /* Speed */ - q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_CONNECT_INFO),PW_TYPE_STRING, func); + q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_CONNECT_INFO, 0),PW_TYPE_STRING, func); p++; break; case 't': /* request timestamp */ CTIME_R(&request->timestamp, tmpdt, sizeof(tmpdt)); nl = strchr(tmpdt, '\n'); if (nl) *nl = '\0'; - strNcpy(q, tmpdt, freespace); + strlcpy(q, tmpdt, freespace); q += strlen(q); p++; break; case 'u': /* User name */ - q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_USER_NAME),PW_TYPE_STRING, func); + q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_USER_NAME, 0),PW_TYPE_STRING, func); p++; break; case 'A': /* radacct_dir */ - strNcpy(q,radacct_dir,freespace-1); + strlcpy(q,radacct_dir,freespace); q += strlen(q); p++; break; case 'C': /* ClientName */ - strNcpy(q,client_name_old(&request->packet->src_ipaddr),freespace-1); + strlcpy(q,request->client->shortname,freespace); q += strlen(q); p++; break; @@ -979,7 +1126,7 @@ int radius_xlat(char *out, int outlen, const char *fmt, TM = localtime_r(&request->timestamp, &s_TM); len = strftime(tmpdt, sizeof(tmpdt), "%Y%m%d", TM); if (len > 0) { - strNcpy(q, tmpdt, freespace); + strlcpy(q, tmpdt, freespace); q += strlen(q); } p++; @@ -988,22 +1135,22 @@ int radius_xlat(char *out, int outlen, const char *fmt, TM = localtime_r(&request->timestamp, &s_TM); len = strftime(tmpdt, sizeof(tmpdt), "%H", TM); if (len > 0) { - strNcpy(q, tmpdt, freespace); + strlcpy(q, tmpdt, freespace); q += strlen(q); } p++; break; case 'L': /* radlog_dir */ - strNcpy(q,radlog_dir,freespace-1); + strlcpy(q,radlog_dir,freespace); q += strlen(q); p++; break; case 'M': /* MTU */ - q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_FRAMED_MTU),PW_TYPE_INTEGER, func); + q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_FRAMED_MTU, 0),PW_TYPE_INTEGER, func); p++; break; case 'R': /* radius_dir */ - strNcpy(q,radius_dir,freespace-1); + strlcpy(q,radius_dir,freespace); q += strlen(q); p++; break; @@ -1011,7 +1158,7 @@ int radius_xlat(char *out, int outlen, const char *fmt, TM = localtime_r(&request->timestamp, &s_TM); len = strftime(tmpdt, sizeof(tmpdt), "%Y-%m-%d %H:%M:%S", TM); if (len > 0) { - strNcpy(q, tmpdt, freespace); + strlcpy(q, tmpdt, freespace); q += strlen(q); } p++; @@ -1020,20 +1167,17 @@ int radius_xlat(char *out, int outlen, const char *fmt, TM = localtime_r(&request->timestamp, &s_TM); len = strftime(tmpdt, sizeof(tmpdt), "%Y-%m-%d-%H.%M.%S.000000", TM); if (len > 0) { - strNcpy(q, tmpdt, freespace); + strlcpy(q, tmpdt, freespace); q += strlen(q); } p++; break; case 'U': /* Stripped User name */ - q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_STRIPPED_USER_NAME),PW_TYPE_STRING, func); + q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_STRIPPED_USER_NAME, 0),PW_TYPE_STRING, func); p++; break; case 'V': /* Request-Authenticator */ - if (request->packet->verified) - strNcpy(q,"Verified",freespace-1); - else - strNcpy(q,"None",freespace-1); + strlcpy(q,"Verified",freespace); q += strlen(q); p++; break; @@ -1041,7 +1185,7 @@ int radius_xlat(char *out, int outlen, const char *fmt, TM = localtime_r(&request->timestamp, &s_TM); len = strftime(tmpdt, sizeof(tmpdt), "%Y", TM); if (len > 0) { - strNcpy(q, tmpdt, freespace); + strlcpy(q, tmpdt, freespace); q += strlen(q); } p++; @@ -1061,7 +1205,7 @@ int radius_xlat(char *out, int outlen, const char *fmt, p++; break; default: - DEBUG2("WARNING: Unknown variable '%%%c': See 'doc/variables.txt'", *p); + RDEBUG2("WARNING: Unknown variable '%%%c': See 'doc/variables.txt'", *p); if (freespace > 2) { *q++ = '%'; *q++ = *p++; @@ -1071,7 +1215,7 @@ int radius_xlat(char *out, int outlen, const char *fmt, } *q = '\0'; - DEBUG2("radius_xlat: '%s'", out); + RDEBUG2("\texpand: %s -> %s", fmt, out); return strlen(out); }