2 * xlat.c Translate strings. This is the first version of xlat
3 * incorporated to RADIUS
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 * Copyright 2000 The FreeRADIUS server project
22 * Copyright 2000 Alan DeKok <aland@ox.org>
25 static const char rcsid[] =
29 #include "libradius.h"
39 char module[MAX_STRING_LEN];
42 RAD_XLAT_FUNC do_xlat;
43 struct xlat_cmp *next;
46 static struct xlat_cmp *cmp;
49 * Register an xlat function.
51 int xlat_register(char *module, RAD_XLAT_FUNC func, void *instance)
55 if (module == NULL || strlen(module) == 0){
56 DEBUG("xlat_register: Invalid module name");
60 xlat_unregister(module, func);
62 c = rad_malloc(sizeof(struct xlat_cmp));
65 strncpy(c->module, module, MAX_STRING_LEN);
66 c->length = strlen(c->module);
67 c->instance = instance;
75 * Unregister an xlat function.
77 void xlat_unregister(char *module, RAD_XLAT_FUNC func)
79 struct xlat_cmp *c, *last;
82 for (c = cmp; c; c = c->next) {
83 if (strncmp(c->module,module,c->length) == 0 && c->do_xlat == func)
88 if (c == NULL) return;
99 * find the appropriate registered xlat function.
101 static struct xlat_cmp *find_xlat_func(char *module)
105 for (c = cmp; c; c = c->next){
106 if (strncmp(c->module,module,c->length) == 0 && *(module+c->length) == ':')
115 Convert the value on a VALUE_PAIR to string
117 static int valuepair2str(char * out,int outlen,VALUE_PAIR * pair,
118 int type, RADIUS_ESCAPE_STRING func)
120 char buffer[MAX_STRING_LEN * 4];
124 vp_prints_value(buffer, sizeof(buffer), pair, 0);
125 return func(out, outlen, buffer);
127 return vp_prints_value(out, outlen, pair, 0);
131 case PW_TYPE_STRING :
132 strNcpy(out,"_",outlen);
134 case PW_TYPE_INTEGER :
135 strNcpy(out,"0",outlen);
137 case PW_TYPE_IPADDR :
138 strNcpy(out,"?.?.?.?",outlen);
141 strNcpy(out,"0",outlen);
144 strNcpy(out,"unknown_type",outlen);
151 * Decode an attribute name into a string.
153 static void decode_attribute(const char **from, char **to, int freespace, int *open, REQUEST *request, RADIUS_ESCAPE_STRING func)
162 int openbraces = *open;
172 * Skip the '}' at the front of 'p'
173 * Increment open braces
178 while ((*p) && (!stop)) {
185 if(*(p+1) && (*(p+1) == '-')) {
190 /* else FALL-THROUGH */
199 if (strncasecmp(attrname,"reply:",6) == 0) {
200 if((tmpda = dict_attrbyname(&attrname[6])) &&
201 (tmppair = pairfind(request->reply->vps, tmpda->attr))) {
202 q += valuepair2str(q,freespace,tmppair,tmpda->type, func);
205 } else if (strncasecmp(attrname,"request:",8) == 0) {
206 if((tmpda = dict_attrbyname(&attrname[8])) &&
207 (tmppair = pairfind(request->packet->vps, tmpda->attr))) {
208 q += valuepair2str(q,freespace,tmppair,tmpda->type, func);
211 } else if ((c = find_xlat_func(attrname)) != NULL){
212 DEBUG("radius_xlat: Runing registered xlat function of module %s for string \'%s\'",
213 c->module, attrname+(c->length+1));
214 q += c->do_xlat(c->instance, request, attrname+(c->length+1), q, freespace, func);
217 if((tmpda = dict_attrbyname(attrname)) &&
218 (tmppair = pairfind(request->packet->vps,tmpda->attr))) {
219 q += valuepair2str(q,freespace,tmppair,tmpda->type, func);
225 * Skip to last '}' if attr is found
226 * The rest of the stuff within the braces is
227 * useless if we found what we need
230 while((*p != '\0') && (openbraces > 0)) {
250 * Replace %<whatever> in a string.
252 * %a Protocol (SLIP/PPP)
254 * %d request day (DD)
255 * %f Framed IP address
256 * %i Calling Station ID
257 * %l request timestamp
258 * %m request month (MM)
261 * %s Speed (PW_CONNECT_INFO)
262 * %t request in ctime format
266 * %D request date (YYYYMMDD)
270 * %S request timestamp in database format (w/ spaces)
271 * %T request timestamp in database format
272 * %U Stripped User name
273 * %V Request-Authenticator (Verified/None)
274 * %Y request year (YYYY)
275 * %Z All request attributes except password (must have big buffer)
276 * ${AttributeName} Corresponding value for AttributeName in request
277 * ${request:AttributeName} Corresponding value for AttributeName in request
278 * ${reply:AttributeName} Corresponding value for AttributeName in reply
281 int radius_xlat(char *out, int outlen, const char *fmt,
282 REQUEST *request, RADIUS_ESCAPE_STRING func)
289 char tmpdt[40]; /* For temporary storing of dates */
293 for (p = fmt; *p ; p++) {
294 /* Calculate freespace in output */
295 freespace = outlen - (q - out);
299 if ((c != '%') && (c != '$') && (c != '\\')) {
301 * We check if we're inside an open brace. If we are
302 * then we assume this brace is NOT literal, but is
303 * a closing brace and apply it
305 if((c == '}') && openbraces) {
312 if (*++p == '\0') break;
313 if (c == '\\') switch(*p) {
327 } else if (c == '$') switch(*p) {
328 case '{': /* Attribute by Name */
329 decode_attribute(&p, &q, freespace, &openbraces, request, func);
336 } else if (c == '%') switch(*p) {
338 decode_attribute(&p, &q, freespace, &openbraces, request, func);
344 case 'a': /* Protocol: */
345 q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_FRAMED_PROTOCOL),PW_TYPE_INTEGER, func);
347 case 'c': /* Callback-Number */
348 q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_CALLBACK_NUMBER),PW_TYPE_STRING, func);
350 case 'd': /* request year */
351 TM = localtime_r(&request->timestamp, &s_TM);
352 strftime(tmpdt,sizeof(tmpdt),"%d",TM);
353 strNcpy(q,tmpdt,freespace);
356 case 'f': /* Framed IP address */
357 q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_FRAMED_IP_ADDRESS),PW_TYPE_IPADDR, func);
359 case 'i': /* Calling station ID */
360 q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_CALLING_STATION_ID),PW_TYPE_STRING, func);
362 case 'l': /* request timestamp */
363 snprintf(tmpdt, sizeof(tmpdt), "%ld",request->timestamp);
364 strNcpy(q,tmpdt,freespace);
367 case 'm': /* request month */
368 TM = localtime_r(&request->timestamp, &s_TM);
369 strftime(tmpdt,sizeof(tmpdt),"%m",TM);
370 strNcpy(q,tmpdt,freespace);
373 case 'n': /* NAS IP address */
374 q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_NAS_IP_ADDRESS),PW_TYPE_IPADDR, func);
376 case 'p': /* Port number */
377 q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_NAS_PORT_ID),PW_TYPE_INTEGER, func);
379 case 's': /* Speed */
380 q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_CONNECT_INFO),PW_TYPE_STRING, func);
382 case 't': /* request timestamp */
383 ctime_r(&request->timestamp, q);
386 case 'u': /* User name */
387 q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_USER_NAME),PW_TYPE_STRING, func);
389 case 'A': /* radacct_dir */
390 strNcpy(q,radacct_dir,freespace-1);
393 case 'C': /* ClientName */
394 strNcpy(q,client_name(request->packet->src_ipaddr),freespace-1);
397 case 'D': /* request date */
398 TM = localtime_r(&request->timestamp, &s_TM);
399 strftime(tmpdt,sizeof(tmpdt),"%Y%m%d",TM);
400 strNcpy(q,tmpdt,freespace);
403 case 'L': /* radlog_dir */
404 strNcpy(q,radlog_dir,freespace-1);
408 q += valuepair2str(q,freespace,pairfind(request->reply->vps,PW_FRAMED_MTU),PW_TYPE_INTEGER, func);
410 case 'R': /* radius_dir */
411 strNcpy(q,radius_dir,freespace-1);
414 case 'S': /* request timestamp in SQL format*/
415 TM = localtime_r(&request->timestamp, &s_TM);
416 strftime(tmpdt,sizeof(tmpdt),"%Y-%m-%d %H:%M:%S",TM);
417 strNcpy(q,tmpdt,freespace);
420 case 'T': /* request timestamp */
421 TM = localtime_r(&request->timestamp, &s_TM);
422 strftime(tmpdt,sizeof(tmpdt),"%Y-%m-%d-%H.%M.%S.000000",TM);
423 strNcpy(q,tmpdt,freespace);
426 case 'U': /* Stripped User name */
427 q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_STRIPPED_USER_NAME),PW_TYPE_STRING, func);
429 case 'V': /* Request-Authenticator */
430 if (request->packet->verified)
431 strNcpy(q,"Verified",freespace-1);
433 strNcpy(q,"None",freespace-1);
436 case 'Y': /* request year */
437 TM = localtime_r(&request->timestamp, &s_TM);
438 strftime(tmpdt,sizeof(tmpdt),"%Y",TM);
439 strNcpy(q,tmpdt,freespace);
442 case 'Z': /* Full request pairs except password */
443 tmp = request->packet->vps;
444 while (tmp && (freespace > 3)) {
445 if (tmp->attribute != PW_PASSWORD) {
447 i = vp_prints(q,freespace-2,tmp);
463 DEBUG2("radius_xlat: '%s'", out);