]> git.ipfire.org Git - thirdparty/squid.git/blame - snmplib/snmp_pdu.c
initial CACHE_DIGEST code
[thirdparty/squid.git] / snmplib / snmp_pdu.c
CommitLineData
85269fdf 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 && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
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 "mibii.h"
92#include "snmp_api_error.h"
93
94#include "util.h"
95
96/* #define DEBUG_PDU 1 */
97/* #define DEBUG_PDU_DECODE 1 */
98/* #define DEBUG_PDU_ENCODE 1 */
99
100#define ASN_PARSE_ERROR(x) { snmpInASNParseErrs_Add(1); return(x); }
101
102/**********************************************************************/
103
104/* Create a PDU.
105 */
106
107struct snmp_pdu *snmp_pdu_create(int command)
108{
109 struct snmp_pdu *pdu;
110
111#ifdef DEBUG_PDU
112 snmplib_debug(8,"PDU: Creating\n");
113#endif
114
115 pdu = (struct snmp_pdu *)xmalloc(sizeof(struct snmp_pdu));
116 if (pdu == NULL) {
117 snmp_set_api_error(SNMPERR_OS_ERR);
118 return(NULL);
119 }
120
121 memset((char *)pdu, '\0', sizeof(struct snmp_pdu));
122
123 pdu->command = command;
124 pdu->errstat = SNMP_DEFAULT_ERRSTAT;
125 pdu->errindex = SNMP_DEFAULT_ERRINDEX;
126 pdu->address.sin_addr.s_addr = SNMP_DEFAULT_ADDRESS;
127 pdu->enterprise = NULL;
128 pdu->enterprise_length = 0;
129 pdu->variables = NULL;
130
131#ifdef DEBUG_PDU
132 snmplib_debug(8,"PDU: Created %x\n", (unsigned int)pdu);
133#endif
134
135 return(pdu);
136}
137
138/**********************************************************************/
139
140/* Clone an existing PDU.
141 */
142struct snmp_pdu *snmp_pdu_clone(struct snmp_pdu *Src)
143{
144 struct snmp_pdu *Dest;
145
146#ifdef DEBUG_PDU
147 snmplib_debug(8,"PDU %x: Cloning\n", (unsigned int)Src);
148#endif
149
150 Dest = (struct snmp_pdu *)xmalloc(sizeof(struct snmp_pdu));
151 if (Dest == NULL) {
152 snmp_set_api_error(SNMPERR_OS_ERR);
153 return(NULL);
154 }
155 xmemcpy((char *)Dest, (char *)Src, sizeof(struct snmp_pdu));
156
157#ifdef DEBUG_PDU
158 snmplib_debug(8,"PDU %x: Created %x\n", (unsigned int)Src, (unsigned int)Dest);
159#endif
160 return(Dest);
161}
162
163/**********************************************************************/
164
165/*
166 * If there was an error in the input pdu, creates a clone of the pdu
167 * that includes all the variables except the one marked by the errindex.
168 * The command is set to the input command and the reqid, errstat, and
169 * errindex are set to default values.
170 * If the error status didn't indicate an error, the error index didn't
171 * indicate a variable, the pdu wasn't a get response message, or there
172 * would be no remaining variables, this function will return NULL.
173 * If everything was successful, a pointer to the fixed cloned pdu will
174 * be returned.
175 */
176struct snmp_pdu *snmp_pdu_fix(struct snmp_pdu *pdu, int command)
177{
178 return(snmp_fix_pdu(pdu, command));
179}
180
181struct snmp_pdu *snmp_fix_pdu(struct snmp_pdu *pdu, int command)
182{
183 struct variable_list *var, *newvar;
184 struct snmp_pdu *newpdu;
185 int index;
186 int copied = 0;
187
188#ifdef DEBUG_PDU
189 snmplib_debug(8,"PDU %x: Fixing. Err index is %d\n",
190 (unsigned int)pdu, (unsigned int)pdu->errindex);
191#endif
192
193 if (pdu->command != SNMP_PDU_RESPONSE ||
194 pdu->errstat == SNMP_ERR_NOERROR ||
195 pdu->errindex <= 0) {
196 snmp_set_api_error(SNMPERR_UNABLE_TO_FIX);
197 return(NULL);
198 }
199
200 /* clone the pdu */
201 newpdu = snmp_pdu_clone(pdu);
202 if (newpdu == NULL)
203 return(NULL);
204
205 newpdu->variables = 0;
206 newpdu->command = command;
207 newpdu->reqid = SNMP_DEFAULT_REQID;
208 newpdu->errstat = SNMP_DEFAULT_ERRSTAT;
209 newpdu->errindex = SNMP_DEFAULT_ERRINDEX;
210
211 /* Loop through the variables, removing whatever isn't necessary */
212
213 var = pdu->variables;
214 index = 1;
215
216 /* skip first variable if necessary*/
217 if (pdu->errindex == index) {
218 var = var->next_variable;
219 index++;
220 }
221
222 if (var != NULL) {
223
224 /* VAR is the first uncopied variable */
225
226 /* Clone this variable */
227 newpdu->variables = snmp_var_clone(var);
228 if (newpdu->variables == NULL) {
229 snmp_pdu_free(newpdu);
230 return(NULL);
231 }
232 copied++;
233
234 newvar = newpdu->variables;
235
236 /* VAR has been copied to NEWVAR. */
237 while(var->next_variable) {
238
239 /* Skip the item that was bad */
240 if (++index == pdu->errindex) {
241 var = var->next_variable;
242 continue;
243 }
244
245 /* Copy this var */
246 newvar->next_variable = snmp_var_clone(var->next_variable);
247 if (newvar->next_variable == NULL) {
248 snmp_pdu_free(newpdu);
249 return(NULL);
250 }
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
260 /* If we didn't copy anything, free the new pdu. */
261 if (index < pdu->errindex || copied == 0) {
262 snmp_free_pdu(newpdu);
263 snmp_set_api_error(SNMPERR_UNABLE_TO_FIX);
264 return(NULL);
265 }
266
267#ifdef DEBUG_PDU
268 snmplib_debug(8,"PDU %x: Fixed PDU is %x\n",
269 (unsigned int)pdu, (unsigned int)newpdu);
270#endif
271 return(newpdu);
272}
273
274
275/**********************************************************************/
276
277void snmp_pdu_free(struct snmp_pdu *pdu)
278{
279 snmp_free_pdu(pdu);
280}
281
282/*
283 * Frees the pdu and any xmalloc'd data associated with it.
284 */
285void snmp_free_pdu(struct snmp_pdu *pdu)
286{
287 struct variable_list *vp, *ovp;
288
289 vp = pdu->variables;
290 while(vp) {
291 ovp = vp;
292 vp = vp->next_variable;
293 snmp_var_free(ovp);
294 }
295
296 if (pdu->enterprise)
297 xfree((char *)pdu->enterprise);
298 xfree((char *)pdu);
299}
300
301/**********************************************************************/
302
303/* Encode this PDU into DestBuf.
304 *
305 * Returns a pointer to the next byte in the buffer (where the Variable
306 * Bindings belong.)
307 */
308
309/*
310 * RFC 1902: Structure of Management Information for SNMPv2
311 *
312 * PDU ::=
313 * SEQUENCE {
314 * request-id INTEGER32
315 * error-status INTEGER
316 * error-index INTEGER
317 * Variable Bindings
318 * }
319 *
320 * BulkPDU ::=
321 * SEQUENCE {
322 * request-id INTEGER32
323 * non-repeaters INTEGER
324 * max-repetitions INTEGER
325 * Variable Bindings
326 * }
327 */
328
329/*
330 * RFC 1157: A Simple Network Management Protocol (SNMP)
331 *
332 * PDU ::=
333 * SEQUENCE {
334 * request-id INTEGER
335 * error-status INTEGER
336 * error-index INTEGER
337 * Variable Bindings
338 * }
339 *
340 * TrapPDU ::=
341 * SEQUENCE {
342 * enterprise NetworkAddress
343 * generic-trap INTEGER
344 * specific-trap INTEGER
345 * time-stamp TIMETICKS
346 * Variable Bindings
347 * }
348 */
349
350u_char *snmp_pdu_encode(u_char *DestBuf, int *DestBufLen,
351 struct snmp_pdu *PDU)
352{
353 u_char *bufp;
354
355#ifdef 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
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
406 /**********************************************************************/
407
408 case SNMP_PDU_GETBULK:
409
410 /* SNMPv2 Bulk Request */
411
412 /* request id */
413 bufp = asn_build_int(DestBuf, DestBufLen,
414 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
415 &PDU->reqid, sizeof(PDU->reqid));
416 if (bufp == NULL)
417 return(NULL);
418
419 /* non-repeaters */
420 bufp = asn_build_int(bufp, DestBufLen,
421 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
422 &PDU->non_repeaters,
423 sizeof(PDU->non_repeaters));
424 if (bufp == NULL)
425 return(NULL);
426
427 /* max-repetitions */
428 bufp = asn_build_int(bufp, DestBufLen,
429 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
430 &PDU->max_repetitions,
431 sizeof(PDU->max_repetitions));
432 if (bufp == NULL)
433 return(NULL);
434 break;
435
436 /**********************************************************************/
437
438 default:
439
440 /* Normal PDU Encoding */
441
442 /* request id */
443#ifdef DEBUG_PDU_ENCODE
444 snmplib_debug(8,"PDU: Request ID %d (0x%x)\n", PDU->reqid, DestBuf);
445#endif
446 bufp = asn_build_int(DestBuf, DestBufLen,
447 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
448 &PDU->reqid, sizeof(PDU->reqid));
449 if (bufp == NULL)
450 return(NULL);
451
452 /* error status */
453#ifdef DEBUG_PDU_ENCODE
454 snmplib_debug(8,"PDU: Error Status %d (0x%x)\n", PDU->errstat, bufp);
455#endif
456 bufp = asn_build_int(bufp, DestBufLen,
457 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
458 &PDU->errstat, sizeof(PDU->errstat));
459 if (bufp == NULL)
460 return(NULL);
461
462 /* error index */
463#ifdef DEBUG_PDU_ENCODE
464 snmplib_debug(8,"PDU: Error index %d (0x%x)\n", PDU->errindex, bufp);
465#endif
466 bufp = asn_build_int(bufp, DestBufLen,
467 (u_char)(ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER),
468 &PDU->errindex, sizeof(PDU->errindex));
469 if (bufp == NULL)
470 return(NULL);
471 break;
472 } /* End of encoding */
473
474 return(bufp);
475}
476
477/**********************************************************************/
478
479/* Decodes PDU from Packet into PDU.
480 *
481 * Returns a pointer to the next byte of the packet, which is where the
482 * Variable Bindings start.
483 */
484u_char *snmp_pdu_decode(u_char *Packet, /* data */
485 int *Length, /* &length */
486 struct snmp_pdu *PDU) /* pdu */
487{
488 u_char *bufp;
489 u_char PDUType;
490 int four;
491 u_char ASNType;
492 oid objid[MAX_NAME_LEN];
493
494 bufp = asn_parse_header(Packet, Length, &PDUType);
495 if (bufp == NULL)
496 ASN_PARSE_ERROR(NULL);
497
498#ifdef DEBUG_PDU_DECODE
499 snmplib_debug(8,"PDU Type: %d\n", PDUType);
500#endif
501
502 PDU->command = PDUType;
503 switch (PDUType) {
504
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
522 xmemcpy((char *)PDU->enterprise, (char *)objid,
523 PDU->enterprise_length * sizeof(oid));
524
525 /* Agent-addr */
526 four = 4;
527 bufp = asn_parse_string(bufp, Length,
528 &ASNType,
529 (u_char *)&PDU->agent_addr.sin_addr.s_addr,
530 &four);
531 if (bufp == NULL)
532 ASN_PARSE_ERROR(NULL);
533
534 /* Generic trap */
535 bufp = asn_parse_int(bufp, Length,
536 &ASNType,
537 (int *)&PDU->trap_type,
538 sizeof(PDU->trap_type));
539 if (bufp == NULL)
540 ASN_PARSE_ERROR(NULL);
541
542 /* Specific Trap */
543 bufp = asn_parse_int(bufp, Length,
544 &ASNType,
545 (int *)&PDU->specific_type,
546 sizeof(PDU->specific_type));
547 if (bufp == NULL)
548 ASN_PARSE_ERROR(NULL);
549
550 /* Timestamp */
551 bufp = asn_parse_unsigned_int(bufp, Length,
552 &ASNType,
553 &PDU->time, sizeof(PDU->time));
554 if (bufp == NULL)
555 ASN_PARSE_ERROR(NULL);
556 break;
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
585 break;
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
632char *snmp_pdu_type(struct snmp_pdu *PDU)
633{
634 switch(PDU->command) {
635 case SNMP_PDU_GET:
636 return("GET");
637 break;
638 case SNMP_PDU_GETNEXT:
639 return("GETNEXT");
640 break;
641 case SNMP_PDU_RESPONSE:
642 return("RESPONSE");
643 break;
644 case SNMP_PDU_SET:
645 return("SET");
646 break;
647 case SNMP_PDU_GETBULK:
648 return("GETBULK");
649 break;
650 case SNMP_PDU_INFORM:
651 return("INFORM");
652 break;
653 case SNMP_PDU_V2TRAP:
654 return("V2TRAP");
655 break;
656 case SNMP_PDU_REPORT:
657 return("REPORT");
658 break;
659
660 case TRP_REQ_MSG:
661 return("V1TRAP");
662 break;
663 default:
664 return("Unknown");
665 break;
666 }
667}
668
669/*
670 * Add a null variable with the requested name to the end of the list of
671 * variables for this pdu.
672 */
673void snmp_add_null_var(struct snmp_pdu *pdu, oid *name, int name_length)
674{
675 struct variable_list *vars;
676 struct variable_list *ptr;
677
678 vars = snmp_var_new(name, name_length);
679 if (vars == NULL) {
680 perror("snmp_add_null_var:xmalloc");
681 return;
682 }
683
684 if (pdu->variables == NULL) {
685 pdu->variables = vars;
686 } else {
687
688 /* Insert at the end */
689 for (ptr = pdu->variables;
690 ptr->next_variable;
691 ptr = ptr->next_variable)
692 /*EXIT*/;
693 ptr->next_variable = vars;
694 }
695
696 return;
697}
698