and added files
[bcm963xx.git] / userapps / opensource / net-snmp / apps / snmptrapd_log.c
1 /*
2  * snmptrapd_log.c - format SNMP trap information for logging
3  *
4  */
5 /*****************************************************************
6         Copyright 1989, 1991, 1992 by Carnegie Mellon University
7
8                       All Rights Reserved
9
10 Permission to use, copy, modify, and distribute this software and its
11 documentation for any purpose and without fee is hereby granted,
12 provided that the above copyright notice appear in all copies and that
13 both that copyright notice and this permission notice appear in
14 supporting documentation, and that the name of CMU not be
15 used in advertising or publicity pertaining to distribution of the
16 software without specific, written prior permission.
17
18 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
19 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
20 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
21 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
22 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
23 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
24 SOFTWARE.
25 ******************************************************************/
26 #include <net-snmp/net-snmp-config.h>
27
28 #if HAVE_STDLIB_H
29 #include <stdlib.h>
30 #endif
31 #if HAVE_UNISTD_H
32 #include <unistd.h>
33 #endif
34 #if HAVE_STRING_H
35 #include <string.h>
36 #else
37 #include <strings.h>
38 #endif
39 #include <sys/types.h>
40 #if HAVE_SYS_WAIT_H
41 #include <sys/wait.h>
42 #endif
43 #if HAVE_WINSOCK_H
44 #include <winsock.h>
45 #else
46 #include <sys/socket.h>
47 #endif
48 #if HAVE_SYS_SOCKIO_H
49 #include <sys/sockio.h>
50 #endif
51 #if HAVE_NETINET_IN_H
52 #include <netinet/in.h>
53 #endif
54 #include <stdio.h>
55 #include <ctype.h>
56 #if HAVE_SYS_TIME_H
57 # include <sys/time.h>
58 # if TIME_WITH_SYS_TIME
59 #  include <time.h>
60 # endif
61 #else
62 # include <time.h>
63 #endif
64 #if HAVE_SYS_SELECT_H
65 #include <sys/select.h>
66 #endif
67 #if HAVE_SYS_PARAM_H
68 #include <sys/param.h>
69 #endif
70 #if HAVE_SYSLOG_H
71 #include <syslog.h>
72 #endif
73 #if HAVE_SYS_IOCTL_H
74 #include <sys/ioctl.h>
75 #endif
76 #if HAVE_NET_IF_H
77 #include <net/if.h>
78 #endif
79 #if HAVE_NETDB_H
80 #include <netdb.h>
81 #endif
82 #if HAVE_ARPA_INET_H
83 #include <arpa/inet.h>
84 #endif
85 #if HAVE_FCNTL_H
86 #include <fcntl.h>
87 #endif
88
89 #include <net-snmp/net-snmp-includes.h>
90 #include "snmptrapd_log.h"
91
92
93 #ifndef BSD4_3
94 #define BSD4_2
95 #endif
96
97 /*
98  * These flags mark undefined values in the options structure 
99  */
100 #define UNDEF_CMD '*'
101 #define UNDEF_PRECISION -1
102
103 /*
104  * This structure holds the options for a single format command 
105  */
106 typedef struct {
107     char            cmd;        /* the format command itself */
108     size_t          width;      /* the field's minimum width */
109     size_t          precision;  /* the field's precision */
110     int             left_justify;       /* if true, left justify this field */
111     int             alt_format; /* if true, display in alternate format */
112     int             leading_zeroes;     /* if true, display with leading zeroes */
113 } options_type;
114
115 /*
116  * These symbols define the characters that the parser recognizes.
117  * The rather odd choice of symbols comes from an attempt to avoid
118  * colliding with the ones that printf uses, so that someone could add
119  * printf functionality to this code and turn it into a library
120  * routine in the future.  
121  */
122 typedef enum {
123     CHR_FMT_DELIM = '%',        /* starts a format command */
124     CHR_LEFT_JUST = '-',        /* left justify */
125     CHR_LEAD_ZERO = '0',        /* use leading zeroes */
126     CHR_ALT_FORM = '#',         /* use alternate format */
127     CHR_FIELD_SEP = '.',        /* separates width and precision fields */
128     CHR_CUR_TIME = 't',         /* current time, Unix format */
129     CHR_CUR_YEAR = 'y',         /* current year */
130     CHR_CUR_MONTH = 'm',        /* current month */
131     CHR_CUR_MDAY = 'l',         /* current day of month */
132     CHR_CUR_HOUR = 'h',         /* current hour */
133     CHR_CUR_MIN = 'j',          /* current minute */
134     CHR_CUR_SEC = 'k',          /* current second */
135     CHR_UP_TIME = 'T',          /* uptime, Unix format */
136     CHR_UP_YEAR = 'Y',          /* uptime year */
137     CHR_UP_MONTH = 'M',         /* uptime month */
138     CHR_UP_MDAY = 'L',          /* uptime day of month */
139     CHR_UP_HOUR = 'H',          /* uptime hour */
140     CHR_UP_MIN = 'J',           /* uptime minute */
141     CHR_UP_SEC = 'K',           /* uptime second */
142     CHR_AGENT_IP = 'a',         /* agent's IP address */
143     CHR_AGENT_NAME = 'A',       /* agent's host name if available */
144     CHR_PDU_IP = 'b',           /* PDU's IP address */
145     CHR_PDU_NAME = 'B',         /* PDU's host name if available */
146     CHR_PDU_ENT = 'N',          /* PDU's enterprise string */
147     CHR_PDU_WRAP = 'P',         /* PDU's wrapper info (community, security) */
148     CHR_TRAP_NUM = 'w',         /* trap number */
149     CHR_TRAP_DESC = 'W',        /* trap's description (textual) */
150     CHR_TRAP_STYPE = 'q',       /* trap's subtype */
151     CHR_TRAP_VARS = 'v'         /* tab-separated list of trap's variables */
152 } parse_chr_type;
153
154 /*
155  * These symbols define the states for the parser's state machine 
156  */
157 typedef enum {
158     PARSE_NORMAL,               /* looking for next character */
159     PARSE_BACKSLASH,            /* saw a backslash */
160     PARSE_IN_FORMAT,            /* saw a % sign, in a format command */
161     PARSE_GET_WIDTH,            /* getting field width */
162     PARSE_GET_PRECISION         /* getting field precision */
163 } parse_state_type;
164
165 /*
166  * macros 
167  */
168
169 #define is_cur_time_cmd(chr) ((((chr) == CHR_CUR_TIME)     \
170                                || ((chr) == CHR_CUR_YEAR)  \
171                                || ((chr) == CHR_CUR_MONTH) \
172                                || ((chr) == CHR_CUR_MDAY)  \
173                                || ((chr) == CHR_CUR_HOUR)  \
174                                || ((chr) == CHR_CUR_MIN)   \
175                                || ((chr) == CHR_CUR_SEC)) ? TRUE : FALSE)
176      /*
177       * Function:
178       *    Returns true if the character is a format command that outputs
179       * some field that deals with the current time.
180       *
181       * Input Parameters:
182       *    chr - character to check
183       */
184
185 #define is_up_time_cmd(chr) ((((chr) == CHR_UP_TIME)     \
186                               || ((chr) == CHR_UP_YEAR)  \
187                               || ((chr) == CHR_UP_MONTH) \
188                               || ((chr) == CHR_UP_MDAY)  \
189                               || ((chr) == CHR_UP_HOUR)  \
190                               || ((chr) == CHR_UP_MIN)   \
191                               || ((chr) == CHR_UP_SEC)) ? TRUE : FALSE)
192      /*
193       * Function:
194       *    Returns true if the character is a format command that outputs
195       * some field that deals with up-time.
196       *
197       * Input Parameters:
198       *    chr - character to check
199       */
200
201 #define is_agent_cmd(chr) ((((chr) == CHR_AGENT_IP) \
202                             || ((chr) == CHR_AGENT_NAME)) ? TRUE : FALSE)
203      /*
204       * Function:
205       *    Returns true if the character outputs information about the
206       * agent.
207       *
208       * Input Parameters:
209       *    chr - the character to check
210       */
211
212 #define is_pdu_ip_cmd(chr) ((((chr) == CHR_PDU_IP)   \
213                           || ((chr) == CHR_PDU_NAME)) ? TRUE : FALSE)
214      /*
215       * Function:
216       *    Returns true if the character outputs information about the PDU's
217       * host name or IP address.
218       *
219       * Input Parameters:
220       *    chr - the character to check
221       */
222
223 #define is_trap_cmd(chr) ((((chr) == CHR_TRAP_NUM)      \
224                            || ((chr) == CHR_TRAP_DESC)  \
225                            || ((chr) == CHR_TRAP_STYPE) \
226                            || ((chr) == CHR_TRAP_VARS)) ? TRUE : FALSE)
227
228      /*
229       * Function:
230       *    Returns true if the character outputs information about the trap.
231       *
232       * Input Parameters:
233       *    chr - the character to check
234       */
235
236 #define is_fmt_cmd(chr) ((is_cur_time_cmd (chr)     \
237                           || is_up_time_cmd (chr)   \
238                           || is_agent_cmd (chr)     \
239                           || is_pdu_ip_cmd (chr)    \
240                           || ((chr) == CHR_PDU_ENT) \
241                           || ((chr) == CHR_PDU_WRAP) \
242                           || is_trap_cmd (chr)) ? TRUE : FALSE)
243      /*
244       * Function:
245       *    Returns true if the character is a format command.
246       * 
247       * Input Parameters:
248       *    chr - character to check
249       */
250
251 #define is_numeric_cmd(chr) ((is_cur_time_cmd(chr)   \
252                               || is_up_time_cmd(chr) \
253                               || (chr) == CHR_TRAP_NUM) ? TRUE : FALSE)
254      /*
255       * Function:
256       *    Returns true if this is a numeric format command.
257       *
258       * Input Parameters:
259       *    chr - character to check
260       */
261
262 #define reference(var) ((var) == (var))
263
264      /*
265       * Function:
266       *    Some compiler options will tell the compiler to be picky and
267       * warn you if you pass a parameter to a function but don't use it.
268       * This macro lets you reference a parameter so that the compiler won't
269       * generate the warning. It has no other effect.
270       *
271       * Input Parameters:
272       *    var - the parameter to reference
273       */
274
275 /*
276  * prototypes 
277  */
278 extern const char *trap_description(int trap);
279
280 static void
281 init_options(options_type * options)
282
283      /*
284       * Function:
285       *    Initialize a structure that contains the option settings for
286       * a format command.
287       *
288       * Input Parameters:
289       *    options - points to the structure to initialize
290       */
291 {
292     /*
293      * initialize the structure's fields 
294      */
295     options->cmd = '*';
296     options->width = 0;
297     options->precision = UNDEF_PRECISION;
298     options->left_justify = FALSE;
299     options->alt_format = FALSE;
300     options->leading_zeroes = FALSE;
301     return;
302 }
303
304
305 static int
306 realloc_output_temp_bfr(u_char ** buf, size_t * buf_len, size_t * out_len,
307                         int allow_realloc,
308                         u_char ** temp_buf, options_type * options)
309
310      /*
311       * Function:
312       *    Append the contents of the temporary buffer to the specified
313       * buffer using the correct justification, leading zeroes, width,
314       * precision, and other characteristics specified in the options
315       * structure.
316       *
317       *    buf, buf_len, out_len, allow_realloc - standard relocatable
318       *                                           buffer parameters
319       *    temp_buf - pointer to string to append onto output buffer.  THIS
320       *               STRING IS free()d BY THIS FUNCTION.
321       *    options  - what options to use when appending string
322       */
323 {
324     size_t          temp_len;   /* length of temporary buffer */
325     size_t          temp_to_write;      /* # of chars to write from temp bfr */
326     size_t          char_to_write;      /* # of other chars to write */
327     size_t          zeroes_to_write;    /* fill to precision with zeroes for numbers */
328
329     if (temp_buf == NULL || *temp_buf == NULL) {
330         return 1;
331     }
332
333     /*
334      * Figure out how many characters are in the temporary buffer now,
335      * and how many of them we'll write.
336      */
337     temp_len = strlen((char *) *temp_buf);
338     temp_to_write = temp_len;
339
340     if (options->precision != UNDEF_PRECISION &&
341         temp_to_write > options->precision) {
342         temp_to_write = options->precision;
343     }
344
345     /*
346      * Handle leading characters.  
347      */
348     if ((!options->left_justify) && (temp_to_write < options->width)) {
349         zeroes_to_write = options->precision - temp_to_write;
350         if (!is_numeric_cmd(options->cmd)) {
351             zeroes_to_write = 0;
352         }
353
354         for (char_to_write = options->width - temp_to_write;
355              char_to_write > 0; char_to_write--) {
356             if ((*out_len + 1) >= *buf_len) {
357                 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
358                     *(*buf + *out_len) = '\0';
359                     free(*temp_buf);
360                     return 0;
361                 }
362             }
363             if (options->leading_zeroes || zeroes_to_write-- > 0) {
364                 *(*buf + *out_len) = '0';
365             } else {
366                 *(*buf + *out_len) = ' ';
367             }
368             (*out_len)++;
369         }
370     }
371
372     /*
373      * Truncate the temporary buffer and append its contents.  
374      */
375     *(*temp_buf + temp_to_write) = '\0';
376     if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, *temp_buf)) {
377         free(*temp_buf);
378         return 0;
379     }
380
381     /*
382      * Handle trailing characters.  
383      */
384     if ((options->left_justify) && (temp_to_write < options->width)) {
385         for (char_to_write = options->width - temp_to_write;
386              char_to_write > 0; char_to_write--) {
387             if ((*out_len + 1) >= *buf_len) {
388                 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
389                     *(*buf + *out_len) = '\0';
390                     free(*temp_buf);
391                     return 0;
392                 }
393             }
394             *(*buf + *out_len) = '0';
395             (*out_len)++;
396         }
397     }
398
399     /*
400      * Slap on a trailing \0 for good measure.  
401      */
402
403     *(*buf + *out_len) = '\0';
404     free(*temp_buf);
405     *temp_buf = NULL;
406     return 1;
407 }
408
409
410 static int
411 realloc_handle_time_fmt(u_char ** buf, size_t * buf_len, size_t * out_len,
412                         int allow_realloc,
413                         options_type * options, netsnmp_pdu *pdu)
414
415      /*
416       * Function:
417       *    Handle a format command that deals with the current or up-time.
418       * Append the correct time information to the buffer subject to the
419       * buffer's length limit.
420       *
421       * Input Parameters:
422       *    buf, buf_len, out_len, allow_realloc - standard relocatable
423       *                                           buffer parameters
424       *    options - options governing how to write the field
425       *    pdu     - information about this trap
426       */
427 {
428     time_t          time_val;   /* the time value to output */
429     unsigned long   time_ul;    /* u_long time/timeticks */
430     struct tm      *parsed_time;        /* parsed version of current time */
431     char           *safe_bfr = NULL;
432     char            fmt_cmd = options->cmd;     /* the format command to use */
433     int             offset = 0; /* offset into string to display */
434     size_t          year_len;   /* length of year string */
435
436     if ((safe_bfr = (char *) calloc(30, 1)) == NULL) {
437         return 0;
438     }
439
440     /*
441      * Get the time field to output.  
442      */
443     if (is_up_time_cmd(fmt_cmd)) {
444         time_ul = pdu->time;
445     } else {
446         /*
447          * Note: a time_t is a signed long.  
448          */
449         time(&time_val);
450         time_ul = (unsigned long) time_val;
451     }
452
453     /*
454      * Handle output in Unix time format.  
455      */
456     if (fmt_cmd == CHR_CUR_TIME) {
457         sprintf(safe_bfr, "%lu", time_ul);
458     } else if (fmt_cmd == CHR_UP_TIME && !options->alt_format) {
459         sprintf(safe_bfr, "%lu", time_ul);
460     } else if (fmt_cmd == CHR_UP_TIME) {
461         unsigned int    centisecs, seconds, minutes, hours, days;
462
463         centisecs = time_ul % 100;
464         time_ul /= 100;
465         days = time_ul / (60 * 60 * 24);
466         time_ul %= (60 * 60 * 24);
467
468         hours = time_ul / (60 * 60);
469         time_ul %= (60 * 60);
470
471         minutes = time_ul / 60;
472         seconds = time_ul % 60;
473
474         switch (days) {
475         case 0:
476             sprintf(safe_bfr, "%u:%02u:%02u.%02u",
477                     hours, minutes, seconds, centisecs);
478             break;
479         case 1:
480             sprintf(safe_bfr, "1 day, %u:%02u:%02u.%02u",
481                     hours, minutes, seconds, centisecs);
482             break;
483         default:
484             sprintf(safe_bfr, "%u days, %u:%02u:%02u.%02u",
485                     days, hours, minutes, seconds, centisecs);
486         }
487     } else {
488         /*
489          * Handle other time fields.  
490          */
491
492         if (options->alt_format) {
493             parsed_time = gmtime(&time_val);
494         } else {
495             parsed_time = localtime(&time_val);
496         }
497
498         switch (fmt_cmd) {
499
500             /*
501              * Output year. The year field is unusual: if there's a restriction 
502              * on precision, we want to truncate from the left of the number,
503              * not the right, so someone printing the year 1972 with 2 digit 
504              * precision gets "72" not "19".
505              */
506         case CHR_CUR_YEAR:
507         case CHR_UP_YEAR:
508             sprintf(safe_bfr, "%d", parsed_time->tm_year + 1900);
509             if (options->precision != UNDEF_PRECISION) {
510                 year_len = (size_t) strlen(safe_bfr);
511                 if (year_len > options->precision)
512                     offset = year_len - options->precision;
513             }
514             break;
515
516             /*
517              * output month 
518              */
519         case CHR_CUR_MONTH:
520         case CHR_UP_MONTH:
521             sprintf(safe_bfr, "%d", parsed_time->tm_mon + 1);
522             break;
523
524             /*
525              * output day of month 
526              */
527         case CHR_CUR_MDAY:
528         case CHR_UP_MDAY:
529             sprintf(safe_bfr, "%d", parsed_time->tm_mday);
530             break;
531
532             /*
533              * output hour 
534              */
535         case CHR_CUR_HOUR:
536         case CHR_UP_HOUR:
537             sprintf(safe_bfr, "%d", parsed_time->tm_hour);
538             break;
539
540             /*
541              * output minute 
542              */
543         case CHR_CUR_MIN:
544         case CHR_UP_MIN:
545             sprintf(safe_bfr, "%d", parsed_time->tm_min);
546             break;
547
548             /*
549              * output second 
550              */
551         case CHR_CUR_SEC:
552         case CHR_UP_SEC:
553             sprintf(safe_bfr, "%d", parsed_time->tm_sec);
554             break;
555
556             /*
557              * unknown format command - just output the character 
558              */
559         default:
560             sprintf(safe_bfr, "%c", fmt_cmd);
561         }
562     }
563
564     /*
565      * Output with correct justification, leading zeroes, etc.  
566      */
567     return realloc_output_temp_bfr(buf, buf_len, out_len, allow_realloc,
568                                    (u_char **) & safe_bfr, options);
569 }
570
571
572 static int
573 realloc_handle_ip_fmt(u_char ** buf, size_t * buf_len, size_t * out_len,
574                       int allow_realloc,
575                       options_type * options, netsnmp_pdu *pdu,
576                       netsnmp_transport *transport)
577
578      /*
579       * Function:
580       *     Handle a format command that deals with an IP address 
581       * or host name.  Append the information to the buffer subject to
582       * the buffer's length limit.
583       *
584       * Input Parameters:
585       *    buf, buf_len, out_len, allow_realloc - standard relocatable
586       *                                           buffer parameters
587       *    options   - options governing how to write the field
588       *    pdu       - information about this trap 
589       *    transport - the transport descriptor
590       */
591 {
592     struct in_addr *agent_inaddr = (struct in_addr *) pdu->agent_addr;
593     struct hostent *host = NULL;       /* corresponding host name */
594     char            fmt_cmd = options->cmd;     /* what we're formatting */
595     u_char         *temp_buf = NULL;
596     size_t          temp_buf_len = 64, temp_out_len = 0;
597
598     if ((temp_buf = calloc(temp_buf_len, 1)) == NULL) {
599         return 0;
600     }
601
602     /*
603      * Decide exactly what to output.  
604      */
605     switch (fmt_cmd) {
606     case CHR_AGENT_IP:
607         /*
608          * Write a numerical address.  
609          */
610         if (!snmp_strcat(&temp_buf, &temp_buf_len, &temp_out_len, 1,
611                          inet_ntoa(*agent_inaddr))) {
612             if (temp_buf != NULL) {
613                 free(temp_buf);
614             }
615             return 0;
616         }
617         break;
618
619     case CHR_AGENT_NAME:
620         /*
621          * Try to resolve the agent_addr field as a hostname; fall back
622          * to numerical address.  
623          */
624         if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
625                                     NETSNMP_DS_APP_NUMERIC_IP)) {
626             host = gethostbyaddr((char *) pdu->agent_addr, 4, AF_INET);
627         }
628         if (host != NULL) {
629             if (!snmp_strcat(&temp_buf, &temp_buf_len, &temp_out_len, 1,
630                              host->h_name)) {
631                 if (temp_buf != NULL) {
632                     free(temp_buf);
633                 }
634                 return 0;
635             }
636         } else {
637             if (!snmp_strcat(&temp_buf, &temp_buf_len, &temp_out_len, 1,
638                              inet_ntoa(*agent_inaddr))) {
639                 if (temp_buf != NULL) {
640                     free(temp_buf);
641                 }
642                 return 0;
643             }
644         }
645         break;
646
647     case CHR_PDU_IP:
648         /*
649          * Write the numerical transport information.  
650          */
651         if (transport != NULL && transport->f_fmtaddr != NULL) {
652             char           *tstr =
653                 transport->f_fmtaddr(transport, pdu->transport_data,
654                                      pdu->transport_data_length);
655             if (!snmp_strcat
656                 (&temp_buf, &temp_buf_len, &temp_out_len, 1, tstr)) {
657                 if (tstr != NULL) {
658                     free(tstr);
659                 }
660                 if (temp_buf != NULL) {
661                     free(temp_buf);
662                 }
663                 return 0;
664             }
665             if (tstr != NULL) {
666                 free(tstr);
667             }
668         } else {
669             if (!snmp_strcat
670                 (&temp_buf, &temp_buf_len, &temp_out_len, 1,
671                  "<UNKNOWN>")) {
672                 if (temp_buf != NULL) {
673                     free(temp_buf);
674                 }
675                 return 0;
676             }
677         }
678         break;
679
680         /*
681          * Write a host name.  
682          */
683     case CHR_PDU_NAME:
684         /*
685          * Right, apparently a name lookup is wanted.  This is only reasonable
686          * for the UDP and TCP transport domains (we don't want to try to be
687          * too clever here).  
688          */
689 #ifdef SNMP_TRANSPORT_TCP_DOMAIN
690         if (transport != NULL && (transport->domain == netsnmpUDPDomain ||
691                                   transport->domain ==
692                                   netsnmp_snmpTCPDomain)) {
693 #else
694         if (transport != NULL && transport->domain == netsnmpUDPDomain) {
695 #endif
696             /*
697              * This is kind of bletcherous -- it breaks the opacity of
698              * transport_data but never mind -- the alternative is a lot of
699              * munging strings from f_fmtaddr.  
700              */
701             struct sockaddr_in *addr =
702                 (struct sockaddr_in *) pdu->transport_data;
703             if (addr != NULL
704                 && pdu->transport_data_length ==
705                 sizeof(struct sockaddr_in)) {
706                 if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
707                                             NETSNMP_DS_APP_NUMERIC_IP)) {
708                     host =
709                         gethostbyaddr((char *) &(addr->sin_addr),
710                                       sizeof(struct in_addr), AF_INET);
711                 }
712                 if (host != NULL) {
713                     if (!snmp_strcat
714                         (&temp_buf, &temp_buf_len, &temp_out_len, 1,
715                          host->h_name)) {
716                         if (temp_buf != NULL) {
717                             free(temp_buf);
718                         }
719                         return 0;
720                     }
721                 } else {
722                     if (!snmp_strcat
723                         (&temp_buf, &temp_buf_len, &temp_out_len, 1,
724                          inet_ntoa(addr->sin_addr))) {
725                         if (temp_buf != NULL) {
726                             free(temp_buf);
727                         }
728                         return 0;
729                     }
730                 }
731             } else {
732                 if (!snmp_strcat
733                     (&temp_buf, &temp_buf_len, &temp_out_len, 1,
734                      "<UNKNOWN>")) {
735                     if (temp_buf != NULL) {
736                         free(temp_buf);
737                     }
738                     return 0;
739                 }
740             }
741         } else if (transport != NULL && transport->f_fmtaddr != NULL) {
742             /*
743              * Some other domain for which we do not know how to do a name
744              * lookup.  Fall back to the formatted transport address.  
745              */
746             char           *tstr =
747                 transport->f_fmtaddr(transport, pdu->transport_data,
748                                      pdu->transport_data_length);
749             if (!snmp_strcat
750                 (&temp_buf, &temp_buf_len, &temp_out_len, 1, tstr)) {
751                 if (tstr != NULL) {
752                     free(tstr);
753                 }
754                 if (temp_buf != NULL) {
755                     free(temp_buf);
756                 }
757                 return 0;
758             }
759             if (tstr != NULL) {
760                 free(tstr);
761             }
762         } else {
763             /*
764              * We are kind of stuck!  
765              */
766             if (!snmp_strcat(&temp_buf, &temp_buf_len, &temp_out_len, 1,
767                              "<UNKNOWN>")) {
768                 if (temp_buf != NULL) {
769                     free(temp_buf);
770                 }
771                 return 0;
772             }
773         }
774         break;
775
776         /*
777          * Don't know how to handle this command - write the character itself.  
778          */
779     default:
780         temp_buf[0] = fmt_cmd;
781     }
782
783     /*
784      * Output with correct justification, leading zeroes, etc.  
785      */
786     return realloc_output_temp_bfr(buf, buf_len, out_len, allow_realloc,
787                                    &temp_buf, options);
788 }
789
790
791 static int
792 realloc_handle_ent_fmt(u_char ** buf, size_t * buf_len, size_t * out_len,
793                        int allow_realloc,
794                        options_type * options, netsnmp_pdu *pdu)
795
796      /*
797       * Function:
798       *     Handle a format command that deals with the enterprise 
799       * string.  Append the information to the buffer subject to the
800       * buffer's length limit.
801       *
802       * Input Parameters:
803       *    buf, buf_len, out_len, allow_realloc - standard relocatable
804       *                                           buffer parameters
805       *    options - options governing how to write the field
806       *    pdu     - information about this trap 
807       */
808 {
809     char            fmt_cmd = options->cmd;     /* what we're formatting */
810     u_char         *temp_buf = NULL;
811     size_t          temp_buf_len = 64, temp_out_len = 0;
812
813     if ((temp_buf = (u_char *) calloc(temp_buf_len, 1)) == NULL) {
814         return 0;
815     }
816
817     /*
818      * Decide exactly what to output.  
819      */
820     switch (fmt_cmd) {
821     case CHR_PDU_ENT:
822         /*
823          * Write the enterprise oid.  
824          */
825         if (!sprint_realloc_objid
826             (&temp_buf, &temp_buf_len, &temp_out_len, 1, pdu->enterprise,
827              pdu->enterprise_length)) {
828             free(temp_buf);
829             return 0;
830         }
831         break;
832
833         /*
834          * Don't know how to handle this command - write the character itself.  
835          */
836     default:
837         temp_buf[0] = fmt_cmd;
838     }
839
840     /*
841      * Output with correct justification, leading zeroes, etc.  
842      */
843     return realloc_output_temp_bfr(buf, buf_len, out_len, allow_realloc,
844                                    &temp_buf, options);
845 }
846
847
848 static int
849 realloc_handle_trap_fmt(u_char ** buf, size_t * buf_len, size_t * out_len,
850                         int allow_realloc,
851                         options_type * options, netsnmp_pdu *pdu)
852
853      /*
854       * Function:
855       *     Handle a format command that deals with the trap itself. 
856       * Append the information to the buffer subject to the buffer's 
857       * length limit.
858       *
859       * Input Parameters:
860       *    buf, buf_len, out_len, allow_realloc - standard relocatable
861       *                                           buffer parameters
862       *    options - options governing how to write the field
863       *    pdu     - information about this trap 
864       */
865 {
866     netsnmp_variable_list *vars;        /* variables assoc with trap */
867     char            fmt_cmd = options->cmd;     /* what we're outputting */
868     u_char         *temp_buf = NULL;
869     size_t          tbuf_len = 64, tout_len = 0;
870
871     if ((temp_buf = (u_char *) calloc(tbuf_len, 1)) == NULL) {
872         return 0;
873     }
874
875     /*
876      * Decide exactly what to output.  
877      */
878     switch (fmt_cmd) {
879     case CHR_TRAP_NUM:
880         /*
881          * Write the trap's number.  
882          */
883         tout_len = sprintf(temp_buf, "%ld", pdu->trap_type);
884         break;
885
886     case CHR_TRAP_DESC:
887         /*
888          * Write the trap's description.  
889          */
890         tout_len =
891             sprintf(temp_buf, "%s", trap_description(pdu->trap_type));
892         break;
893
894     case CHR_TRAP_STYPE:
895         /*
896          * Write the trap's subtype.  
897          */
898         if (pdu->trap_type != SNMP_TRAP_ENTERPRISESPECIFIC) {
899             tout_len = sprintf(temp_buf, "%ld", pdu->specific_type);
900         } else {
901             /*
902              * Get object ID for the trap.  
903              */
904             size_t          obuf_len = 64, oout_len = 0, trap_oid_len = 0;
905             oid             trap_oid[MAX_OID_LEN + 2] = { 0 };
906             u_char         *obuf = NULL;
907             char           *ptr = NULL;
908
909             if ((obuf = (u_char *) calloc(obuf_len, 1)) == NULL) {
910                 free(temp_buf);
911                 return 0;
912             }
913
914             trap_oid_len = pdu->enterprise_length;
915             memcpy(trap_oid, pdu->enterprise, trap_oid_len * sizeof(oid));
916             if (trap_oid[trap_oid_len - 1] != 0) {
917                 trap_oid[trap_oid_len] = 0;
918                 trap_oid_len++;
919             }
920             trap_oid[trap_oid_len] = pdu->specific_type;
921             trap_oid_len++;
922
923             /*
924              * Find the element after the last dot.  
925              */
926             if (!sprint_realloc_objid(&obuf, &obuf_len, &oout_len, 1,
927                                       trap_oid, trap_oid_len)) {
928                 if (obuf != NULL) {
929                     free(obuf);
930                 }
931                 free(temp_buf);
932                 return 0;
933             }
934
935             ptr = strrchr((char *) obuf, '.');
936             if (ptr != NULL) {
937                 if (!snmp_strcat
938                     (&temp_buf, &tbuf_len, &tout_len, 1, (u_char *) ptr)) {
939                     free(obuf);
940                     if (temp_buf != NULL) {
941                         free(temp_buf);
942                     }
943                     return 0;
944                 }
945                 free(obuf);
946             } else {
947                 free(temp_buf);
948                 temp_buf = obuf;
949                 tbuf_len = obuf_len;
950                 tout_len = oout_len;
951             }
952         }
953         break;
954
955     case CHR_TRAP_VARS:
956         /*
957          * Write the trap's variables.  
958          */
959         for (vars = pdu->variables; vars != NULL;
960              vars = vars->next_variable) {
961             if (options->alt_format) {
962                 if (!snmp_strcat(&temp_buf, &tbuf_len, &tout_len, 1, ", ")) {
963                     if (temp_buf != NULL) {
964                         free(temp_buf);
965                     }
966                     return 0;
967                 }
968             } else {
969                 if (!snmp_strcat(&temp_buf, &tbuf_len, &tout_len, 1, "\t")) {
970                     if (temp_buf != NULL) {
971                         free(temp_buf);
972                     }
973                     return 0;
974                 }
975             }
976             if (!sprint_realloc_variable
977                 (&temp_buf, &tbuf_len, &tout_len, 1, vars->name,
978                  vars->name_length, vars)) {
979                 if (temp_buf != NULL) {
980                     free(temp_buf);
981                 }
982                 return 0;
983             }
984         }
985         break;
986
987     default:
988         /*
989          * Don't know how to handle this command - write the character itself.  
990          */
991         temp_buf[0] = fmt_cmd;
992     }
993
994     /*
995      * Output with correct justification, leading zeroes, etc.  
996      */
997     return realloc_output_temp_bfr(buf, buf_len, out_len, allow_realloc,
998                                    &temp_buf, options);
999 }
1000
1001
1002 static int
1003 realloc_handle_wrap_fmt(u_char ** buf, size_t * buf_len, size_t * out_len,
1004                         int allow_realloc, netsnmp_pdu *pdu)
1005 {
1006     size_t          i = 0;
1007
1008     switch (pdu->command) {
1009     case SNMP_MSG_TRAP:
1010         if (!snmp_strcat
1011             (buf, buf_len, out_len, allow_realloc,
1012              (const u_char *) "TRAP")) {
1013             return 0;
1014         }
1015         break;
1016     case SNMP_MSG_TRAP2:
1017         if (!snmp_strcat
1018             (buf, buf_len, out_len, allow_realloc,
1019              (const u_char *) "TRAP2")) {
1020             return 0;
1021         }
1022         break;
1023     case SNMP_MSG_INFORM:
1024         if (!snmp_strcat
1025             (buf, buf_len, out_len, allow_realloc,
1026              (const u_char *) "INFORM")) {
1027             return 0;
1028         }
1029         break;
1030     }
1031
1032     switch (pdu->version) {
1033     case SNMP_VERSION_1:
1034         if (!snmp_strcat
1035             (buf, buf_len, out_len, allow_realloc,
1036              (const u_char *) ", SNMP v1")) {
1037             return 0;
1038         }
1039         break;
1040     case SNMP_VERSION_2c:
1041         if (!snmp_strcat
1042             (buf, buf_len, out_len, allow_realloc,
1043              (const u_char *) ", SNMP v2c")) {
1044             return 0;
1045         }
1046         break;
1047     case SNMP_VERSION_3:
1048         if (!snmp_strcat
1049             (buf, buf_len, out_len, allow_realloc,
1050              (const u_char *) ", SNMP v3")) {
1051             return 0;
1052         }
1053         break;
1054     }
1055
1056     switch (pdu->version) {
1057     case SNMP_VERSION_1:
1058     case SNMP_VERSION_2c:
1059         if (!snmp_strcat
1060             (buf, buf_len, out_len, allow_realloc,
1061              (const u_char *) ", community ")) {
1062             return 0;
1063         }
1064
1065         while ((*out_len + pdu->community_len + 1) >= *buf_len) {
1066             if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
1067                 return 0;
1068             }
1069         }
1070
1071         for (i = 0; i < pdu->community_len; i++) {
1072             if (isprint(pdu->community[i])) {
1073                 *(*buf + *out_len) = pdu->community[i];
1074             } else {
1075                 *(*buf + *out_len) = '.';
1076             }
1077             (*out_len)++;
1078         }
1079         *(*buf + *out_len) = '\0';
1080         break;
1081     case SNMP_VERSION_3:
1082         if (!snmp_strcat
1083             (buf, buf_len, out_len, allow_realloc,
1084              (const u_char *) ", user ")) {
1085             return 0;
1086         }
1087
1088         while ((*out_len + pdu->securityNameLen + 1) >= *buf_len) {
1089             if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
1090                 return 0;
1091             }
1092         }
1093
1094         for (i = 0; i < pdu->securityNameLen; i++) {
1095             if (isprint(pdu->securityName[i])) {
1096                 *(*buf + *out_len) = pdu->securityName[i];
1097             } else {
1098                 *(*buf + *out_len) = '.';
1099             }
1100             (*out_len)++;
1101         }
1102         *(*buf + *out_len) = '\0';
1103
1104         if (!snmp_strcat
1105             (buf, buf_len, out_len, allow_realloc,
1106              (const u_char *) ", context ")) {
1107             return 0;
1108         }
1109
1110         while ((*out_len + pdu->contextNameLen + 1) >= *buf_len) {
1111             if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
1112                 return 0;
1113             }
1114         }
1115
1116         for (i = 0; i < pdu->contextNameLen; i++) {
1117             if (isprint(pdu->contextName[i])) {
1118                 *(*buf + *out_len) = pdu->contextName[i];
1119             } else {
1120                 *(*buf + *out_len) = '.';
1121             }
1122             (*out_len)++;
1123         }
1124         *(*buf + *out_len) = '\0';
1125     }
1126     return 1;
1127 }
1128
1129
1130 static int
1131 realloc_dispatch_format_cmd(u_char ** buf, size_t * buf_len,
1132                             size_t * out_len, int allow_realloc,
1133                             options_type * options, netsnmp_pdu *pdu,
1134                             netsnmp_transport *transport)
1135
1136      /*
1137       * Function:
1138       *     Dispatch a format command to the appropriate command handler.
1139       *
1140       * Input Parameters:
1141       *    buf, buf_len, out_len, allow_realloc - standard relocatable
1142       *                                           buffer parameters
1143       *    options   - options governing how to write the field
1144       *    pdu       - information about this trap
1145       *    transport - the transport descriptor
1146       */
1147 {
1148     char            fmt_cmd = options->cmd;     /* for speed */
1149
1150     /*
1151      * choose the appropriate command handler 
1152      */
1153
1154     if (is_cur_time_cmd(fmt_cmd) || is_up_time_cmd(fmt_cmd)) {
1155         return realloc_handle_time_fmt(buf, buf_len, out_len,
1156                                        allow_realloc, options, pdu);
1157     } else if (is_agent_cmd(fmt_cmd) || is_pdu_ip_cmd(fmt_cmd)) {
1158         return realloc_handle_ip_fmt(buf, buf_len, out_len, allow_realloc,
1159                                      options, pdu, transport);
1160     } else if (is_trap_cmd(fmt_cmd)) {
1161         return realloc_handle_trap_fmt(buf, buf_len, out_len,
1162                                        allow_realloc, options, pdu);
1163     } else if (fmt_cmd == CHR_PDU_ENT) {
1164         return realloc_handle_ent_fmt(buf, buf_len, out_len, allow_realloc,
1165                                       options, pdu);
1166     } else if (fmt_cmd == CHR_PDU_WRAP) {
1167         return realloc_handle_wrap_fmt(buf, buf_len, out_len,
1168                                        allow_realloc, pdu);
1169     } else {
1170         /*
1171          * unknown format command - just output the character 
1172          */
1173         char            fmt_cmd_string[2] = { 0, 0 };
1174         fmt_cmd_string[0] = fmt_cmd;
1175
1176         return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1177                            (const u_char *) fmt_cmd_string);
1178     }
1179 }
1180
1181
1182 static int
1183 realloc_handle_backslash(u_char ** buf, size_t * buf_len, size_t * out_len,
1184                          int allow_realloc, char fmt_cmd)
1185
1186      /*
1187       * Function:
1188       *     Handle a character following a backslash. Append the resulting 
1189       * character to the buffer subject to the buffer's length limit.
1190       *     This routine currently isn't sophisticated enough to handle
1191       * \nnn or \xhh formats.
1192       *
1193       * Input Parameters:
1194       *    buf, buf_len, out_len, allow_realloc - standard relocatable
1195       *                                           buffer parameters
1196       *    fmt_cmd - the character after the backslash
1197       */
1198 {
1199     char            temp_bfr[3];        /* for bulding temporary strings */
1200
1201     /*
1202      * select the proper output character(s) 
1203      */
1204     switch (fmt_cmd) {
1205     case 'a':
1206         return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1207                            (const u_char *) "\a");
1208     case 'b':
1209         return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1210                            (const u_char *) "\b");
1211     case 'f':
1212         return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1213                            (const u_char *) "\f");
1214     case 'n':
1215         return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1216                            (const u_char *) "\n");
1217     case 'r':
1218         return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1219                            (const u_char *) "\r");
1220     case 't':
1221         return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1222                            (const u_char *) "\t");
1223     case 'v':
1224         return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1225                            (const u_char *) "\v");
1226     case '\\':
1227         return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1228                            (const u_char *) "\\");
1229     case '?':
1230         return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1231                            (const u_char *) "\?");
1232     case '\'':
1233         return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1234                            (const u_char *) "\'");
1235     case '"':
1236         return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1237                            (const u_char *) "\"");
1238     default:
1239         sprintf(temp_bfr, "\\%c", fmt_cmd);
1240         return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1241                            (const u_char *) temp_bfr);
1242     }
1243 }
1244
1245
1246 int
1247 realloc_format_plain_trap(u_char ** buf, size_t * buf_len,
1248                           size_t * out_len, int allow_realloc,
1249                           netsnmp_pdu *pdu, netsnmp_transport *transport)
1250
1251      /*
1252       * Function:
1253       *    Format the trap information in the default way and put the results
1254       * into the buffer, truncating at the buffer's length limit. This
1255       * routine returns 1 if the output was completed successfully or
1256       * 0 if it is truncated due to a memory allocation failure.
1257       *
1258       * Input Parameters:
1259       *    buf, buf_len, out_len, allow_realloc - standard relocatable
1260       *                                           buffer parameters
1261       *    pdu       - the pdu information
1262       *    transport - the transport descriptor
1263       */
1264 {
1265     time_t          now;        /* the current time */
1266     struct tm      *now_parsed; /* time in struct format */
1267     char            safe_bfr[200];      /* holds other strings */
1268     struct in_addr *agent_inaddr = (struct in_addr *) pdu->agent_addr;
1269     struct hostent *host = NULL;       /* host name */
1270     netsnmp_variable_list *vars;        /* variables assoc with trap */
1271
1272     if (buf == NULL) {
1273         return 0;
1274     }
1275
1276     /*
1277      * Print the current time. Since we don't know how long the buffer is,
1278      * and snprintf isn't yet standard, build the timestamp in a separate
1279      * buffer of guaranteed length and then copy it to the output buffer.
1280      */
1281     time(&now);
1282     now_parsed = localtime(&now);
1283     sprintf(safe_bfr, "%.4d-%.2d-%.2d %.2d:%.2d:%.2d ",
1284             now_parsed->tm_year + 1900, now_parsed->tm_mon + 1,
1285             now_parsed->tm_mday, now_parsed->tm_hour,
1286             now_parsed->tm_min, now_parsed->tm_sec);
1287     if (!snmp_strcat
1288         (buf, buf_len, out_len, allow_realloc,
1289          (const u_char *) safe_bfr)) {
1290         return 0;
1291     }
1292
1293     /*
1294      * Get info about the sender.  
1295      */
1296     if (!netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, 
1297                                 NETSNMP_DS_APP_NUMERIC_IP)) {
1298         host = gethostbyaddr((char *) pdu->agent_addr, 4, AF_INET);
1299     }
1300     if (host != (struct hostent *) NULL) {
1301         if (!snmp_strcat
1302             (buf, buf_len, out_len, allow_realloc,
1303              (const u_char *) host->h_name)) {
1304             return 0;
1305         }
1306         if (!snmp_strcat
1307             (buf, buf_len, out_len, allow_realloc,
1308              (const u_char *) " [")) {
1309             return 0;
1310         }
1311         if (!snmp_strcat(buf, buf_len, out_len, allow_realloc,
1312                          (const u_char *) inet_ntoa(*agent_inaddr))) {
1313             return 0;
1314         }
1315         if (!snmp_strcat
1316             (buf, buf_len, out_len, allow_realloc,
1317              (const u_char *) "] ")) {
1318             return 0;
1319         }
1320     } else {
1321         if (!snmp_strcat(buf, buf_len, out_len, allow_realloc,
1322                          (const u_char *) inet_ntoa(*agent_inaddr))) {
1323             return 0;
1324         }
1325     }
1326
1327     /*
1328      * Append PDU transport info.  
1329      */
1330     if (transport != NULL && transport->f_fmtaddr != NULL) {
1331         char           *tstr =
1332             transport->f_fmtaddr(transport, pdu->transport_data,
1333                                  pdu->transport_data_length);
1334         if (!snmp_strcat
1335             (buf, buf_len, out_len, allow_realloc,
1336              (const u_char *) "(via ")) {
1337             return 0;
1338         }
1339         if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, tstr)) {
1340             free(tstr);
1341             return 0;
1342         }
1343         free(tstr);
1344         if (!snmp_strcat
1345             (buf, buf_len, out_len, allow_realloc,
1346              (const u_char *) ") ")) {
1347             return 0;
1348         }
1349     }
1350
1351     /*
1352      * Add security wrapper information.  
1353      */
1354     if (!realloc_handle_wrap_fmt
1355         (buf, buf_len, out_len, allow_realloc, pdu)) {
1356         return 0;
1357     }
1358
1359     if (!snmp_strcat
1360         (buf, buf_len, out_len, allow_realloc, (const u_char *) "\n\t")) {
1361         return 0;
1362     }
1363
1364     /*
1365      * Add enterprise information.  
1366      */
1367     if (!sprint_realloc_objid(buf, buf_len, out_len, allow_realloc,
1368                               pdu->enterprise, pdu->enterprise_length)) {
1369         return 0;
1370     }
1371
1372     if (!snmp_strcat
1373         (buf, buf_len, out_len, allow_realloc, (const u_char *) " ")) {
1374         return 0;
1375     }
1376     if (!snmp_strcat(buf, buf_len, out_len, allow_realloc,
1377                      trap_description(pdu->trap_type))) {
1378         return 0;
1379     }
1380     if (!snmp_strcat
1381         (buf, buf_len, out_len, allow_realloc,
1382          (const u_char *) " Trap (")) {
1383         return 0;
1384     }
1385
1386     /*
1387      * Handle enterprise specific traps.  
1388      */
1389     if (pdu->trap_type == SNMP_TRAP_ENTERPRISESPECIFIC) {
1390         size_t          obuf_len = 64, oout_len = 0, trap_oid_len = 0;
1391         oid             trap_oid[MAX_OID_LEN + 2] = { 0 };
1392         char           *ent_spec_code = NULL;
1393         u_char         *obuf = NULL;
1394
1395         if ((obuf = (u_char *) calloc(obuf_len, 1)) == NULL) {
1396             return 0;
1397         }
1398
1399         /*
1400          * Get object ID for the trap.  
1401          */
1402         trap_oid_len = pdu->enterprise_length;
1403         memcpy(trap_oid, pdu->enterprise, trap_oid_len * sizeof(oid));
1404         if (trap_oid[trap_oid_len - 1] != 0) {
1405             trap_oid[trap_oid_len] = 0;
1406             trap_oid_len++;
1407         }
1408         trap_oid[trap_oid_len] = pdu->specific_type;
1409         trap_oid_len++;
1410
1411         /*
1412          * Find the element after the last dot.  
1413          */
1414         if (!sprint_realloc_objid(&obuf, &obuf_len, &oout_len, 1,
1415                                   trap_oid, trap_oid_len)) {
1416             if (obuf != NULL) {
1417                 free(obuf);
1418             }
1419             return 0;
1420         }
1421         ent_spec_code = strrchr((char *) obuf, '.');
1422         if (ent_spec_code != NULL) {
1423             ent_spec_code++;
1424         } else {
1425             ent_spec_code = (char *) obuf;
1426         }
1427
1428         /*
1429          * Print trap info.  
1430          */
1431         if (!snmp_strcat
1432             (buf, buf_len, out_len, allow_realloc,
1433              (const u_char *) ent_spec_code)) {
1434             free(obuf);
1435             return 0;
1436         }
1437         free(obuf);
1438     } else {
1439         /*
1440          * Handle traps that aren't enterprise specific.  
1441          */
1442         sprintf(safe_bfr, "%ld", pdu->specific_type);
1443         if (!snmp_strcat
1444             (buf, buf_len, out_len, allow_realloc,
1445              (const u_char *) safe_bfr)) {
1446             return 0;
1447         }
1448     }
1449
1450     /*
1451      * Finish the line.  
1452      */
1453     if (!snmp_strcat
1454         (buf, buf_len, out_len, allow_realloc,
1455          (const u_char *) ") Uptime: ")) {
1456         return 0;
1457     }
1458     if (!snmp_strcat(buf, buf_len, out_len, allow_realloc,
1459                      (const u_char *) uptime_string(pdu->time,
1460                                                     safe_bfr))) {
1461         return 0;
1462     }
1463     if (!snmp_strcat
1464         (buf, buf_len, out_len, allow_realloc, (const u_char *) "\n")) {
1465         return 0;
1466     }
1467
1468     /*
1469      * Finally, output the PDU variables. 
1470      */
1471     for (vars = pdu->variables; vars != NULL; vars = vars->next_variable) {
1472         if (!snmp_strcat
1473             (buf, buf_len, out_len, allow_realloc,
1474              (const u_char *) "\t")) {
1475             return 0;
1476         }
1477         if (!sprint_realloc_variable(buf, buf_len, out_len, allow_realloc,
1478                                      vars->name, vars->name_length,
1479                                      vars)) {
1480             return 0;
1481         }
1482     }
1483     if (!snmp_strcat
1484         (buf, buf_len, out_len, allow_realloc, (const u_char *) "\n")) {
1485         return 0;
1486     }
1487
1488     /*
1489      * String is already null-terminated.  That's all folks!  
1490      */
1491     return 1;
1492 }
1493
1494
1495 int
1496 realloc_format_trap(u_char ** buf, size_t * buf_len, size_t * out_len,
1497                     int allow_realloc, const char *format_str,
1498                     netsnmp_pdu *pdu, netsnmp_transport *transport)
1499
1500      /*
1501       * Function:
1502       *    Format the trap information for display in a log. Place the results
1503       *    in the specified buffer (truncating to the length of the buffer).
1504       *    Returns the number of characters it put in the buffer.
1505       *
1506       * Input Parameters:
1507       *    buf, buf_len, out_len, allow_realloc - standard relocatable
1508       *                                           buffer parameters
1509       *    format_str - specifies how to format the trap info
1510       *    pdu        - the pdu information
1511       *    transport  - the transport descriptor
1512       */
1513 {
1514     unsigned long   fmt_idx = 0;        /* index into the format string */
1515     options_type    options;    /* formatting options */
1516     parse_state_type state = PARSE_NORMAL;      /* state of the parser */
1517     char            next_chr;   /* for speed */
1518     int             reset_options = TRUE;       /* reset opts on next NORMAL state */
1519
1520     if (buf == NULL) {
1521         return 0;
1522     }
1523
1524     /*
1525      * Go until we reach the end of the format string:  
1526      */
1527     for (fmt_idx = 0; format_str[fmt_idx] != '\0'; fmt_idx++) {
1528         next_chr = format_str[fmt_idx];
1529         switch (state) {
1530         case PARSE_NORMAL:
1531             /*
1532              * Looking for next character.  
1533              */
1534             if (reset_options) {
1535                 init_options(&options);
1536                 reset_options = FALSE;
1537             }
1538             if (next_chr == '\\') {
1539                 state = PARSE_BACKSLASH;
1540             } else if (next_chr == CHR_FMT_DELIM) {
1541                 state = PARSE_IN_FORMAT;
1542             } else {
1543                 if ((*out_len + 1) >= *buf_len) {
1544                     if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
1545                         return 0;
1546                     }
1547                 }
1548                 *(*buf + *out_len) = next_chr;
1549                 (*out_len)++;
1550             }
1551             break;
1552
1553         case PARSE_BACKSLASH:
1554             /*
1555              * Found a backslash.  
1556              */
1557             if (!realloc_handle_backslash
1558                 (buf, buf_len, out_len, allow_realloc, next_chr)) {
1559                 return 0;
1560             }
1561             state = PARSE_NORMAL;
1562             break;
1563
1564         case PARSE_IN_FORMAT:
1565             /*
1566              * In a format command.  
1567              */
1568             reset_options = TRUE;
1569             if (next_chr == CHR_LEFT_JUST) {
1570                 options.left_justify = TRUE;
1571             } else if (next_chr == CHR_LEAD_ZERO) {
1572                 options.leading_zeroes = TRUE;
1573             } else if (next_chr == CHR_ALT_FORM) {
1574                 options.alt_format = TRUE;
1575             } else if (next_chr == CHR_FIELD_SEP) {
1576                 state = PARSE_GET_PRECISION;
1577             } else if ((next_chr >= '1') && (next_chr <= '9')) {
1578                 options.width =
1579                     ((unsigned long) next_chr) - ((unsigned long) '0');
1580                 state = PARSE_GET_WIDTH;
1581             } else if (is_fmt_cmd(next_chr)) {
1582                 options.cmd = next_chr;
1583                 if (!realloc_dispatch_format_cmd
1584                     (buf, buf_len, out_len, allow_realloc, &options, pdu,
1585                      transport)) {
1586                     return 0;
1587                 }
1588                 state = PARSE_NORMAL;
1589             } else {
1590                 if ((*out_len + 1) >= *buf_len) {
1591                     if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
1592                         return 0;
1593                     }
1594                 }
1595                 *(*buf + *out_len) = next_chr;
1596                 (*out_len)++;
1597                 state = PARSE_NORMAL;
1598             }
1599             break;
1600
1601         case PARSE_GET_WIDTH:
1602             /*
1603              * Parsing a width field.  
1604              */
1605             reset_options = TRUE;
1606             if (isdigit(next_chr)) {
1607                 options.width *= 10;
1608                 options.width +=
1609                     (unsigned long) next_chr - (unsigned long) '0';
1610             } else if (next_chr == CHR_FIELD_SEP) {
1611                 state = PARSE_GET_PRECISION;
1612             } else if (is_fmt_cmd(next_chr)) {
1613                 options.cmd = next_chr;
1614                 if (!realloc_dispatch_format_cmd
1615                     (buf, buf_len, out_len, allow_realloc, &options, pdu,
1616                      transport)) {
1617                     return 0;
1618                 }
1619                 state = PARSE_NORMAL;
1620             } else {
1621                 if ((*out_len + 1) >= *buf_len) {
1622                     if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
1623                         return 0;
1624                     }
1625                 }
1626                 *(*buf + *out_len) = next_chr;
1627                 (*out_len)++;
1628                 state = PARSE_NORMAL;
1629             }
1630             break;
1631
1632         case PARSE_GET_PRECISION:
1633             /*
1634              * Parsing a precision field.  
1635              */
1636             reset_options = TRUE;
1637             if (isdigit(next_chr)) {
1638                 if (options.precision == UNDEF_PRECISION) {
1639                     options.precision =
1640                         (unsigned long) next_chr - (unsigned long) '0';
1641                 } else {
1642                     options.precision *= 10;
1643                     options.precision +=
1644                         (unsigned long) next_chr - (unsigned long) '0';
1645                 }
1646             } else if (is_fmt_cmd(next_chr)) {
1647                 options.cmd = next_chr;
1648                 if (options.width < options.precision) {
1649                     options.width = options.precision;
1650                 }
1651                 if (!realloc_dispatch_format_cmd
1652                     (buf, buf_len, out_len, allow_realloc, &options, pdu,
1653                      transport)) {
1654                     return 0;
1655                 }
1656                 state = PARSE_NORMAL;
1657             } else {
1658                 if ((*out_len + 1) >= *buf_len) {
1659                     if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
1660                         return 0;
1661                     }
1662                 }
1663                 *(*buf + *out_len) = next_chr;
1664                 (*out_len)++;
1665                 state = PARSE_NORMAL;
1666             }
1667             break;
1668
1669         default:
1670             /*
1671              * Unknown state.  
1672              */
1673             reset_options = TRUE;
1674             if ((*out_len + 1) >= *buf_len) {
1675                 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
1676                     return 0;
1677                 }
1678             }
1679             *(*buf + *out_len) = next_chr;
1680             (*out_len)++;
1681             state = PARSE_NORMAL;
1682         }
1683     }
1684
1685     *(*buf + *out_len) = '\0';
1686     return 1;
1687 }