- Add some additional date expansions (%Y, %y, %m, %d)
[freeradius.git] / src / main / xlat.c
1 /*
2  * xlat.c       Translate strings.
3  *
4  * Version:     $Id$
5  *
6  *              This is the first version of xlat incorporated to RADIUS
7  */
8
9 static const char rcsid[] = 
10 "$Id$";
11
12 #include        "autoconf.h"
13
14 #include        <sys/types.h>
15
16 #include        <stdio.h>
17 #include        <stdlib.h>
18 #include        <string.h>
19 #include        <ctype.h>
20
21 #include        "radiusd.h"
22
23 /*
24    Convert the value on a VALUE_PAIR to string
25 */
26 static int valuepair2str(char * out,int outlen,VALUE_PAIR * pair,int type)
27 {
28    if (pair)
29          return vp_prints_value(out,outlen,pair,0);
30    else {
31          switch (type) {
32            case PW_TYPE_STRING :
33                   strncpy(out,"_",outlen-1);
34                   break;
35            case PW_TYPE_INTEGER :
36                   strncpy(out,"0",outlen-1);
37                   break;
38            case PW_TYPE_IPADDR :
39                   strncpy(out,"?.?.?.?",outlen-1);
40                   break;
41            case PW_TYPE_DATE :
42                   strncpy(out,"0",outlen-1);
43                   break;
44            default :
45                   strncpy(out,"unknown_type",outlen-1);
46          }
47          out[outlen-1] = '\0';
48          return strlen(out);
49    }
50 }
51
52 /*
53   Returns a string with value of Attribute
54 */
55 static int valuebyname(char * out,int outlen,VALUE_PAIR * request, char * attrname)
56 {
57         DICT_ATTR * da;
58
59         da = dict_attrbyname(attrname);
60         if (da) {
61           return (valuepair2str(out,outlen,pairfind(request,da->attr),da->type));
62         } else {
63           *out = '\0';
64           return 0;
65         }
66 }
67
68
69 /*
70  *      Based on radius_xlat from exec.c
71  *      After testing will replace the radius_xlat
72  *
73  *      Replace %<whatever> in a string.
74  *
75  *      %a       Protocol (SLIP/PPP)
76  *      %c       Callback-Number
77  *      %d       request day (DD)
78  *      %f       Framed IP address
79  *      %i       Calling Station ID
80  *      %l       request timestamp
81  *      %m       request month (MM)
82  *      %n       NAS IP address
83  *      %p       Port number
84  *      %s       Speed (PW_CONNECT_INFO)
85  *      %t       MTU
86  *      %u       User name
87  *      %y       request year (YY)
88  *      %A       radacct_dir
89  *      %C       clientname
90  *      %D       request date (YYYYMMDD)
91  *      %I       request in ctime format
92  *      %L       radlog_dir
93  *      %R       radius_dir
94  *      %T       request timestamp in database format
95  *      %U       Stripped User name
96  *      %V       Request-Authenticator (Verified/None)
97  *      %Y       request year (YYYY)
98  *      %Z       All request attributes except password (must have big buffer)
99  *      ${AttributeName}                Corresponding value for AttributeName in request
100  *      ${request:AttributeName}        Corresponding value for AttributeName in request
101  *      ${reply:AttributeName}          Corresponding value for AttributeName in reply
102  */
103
104 int radius_xlat2(char * out,int outlen, char *str, REQUEST * request, VALUE_PAIR *reply)
105 {
106         char attrname[128];
107         char *pa;
108         int i, c,freespace;
109         char *p;
110         char *q;
111         VALUE_PAIR *tmp;
112         struct tm * TM;
113         char tmpdt[40]; /* For temporary storing of dates */
114
115         q = out;
116         for (p = str; *p ; p++) {
117         /* Calculate freespace in output */
118         freespace = outlen - ((int)q-(int)out);
119                 if (freespace <= 1)
120                   break;
121                 c = *p;
122                 if ((c != '%') && (c != '$') && (c != '\\')) {
123                         *q++ = *p;
124                         continue;
125                 }
126                 if (*++p == 0) break;
127                 if (c == '\\') switch(*p) {
128                         case '\\':
129                                 *q++ = *p;
130                                 break;
131                         case 't':
132                                 *q++ = '\t';
133                                 break;
134                         case 'n':
135                                 *q++ = '\n';
136                                 break;
137                         default:
138                                 *q++ = c;
139                                 *q++ = *p;
140                                 break;
141                 } else if (c == '$') switch(*p) {
142                         case '{': /* Attribute by Name */
143                                 pa = &attrname[0];
144                                 p++;
145                                 while (*p && (*p != '}')) {
146                                   *pa++ = *p++;
147                                 }
148                                 *pa = '\0';
149                                 if (strncasecmp(attrname,"reply:",6) == 0) {
150                                   q += valuebyname(q,freespace,reply,&attrname[6]);
151                                 } else if (strncasecmp(attrname,"request:",8) == 0) {
152                                   q += valuebyname(q,freespace,request->packet->vps,&attrname[8]);
153                                 } else {
154                                   q += valuebyname(q,freespace,request->packet->vps,attrname);
155                                 }
156                                 break;
157                         default:
158                                 *q++ = c;
159                                 *q++ = *p;
160                                 break;
161                 } else if (c == '%') switch(*p) {
162                         case '%':
163                                 *q++ = *p;
164                                 break;
165                         case 'a': /* Protocol: */
166                                 q += valuepair2str(q,freespace,pairfind(reply,PW_FRAMED_PROTOCOL),PW_TYPE_INTEGER);
167                                 break;
168                         case 'c': /* Callback-Number */
169                                 q += valuepair2str(q,freespace,pairfind(reply,PW_CALLBACK_NUMBER),PW_TYPE_STRING);
170                                 break;
171                         case 'd': /* request year */
172                                 TM = localtime(&request->timestamp);
173                                 strftime(tmpdt,sizeof(tmpdt),"%d",TM);
174                                 strncpy(q,tmpdt,freespace);
175                                 i = strlen(q); q[i] = '\0'; q += i;
176                                 break;
177                         case 'f': /* Framed IP address */
178                                 q += valuepair2str(q,freespace,pairfind(reply,PW_FRAMED_IP_ADDRESS),PW_TYPE_IPADDR);
179                                 break;
180                         case 'i': /* Calling station ID */
181                                 q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_CALLING_STATION_ID),PW_TYPE_STRING);
182                                 break;
183                         case 'l': /* request timestamp */
184                                 sprintf(tmpdt,"%ld",request->timestamp);
185                                 strncpy(q,tmpdt,freespace);
186                                 i = strlen(q); q[i] = '\0'; q += i;
187                                 break;
188                         case 'm': /* request month */
189                                 TM = localtime(&request->timestamp);
190                                 strftime(tmpdt,sizeof(tmpdt),"%m",TM);
191                                 strncpy(q,tmpdt,freespace);
192                                 i = strlen(q); q[i] = '\0'; q += i;
193                                 break;
194                         case 'n': /* NAS IP address */
195                                 q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_NAS_IP_ADDRESS),PW_TYPE_IPADDR);
196                                 break;
197                         case 'p': /* Port number */
198                                 q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_NAS_PORT_ID),PW_TYPE_INTEGER);
199                                 break;
200                         case 's': /* Speed */
201                                 q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_CONNECT_INFO),PW_TYPE_STRING);
202                                 break;
203                         case 't': /* MTU */
204                                 q += valuepair2str(q,freespace,pairfind(reply,PW_FRAMED_MTU),PW_TYPE_INTEGER);
205                                 break;
206                         case 'u': /* User name */
207                                 q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_USER_NAME),PW_TYPE_STRING);
208                                 break;
209                         case 'y': /* request year */
210                                 TM = localtime(&request->timestamp);
211                                 strftime(tmpdt,sizeof(tmpdt),"%y",TM);
212                                 strncpy(q,tmpdt,freespace);
213                                 i = strlen(q); q[i] = '\0'; q += i;
214                                 break;
215                         case 'A': /* radacct_dir */
216                                 strncpy(q,radacct_dir,freespace-1);
217                                 i = strlen(q); q[i] = '\0'; q += i;
218                                 break;
219                         case 'C': /* ClientName */
220                                 strncpy(q,client_name(request->packet->src_ipaddr),freespace-1);
221                                 i = strlen(q); q[i] = '\0'; q += i;
222                                 break;
223                         case 'D': /* request date */
224                                 TM = localtime(&request->timestamp);
225                                 strftime(tmpdt,sizeof(tmpdt),"%Y%m%d",TM);
226                                 strncpy(q,tmpdt,freespace);
227                                 i = strlen(q); q[i] = '\0'; q += i;
228                                 break;
229                         case 'I': /* request timestamp */
230                                 strncpy(q,ctime(&request->timestamp),freespace);
231                                 i = strlen(q); q[i] = '\0'; q += i;
232                                 break;
233                         case 'L': /* radlog_dir */
234                                 strncpy(q,radlog_dir,freespace-1);
235                                 i = strlen(q); q[i] = '\0'; q += i;
236                                 break;
237                         case 'R': /* radius_dir */
238                                 strncpy(q,radius_dir,freespace-1);
239                                 i = strlen(q); q[i] = '\0'; q += i;
240                                 break;
241                         case 'T': /* request timestamp */
242                                 TM = localtime(&request->timestamp);
243                                 strftime(tmpdt,sizeof(tmpdt),"%Y-%m-%d-%H.%M.%S.000000",TM);
244                                 strncpy(q,tmpdt,freespace);
245                                 i = strlen(q); q[i] = '\0'; q += i;
246                                 break;
247                         case 'U': /* Stripped User name */
248                                 q += valuepair2str(q,freespace,pairfind(request->packet->vps,PW_STRIPPED_USER_NAME),PW_TYPE_STRING);
249                                 break;
250                         case 'V': /* Request-Authenticator */
251                                 if (request->packet->verified)
252                                         strncpy(q,"Verified",freespace-1);
253                                 else
254                                         strncpy(q,"None",freespace-1);
255                                 i = strlen(q); q[i] = '\0'; q += i;
256                                 break;
257                         case 'Y': /* request year */
258                                 TM = localtime(&request->timestamp);
259                                 strftime(tmpdt,sizeof(tmpdt),"%Y",TM);
260                                 strncpy(q,tmpdt,freespace);
261                                 i = strlen(q); q[i] = '\0'; q += i;
262                                 break;
263                         case 'Z': /* Full request pairs except password */
264                                 tmp = request->packet->vps;
265                                 while (tmp && (freespace > 3)) {
266                                         if (tmp->attribute != PW_PASSWORD) {
267                                                 *q++ = '\t';
268                                                 i = vp_prints(q,freespace-2,tmp);
269                                                 q += i;
270                                                 freespace -= (i+2);
271                                                 *q++ = '\n';
272                                         }
273                                         tmp = tmp->next;
274                                 }
275                                 break;
276                         default:
277                                 *q++ = '%';
278                                 *q++ = *p;
279                                 break;
280                 }
281         }
282         *q = 0;
283
284         return strlen(out);
285 }
286
287 /*
288  * print a string passing by the radius_xlat2
289  *
290  */
291 static void printf_xlat(char *str, REQUEST * request, VALUE_PAIR *reply)
292 {
293   char * p;
294   p = malloc(4096);
295   radius_xlat2(p,4096,str,request,reply);
296   printf("%s",p);
297   free(p);
298 }
299