📄 xlat.c
字号:
/* * xlat.c Translate strings. This is the first version of xlat * incorporated to RADIUS * * Version: $Id: xlat.c,v 1.135 2008/03/16 17:59:29 aland Exp $ * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA * * Copyright 2000,2006 The FreeRADIUS server project * Copyright 2000 Alan DeKok <aland@ox.org> */#include <freeradius-devel/ident.h>RCSID("$Id: xlat.c,v 1.135 2008/03/16 17:59:29 aland Exp $")#include <freeradius-devel/radiusd.h>#include <freeradius-devel/rad_assert.h>#include <ctype.h>typedef struct xlat_t { char module[MAX_STRING_LEN]; int length; void *instance; RAD_XLAT_FUNC do_xlat; int internal; /* not allowed to re-define these */} xlat_t;static rbtree_t *xlat_root = NULL;/* * Define all xlat's in the structure. */static const char * const internal_xlat[] = {"check", "request", "reply", "proxy-request", "proxy-reply", "outer.request", "outer.reply", NULL};#if REQUEST_MAX_REGEX > 8#error Please fix the following line#endifstatic const int xlat_inst[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }; /* up to 8 for regex *//* * Convert the value on a VALUE_PAIR to string */static int valuepair2str(char * out,int outlen,VALUE_PAIR * pair, int type, RADIUS_ESCAPE_STRING func){ char buffer[MAX_STRING_LEN * 4]; if (pair != NULL) { vp_prints_value(buffer, sizeof(buffer), pair, -1); return func(out, outlen, buffer); } switch (type) { case PW_TYPE_STRING : strlcpy(out,"_",outlen); break; case PW_TYPE_INTEGER : strlcpy(out,"0",outlen); break; case PW_TYPE_IPADDR : strlcpy(out,"?.?.?.?",outlen); break; case PW_TYPE_IPV6ADDR : strlcpy(out,":?:",outlen); break; case PW_TYPE_DATE : strlcpy(out,"0",outlen); break; default : strlcpy(out,"unknown_type",outlen); } return strlen(out);}/* * Dynamically translate for check:, request:, reply:, etc. */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; VALUE_PAIR *vps = NULL; RADIUS_PACKET *packet = NULL; switch (*(int*) instance) { case 0: vps = request->config_items; break; case 1: vps = request->packet->vps; packet = request->packet; break; case 2: vps = request->reply->vps; packet = request->reply; break; case 3: if (request->proxy) vps = request->proxy->vps; packet = request->proxy; break; case 4: if (request->proxy_reply) vps = request->proxy_reply->vps; packet = request->proxy_reply; 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; } /* * The "format" string is the attribute name. */ da = dict_attrbyname(fmt); if (!da) { size_t count; const char *p = strchr(fmt, '['); char buffer[256]; if (!p) return 0; if (strlen(fmt) > sizeof(buffer)) return 0; strlcpy(buffer, fmt, p - fmt + 1); da = dict_attrbyname(buffer); if (!da) return 0; /* * %{Attribute-Name[#]} returns the count of * attributes of that name in the list. */ if ((p[1] == '#') && (p[2] == ']')) { count = 0; for (vp = pairfind(vps, da->attr); vp != NULL; vp = pairfind(vp->next, da->attr)) { count++; } snprintf(out, outlen, "%d", 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); vp != NULL; vp = pairfind(vp->next, da->attr)) { 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; } return total; } count = atoi(p + 1); /* * Skip the numbers. */ p += 1 + strspn(p + 1, "0123456789"); if (*p != ']') { DEBUG2("xlat: Invalid array reference in string at %s %s", fmt, p); return 0; } /* * Find the N'th value. */ for (vp = pairfind(vps, da->attr); vp != NULL; vp = pairfind(vp->next, da->attr)) { if (count == 0) break; count--; } /* * Non-existent array reference. */ if (!vp) return 0; return valuepair2str(out, outlen, vp, da->type, func); } vp = pairfind(vps, da->attr); if (!vp) { /* * Some "magic" handlers, which are never in VP's, but * which are in the packet. * * FIXME: We should really do this in a more * intelligent way... */ if (packet) { VALUE_PAIR localvp; memset(&localvp, 0, sizeof(localvp)); switch (da->attr) { case PW_PACKET_TYPE: { DICT_VALUE *dval; dval = dict_valbyattr(da->attr, packet->code); if (dval) { snprintf(out, outlen, "%s", dval->name); } else { snprintf(out, outlen, "%d", packet->code); } return strlen(out); } break; case PW_CLIENT_SHORTNAME: if (request->client && request->client->shortname) { strlcpy(out, request->client->shortname, outlen); } else { strlcpy(out, "<UNKNOWN-CLIENT>", 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.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.vp_ipaddr = packet->dst_ipaddr.ipaddr.ip4addr.s_addr; break; case PW_PACKET_SRC_PORT: localvp.attribute = da->attr; localvp.vp_integer = packet->src_port; break; case PW_PACKET_DST_PORT: localvp.attribute = da->attr; localvp.vp_integer = packet->dst_port; break; case PW_PACKET_AUTHENTICATION_VECTOR: localvp.attribute = da->attr; memcpy(localvp.vp_strvalue, packet->vector, sizeof(packet->vector)); localvp.length = sizeof(packet->vector); break; /* * Authorization, accounting, etc. */ case PW_REQUEST_PROCESSING_STAGE: if (request->component) { strlcpy(out, request->component, outlen); } else { strlcpy(out, "server_core", outlen); } return strlen(out); case PW_PACKET_SRC_IPV6_ADDRESS: if (packet->src_ipaddr.af != AF_INET6) { return 0; } localvp.attribute = da->attr; memcpy(localvp.vp_strvalue, &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; } localvp.attribute = da->attr; memcpy(localvp.vp_strvalue, &packet->dst_ipaddr.ipaddr.ip6addr, sizeof(packet->dst_ipaddr.ipaddr.ip6addr)); break; 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; } localvp.type = da->type; return valuepair2str(out, outlen, &localvp, da->type, func); } /* * Not found, die. */ return 0; } if (!vps) return 0; /* silently fail */ /* * Convert the VP to a string, and return it. */ return valuepair2str(out, outlen, vp, da->type, func);}#ifdef HAVE_REGEX_H/* * Pull %{0} to %{8} out of the packet. */static size_t xlat_regex(void *instance, REQUEST *request, char *fmt, char *out, size_t outlen, RADIUS_ESCAPE_STRING func){ char *regex; /* * We cheat: fmt is "0" to "8", but those numbers * are already in the "instance". */ fmt = fmt; /* -Wunused */ func = func; /* -Wunused FIXME: do escaping? */ regex = request_data_reference(request, request, REQUEST_DATA_REGEX | *(int *)instance); if (!regex) return 0; /* * Copy UP TO "freespace" bytes, including * a zero byte. */ strlcpy(out, regex, outlen); return strlen(out);}#endif /* HAVE_REGEX_H *//* * Compare two xlat_t structs, based ONLY on the module name. */static int xlat_cmp(const void *a, const void *b){ if (((const xlat_t *)a)->length != ((const xlat_t *)b)->length) { return ((const xlat_t *)a)->length - ((const xlat_t *)b)->length; } return memcmp(((const xlat_t *)a)->module, ((const xlat_t *)b)->module, ((const xlat_t *)a)->length);}/* * find the appropriate registered xlat function. */static xlat_t *xlat_find(const char *module){ xlat_t my_xlat; /* * Look for dictionary attributes first. */ if ((dict_attrbyname(module) != NULL) || (strchr(module, '[') != NULL)) { module = "request"; } strlcpy(my_xlat.module, module, sizeof(my_xlat.module)); my_xlat.length = strlen(my_xlat.module); return rbtree_finddata(xlat_root, &my_xlat);}/* * Register an xlat function. */int xlat_register(const char *module, RAD_XLAT_FUNC func, void *instance){ xlat_t *c; xlat_t my_xlat; if ((module == NULL) || (strlen(module) == 0)) { DEBUG("xlat_register: Invalid module name"); return -1; } /* * First time around, build up the tree... * * FIXME: This code should be hoisted out of this function, * and into a global "initialization". But it isn't critical... */ if (!xlat_root) { int i;#ifdef HAVE_REGEX_H char buffer[2];#endif xlat_root = rbtree_create(xlat_cmp, free, 0); if (!xlat_root) { DEBUG("xlat_register: Failed to create tree."); return -1; } /* * Register the internal packet xlat's. */ for (i = 0; internal_xlat[i] != NULL; i++) { xlat_register(internal_xlat[i], xlat_packet, &xlat_inst[i]); c = xlat_find(internal_xlat[i]); rad_assert(c != NULL); 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. */ buffer[1] = '\0'; for (i = 0; i <= REQUEST_MAX_REGEX; i++) { buffer[0] = '0' + i; xlat_register(buffer, xlat_regex, &xlat_inst[i]); c = xlat_find(buffer); rad_assert(c != NULL); c->internal = TRUE; }#endif /* HAVE_REGEX_H */ } /* * If it already exists, replace the instance. */ 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) { if (c->internal) { DEBUG("xlat_register: Cannot re-define internal xlat"); return -1; } c->do_xlat = func; c->instance = instance; return 0; } /* * Doesn't exist. Create it. */ c = rad_malloc(sizeof(*c)); memset(c, 0, sizeof(*c)); c->do_xlat = func; strlcpy(c->module, module, sizeof(c->module)); c->length = strlen(c->module); c->instance = instance; rbtree_insert(xlat_root, c); return 0;}/* * Unregister an xlat function. * * We can only have one function to call per name, so the * passing of "func" here is extraneous. */void xlat_unregister(const char *module, RAD_XLAT_FUNC func){ rbnode_t *node; xlat_t my_xlat; func = func; /* -Wunused */ if (!module) return; strlcpy(my_xlat.module, module, sizeof(my_xlat.module)); my_xlat.length = strlen(my_xlat.module); node = rbtree_find(xlat_root, &my_xlat); if (!node) return; rbtree_delete(xlat_root, node);}/* * De-register all xlat functions, * used mainly for debugging. */void xlat_free(void){ rbtree_free(xlat_root);}/* * Decode an attribute name into a string. */static void decode_attribute(const char **from, char **to, int freespace, int *open_p, 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_p; const xlat_t *c;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -