1 /* $Id$ */
2 /*
3 ** Copyright (C) 1998-2002 Martin Roesch <roesch@sourcefire.com>
4 **
5 ** This program is free software; you can redistribute it and/or modify
6 ** it under the terms of the GNU General Public License Version 2 as
7 ** published by the Free Software Foundation.  You may not use, modify or
8 ** distribute this program under any other version of the GNU General
9 ** Public License.
10 **
11 ** This program 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
14 ** GNU General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program; if not, write to the Free Software
18 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 */
20 
21 /*
22 ** This file contains various routines which we shamelessly steal from other
23 ** opensource products :-P (I love code reuseability idea)
24 ** 			fygrave@tigerteam.net
25 */
26 
27 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30 
31 #ifndef HAVE_SNPRINTF
32     #include "snprintf.h"
33 
34 /* snprintf() and all supporting routines were taken from sendmail, hence the
35  * copyleft message
36  */
37 
38 /*
39  * Copyright (c) 1998 Sendmail, Inc.  All rights reserved.
40  * Copyright (c) 1997 Eric P. Allman.  All rights reserved.
41  * Copyright (c) 1988, 1993
42  *	The Regents of the University of California.  All rights reserved.
43  *
44  * By using this file, you agree to the terms and conditions set
45  * forth in the LICENSE file which can be found at the top level of
46  * the sendmail distribution.
47  *
48  */
49 
50 /*
51 **  SNPRINTF, VSNPRINT -- counted versions of printf
52 **
53 **	These versions have been grabbed off the net.  They have been
54 **	cleaned up to compile properly and support for .precision and
55 **	%lx has been added.
56 */
57 
58 /**************************************************************
59  * Original:
60  * Patrick Powell Tue Apr 11 09:48:21 PDT 1995
61  * A bombproof version of doprnt (sm_dopr) included.
62  * Sigh.  This sort of thing is always nasty do deal with.  Note that
63  * the version here does not include floating point...
64  *
65  * snprintf() is used instead of sprintf() as it does limit checks
66  * for string length.  This covers a nasty loophole.
67  *
68  * The other functions are there to prevent NULL pointers from
69  * causing nast effects.
70  **************************************************************/
71 
72 void    sm_dopr();
73 char    *DoprEnd;
74 int SnprfOverflow;
75 
76     #ifndef HAVE_SNPRINTF
77 
78 /* VARARGS3 */
79 int
80         #ifdef __STDC__
snprintf(char * str,size_t count,const char * fmt,...)81 snprintf(char *str, size_t count, const char *fmt, ...)
82         #else
83 snprintf(str, count, fmt, va_alist)
84 char *str;
85 size_t count;
86 const char *fmt;
87 va_dcl
88         #endif
89 {
90     int len;
91     VA_LOCAL_DECL
92 
93     VA_START(fmt);
94     len = vsnprintf(str, count, fmt, ap);
95     VA_END;
96     return len;
97 }
98 
99 
100         #ifndef luna2
101 #ifndef HAVE_VSNPRINTF
102 
103 int
vsnprintf(str,count,fmt,args)104 vsnprintf(str, count, fmt, args)
105 char *str;
106 size_t count;
107 const char *fmt;
108 va_list args;
109 {
110     str[0] = 0;
111     DoprEnd = str + count - 1;
112     SnprfOverflow = 0;
113     sm_dopr( str, fmt, args );
114     if(count > 0)
115         DoprEnd[0] = 0;
116     if(SnprfOverflow && tTd(57, 2))
117         printf("\nvsnprintf overflow, len = %ld, str = %s",
118                (long) count, shortenstring(str, MAXSHORTSTR));
119     return strlen((const char *)str);
120 }
121 
122 #endif /* !HAVE_VSNPRINTF */
123 
124         #endif /* !luna2 */
125     #endif /* !HASSNPRINTF */
126 
127 /*
128  * sm_dopr(): poor man's version of doprintf
129  */
130 
131 void fmtstr __P((char *value, int ljust, int len, int zpad, int maxwidth));
132 void fmtnum __P((long value, int base, int dosign, int ljust, int len, int zpad));
133 void dostr __P(( char * , int ));
134 char *output;
135 void dopr_outch __P(( int c ));
136 int SyslogErrno;
137 
138 void
sm_dopr(buffer,format,args)139 sm_dopr( buffer, format, args )
140 char *buffer;
141 const char *format;
142 va_list args;
143 {
144     int ch;
145     long value;
146     int longflag  = 0;
147     int pointflag = 0;
148     int maxwidth  = 0;
149     char *strvalue;
150     int ljust;
151     int len;
152     int zpad;
153 #if !HAVE_STRERROR && !defined(ERRLIST_PREDEFINED)
154     extern char *sys_errlist[];
155     extern int sys_nerr;
156 #endif
157 
158 
159     output = buffer;
160     while((ch = *format++) != '\0')
161     {
162         switch(ch)
163         {
164             case '%':
165                 ljust = len = zpad = maxwidth = 0;
166                 longflag = pointflag = 0;
167                 nextch:
168                 ch = *format++;
169                 switch(ch)
170                 {
171                     case 0:
172                         dostr( "**end of format**" , 0);
173                         return;
174                     case '-': ljust = 1; goto nextch;
175                     case '0': /* set zero padding if len not set */
176                         if(len==0 && !pointflag) zpad = '0';
177                     case '1':
178                     case '2':
179                     case '3':
180                     case '4':
181                     case '5':
182                     case '6':
183                     case '7':
184                     case '8':
185                     case '9':
186                         if(pointflag)
187                             maxwidth = maxwidth*10 + ch - '0';
188                         else
189                             len = len*10 + ch - '0';
190                         goto nextch;
191                     case '*':
192                         if(pointflag)
193                             maxwidth = va_arg( args, int );
194                         else
195                             len = va_arg( args, int );
196                         goto nextch;
197                     case '.': pointflag = 1; goto nextch;
198                     case 'l': longflag = 1; goto nextch;
199                     case 'u':
200                     case 'U':
201                         /*fmtnum(value,base,dosign,ljust,len,zpad) */
202                         if(longflag)
203                         {
204                             value = va_arg( args, long );
205                         }
206                         else
207                         {
208                             value = va_arg( args, int );
209                         }
210                         fmtnum( value, 10,0, ljust, len, zpad ); break;
211                     case 'o':
212                     case 'O':
213                         /*fmtnum(value,base,dosign,ljust,len,zpad) */
214                         if(longflag)
215                         {
216                             value = va_arg( args, long );
217                         }
218                         else
219                         {
220                             value = va_arg( args, int );
221                         }
222                         fmtnum( value, 8,0, ljust, len, zpad ); break;
223                     case 'd':
224                     case 'D':
225                         if(longflag)
226                         {
227                             value = va_arg( args, long );
228                         }
229                         else
230                         {
231                             value = va_arg( args, int );
232                         }
233                         fmtnum( value, 10,1, ljust, len, zpad ); break;
234                     case 'x':
235                         if(longflag)
236                         {
237                             value = va_arg( args, long );
238                         }
239                         else
240                         {
241                             value = va_arg( args, int );
242                         }
243                         fmtnum( value, 16,0, ljust, len, zpad ); break;
244                     case 'X':
245                         if(longflag)
246                         {
247                             value = va_arg( args, long );
248                         }
249                         else
250                         {
251                             value = va_arg( args, int );
252                         }
253                         fmtnum( value,-16,0, ljust, len, zpad ); break;
254                     case 's':
255                         strvalue = va_arg( args, char *);
256                         if(maxwidth > 0 || !pointflag)
257                         {
258                             if(pointflag && len > maxwidth)
259                                 len = maxwidth; /* Adjust padding */
260                             fmtstr( strvalue,ljust,len,zpad, maxwidth);
261                         }
262                         break;
263                     case 'c':
264                         ch = va_arg( args, int );
265                         dopr_outch( ch ); break;
266                     case 'm':
267 #if HAVE_STRERROR
268                         dostr(strerror(SyslogErrno), 0);
269 #else
270                         if(SyslogErrno < 0 || SyslogErrno >= sys_nerr)
271                         {
272                             dostr("Error ", 0);
273                             fmtnum(SyslogErrno, 10, 0, 0, 0, 0);
274                         }
275                         else
276                             dostr((char *)sys_errlist[SyslogErrno], 0);
277 #endif
278                         break;
279 
280                     case '%': dopr_outch( ch ); continue;
281                     default:
282                         dostr(  "???????" , 0);
283                 }
284                 break;
285             default:
286                 dopr_outch( ch );
287                 break;
288         }
289     }
290     *output = 0;
291 }
292 
293 void
fmtstr(value,ljust,len,zpad,maxwidth)294 fmtstr(  value, ljust, len, zpad, maxwidth )
295 char *value;
296 int ljust, len, zpad, maxwidth;
297 {
298     int padlen, strlen;     /* amount to pad */
299 
300     if(value == 0)
301     {
302         value = "<NULL>";
303     }
304     for(strlen = 0; value[strlen]; ++ strlen); /* strlen */
305     if(strlen > maxwidth && maxwidth)
306         strlen = maxwidth;
307     padlen = len - strlen;
308     if(padlen < 0) padlen = 0;
309     if(ljust) padlen = -padlen;
310     while(padlen > 0)
311     {
312         dopr_outch( ' ' );
313         --padlen;
314     }
315     dostr( value, maxwidth );
316     while(padlen < 0)
317     {
318         dopr_outch( ' ' );
319         ++padlen;
320     }
321 }
322 
323 void
fmtnum(value,base,dosign,ljust,len,zpad)324 fmtnum(  value, base, dosign, ljust, len, zpad )
325 long value;
326 int base, dosign, ljust, len, zpad;
327 {
328     int signvalue = 0;
329     unsigned long uvalue;
330     char convert[20];
331     int place = 0;
332     int padlen = 0; /* amount to pad */
333     int caps = 0;
334 
335     /* DEBUGP(("value 0x%x, base %d, dosign %d, ljust %d, len %d, zpad %d\n",
336         value, base, dosign, ljust, len, zpad )); */
337     uvalue = value;
338     if(dosign)
339     {
340         if(value < 0)
341         {
342             signvalue = '-';
343             uvalue = -value;
344         }
345     }
346     if(base < 0)
347     {
348         caps = 1;
349         base = -base;
350     }
351     do
352     {
353         convert[place++] =
354         (caps? "0123456789ABCDEF":"0123456789abcdef")
355         [uvalue % (unsigned)base  ];
356         uvalue = (uvalue / (unsigned)base );
357     }while(uvalue);
358     convert[place] = 0;
359     padlen = len - place;
360     if(padlen < 0) padlen = 0;
361     if(ljust) padlen = -padlen;
362     /* DEBUGP(( "str '%s', place %d, sign %c, padlen %d\n",
363         convert,place,signvalue,padlen)); */
364     if(zpad && padlen > 0)
365     {
366         if(signvalue)
367         {
368             dopr_outch( signvalue );
369             --padlen;
370             signvalue = 0;
371         }
372         while(padlen > 0)
373         {
374             dopr_outch( zpad );
375             --padlen;
376         }
377     }
378     while(padlen > 0)
379     {
380         dopr_outch( ' ' );
381         --padlen;
382     }
383     if(signvalue) dopr_outch( signvalue );
384     while(place > 0) dopr_outch( convert[--place] );
385     while(padlen < 0)
386     {
387         dopr_outch( ' ' );
388         ++padlen;
389     }
390 }
391 
392 void
dostr(str,cut)393 dostr( str , cut)
394 char *str;
395 int cut;
396 {
397     if(cut)
398     {
399         while(*str && cut-- > 0) dopr_outch(*str++);
400     }
401     else
402     {
403         while(*str) dopr_outch(*str++);
404     }
405 }
406 
407 void
dopr_outch(c)408 dopr_outch( c )
409 int c;
410 {
411 #if 0
412     if(iscntrl(c) && c != '\n' && c != '\t')
413     {
414         c = '@' + (c & 0x1F);
415         if(DoprEnd == 0 || output < DoprEnd)
416             *output++ = '^';
417     }
418 #endif
419     if(DoprEnd == 0 || output < DoprEnd)
420         *output++ = c;
421     else
422         SnprfOverflow++;
423 }
424 
425 /*
426 **  QUAD_TO_STRING -- Convert a quad type to a string.
427 **
428 **	Convert a quad type to a string.  This must be done
429 **	separately as %lld/%qd are not supported by snprint()
430 **	and adding support would slow down systems which only
431 **	emulate the data type.
432 **
433 **	Parameters:
434 **		value -- number to convert to a string.
435 **
436 **	Returns:
437 **		pointer to a string.
438 */
439 
440 char *
quad_to_string(value)441 quad_to_string(value)
442 QUAD_T value;
443 {
444     char *fmtstr;
445     static char buf[64];
446 
447     /*
448     **  Use sprintf() instead of snprintf() since snprintf()
449     **  does not support %qu or %llu.  The buffer is large enough
450     **  to hold the string so there is no danger of buffer
451     **  overflow.
452     */
453 
454 #if NEED_PERCENTQ
455     fmtstr = "%qu";
456 #elif SIZEOF_UNSIGNED_LONG_INT == 8
457     fmtstr = "%lu";
458 #else
459     fmtstr = "%llu";
460 #endif
461     sprintf(buf, fmtstr, value);
462     return buf;
463 }
464 /*
465 **  SHORTENSTRING -- return short version of a string
466 **
467 **	If the string is already short, just return it.  If it is too
468 **	long, return the head and tail of the string.
469 **
470 **	Parameters:
471 **		s -- the string to shorten.
472 **		m -- the max length of the string.
473 **
474 **	Returns:
475 **		Either s or a short version of s.
476 */
477 
478 char *
shortenstring(s,m)479 shortenstring(s, m)
480 register const char *s;
481 int m;
482 {
483     int l;
484     static char buf[MAXSHORTSTR + 1];
485 
486     l = strlen(s);
487     if(l < m)
488         return(char *) s;
489     if(m > MAXSHORTSTR)
490         m = MAXSHORTSTR;
491     else if(m < 10)
492     {
493         if(m < 5)
494         {
495             strncpy(buf, s, m);
496             buf[m] = '\0';
497             return buf;
498         }
499         strncpy(buf, s, m - 3);
500         strcpy(buf + m - 3, "...");
501         return buf;
502     }
503     m = (m - 3) / 2;
504     strncpy(buf, s, m);
505     strcpy(buf + m, "...");
506     strcpy(buf + m + 3, s + l - m);
507     return buf;
508 }
509 
510 #endif
511