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