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