port fix from branch_1_1
[freeradius.git] / src / lib / print.c
1 /*
2  * print.c      Routines to print stuff.
3  *
4  * Version:     $Id$
5  *
6  *   This library is free software; you can redistribute it and/or
7  *   modify it under the terms of the GNU Lesser General Public
8  *   License as published by the Free Software Foundation; either
9  *   version 2.1 of the License, or (at your option) any later version.
10  *
11  *   This library is distributed in the hope that it will be useful,
12  *   but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  *   Lesser General Public License for more details.
15  *
16  *   You should have received a copy of the GNU Lesser General Public
17  *   License along with this library; if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  *
20  * Copyright 2000,2006  The FreeRADIUS server project
21  */
22
23 #include        <freeradius-devel/ident.h>
24 RCSID("$Id$")
25
26 #include        <freeradius-devel/autoconf.h>
27
28 #include        <stdio.h>
29 #include        <stdlib.h>
30 #include        <sys/types.h>
31 #include        <ctype.h>
32 #include        <string.h>
33
34 #include        <freeradius-devel/missing.h>
35 #include        <freeradius-devel/libradius.h>
36
37 /*
38  *      Convert a string to something printable.
39  *      The output string has to be _at least_ 4x the size
40  *      of the input string!
41  */
42 void librad_safeprint(char *in, int inlen, char *out, int outlen)
43 {
44         unsigned char   *str = (unsigned char *)in;
45         int             done = 0;
46         int             sp = 0;
47
48         if (inlen < 0) inlen = strlen(in);
49
50         while (inlen-- > 0 && (done + 3) < outlen) {
51                 /*
52                  *      Hack: never print trailing zero.
53                  *      Some clients send strings with an off-by-one
54                  *      length (confused with strings in C).
55                  */
56                 if (inlen == 0 && *str == 0)
57                         break;
58
59                 sp = 0;
60
61                 switch (*str) {
62                         case '\\':
63                                 sp = '\\';
64                                 break;
65                         case '\r':
66                                 sp = 'r';
67                                 break;
68                         case '\n':
69                                 sp = 'n';
70                                 break;
71                         case '\t':
72                                 sp = 't';
73                                 break;
74                         case '"':
75                                 sp = '"';
76                                 break;
77                         default:
78                           if (*str < 32 || (*str >= 128)){
79                                         snprintf(out, outlen, "\\%03o", *str);
80                                         done += 4;
81                                         out  += 4;
82                                         outlen -= 4;
83                                 } else {
84                                         *out++ = *str;
85                                         outlen--;
86                                         done++;
87                                 }
88                 }
89                 if (sp) {
90                         *out++ = '\\';
91                         *out++ = sp;
92                         outlen -= 2;
93                         done += 2;
94                 }
95                 str++;
96         }
97         *out = 0;
98 }
99
100
101 /*
102  *  Print one value into a string.
103  *  delimitst will define if strings and dates will be delimited by '"'
104  */
105 int vp_prints_value(char * out, int outlen, VALUE_PAIR *vp, int delimitst)
106 {
107         DICT_VALUE  *v;
108         char        buf[1024];
109         const char  *a = NULL;
110         size_t      len;
111         time_t      t;
112         struct tm   s_tm;
113
114         out[0] = '\0';
115         if (!vp) return 0;
116
117         switch (vp->type) {
118                 case PW_TYPE_STRING:
119                         if ((delimitst == 1) && vp->flags.has_tag) {
120                                 /* Tagged attribute: print delimter and ignore tag */
121                                 buf[0] = '"';
122                                 librad_safeprint((char *)(vp->vp_strvalue),
123                                                  vp->length, buf + 1, sizeof(buf) - 2);
124                                 strcat(buf, "\"");
125                         } else if (delimitst == 1) {
126                                 /* Non-tagged attribute: print delimter */
127                                 buf[0] = '"';
128                                 librad_safeprint((char *)vp->vp_strvalue,
129                                                  vp->length, buf + 1, sizeof(buf) - 2);
130                                 strcat(buf, "\"");
131
132                         } else if (delimitst < 0) {
133                                 strlcpy(out, vp->vp_strvalue, outlen);
134                                 return strlen(out);
135
136                         } else {
137                                 /* Non-tagged attribute: no delimiter */
138                                 librad_safeprint((char *)vp->vp_strvalue,
139                                                  vp->length, buf, sizeof(buf));
140                         }
141                         a = buf;
142                         break;
143                 case PW_TYPE_INTEGER:
144                         if ( vp->flags.has_tag ) {
145                                 /* Attribute value has a tag, need to ignore it */
146                                 if ((v = dict_valbyattr(vp->attribute, (vp->lvalue & 0xffffff)))
147                                     != NULL)
148                                         a = v->name;
149                                 else {
150                                         snprintf(buf, sizeof(buf), "%u", (vp->lvalue & 0xffffff));
151                                         a = buf;
152                                 }
153                         } else {
154                         case PW_TYPE_BYTE:
155                         case PW_TYPE_SHORT:
156                                 /* Normal, non-tagged attribute */
157                                 if ((v = dict_valbyattr(vp->attribute, vp->lvalue))
158                                     != NULL)
159                                         a = v->name;
160                                 else {
161                                         snprintf(buf, sizeof(buf), "%u", vp->lvalue);
162                                         a = buf;
163                                 }
164                         }
165                         break;
166                 case PW_TYPE_DATE:
167                         t = vp->lvalue;
168                         if (delimitst) {
169                           len = strftime(buf, sizeof(buf), "\"%b %e %Y %H:%M:%S %Z\"",
170                                          localtime_r(&t, &s_tm));
171                         } else {
172                           len = strftime(buf, sizeof(buf), "%b %e %Y %H:%M:%S %Z",
173                                          localtime_r(&t, &s_tm));
174                         }
175                         if (len > 0) a = buf;
176                         break;
177                 case PW_TYPE_IPADDR:
178                         a = inet_ntop(AF_INET, &(vp->lvalue),
179                                       buf, sizeof(buf));
180                         break;
181                 case PW_TYPE_ABINARY:
182 #ifdef ASCEND_BINARY
183                         a = buf;
184                         print_abinary(vp, buf, sizeof(buf));
185                         break;
186 #else
187                   /* FALL THROUGH */
188 #endif
189                 case PW_TYPE_OCTETS:
190                         if (outlen <= (2 * (vp->length + 1))) return 0;
191
192                         strcpy(buf, "0x");
193                         
194                         lrad_bin2hex(vp->vp_octets, buf + 2, vp->length);
195                         a = buf;
196                   break;
197
198                 case PW_TYPE_IFID:
199                         a = ifid_ntoa(buf, sizeof(buf), vp->vp_octets);
200                         break;
201
202                 case PW_TYPE_IPV6ADDR:
203                         a = inet_ntop(AF_INET6,
204                                       (const struct in6_addr *) vp->vp_strvalue,
205                                       buf, sizeof(buf));
206                         break;
207
208                 case PW_TYPE_IPV6PREFIX:
209                 {
210                         struct in6_addr addr;
211
212                         /*
213                          *      Alignment issues.
214                          */
215                         memcpy(&addr, vp->vp_strvalue + 2, sizeof(addr));
216
217                         a = inet_ntop(AF_INET6, &addr, buf, sizeof(buf));
218                         if (a) {
219                                 char *p = buf + strlen(buf);
220                                 sprintf(p, "/%u", (unsigned int) vp->vp_strvalue[1]);
221                         }
222                 }
223                         break;
224
225                 default:
226                         a = "UNKNOWN-TYPE";
227                         break;
228         }
229
230         if (a != NULL) strlcpy(out, a, outlen);
231
232         return strlen(out);
233 }
234
235 /*
236  *  This is a hack, and has to be kept in sync with tokens.h
237  */
238 static const char *vp_tokens[] = {
239   "?",                          /* T_OP_INVALID */
240   "EOL",                        /* T_EOL */
241   "{",
242   "}",
243   "(",
244   ")",
245   ",",
246   ";",
247   "+=",
248   "-=",
249   ":=",
250   "=",
251   "!=",
252   ">=",
253   ">",
254   "<=",
255   "<",
256   "=~",
257   "!~",
258   "=*",
259   "!*",
260   "==",
261   "#",
262   "<BARE-WORD>",
263   "<\"STRING\">",
264   "<'STRING'>",
265   "<`STRING`>"
266 };
267
268
269 /*
270  *      Print one attribute and value into a string.
271  */
272 int vp_prints(char *out, int outlen, VALUE_PAIR *vp)
273 {
274         int             len;
275         const char      *token = NULL;
276         const char      *name;
277
278         out[0] = 0;
279         if (!vp) return 0;
280         name = vp->name;
281
282         if (!*name) {
283                 DICT_ATTR *da = dict_attrbyvalue(vp->attribute);
284                 if (!da) return 0;
285
286                 name = da->name;
287         }
288
289         if (strlen(name) + 3 > (size_t)outlen) {
290                 return 0;
291         }
292
293         if ((vp->operator > T_OP_INVALID) &&
294             (vp->operator < T_TOKEN_LAST)) {
295                 token = vp_tokens[vp->operator];
296         } else {
297                 token = "<INVALID-TOKEN>";
298         }
299
300         if( vp->flags.has_tag ) {
301
302                 snprintf(out, outlen, "%s:%d %s ", name, vp->flags.tag,
303                          token);
304
305                 len = strlen(out);
306                 vp_prints_value(out + len, outlen - len, vp, 1);
307
308         } else {
309
310                 snprintf(out, outlen, "%s %s ", name, token);
311                 len = strlen(out);
312                 vp_prints_value(out + len, outlen - len, vp, 1);
313
314         }
315
316         return strlen(out);
317 }
318
319
320 /*
321  *      Print one attribute and value.
322  */
323 void vp_print(FILE *fp, VALUE_PAIR *vp)
324 {
325         char    buf[1024];
326
327         vp_prints(buf, sizeof(buf), vp);
328         fputs(buf, fp);
329 }
330
331
332 /*
333  *      Print a whole list of attributes, indented by a TAB
334  *      and with a newline at the end.
335  */
336 void vp_printlist(FILE *fp, VALUE_PAIR *vp)
337 {
338         for (; vp; vp = vp->next) {
339                 fprintf(fp, "\t");
340                 vp_print(fp, vp);
341                 fprintf(fp, "\n");
342         }
343 }
344