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