2 * snmptrapd_log.c - format SNMP trap information for logging
5 /*****************************************************************
6 Copyright 1989, 1991, 1992 by Carnegie Mellon University
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.
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
25 ******************************************************************/
26 #include <net-snmp/net-snmp-config.h>
39 #include <sys/types.h>
46 #include <sys/socket.h>
49 #include <sys/sockio.h>
52 #include <netinet/in.h>
57 # include <sys/time.h>
58 # if TIME_WITH_SYS_TIME
65 #include <sys/select.h>
68 #include <sys/param.h>
74 #include <sys/ioctl.h>
83 #include <arpa/inet.h>
89 #include <net-snmp/net-snmp-includes.h>
90 #include "snmptrapd_log.h"
98 * These flags mark undefined values in the options structure
100 #define UNDEF_CMD '*'
101 #define UNDEF_PRECISION -1
104 * This structure holds the options for a single format command
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 */
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.
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 */
155 * These symbols define the states for the parser's state machine
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 */
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)
178 * Returns true if the character is a format command that outputs
179 * some field that deals with the current time.
182 * chr - character to check
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)
194 * Returns true if the character is a format command that outputs
195 * some field that deals with up-time.
198 * chr - character to check
201 #define is_agent_cmd(chr) ((((chr) == CHR_AGENT_IP) \
202 || ((chr) == CHR_AGENT_NAME)) ? TRUE : FALSE)
205 * Returns true if the character outputs information about the
209 * chr - the character to check
212 #define is_pdu_ip_cmd(chr) ((((chr) == CHR_PDU_IP) \
213 || ((chr) == CHR_PDU_NAME)) ? TRUE : FALSE)
216 * Returns true if the character outputs information about the PDU's
217 * host name or IP address.
220 * chr - the character to check
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)
230 * Returns true if the character outputs information about the trap.
233 * chr - the character to check
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)
245 * Returns true if the character is a format command.
248 * chr - character to check
251 #define is_numeric_cmd(chr) ((is_cur_time_cmd(chr) \
252 || is_up_time_cmd(chr) \
253 || (chr) == CHR_TRAP_NUM) ? TRUE : FALSE)
256 * Returns true if this is a numeric format command.
259 * chr - character to check
262 #define reference(var) ((var) == (var))
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.
272 * var - the parameter to reference
278 extern const char *trap_description(int trap);
281 init_options(options_type * options)
285 * Initialize a structure that contains the option settings for
289 * options - points to the structure to initialize
293 * initialize the structure's fields
297 options->precision = UNDEF_PRECISION;
298 options->left_justify = FALSE;
299 options->alt_format = FALSE;
300 options->leading_zeroes = FALSE;
306 realloc_output_temp_bfr(u_char ** buf, size_t * buf_len, size_t * out_len,
308 u_char ** temp_buf, options_type * options)
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
317 * buf, buf_len, out_len, allow_realloc - standard relocatable
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
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 */
329 if (temp_buf == NULL || *temp_buf == NULL) {
334 * Figure out how many characters are in the temporary buffer now,
335 * and how many of them we'll write.
337 temp_len = strlen((char *) *temp_buf);
338 temp_to_write = temp_len;
340 if (options->precision != UNDEF_PRECISION &&
341 temp_to_write > options->precision) {
342 temp_to_write = options->precision;
346 * Handle leading characters.
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)) {
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';
363 if (options->leading_zeroes || zeroes_to_write-- > 0) {
364 *(*buf + *out_len) = '0';
366 *(*buf + *out_len) = ' ';
373 * Truncate the temporary buffer and append its contents.
375 *(*temp_buf + temp_to_write) = '\0';
376 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, *temp_buf)) {
382 * Handle trailing characters.
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';
394 *(*buf + *out_len) = '0';
400 * Slap on a trailing \0 for good measure.
403 *(*buf + *out_len) = '\0';
411 realloc_handle_time_fmt(u_char ** buf, size_t * buf_len, size_t * out_len,
413 options_type * options, netsnmp_pdu *pdu)
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.
422 * buf, buf_len, out_len, allow_realloc - standard relocatable
424 * options - options governing how to write the field
425 * pdu - information about this trap
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 */
436 if ((safe_bfr = (char *) calloc(30, 1)) == NULL) {
441 * Get the time field to output.
443 if (is_up_time_cmd(fmt_cmd)) {
447 * Note: a time_t is a signed long.
450 time_ul = (unsigned long) time_val;
454 * Handle output in Unix time format.
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;
463 centisecs = time_ul % 100;
465 days = time_ul / (60 * 60 * 24);
466 time_ul %= (60 * 60 * 24);
468 hours = time_ul / (60 * 60);
469 time_ul %= (60 * 60);
471 minutes = time_ul / 60;
472 seconds = time_ul % 60;
476 sprintf(safe_bfr, "%u:%02u:%02u.%02u",
477 hours, minutes, seconds, centisecs);
480 sprintf(safe_bfr, "1 day, %u:%02u:%02u.%02u",
481 hours, minutes, seconds, centisecs);
484 sprintf(safe_bfr, "%u days, %u:%02u:%02u.%02u",
485 days, hours, minutes, seconds, centisecs);
489 * Handle other time fields.
492 if (options->alt_format) {
493 parsed_time = gmtime(&time_val);
495 parsed_time = localtime(&time_val);
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".
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;
521 sprintf(safe_bfr, "%d", parsed_time->tm_mon + 1);
525 * output day of month
529 sprintf(safe_bfr, "%d", parsed_time->tm_mday);
537 sprintf(safe_bfr, "%d", parsed_time->tm_hour);
545 sprintf(safe_bfr, "%d", parsed_time->tm_min);
553 sprintf(safe_bfr, "%d", parsed_time->tm_sec);
557 * unknown format command - just output the character
560 sprintf(safe_bfr, "%c", fmt_cmd);
565 * Output with correct justification, leading zeroes, etc.
567 return realloc_output_temp_bfr(buf, buf_len, out_len, allow_realloc,
568 (u_char **) & safe_bfr, options);
573 realloc_handle_ip_fmt(u_char ** buf, size_t * buf_len, size_t * out_len,
575 options_type * options, netsnmp_pdu *pdu,
576 netsnmp_transport *transport)
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.
585 * buf, buf_len, out_len, allow_realloc - standard relocatable
587 * options - options governing how to write the field
588 * pdu - information about this trap
589 * transport - the transport descriptor
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;
598 if ((temp_buf = calloc(temp_buf_len, 1)) == NULL) {
603 * Decide exactly what to output.
608 * Write a numerical address.
610 if (!snmp_strcat(&temp_buf, &temp_buf_len, &temp_out_len, 1,
611 inet_ntoa(*agent_inaddr))) {
612 if (temp_buf != NULL) {
621 * Try to resolve the agent_addr field as a hostname; fall back
622 * to numerical address.
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);
629 if (!snmp_strcat(&temp_buf, &temp_buf_len, &temp_out_len, 1,
631 if (temp_buf != NULL) {
637 if (!snmp_strcat(&temp_buf, &temp_buf_len, &temp_out_len, 1,
638 inet_ntoa(*agent_inaddr))) {
639 if (temp_buf != NULL) {
649 * Write the numerical transport information.
651 if (transport != NULL && transport->f_fmtaddr != NULL) {
653 transport->f_fmtaddr(transport, pdu->transport_data,
654 pdu->transport_data_length);
656 (&temp_buf, &temp_buf_len, &temp_out_len, 1, tstr)) {
660 if (temp_buf != NULL) {
670 (&temp_buf, &temp_buf_len, &temp_out_len, 1,
672 if (temp_buf != NULL) {
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
689 #ifdef SNMP_TRANSPORT_TCP_DOMAIN
690 if (transport != NULL && (transport->domain == netsnmpUDPDomain ||
692 netsnmp_snmpTCPDomain)) {
694 if (transport != NULL && transport->domain == netsnmpUDPDomain) {
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.
701 struct sockaddr_in *addr =
702 (struct sockaddr_in *) pdu->transport_data;
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)) {
709 gethostbyaddr((char *) &(addr->sin_addr),
710 sizeof(struct in_addr), AF_INET);
714 (&temp_buf, &temp_buf_len, &temp_out_len, 1,
716 if (temp_buf != NULL) {
723 (&temp_buf, &temp_buf_len, &temp_out_len, 1,
724 inet_ntoa(addr->sin_addr))) {
725 if (temp_buf != NULL) {
733 (&temp_buf, &temp_buf_len, &temp_out_len, 1,
735 if (temp_buf != NULL) {
741 } else if (transport != NULL && transport->f_fmtaddr != NULL) {
743 * Some other domain for which we do not know how to do a name
744 * lookup. Fall back to the formatted transport address.
747 transport->f_fmtaddr(transport, pdu->transport_data,
748 pdu->transport_data_length);
750 (&temp_buf, &temp_buf_len, &temp_out_len, 1, tstr)) {
754 if (temp_buf != NULL) {
764 * We are kind of stuck!
766 if (!snmp_strcat(&temp_buf, &temp_buf_len, &temp_out_len, 1,
768 if (temp_buf != NULL) {
777 * Don't know how to handle this command - write the character itself.
780 temp_buf[0] = fmt_cmd;
784 * Output with correct justification, leading zeroes, etc.
786 return realloc_output_temp_bfr(buf, buf_len, out_len, allow_realloc,
792 realloc_handle_ent_fmt(u_char ** buf, size_t * buf_len, size_t * out_len,
794 options_type * options, netsnmp_pdu *pdu)
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.
803 * buf, buf_len, out_len, allow_realloc - standard relocatable
805 * options - options governing how to write the field
806 * pdu - information about this trap
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;
813 if ((temp_buf = (u_char *) calloc(temp_buf_len, 1)) == NULL) {
818 * Decide exactly what to output.
823 * Write the enterprise oid.
825 if (!sprint_realloc_objid
826 (&temp_buf, &temp_buf_len, &temp_out_len, 1, pdu->enterprise,
827 pdu->enterprise_length)) {
834 * Don't know how to handle this command - write the character itself.
837 temp_buf[0] = fmt_cmd;
841 * Output with correct justification, leading zeroes, etc.
843 return realloc_output_temp_bfr(buf, buf_len, out_len, allow_realloc,
849 realloc_handle_trap_fmt(u_char ** buf, size_t * buf_len, size_t * out_len,
851 options_type * options, netsnmp_pdu *pdu)
855 * Handle a format command that deals with the trap itself.
856 * Append the information to the buffer subject to the buffer's
860 * buf, buf_len, out_len, allow_realloc - standard relocatable
862 * options - options governing how to write the field
863 * pdu - information about this trap
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;
871 if ((temp_buf = (u_char *) calloc(tbuf_len, 1)) == NULL) {
876 * Decide exactly what to output.
881 * Write the trap's number.
883 tout_len = sprintf(temp_buf, "%ld", pdu->trap_type);
888 * Write the trap's description.
891 sprintf(temp_buf, "%s", trap_description(pdu->trap_type));
896 * Write the trap's subtype.
898 if (pdu->trap_type != SNMP_TRAP_ENTERPRISESPECIFIC) {
899 tout_len = sprintf(temp_buf, "%ld", pdu->specific_type);
902 * Get object ID for the trap.
904 size_t obuf_len = 64, oout_len = 0, trap_oid_len = 0;
905 oid trap_oid[MAX_OID_LEN + 2] = { 0 };
909 if ((obuf = (u_char *) calloc(obuf_len, 1)) == NULL) {
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;
920 trap_oid[trap_oid_len] = pdu->specific_type;
924 * Find the element after the last dot.
926 if (!sprint_realloc_objid(&obuf, &obuf_len, &oout_len, 1,
927 trap_oid, trap_oid_len)) {
935 ptr = strrchr((char *) obuf, '.');
938 (&temp_buf, &tbuf_len, &tout_len, 1, (u_char *) ptr)) {
940 if (temp_buf != NULL) {
957 * Write the trap's variables.
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) {
969 if (!snmp_strcat(&temp_buf, &tbuf_len, &tout_len, 1, "\t")) {
970 if (temp_buf != NULL) {
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) {
989 * Don't know how to handle this command - write the character itself.
991 temp_buf[0] = fmt_cmd;
995 * Output with correct justification, leading zeroes, etc.
997 return realloc_output_temp_bfr(buf, buf_len, out_len, allow_realloc,
1003 realloc_handle_wrap_fmt(u_char ** buf, size_t * buf_len, size_t * out_len,
1004 int allow_realloc, netsnmp_pdu *pdu)
1008 switch (pdu->command) {
1011 (buf, buf_len, out_len, allow_realloc,
1012 (const u_char *) "TRAP")) {
1016 case SNMP_MSG_TRAP2:
1018 (buf, buf_len, out_len, allow_realloc,
1019 (const u_char *) "TRAP2")) {
1023 case SNMP_MSG_INFORM:
1025 (buf, buf_len, out_len, allow_realloc,
1026 (const u_char *) "INFORM")) {
1032 switch (pdu->version) {
1033 case SNMP_VERSION_1:
1035 (buf, buf_len, out_len, allow_realloc,
1036 (const u_char *) ", SNMP v1")) {
1040 case SNMP_VERSION_2c:
1042 (buf, buf_len, out_len, allow_realloc,
1043 (const u_char *) ", SNMP v2c")) {
1047 case SNMP_VERSION_3:
1049 (buf, buf_len, out_len, allow_realloc,
1050 (const u_char *) ", SNMP v3")) {
1056 switch (pdu->version) {
1057 case SNMP_VERSION_1:
1058 case SNMP_VERSION_2c:
1060 (buf, buf_len, out_len, allow_realloc,
1061 (const u_char *) ", community ")) {
1065 while ((*out_len + pdu->community_len + 1) >= *buf_len) {
1066 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
1071 for (i = 0; i < pdu->community_len; i++) {
1072 if (isprint(pdu->community[i])) {
1073 *(*buf + *out_len) = pdu->community[i];
1075 *(*buf + *out_len) = '.';
1079 *(*buf + *out_len) = '\0';
1081 case SNMP_VERSION_3:
1083 (buf, buf_len, out_len, allow_realloc,
1084 (const u_char *) ", user ")) {
1088 while ((*out_len + pdu->securityNameLen + 1) >= *buf_len) {
1089 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
1094 for (i = 0; i < pdu->securityNameLen; i++) {
1095 if (isprint(pdu->securityName[i])) {
1096 *(*buf + *out_len) = pdu->securityName[i];
1098 *(*buf + *out_len) = '.';
1102 *(*buf + *out_len) = '\0';
1105 (buf, buf_len, out_len, allow_realloc,
1106 (const u_char *) ", context ")) {
1110 while ((*out_len + pdu->contextNameLen + 1) >= *buf_len) {
1111 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
1116 for (i = 0; i < pdu->contextNameLen; i++) {
1117 if (isprint(pdu->contextName[i])) {
1118 *(*buf + *out_len) = pdu->contextName[i];
1120 *(*buf + *out_len) = '.';
1124 *(*buf + *out_len) = '\0';
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)
1138 * Dispatch a format command to the appropriate command handler.
1141 * buf, buf_len, out_len, allow_realloc - standard relocatable
1143 * options - options governing how to write the field
1144 * pdu - information about this trap
1145 * transport - the transport descriptor
1148 char fmt_cmd = options->cmd; /* for speed */
1151 * choose the appropriate command handler
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,
1166 } else if (fmt_cmd == CHR_PDU_WRAP) {
1167 return realloc_handle_wrap_fmt(buf, buf_len, out_len,
1168 allow_realloc, pdu);
1171 * unknown format command - just output the character
1173 char fmt_cmd_string[2] = { 0, 0 };
1174 fmt_cmd_string[0] = fmt_cmd;
1176 return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1177 (const u_char *) fmt_cmd_string);
1183 realloc_handle_backslash(u_char ** buf, size_t * buf_len, size_t * out_len,
1184 int allow_realloc, char fmt_cmd)
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.
1194 * buf, buf_len, out_len, allow_realloc - standard relocatable
1196 * fmt_cmd - the character after the backslash
1199 char temp_bfr[3]; /* for bulding temporary strings */
1202 * select the proper output character(s)
1206 return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1207 (const u_char *) "\a");
1209 return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1210 (const u_char *) "\b");
1212 return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1213 (const u_char *) "\f");
1215 return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1216 (const u_char *) "\n");
1218 return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1219 (const u_char *) "\r");
1221 return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1222 (const u_char *) "\t");
1224 return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1225 (const u_char *) "\v");
1227 return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1228 (const u_char *) "\\");
1230 return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1231 (const u_char *) "\?");
1233 return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1234 (const u_char *) "\'");
1236 return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1237 (const u_char *) "\"");
1239 sprintf(temp_bfr, "\\%c", fmt_cmd);
1240 return snmp_strcat(buf, buf_len, out_len, allow_realloc,
1241 (const u_char *) temp_bfr);
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)
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.
1259 * buf, buf_len, out_len, allow_realloc - standard relocatable
1261 * pdu - the pdu information
1262 * transport - the transport descriptor
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 */
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.
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);
1288 (buf, buf_len, out_len, allow_realloc,
1289 (const u_char *) safe_bfr)) {
1294 * Get info about the sender.
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);
1300 if (host != (struct hostent *) NULL) {
1302 (buf, buf_len, out_len, allow_realloc,
1303 (const u_char *) host->h_name)) {
1307 (buf, buf_len, out_len, allow_realloc,
1308 (const u_char *) " [")) {
1311 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc,
1312 (const u_char *) inet_ntoa(*agent_inaddr))) {
1316 (buf, buf_len, out_len, allow_realloc,
1317 (const u_char *) "] ")) {
1321 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc,
1322 (const u_char *) inet_ntoa(*agent_inaddr))) {
1328 * Append PDU transport info.
1330 if (transport != NULL && transport->f_fmtaddr != NULL) {
1332 transport->f_fmtaddr(transport, pdu->transport_data,
1333 pdu->transport_data_length);
1335 (buf, buf_len, out_len, allow_realloc,
1336 (const u_char *) "(via ")) {
1339 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc, tstr)) {
1345 (buf, buf_len, out_len, allow_realloc,
1346 (const u_char *) ") ")) {
1352 * Add security wrapper information.
1354 if (!realloc_handle_wrap_fmt
1355 (buf, buf_len, out_len, allow_realloc, pdu)) {
1360 (buf, buf_len, out_len, allow_realloc, (const u_char *) "\n\t")) {
1365 * Add enterprise information.
1367 if (!sprint_realloc_objid(buf, buf_len, out_len, allow_realloc,
1368 pdu->enterprise, pdu->enterprise_length)) {
1373 (buf, buf_len, out_len, allow_realloc, (const u_char *) " ")) {
1376 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc,
1377 trap_description(pdu->trap_type))) {
1381 (buf, buf_len, out_len, allow_realloc,
1382 (const u_char *) " Trap (")) {
1387 * Handle enterprise specific traps.
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;
1395 if ((obuf = (u_char *) calloc(obuf_len, 1)) == NULL) {
1400 * Get object ID for the trap.
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;
1408 trap_oid[trap_oid_len] = pdu->specific_type;
1412 * Find the element after the last dot.
1414 if (!sprint_realloc_objid(&obuf, &obuf_len, &oout_len, 1,
1415 trap_oid, trap_oid_len)) {
1421 ent_spec_code = strrchr((char *) obuf, '.');
1422 if (ent_spec_code != NULL) {
1425 ent_spec_code = (char *) obuf;
1432 (buf, buf_len, out_len, allow_realloc,
1433 (const u_char *) ent_spec_code)) {
1440 * Handle traps that aren't enterprise specific.
1442 sprintf(safe_bfr, "%ld", pdu->specific_type);
1444 (buf, buf_len, out_len, allow_realloc,
1445 (const u_char *) safe_bfr)) {
1454 (buf, buf_len, out_len, allow_realloc,
1455 (const u_char *) ") Uptime: ")) {
1458 if (!snmp_strcat(buf, buf_len, out_len, allow_realloc,
1459 (const u_char *) uptime_string(pdu->time,
1464 (buf, buf_len, out_len, allow_realloc, (const u_char *) "\n")) {
1469 * Finally, output the PDU variables.
1471 for (vars = pdu->variables; vars != NULL; vars = vars->next_variable) {
1473 (buf, buf_len, out_len, allow_realloc,
1474 (const u_char *) "\t")) {
1477 if (!sprint_realloc_variable(buf, buf_len, out_len, allow_realloc,
1478 vars->name, vars->name_length,
1484 (buf, buf_len, out_len, allow_realloc, (const u_char *) "\n")) {
1489 * String is already null-terminated. That's all folks!
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)
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.
1507 * buf, buf_len, out_len, allow_realloc - standard relocatable
1509 * format_str - specifies how to format the trap info
1510 * pdu - the pdu information
1511 * transport - the transport descriptor
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 */
1525 * Go until we reach the end of the format string:
1527 for (fmt_idx = 0; format_str[fmt_idx] != '\0'; fmt_idx++) {
1528 next_chr = format_str[fmt_idx];
1532 * Looking for next character.
1534 if (reset_options) {
1535 init_options(&options);
1536 reset_options = FALSE;
1538 if (next_chr == '\\') {
1539 state = PARSE_BACKSLASH;
1540 } else if (next_chr == CHR_FMT_DELIM) {
1541 state = PARSE_IN_FORMAT;
1543 if ((*out_len + 1) >= *buf_len) {
1544 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
1548 *(*buf + *out_len) = next_chr;
1553 case PARSE_BACKSLASH:
1555 * Found a backslash.
1557 if (!realloc_handle_backslash
1558 (buf, buf_len, out_len, allow_realloc, next_chr)) {
1561 state = PARSE_NORMAL;
1564 case PARSE_IN_FORMAT:
1566 * In a format command.
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')) {
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,
1588 state = PARSE_NORMAL;
1590 if ((*out_len + 1) >= *buf_len) {
1591 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
1595 *(*buf + *out_len) = next_chr;
1597 state = PARSE_NORMAL;
1601 case PARSE_GET_WIDTH:
1603 * Parsing a width field.
1605 reset_options = TRUE;
1606 if (isdigit(next_chr)) {
1607 options.width *= 10;
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,
1619 state = PARSE_NORMAL;
1621 if ((*out_len + 1) >= *buf_len) {
1622 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
1626 *(*buf + *out_len) = next_chr;
1628 state = PARSE_NORMAL;
1632 case PARSE_GET_PRECISION:
1634 * Parsing a precision field.
1636 reset_options = TRUE;
1637 if (isdigit(next_chr)) {
1638 if (options.precision == UNDEF_PRECISION) {
1640 (unsigned long) next_chr - (unsigned long) '0';
1642 options.precision *= 10;
1643 options.precision +=
1644 (unsigned long) next_chr - (unsigned long) '0';
1646 } else if (is_fmt_cmd(next_chr)) {
1647 options.cmd = next_chr;
1648 if (options.width < options.precision) {
1649 options.width = options.precision;
1651 if (!realloc_dispatch_format_cmd
1652 (buf, buf_len, out_len, allow_realloc, &options, pdu,
1656 state = PARSE_NORMAL;
1658 if ((*out_len + 1) >= *buf_len) {
1659 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
1663 *(*buf + *out_len) = next_chr;
1665 state = PARSE_NORMAL;
1673 reset_options = TRUE;
1674 if ((*out_len + 1) >= *buf_len) {
1675 if (!(allow_realloc && snmp_realloc(buf, buf_len))) {
1679 *(*buf + *out_len) = next_chr;
1681 state = PARSE_NORMAL;
1685 *(*buf + *out_len) = '\0';