Coverage Report

Created: 2026-01-17 06:46

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