]> git.ipfire.org Git - thirdparty/squid.git/blob - lib/snmplib/snmp_pdu.c
Source Format Enforcement (#763)
[thirdparty/squid.git] / lib / snmplib / snmp_pdu.c
1 /*
2 * Copyright (C) 1996-2021 The Squid Software Foundation and contributors
3 *
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
7 */
8
9 /*
10 * SNMP PDU Encoding
11 *
12 * Complies with:
13 *
14 * RFC 1902: Structure of Management Information for SNMPv2
15 *
16 */
17
18 /**********************************************************************
19 *
20 * Copyright 1997 by Carnegie Mellon University
21 *
22 * All Rights Reserved
23 *
24 * Permission to use, copy, modify, and distribute this software and its
25 * documentation for any purpose and without fee is hereby granted,
26 * provided that the above copyright notice appear in all copies and that
27 * both that copyright notice and this permission notice appear in
28 * supporting documentation, and that the name of CMU not be
29 * used in advertising or publicity pertaining to distribution of the
30 * software without specific, written prior permission.
31 *
32 * CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
33 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
34 * CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
35 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
36 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
37 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
38 * SOFTWARE.
39 *
40 * Author: Ryan Troll <ryan+@andrew.cmu.edu>
41 *
42 **********************************************************************/
43
44 #include "squid.h"
45
46 #if HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49 #if HAVE_STDLIB_H
50 #include <stdlib.h>
51 #endif
52 #if HAVE_SYS_TYPES_H
53 #include <sys/types.h>
54 #endif
55 #if HAVE_CTYPE_H
56 #include <ctype.h>
57 #endif
58 #if HAVE_GNUMALLOC_H
59 #include <gnumalloc.h>
60 #elif HAVE_MALLOC_H
61 #include <malloc.h>
62 #endif
63 #if HAVE_MEMORY_H
64 #include <memory.h>
65 #endif
66 #if HAVE_STRING_H
67 #include <string.h>
68 #endif
69 #if HAVE_STRINGS_H
70 #include <strings.h>
71 #endif
72 #if HAVE_BSTRING_H
73 #include <bstring.h>
74 #endif
75 #if HAVE_SYS_SOCKET_H
76 #include <sys/socket.h>
77 #endif
78 #if HAVE_NETINET_IN_H
79 #include <netinet/in.h>
80 #endif
81 #if HAVE_ARPA_INET_H
82 #include <arpa/inet.h>
83 #endif
84 #if HAVE_SYS_TIME_H
85 #include <sys/time.h>
86 #endif
87 #if HAVE_NETDB_H
88 #include <netdb.h>
89 #endif
90
91 #include "asn1.h"
92 #include "snmp.h"
93 #include "snmp_api_error.h"
94 #include "snmp_error.h"
95 #include "snmp_msg.h"
96 #include "snmp_pdu.h"
97 #include "snmp_vars.h"
98
99 #include "util.h"
100
101 /* #define DEBUG_PDU 1 */
102 /* #define DEBUG_PDU_DECODE 1 */
103 /* #define DEBUG_PDU_ENCODE 1 */
104
105 #define ASN_PARSE_ERROR(x) { return(x); }
106
107 /**********************************************************************/
108
109 /* Create a PDU.
110 */
111
112 struct snmp_pdu *
113 snmp_pdu_create(int command) {
114 struct snmp_pdu *pdu;
115
116 #if DEBUG_PDU
117 snmplib_debug(8, "PDU: Creating\n");
118 #endif
119
120 pdu = (struct snmp_pdu *) xmalloc(sizeof(struct snmp_pdu));
121 if (pdu == NULL) {
122 snmp_set_api_error(SNMPERR_OS_ERR);
123 return (NULL);
124 }
125 memset((char *) pdu, '\0', sizeof(struct snmp_pdu));
126
127 pdu->command = command;
128 pdu->errstat = SNMP_DEFAULT_ERRSTAT;
129 pdu->errindex = SNMP_DEFAULT_ERRINDEX;
130 pdu->address.sin_addr.s_addr = SNMP_DEFAULT_ADDRESS;
131 pdu->enterprise = NULL;
132 pdu->enterprise_length = 0;
133 pdu->variables = NULL;
134
135 #if DEBUG_PDU
136 snmplib_debug(8, "PDU: Created %x\n", (unsigned int) pdu);
137 #endif
138
139 return (pdu);
140 }
141
142 /**********************************************************************/
143
144 /* Clone an existing PDU.
145 */
146 struct snmp_pdu *
147 snmp_pdu_clone(struct snmp_pdu *Src) {
148 struct snmp_pdu *Dest;
149
150 #if DEBUG_PDU
151 snmplib_debug(8, "PDU %x: Cloning\n", (unsigned int) Src);
152 #endif
153
154 Dest = (struct snmp_pdu *) xmalloc(sizeof(struct snmp_pdu));
155 if (Dest == NULL) {
156 snmp_set_api_error(SNMPERR_OS_ERR);
157 return (NULL);
158 }
159 memcpy((char *) Dest, (char *) Src, sizeof(struct snmp_pdu));
160
161 #if DEBUG_PDU
162 snmplib_debug(8, "PDU %x: Created %x\n", (unsigned int) Src, (unsigned int) Dest);
163 #endif
164 return (Dest);
165 }
166
167 /**********************************************************************/
168
169 /*
170 * If there was an error in the input pdu, creates a clone of the pdu
171 * that includes all the variables except the one marked by the errindex.
172 * The command is set to the input command and the reqid, errstat, and
173 * errindex are set to default values.
174 * If the error status didn't indicate an error, the error index didn't
175 * indicate a variable, the pdu wasn't a get response message, or there
176 * would be no remaining variables, this function will return NULL.
177 * If everything was successful, a pointer to the fixed cloned pdu will
178 * be returned.
179 */
180 struct snmp_pdu *
181 snmp_pdu_fix(struct snmp_pdu *pdu, int command) {
182 return (snmp_fix_pdu(pdu, command));
183 }
184
185 struct snmp_pdu *
186 snmp_fix_pdu(struct snmp_pdu *pdu, int command) {
187 struct variable_list *var, *newvar;
188 struct snmp_pdu *newpdu;
189 int i;
190 int copied = 0;
191
192 #if DEBUG_PDU
193 snmplib_debug(8, "PDU %x: Fixing. Err index is %d\n",
194 (unsigned int) pdu, (unsigned int) pdu->errindex);
195 #endif
196
197 if (pdu->command != SNMP_PDU_RESPONSE ||
198 pdu->errstat == SNMP_ERR_NOERROR ||
199 pdu->errindex <= 0) {
200 snmp_set_api_error(SNMPERR_UNABLE_TO_FIX);
201 return (NULL);
202 }
203 /* clone the pdu */
204 newpdu = snmp_pdu_clone(pdu);
205 if (newpdu == NULL)
206 return (NULL);
207
208 newpdu->variables = 0;
209 newpdu->command = command;
210 newpdu->reqid = SNMP_DEFAULT_REQID;
211 newpdu->errstat = SNMP_DEFAULT_ERRSTAT;
212 newpdu->errindex = SNMP_DEFAULT_ERRINDEX;
213
214 /* Loop through the variables, removing whatever isn't necessary */
215
216 var = pdu->variables;
217 i = 1;
218
219 /* skip first variable if necessary */
220 if (pdu->errindex == i) {
221 var = var->next_variable;
222 i++;
223 }
224 if (var != NULL) {
225
226 /* VAR is the first uncopied variable */
227
228 /* Clone this variable */
229 newpdu->variables = snmp_var_clone(var);
230 if (newpdu->variables == NULL) {
231 snmp_pdu_free(newpdu);
232 return (NULL);
233 }
234 copied++;
235
236 newvar = newpdu->variables;
237
238 /* VAR has been copied to NEWVAR. */
239 while (var->next_variable) {
240
241 /* Skip the item that was bad */
242 if (++i == pdu->errindex) {
243 var = var->next_variable;
244 continue;
245 }
246 /* Copy this var */
247 newvar->next_variable = snmp_var_clone(var->next_variable);
248 if (newvar->next_variable == NULL) {
249 snmp_pdu_free(newpdu);
250 return (NULL);
251 }
252 /* Move to the next one */
253 newvar = newvar->next_variable;
254 var = var->next_variable;
255 copied++;
256 }
257 newvar->next_variable = NULL;
258 }
259 /* If we didn't copy anything, free the new pdu. */
260 if (i < pdu->errindex || copied == 0) {
261 snmp_free_pdu(newpdu);
262 snmp_set_api_error(SNMPERR_UNABLE_TO_FIX);
263 return (NULL);
264 }
265 #if DEBUG_PDU
266 snmplib_debug(8, "PDU %x: Fixed PDU is %x\n",
267 (unsigned int) pdu, (unsigned int) newpdu);
268 #endif
269 return (newpdu);
270 }
271
272 /**********************************************************************/
273
274 void
275 snmp_pdu_free(struct snmp_pdu *pdu)
276 {
277 snmp_free_pdu(pdu);
278 }
279
280 /*
281 * Frees the pdu and any xmalloc'd data associated with it.
282 */
283 void
284 snmp_free_pdu(struct snmp_pdu *pdu)
285 {
286 struct variable_list *vp, *ovp;
287
288 vp = pdu->variables;
289 while (vp) {
290 ovp = vp;
291 vp = vp->next_variable;
292 snmp_var_free(ovp);
293 }
294
295 if (pdu->enterprise)
296 xfree((char *) pdu->enterprise);
297 xfree((char *) pdu);
298 }
299
300 /**********************************************************************/
301
302 /* Encode this PDU into DestBuf.
303 *
304 * Returns a pointer to the next byte in the buffer (where the Variable
305 * Bindings belong.)
306 */
307
308 /*
309 * RFC 1902: Structure of Management Information for SNMPv2
310 *
311 * PDU ::=
312 * SEQUENCE {
313 * request-id INTEGER32
314 * error-status INTEGER
315 * error-index INTEGER
316 * Variable Bindings
317 * }
318 *
319 * BulkPDU ::=
320 * SEQUENCE {
321 * request-id INTEGER32
322 * non-repeaters INTEGER
323 * max-repetitions INTEGER
324 * Variable Bindings
325 * }
326 */
327
328 /*
329 * RFC 1157: A Simple Network Management Protocol (SNMP)
330 *
331 * PDU ::=
332 * SEQUENCE {
333 * request-id INTEGER
334 * error-status INTEGER
335 * error-index INTEGER
336 * Variable Bindings
337 * }
338 *
339 * TrapPDU ::=
340 * SEQUENCE {
341 * enterprise NetworkAddress
342 * generic-trap INTEGER
343 * specific-trap INTEGER
344 * time-stamp TIMETICKS
345 * Variable Bindings
346 * }
347 */
348
349 u_char *
350 snmp_pdu_encode(u_char * DestBuf, int *DestBufLen,
351 struct snmp_pdu *PDU)
352 {
353 u_char *bufp;
354
355 #if DEBUG_PDU_ENCODE
356 snmplib_debug(8, "PDU: Encoding %d\n", PDU->command);
357 #endif
358
359 /* ASN.1 Header */
360 switch (PDU->command) {
361
362 /**********************************************************************/
363 #if TRP_REQ_MSG
364 case TRP_REQ_MSG:
365
366 /* SNMPv1 Trap */
367
368 /* enterprise */
369 bufp = asn_build_objid(DestBuf, DestBufLen,
370 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_OBJECT_ID),
371 (oid *) PDU->enterprise, PDU->enterprise_length);
372 if (bufp == NULL)
373 return (NULL);
374
375 /* agent-addr */
376 bufp = asn_build_string(bufp, DestBufLen,
377 (u_char) (SMI_IPADDRESS | ASN_PRIMITIVE),
378 (u_char *) & PDU->agent_addr.sin_addr.s_addr,
379 sizeof(PDU->agent_addr.sin_addr.s_addr));
380 if (bufp == NULL)
381 return (NULL);
382
383 /* generic trap */
384 bufp = asn_build_int(bufp, DestBufLen,
385 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
386 (int *) &PDU->trap_type, sizeof(PDU->trap_type));
387 if (bufp == NULL)
388 return (NULL);
389
390 /* specific trap */
391 bufp = asn_build_int(bufp, DestBufLen,
392 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
393 (int *) &PDU->specific_type,
394 sizeof(PDU->specific_type));
395 if (bufp == NULL)
396 return (NULL);
397
398 /* timestamp */
399 bufp = asn_build_unsigned_int(bufp, DestBufLen,
400 (u_char) (SMI_TIMETICKS | ASN_PRIMITIVE),
401 &PDU->time, sizeof(PDU->time));
402 if (bufp == NULL)
403 return (NULL);
404 break;
405 #endif
406
407 /**********************************************************************/
408
409 case SNMP_PDU_GETBULK:
410
411 /* SNMPv2 Bulk Request */
412
413 /* request id */
414 bufp = asn_build_int(DestBuf, DestBufLen,
415 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
416 &PDU->reqid, sizeof(PDU->reqid));
417 if (bufp == NULL)
418 return (NULL);
419
420 /* non-repeaters */
421 bufp = asn_build_int(bufp, DestBufLen,
422 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
423 &PDU->non_repeaters,
424 sizeof(PDU->non_repeaters));
425 if (bufp == NULL)
426 return (NULL);
427
428 /* max-repetitions */
429 bufp = asn_build_int(bufp, DestBufLen,
430 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
431 &PDU->max_repetitions,
432 sizeof(PDU->max_repetitions));
433 if (bufp == NULL)
434 return (NULL);
435 break;
436
437 /**********************************************************************/
438
439 default:
440
441 /* Normal PDU Encoding */
442
443 /* request id */
444 #if DEBUG_PDU_ENCODE
445 snmplib_debug(8, "PDU: Request ID %d (0x%x)\n", PDU->reqid, DestBuf);
446 #endif
447 bufp = asn_build_int(DestBuf, DestBufLen,
448 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
449 &PDU->reqid, sizeof(PDU->reqid));
450 if (bufp == NULL)
451 return (NULL);
452
453 /* error status */
454 #if DEBUG_PDU_ENCODE
455 snmplib_debug(8, "PDU: Error Status %d (0x%x)\n", PDU->errstat, bufp);
456 #endif
457 bufp = asn_build_int(bufp, DestBufLen,
458 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
459 &PDU->errstat, sizeof(PDU->errstat));
460 if (bufp == NULL)
461 return (NULL);
462
463 /* error index */
464 #if DEBUG_PDU_ENCODE
465 snmplib_debug(8, "PDU: Error index %d (0x%x)\n", PDU->errindex, bufp);
466 #endif
467 bufp = asn_build_int(bufp, DestBufLen,
468 (u_char) (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
469 &PDU->errindex, sizeof(PDU->errindex));
470 if (bufp == NULL)
471 return (NULL);
472 break;
473 } /* End of encoding */
474
475 return (bufp);
476 }
477
478 /**********************************************************************/
479
480 /* Decodes PDU from Packet into PDU.
481 *
482 * Returns a pointer to the next byte of the packet, which is where the
483 * Variable Bindings start.
484 */
485 u_char *
486 snmp_pdu_decode(u_char * Packet, /* data */
487 int *Length, /* &length */
488 struct snmp_pdu * PDU)
489 { /* pdu */
490 u_char *bufp;
491 u_char PDUType;
492 u_char ASNType;
493 #if UNUSED_CODE
494 int four;
495 oid objid[MAX_NAME_LEN];
496 #endif
497
498 bufp = asn_parse_header(Packet, Length, &PDUType);
499 if (bufp == NULL)
500 ASN_PARSE_ERROR(NULL);
501
502 #if DEBUG_PDU_DECODE
503 snmplib_debug(8, "PDU Type: %d\n", PDUType);
504 #endif
505
506 PDU->command = PDUType;
507 switch (PDUType) {
508
509 #if TRP_REQ_MSG
510 case TRP_REQ_MSG:
511
512 /* SNMPv1 Trap Message */
513
514 /* enterprise */
515 PDU->enterprise_length = MAX_NAME_LEN;
516 bufp = asn_parse_objid(bufp, Length,
517 &ASNType, objid, &PDU->enterprise_length);
518 if (bufp == NULL)
519 ASN_PARSE_ERROR(NULL);
520
521 PDU->enterprise = (oid *) xmalloc(PDU->enterprise_length * sizeof(oid));
522 if (PDU->enterprise == NULL) {
523 snmp_set_api_error(SNMPERR_OS_ERR);
524 return (NULL);
525 }
526 memcpy((char *) PDU->enterprise, (char *) objid,
527 PDU->enterprise_length * sizeof(oid));
528
529 /* Agent-addr */
530 four = 4;
531 bufp = asn_parse_string(bufp, Length,
532 &ASNType,
533 (u_char *) & PDU->agent_addr.sin_addr.s_addr,
534 &four);
535 if (bufp == NULL)
536 ASN_PARSE_ERROR(NULL);
537
538 /* Generic trap */
539 bufp = asn_parse_int(bufp, Length,
540 &ASNType,
541 (int *) &PDU->trap_type,
542 sizeof(PDU->trap_type));
543 if (bufp == NULL)
544 ASN_PARSE_ERROR(NULL);
545
546 /* Specific Trap */
547 bufp = asn_parse_int(bufp, Length,
548 &ASNType,
549 (int *) &PDU->specific_type,
550 sizeof(PDU->specific_type));
551 if (bufp == NULL)
552 ASN_PARSE_ERROR(NULL);
553
554 /* Timestamp */
555 bufp = asn_parse_unsigned_int(bufp, Length,
556 &ASNType,
557 &PDU->time, sizeof(PDU->time));
558 if (bufp == NULL)
559 ASN_PARSE_ERROR(NULL);
560 break;
561 #endif
562
563 /**********************************************************************/
564
565 case SNMP_PDU_GETBULK:
566
567 /* SNMPv2 Bulk Request */
568
569 /* request id */
570 bufp = asn_parse_int(bufp, Length,
571 &ASNType,
572 &PDU->reqid, sizeof(PDU->reqid));
573 if (bufp == NULL)
574 ASN_PARSE_ERROR(NULL);
575
576 /* non-repeaters */
577 bufp = asn_parse_int(bufp, Length,
578 &ASNType,
579 &PDU->non_repeaters, sizeof(PDU->non_repeaters));
580 if (bufp == NULL)
581 ASN_PARSE_ERROR(NULL);
582
583 /* max-repetitions */
584 bufp = asn_parse_int(bufp, Length,
585 &ASNType,
586 &PDU->max_repetitions, sizeof(PDU->max_repetitions));
587 if (bufp == NULL)
588 ASN_PARSE_ERROR(NULL);
589 break;
590
591 /**********************************************************************/
592
593 default:
594
595 /* Normal PDU Encoding */
596
597 /* request id */
598 bufp = asn_parse_int(bufp, Length,
599 &ASNType,
600 &PDU->reqid, sizeof(PDU->reqid));
601 if (bufp == NULL)
602 ASN_PARSE_ERROR(NULL);
603
604 #if DEBUG_PDU_DECODE
605 snmplib_debug(8, "PDU Request ID: %d\n", PDU->reqid);
606 #endif
607
608 /* error status */
609 bufp = asn_parse_int(bufp, Length,
610 &ASNType,
611 &PDU->errstat, sizeof(PDU->errstat));
612 if (bufp == NULL)
613 ASN_PARSE_ERROR(NULL);
614
615 #if DEBUG_PDU_DECODE
616 snmplib_debug(8, "PDU Error Status: %d\n", PDU->errstat);
617 #endif
618
619 /* error index */
620 bufp = asn_parse_int(bufp, Length,
621 &ASNType,
622 &PDU->errindex, sizeof(PDU->errindex));
623 if (bufp == NULL)
624 ASN_PARSE_ERROR(NULL);
625
626 #if DEBUG_PDU_DECODE
627 snmplib_debug(8, "PDU Error Index: %d\n", PDU->errindex);
628 #endif
629
630 break;
631 }
632
633 return (bufp);
634 }
635
636 /*
637 * Add a null variable with the requested name to the end of the list of
638 * variables for this pdu.
639 */
640 void
641 snmp_add_null_var(struct snmp_pdu *pdu, oid * name, int name_length)
642 {
643 struct variable_list *vars;
644 struct variable_list *ptr;
645
646 vars = snmp_var_new(name, name_length);
647 if (vars == NULL) {
648 perror("snmp_add_null_var:xmalloc");
649 return;
650 }
651 if (pdu->variables == NULL) {
652 pdu->variables = vars;
653 } else {
654
655 /* Insert at the end */
656 for (ptr = pdu->variables;
657 ptr->next_variable;
658 ptr = ptr->next_variable)
659 /*EXIT */ ;
660 ptr->next_variable = vars;
661 }
662
663 return;
664 }
665