]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/bsnmp/lib/snmp.c
MFstable/11 r310901:
[FreeBSD/stable/10.git] / contrib / bsnmp / lib / snmp.c
1 /*
2  * Copyright (c) 2001-2003
3  *      Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4  *      All rights reserved.
5  *
6  * Author: Harti Brandt <harti@freebsd.org>
7  *
8  * Copyright (c) 2010 The FreeBSD Foundation
9  * All rights reserved.
10  *
11  * Portions of this software were developed by Shteryana Sotirova Shopova
12  * under sponsorship from the FreeBSD Foundation.
13  *
14  * Redistribution and use in source and binary forms, with or without
15  * modification, are permitted provided that the following conditions
16  * are met:
17  * 1. Redistributions of source code must retain the above copyright
18  *    notice, this list of conditions and the following disclaimer.
19  * 2. Redistributions in binary form must reproduce the above copyright
20  *    notice, this list of conditions and the following disclaimer in the
21  *    documentation and/or other materials provided with the distribution.
22  *
23  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  * $Begemot: bsnmp/lib/snmp.c,v 1.40 2005/10/04 14:32:42 brandt_h Exp $
36  *
37  * SNMP
38  */
39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <ctype.h>
42 #include <errno.h>
43 #include <netdb.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <stddef.h>
47 #include <stdarg.h>
48 #include <string.h>
49 #ifdef HAVE_STDINT_H
50 #include <stdint.h>
51 #elif defined(HAVE_INTTYPES_H)
52 #include <inttypes.h>
53 #endif
54
55 #include "asn1.h"
56 #include "snmp.h"
57 #include "snmppriv.h"
58
59 static void snmp_error_func(const char *, ...);
60 static void snmp_printf_func(const char *, ...);
61
62 void (*snmp_error)(const char *, ...) = snmp_error_func;
63 void (*snmp_printf)(const char *, ...) = snmp_printf_func;
64
65 /*
66  * Get the next variable binding from the list.
67  * ASN errors on the sequence or the OID are always fatal.
68  */
69 static enum asn_err
70 get_var_binding(struct asn_buf *b, struct snmp_value *binding)
71 {
72         u_char type;
73         asn_len_t len, trailer;
74         enum asn_err err;
75
76         if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
77                 snmp_error("cannot parse varbind header");
78                 return (ASN_ERR_FAILED);
79         }
80
81         /* temporary truncate the length so that the parser does not
82          * eat up bytes behind the sequence in the case the encoding is
83          * wrong of inner elements. */
84         trailer = b->asn_len - len;
85         b->asn_len = len;
86
87         if (asn_get_objid(b, &binding->var) != ASN_ERR_OK) {
88                 snmp_error("cannot parse binding objid");
89                 return (ASN_ERR_FAILED);
90         }
91         if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
92                 snmp_error("cannot parse binding value header");
93                 return (ASN_ERR_FAILED);
94         }
95
96         switch (type) {
97
98           case ASN_TYPE_NULL:
99                 binding->syntax = SNMP_SYNTAX_NULL;
100                 err = asn_get_null_raw(b, len);
101                 break;
102
103           case ASN_TYPE_INTEGER:
104                 binding->syntax = SNMP_SYNTAX_INTEGER;
105                 err = asn_get_integer_raw(b, len, &binding->v.integer);
106                 break;
107
108           case ASN_TYPE_OCTETSTRING:
109                 binding->syntax = SNMP_SYNTAX_OCTETSTRING;
110                 binding->v.octetstring.octets = malloc(len);
111                 if (binding->v.octetstring.octets == NULL) {
112                         snmp_error("%s", strerror(errno));
113                         return (ASN_ERR_FAILED);
114                 }
115                 binding->v.octetstring.len = len;
116                 err = asn_get_octetstring_raw(b, len,
117                     binding->v.octetstring.octets,
118                     &binding->v.octetstring.len);
119                 if (ASN_ERR_STOPPED(err)) {
120                         free(binding->v.octetstring.octets);
121                         binding->v.octetstring.octets = NULL;
122                 }
123                 break;
124
125           case ASN_TYPE_OBJID:
126                 binding->syntax = SNMP_SYNTAX_OID;
127                 err = asn_get_objid_raw(b, len, &binding->v.oid);
128                 break;
129
130           case ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS:
131                 binding->syntax = SNMP_SYNTAX_IPADDRESS;
132                 err = asn_get_ipaddress_raw(b, len, binding->v.ipaddress);
133                 break;
134
135           case ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS:
136                 binding->syntax = SNMP_SYNTAX_TIMETICKS;
137                 err = asn_get_uint32_raw(b, len, &binding->v.uint32);
138                 break;
139
140           case ASN_CLASS_APPLICATION|ASN_APP_COUNTER:
141                 binding->syntax = SNMP_SYNTAX_COUNTER;
142                 err = asn_get_uint32_raw(b, len, &binding->v.uint32);
143                 break;
144
145           case ASN_CLASS_APPLICATION|ASN_APP_GAUGE:
146                 binding->syntax = SNMP_SYNTAX_GAUGE;
147                 err = asn_get_uint32_raw(b, len, &binding->v.uint32);
148                 break;
149
150           case ASN_CLASS_APPLICATION|ASN_APP_COUNTER64:
151                 binding->syntax = SNMP_SYNTAX_COUNTER64;
152                 err = asn_get_counter64_raw(b, len, &binding->v.counter64);
153                 break;
154
155           case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHOBJECT:
156                 binding->syntax = SNMP_SYNTAX_NOSUCHOBJECT;
157                 err = asn_get_null_raw(b, len);
158                 break;
159
160           case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHINSTANCE:
161                 binding->syntax = SNMP_SYNTAX_NOSUCHINSTANCE;
162                 err = asn_get_null_raw(b, len);
163                 break;
164
165           case ASN_CLASS_CONTEXT | ASN_EXCEPT_ENDOFMIBVIEW:
166                 binding->syntax = SNMP_SYNTAX_ENDOFMIBVIEW;
167                 err = asn_get_null_raw(b, len);
168                 break;
169
170           default:
171                 if ((err = asn_skip(b, len)) == ASN_ERR_OK)
172                         err = ASN_ERR_TAG;
173                 snmp_error("bad binding value type 0x%x", type);
174                 break;
175         }
176
177         if (ASN_ERR_STOPPED(err)) {
178                 snmp_error("cannot parse binding value");
179                 return (err);
180         }
181
182         if (b->asn_len != 0)
183                 snmp_error("ignoring junk at end of binding");
184
185         b->asn_len = trailer;
186
187         return (err);
188 }
189
190 /*
191  * Parse the different PDUs contents. Any ASN error in the outer components
192  * are fatal. Only errors in variable values may be tolerated. If all
193  * components can be parsed it returns either ASN_ERR_OK or the first
194  * error that was found.
195  */
196 enum asn_err
197 snmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp)
198 {
199         if (pdu->type == SNMP_PDU_TRAP) {
200                 if (asn_get_objid(b, &pdu->enterprise) != ASN_ERR_OK) {
201                         snmp_error("cannot parse trap enterprise");
202                         return (ASN_ERR_FAILED);
203                 }
204                 if (asn_get_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK) {
205                         snmp_error("cannot parse trap agent address");
206                         return (ASN_ERR_FAILED);
207                 }
208                 if (asn_get_integer(b, &pdu->generic_trap) != ASN_ERR_OK) {
209                         snmp_error("cannot parse 'generic-trap'");
210                         return (ASN_ERR_FAILED);
211                 }
212                 if (asn_get_integer(b, &pdu->specific_trap) != ASN_ERR_OK) {
213                         snmp_error("cannot parse 'specific-trap'");
214                         return (ASN_ERR_FAILED);
215                 }
216                 if (asn_get_timeticks(b, &pdu->time_stamp) != ASN_ERR_OK) {
217                         snmp_error("cannot parse trap 'time-stamp'");
218                         return (ASN_ERR_FAILED);
219                 }
220         } else {
221                 if (asn_get_integer(b, &pdu->request_id) != ASN_ERR_OK) {
222                         snmp_error("cannot parse 'request-id'");
223                         return (ASN_ERR_FAILED);
224                 }
225                 if (asn_get_integer(b, &pdu->error_status) != ASN_ERR_OK) {
226                         snmp_error("cannot parse 'error_status'");
227                         return (ASN_ERR_FAILED);
228                 }
229                 if (asn_get_integer(b, &pdu->error_index) != ASN_ERR_OK) {
230                         snmp_error("cannot parse 'error_index'");
231                         return (ASN_ERR_FAILED);
232                 }
233         }
234
235         if (asn_get_sequence(b, lenp) != ASN_ERR_OK) {
236                 snmp_error("cannot get varlist header");
237                 return (ASN_ERR_FAILED);
238         }
239
240         return (ASN_ERR_OK);
241 }
242
243 static enum asn_err
244 parse_pdus(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
245 {
246         asn_len_t len, trailer;
247         struct snmp_value *v;
248         enum asn_err err, err1;
249
250         err = snmp_parse_pdus_hdr(b, pdu, &len);
251         if (ASN_ERR_STOPPED(err))
252                 return (err);
253
254         trailer = b->asn_len - len;
255
256         v = pdu->bindings;
257         err = ASN_ERR_OK;
258         while (b->asn_len != 0) {
259                 if (pdu->nbindings == SNMP_MAX_BINDINGS) {
260                         snmp_error("too many bindings (> %u) in PDU",
261                             SNMP_MAX_BINDINGS);
262                         return (ASN_ERR_FAILED);
263                 }
264                 err1 = get_var_binding(b, v);
265                 if (ASN_ERR_STOPPED(err1))
266                         return (ASN_ERR_FAILED);
267                 if (err1 != ASN_ERR_OK && err == ASN_ERR_OK) {
268                         err = err1;
269                         *ip = pdu->nbindings + 1;
270                 }
271                 pdu->nbindings++;
272                 v++;
273         }
274
275         b->asn_len = trailer;
276
277         return (err);
278 }
279
280
281 static enum asn_err
282 parse_secparams(struct asn_buf *b, struct snmp_pdu *pdu)
283 {
284         asn_len_t octs_len;
285         u_char buf[256]; /* XXX: calc max possible size here */
286         struct asn_buf tb;
287
288         memset(buf, 0, 256);
289         tb.asn_ptr = buf;
290         tb.asn_len = 256;
291         u_int len;
292
293         if (asn_get_octetstring(b, buf, &len) != ASN_ERR_OK) {
294                 snmp_error("cannot parse usm header");
295                 return (ASN_ERR_FAILED);
296         }
297         tb.asn_len = len;
298
299         if (asn_get_sequence(&tb, &octs_len) != ASN_ERR_OK) {
300                 snmp_error("cannot decode usm header");
301                 return (ASN_ERR_FAILED);
302         }
303
304         octs_len = SNMP_ENGINE_ID_SIZ;
305         if (asn_get_octetstring(&tb, (u_char *)&pdu->engine.engine_id,
306             &octs_len) != ASN_ERR_OK) {
307                 snmp_error("cannot decode msg engine id");
308                 return (ASN_ERR_FAILED);
309         }
310         pdu->engine.engine_len = octs_len;
311
312         if (asn_get_integer(&tb, &pdu->engine.engine_boots) != ASN_ERR_OK) {
313                 snmp_error("cannot decode msg engine boots");
314                 return (ASN_ERR_FAILED);
315         }
316
317         if (asn_get_integer(&tb, &pdu->engine.engine_time) != ASN_ERR_OK) {
318                 snmp_error("cannot decode msg engine time");
319                 return (ASN_ERR_FAILED);
320         }
321
322         octs_len = SNMP_ADM_STR32_SIZ - 1;
323         if (asn_get_octetstring(&tb, (u_char *)&pdu->user.sec_name, &octs_len)
324             != ASN_ERR_OK) {
325                 snmp_error("cannot decode msg user name");
326                 return (ASN_ERR_FAILED);
327         }
328         pdu->user.sec_name[octs_len] = '\0';
329
330         octs_len = sizeof(pdu->msg_digest);
331         if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_digest, &octs_len) !=
332             ASN_ERR_OK || ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0 &&
333             octs_len != sizeof(pdu->msg_digest))) {
334                 snmp_error("cannot decode msg authentication param");
335                 return (ASN_ERR_FAILED);
336         }
337
338         octs_len = sizeof(pdu->msg_salt);
339         if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_salt, &octs_len) !=
340             ASN_ERR_OK ||((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 &&
341             octs_len != sizeof(pdu->msg_salt))) {
342                 snmp_error("cannot decode msg authentication param");
343                 return (ASN_ERR_FAILED);
344         }
345
346         if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) {
347                 pdu->digest_ptr = b->asn_ptr - SNMP_USM_AUTH_SIZE;
348                 pdu->digest_ptr -= octs_len + ASN_MAXLENLEN;
349         }
350
351         return (ASN_ERR_OK);
352 }
353
354 static enum snmp_code
355 pdu_encode_secparams(struct asn_buf *b, struct snmp_pdu *pdu)
356 {
357         u_char buf[256], *sptr;
358         struct asn_buf tb;
359         size_t auth_off, moved = 0;
360
361         auth_off = 0;
362         memset(buf, 0, 256);
363         tb.asn_ptr = buf;
364         tb.asn_len = 256;
365
366         if (asn_put_temp_header(&tb, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
367             &sptr) != ASN_ERR_OK)
368                 return (SNMP_CODE_FAILED);
369
370         if (asn_put_octetstring(&tb, (u_char *)pdu->engine.engine_id,
371             pdu->engine.engine_len) != ASN_ERR_OK)
372                 return (SNMP_CODE_FAILED);
373
374         if (asn_put_integer(&tb, pdu->engine.engine_boots) != ASN_ERR_OK)
375                 return (SNMP_CODE_FAILED);
376
377         if (asn_put_integer(&tb, pdu->engine.engine_time) != ASN_ERR_OK)
378                 return (SNMP_CODE_FAILED);
379
380         if (asn_put_octetstring(&tb, (u_char *)pdu->user.sec_name,
381             strlen(pdu->user.sec_name)) != ASN_ERR_OK)
382                 return (SNMP_CODE_FAILED);
383
384         if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) {
385                 auth_off = sizeof(buf) - tb.asn_len + ASN_MAXLENLEN;
386                 if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest,
387                     sizeof(pdu->msg_digest)) != ASN_ERR_OK)
388                         return (SNMP_CODE_FAILED);
389         } else {
390                 if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest, 0)
391                     != ASN_ERR_OK)
392                         return (SNMP_CODE_FAILED);
393         }
394
395         if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0) {
396                 if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt,
397                     sizeof(pdu->msg_salt)) != ASN_ERR_OK)
398                         return (SNMP_CODE_FAILED);
399         } else {
400                 if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt, 0)
401                     != ASN_ERR_OK)
402                         return (SNMP_CODE_FAILED);
403         }
404
405         if (asn_commit_header(&tb, sptr, &moved) != ASN_ERR_OK)
406                 return (SNMP_CODE_FAILED);
407
408         if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0)
409                 pdu->digest_ptr = b->asn_ptr + auth_off - moved;
410
411         if (asn_put_octetstring(b, buf, sizeof(buf) - tb.asn_len) != ASN_ERR_OK)
412                 return (SNMP_CODE_FAILED);
413         pdu->digest_ptr += ASN_MAXLENLEN;
414
415         if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && asn_put_temp_header(b,
416             ASN_TYPE_OCTETSTRING, &pdu->encrypted_ptr) != ASN_ERR_OK)
417                         return (SNMP_CODE_FAILED);
418
419         return (SNMP_CODE_OK);
420 }
421
422 /*
423  * Decode the PDU except for the variable bindings itself.
424  * If decoding fails because of a bad binding, but the rest can be
425  * decoded, ip points to the index of the failed variable (errors
426  * OORANGE, BADLEN or BADVERS).
427  */
428 enum snmp_code
429 snmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
430 {
431         enum snmp_code code;
432
433         if ((code = snmp_pdu_decode_header(b, pdu)) != SNMP_CODE_OK)
434                 return (code);
435
436         if (pdu->version == SNMP_V3) {
437                 if (pdu->security_model != SNMP_SECMODEL_USM)
438                         return (SNMP_CODE_FAILED);
439                 if ((code = snmp_pdu_decode_secmode(b, pdu)) != SNMP_CODE_OK)
440                         return (code);
441         }
442
443         code = snmp_pdu_decode_scoped(b, pdu, ip);
444
445         switch (code) {
446           case SNMP_CODE_FAILED:
447                 snmp_pdu_free(pdu);
448                 break;
449
450           case SNMP_CODE_BADENC:
451                 if (pdu->version == SNMP_Verr)
452                         return (SNMP_CODE_BADVERS);
453
454           default:
455                 break;
456         }
457
458         return (code);
459 }
460
461 enum snmp_code
462 snmp_pdu_decode_header(struct asn_buf *b, struct snmp_pdu *pdu)
463 {
464         int32_t version;
465         u_int octs_len;
466         asn_len_t len;
467
468         pdu->outer_ptr = b->asn_ptr;
469         pdu->outer_len = b->asn_len;
470
471         if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
472                 snmp_error("cannot decode pdu header");
473                 return (SNMP_CODE_FAILED);
474         }
475         if (b->asn_len < len) {
476                 snmp_error("outer sequence value too short");
477                 return (SNMP_CODE_FAILED);
478         }
479         if (b->asn_len != len) {
480                 snmp_error("ignoring trailing junk in message");
481                 b->asn_len = len;
482         }
483
484         if (asn_get_integer(b, &version) != ASN_ERR_OK) {
485                 snmp_error("cannot decode version");
486                 return (SNMP_CODE_FAILED);
487         }
488
489         if (version == 0)
490                 pdu->version = SNMP_V1;
491         else if (version == 1)
492                 pdu->version = SNMP_V2c;
493         else if (version == 3)
494                 pdu->version = SNMP_V3;
495         else {
496                 pdu->version = SNMP_Verr;
497                 snmp_error("unsupported SNMP version");
498                 return (SNMP_CODE_BADENC);
499         }
500
501         if (pdu->version == SNMP_V3) {
502                 if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
503                         snmp_error("cannot decode pdu global data header");
504                         return (SNMP_CODE_FAILED);
505                 }
506
507                 if (asn_get_integer(b, &pdu->identifier) != ASN_ERR_OK) {
508                         snmp_error("cannot decode msg indetifier");
509                         return (SNMP_CODE_FAILED);
510                 }
511
512                 if (asn_get_integer(b, &pdu->engine.max_msg_size)
513                     != ASN_ERR_OK) {
514                         snmp_error("cannot decode msg size");
515                         return (SNMP_CODE_FAILED);
516                 }
517
518                 octs_len = 1;
519                 if (asn_get_octetstring(b, (u_char *)&pdu->flags,
520                     &octs_len) != ASN_ERR_OK) {
521                         snmp_error("cannot decode msg flags");
522                         return (SNMP_CODE_FAILED);
523                 }
524
525                 if (asn_get_integer(b, &pdu->security_model) != ASN_ERR_OK) {
526                         snmp_error("cannot decode msg size");
527                         return (SNMP_CODE_FAILED);
528                 }
529
530                 if (pdu->security_model != SNMP_SECMODEL_USM)
531                         return (SNMP_CODE_FAILED);
532
533                 if (parse_secparams(b, pdu) != ASN_ERR_OK)
534                         return (SNMP_CODE_FAILED);
535         } else {
536                 octs_len = SNMP_COMMUNITY_MAXLEN;
537                 if (asn_get_octetstring(b, (u_char *)pdu->community,
538                     &octs_len) != ASN_ERR_OK) {
539                         snmp_error("cannot decode community");
540                         return (SNMP_CODE_FAILED);
541                 }
542                 pdu->community[octs_len] = '\0';
543         }
544
545         return (SNMP_CODE_OK);
546 }
547
548 enum snmp_code
549 snmp_pdu_decode_scoped(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
550 {
551         u_char type;
552         asn_len_t len, trailer;
553         enum asn_err err;
554
555         if (pdu->version == SNMP_V3) {
556                 if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
557                         snmp_error("cannot decode scoped pdu header");
558                         return (SNMP_CODE_FAILED);
559                 }
560
561                 len = SNMP_ENGINE_ID_SIZ;
562                 if (asn_get_octetstring(b, (u_char *)&pdu->context_engine,
563                     &len) != ASN_ERR_OK) {
564                         snmp_error("cannot decode msg context engine");
565                         return (SNMP_CODE_FAILED);
566                 }
567                 pdu->context_engine_len = len;
568
569                 len = SNMP_CONTEXT_NAME_SIZ;
570                 if (asn_get_octetstring(b, (u_char *)&pdu->context_name,
571                     &len) != ASN_ERR_OK) {
572                         snmp_error("cannot decode msg context name");
573                         return (SNMP_CODE_FAILED);
574                 }
575                 pdu->context_name[len] = '\0';
576         }
577
578         if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
579                 snmp_error("cannot get pdu header");
580                 return (SNMP_CODE_FAILED);
581         }
582         if ((type & ~ASN_TYPE_MASK) !=
583             (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) {
584                 snmp_error("bad pdu header tag");
585                 return (SNMP_CODE_FAILED);
586         }
587         pdu->type = type & ASN_TYPE_MASK;
588
589         switch (pdu->type) {
590
591           case SNMP_PDU_GET:
592           case SNMP_PDU_GETNEXT:
593           case SNMP_PDU_RESPONSE:
594           case SNMP_PDU_SET:
595                 break;
596
597           case SNMP_PDU_TRAP:
598                 if (pdu->version != SNMP_V1) {
599                         snmp_error("bad pdu type %u", pdu->type);
600                         return (SNMP_CODE_FAILED);
601                 }
602                 break;
603
604           case SNMP_PDU_GETBULK:
605           case SNMP_PDU_INFORM:
606           case SNMP_PDU_TRAP2:
607           case SNMP_PDU_REPORT:
608                 if (pdu->version == SNMP_V1) {
609                         snmp_error("bad pdu type %u", pdu->type);
610                         return (SNMP_CODE_FAILED);
611                 }
612                 break;
613
614           default:
615                 snmp_error("bad pdu type %u", pdu->type);
616                 return (SNMP_CODE_FAILED);
617         }
618
619         trailer = b->asn_len - len;
620         b->asn_len = len;
621
622         err = parse_pdus(b, pdu, ip);
623         if (ASN_ERR_STOPPED(err))
624                 return (SNMP_CODE_FAILED);
625
626         if (b->asn_len != 0)
627                 snmp_error("ignoring trailing junk after pdu");
628
629         b->asn_len = trailer;
630
631         return (SNMP_CODE_OK);
632 }
633
634 enum snmp_code
635 snmp_pdu_decode_secmode(struct asn_buf *b, struct snmp_pdu *pdu)
636 {
637         u_char type;
638         enum snmp_code code;
639         uint8_t digest[SNMP_USM_AUTH_SIZE];
640
641         if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH &&
642             (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0)
643                 return (SNMP_CODE_BADSECLEVEL);
644
645         if ((code = snmp_pdu_calc_digest(pdu, digest)) !=
646             SNMP_CODE_OK)
647                 return (SNMP_CODE_FAILED);
648
649         if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH &&
650             memcmp(digest, pdu->msg_digest, sizeof(pdu->msg_digest)) != 0)
651                 return (SNMP_CODE_BADDIGEST);
652
653         if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV && (asn_get_header(b, &type,
654             &pdu->scoped_len) != ASN_ERR_OK || type != ASN_TYPE_OCTETSTRING)) {
655                 snmp_error("cannot decode encrypted pdu");
656                 return (SNMP_CODE_FAILED);
657         }
658         pdu->scoped_ptr = b->asn_ptr;
659
660         if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV &&
661             (pdu->flags & SNMP_MSG_PRIV_FLAG) == 0)
662                 return (SNMP_CODE_BADSECLEVEL);
663
664         if ((code = snmp_pdu_decrypt(pdu)) != SNMP_CODE_OK)
665                 return (SNMP_CODE_FAILED);
666
667         return (code);
668 }
669
670 /*
671  * Check whether what we have is the complete PDU by snooping at the
672  * enclosing structure header. This returns:
673  *   -1         if there are ASN.1 errors
674  *    0         if we need more data
675  *  > 0         the length of this PDU
676  */
677 int
678 snmp_pdu_snoop(const struct asn_buf *b0)
679 {
680         u_int length;
681         asn_len_t len;
682         struct asn_buf b = *b0;
683
684         /* <0x10|0x20> <len> <data...> */
685
686         if (b.asn_len == 0)
687                 return (0);
688         if (b.asn_cptr[0] != (ASN_TYPE_SEQUENCE | ASN_TYPE_CONSTRUCTED)) {
689                 asn_error(&b, "bad sequence type %u", b.asn_cptr[0]);
690                 return (-1);
691         }
692         b.asn_len--;
693         b.asn_cptr++;
694
695         if (b.asn_len == 0)
696                 return (0);
697
698         if (*b.asn_cptr & 0x80) {
699                 /* long length */
700                 length = *b.asn_cptr++ & 0x7f;
701                 b.asn_len--;
702                 if (length == 0) {
703                         asn_error(&b, "indefinite length not supported");
704                         return (-1);
705                 }
706                 if (length > ASN_MAXLENLEN) {
707                         asn_error(&b, "long length too long (%u)", length);
708                         return (-1);
709                 }
710                 if (length > b.asn_len)
711                         return (0);
712                 len = 0;
713                 while (length--) {
714                         len = (len << 8) | *b.asn_cptr++;
715                         b.asn_len--;
716                 }
717         } else {
718                 len = *b.asn_cptr++;
719                 b.asn_len--;
720         }
721
722         if (len > b.asn_len)
723                 return (0);
724
725         return (len + b.asn_cptr - b0->asn_cptr);
726 }
727
728 /*
729  * Encode the SNMP PDU without the variable bindings field.
730  * We do this the rather uneffective way by
731  * moving things around and assuming that the length field will never
732  * use more than 2 bytes.
733  * We need a number of pointers to apply the fixes afterwards.
734  */
735 enum snmp_code
736 snmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu)
737 {
738         enum asn_err err;
739         u_char *v3_hdr_ptr;
740
741         if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
742             &pdu->outer_ptr) != ASN_ERR_OK)
743                 return (SNMP_CODE_FAILED);
744
745         if (pdu->version == SNMP_V1)
746                 err = asn_put_integer(b, 0);
747         else if (pdu->version == SNMP_V2c)
748                 err = asn_put_integer(b, 1);
749         else if (pdu->version == SNMP_V3)
750                 err = asn_put_integer(b, 3);
751         else
752                 return (SNMP_CODE_BADVERS);
753         if (err != ASN_ERR_OK)
754                 return (SNMP_CODE_FAILED);
755
756         if (pdu->version == SNMP_V3) {
757                 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
758                     ASN_TYPE_CONSTRUCTED), &v3_hdr_ptr) != ASN_ERR_OK)
759                         return (SNMP_CODE_FAILED);
760
761                 if (asn_put_integer(b, pdu->identifier) != ASN_ERR_OK)
762                         return (SNMP_CODE_FAILED);
763
764                 if (asn_put_integer(b, pdu->engine.max_msg_size) != ASN_ERR_OK)
765                         return (SNMP_CODE_FAILED);
766
767                 if (pdu->type != SNMP_PDU_RESPONSE &&
768                     pdu->type != SNMP_PDU_TRAP &&
769                     pdu->type != SNMP_PDU_TRAP2 &&
770                     pdu->type != SNMP_PDU_REPORT)
771                         pdu->flags |= SNMP_MSG_REPORT_FLAG;
772
773                 if (asn_put_octetstring(b, (u_char *)&pdu->flags, 1)
774                     != ASN_ERR_OK)
775                         return (SNMP_CODE_FAILED);
776
777                 if (asn_put_integer(b, pdu->security_model) != ASN_ERR_OK)
778                         return (SNMP_CODE_FAILED);
779
780                 if (asn_commit_header(b, v3_hdr_ptr, NULL) != ASN_ERR_OK)
781                         return (SNMP_CODE_FAILED);
782
783                 if (pdu->security_model != SNMP_SECMODEL_USM)
784                         return (SNMP_CODE_FAILED);
785
786                 if (pdu_encode_secparams(b, pdu) != SNMP_CODE_OK)
787                         return (SNMP_CODE_FAILED);
788
789                 /*  View-based Access Conntrol information */
790                 if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
791                     ASN_TYPE_CONSTRUCTED), &pdu->scoped_ptr) != ASN_ERR_OK)
792                         return (SNMP_CODE_FAILED);
793
794                 if (asn_put_octetstring(b, (u_char *)pdu->context_engine,
795                     pdu->context_engine_len) != ASN_ERR_OK)
796                         return (SNMP_CODE_FAILED);
797
798                 if (asn_put_octetstring(b, (u_char *)pdu->context_name,
799                     strlen(pdu->context_name)) != ASN_ERR_OK)
800                         return (SNMP_CODE_FAILED);
801         } else {
802                 if (asn_put_octetstring(b, (u_char *)pdu->community,
803                     strlen(pdu->community)) != ASN_ERR_OK)
804                         return (SNMP_CODE_FAILED);
805         }
806
807         if (asn_put_temp_header(b, (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT |
808             pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK)
809                 return (SNMP_CODE_FAILED);
810
811         if (pdu->type == SNMP_PDU_TRAP) {
812                 if (pdu->version != SNMP_V1 ||
813                     asn_put_objid(b, &pdu->enterprise) != ASN_ERR_OK ||
814                     asn_put_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK ||
815                     asn_put_integer(b, pdu->generic_trap) != ASN_ERR_OK ||
816                     asn_put_integer(b, pdu->specific_trap) != ASN_ERR_OK ||
817                     asn_put_timeticks(b, pdu->time_stamp) != ASN_ERR_OK)
818                         return (SNMP_CODE_FAILED);
819         } else {
820                 if (pdu->version == SNMP_V1 && (pdu->type == SNMP_PDU_GETBULK ||
821                     pdu->type == SNMP_PDU_INFORM ||
822                     pdu->type == SNMP_PDU_TRAP2 ||
823                     pdu->type == SNMP_PDU_REPORT))
824                         return (SNMP_CODE_FAILED);
825
826                 if (asn_put_integer(b, pdu->request_id) != ASN_ERR_OK ||
827                     asn_put_integer(b, pdu->error_status) != ASN_ERR_OK ||
828                     asn_put_integer(b, pdu->error_index) != ASN_ERR_OK)
829                         return (SNMP_CODE_FAILED);
830         }
831
832         if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
833             &pdu->vars_ptr) != ASN_ERR_OK)
834                 return (SNMP_CODE_FAILED);
835
836         return (SNMP_CODE_OK);
837 }
838
839 static enum asn_err
840 snmp_pdu_fix_padd(struct asn_buf *b, struct snmp_pdu *pdu)
841 {
842         asn_len_t padlen;
843
844         if (pdu->user.priv_proto == SNMP_PRIV_DES && pdu->scoped_len % 8 != 0) {
845                 padlen = 8 - (pdu->scoped_len % 8);
846                 if (asn_pad(b, padlen) != ASN_ERR_OK)
847                         return (ASN_ERR_FAILED);
848                 pdu->scoped_len += padlen;
849         }
850
851         return (ASN_ERR_OK);
852 }
853
854 enum snmp_code
855 snmp_fix_encoding(struct asn_buf *b, struct snmp_pdu *pdu)
856 {
857         size_t moved = 0;
858         enum snmp_code code;
859
860         if (asn_commit_header(b, pdu->vars_ptr, NULL) != ASN_ERR_OK ||
861             asn_commit_header(b, pdu->pdu_ptr, NULL) != ASN_ERR_OK)
862                 return (SNMP_CODE_FAILED);
863
864         if (pdu->version == SNMP_V3) {
865                 if (asn_commit_header(b, pdu->scoped_ptr, NULL) != ASN_ERR_OK)
866                         return (SNMP_CODE_FAILED);
867
868                 pdu->scoped_len = b->asn_ptr - pdu->scoped_ptr;
869                 if (snmp_pdu_fix_padd(b, pdu) != ASN_ERR_OK)
870                         return (SNMP_CODE_FAILED);
871
872                 if (pdu->security_model != SNMP_SECMODEL_USM)
873                         return (SNMP_CODE_FAILED);
874
875                 if (snmp_pdu_encrypt(pdu) != SNMP_CODE_OK)
876                         return (SNMP_CODE_FAILED);
877
878                 if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV &&
879                     asn_commit_header(b, pdu->encrypted_ptr, NULL) != ASN_ERR_OK)
880                         return (SNMP_CODE_FAILED);
881         }
882
883         if (asn_commit_header(b, pdu->outer_ptr, &moved) != ASN_ERR_OK)
884                 return (SNMP_CODE_FAILED);
885
886         pdu->outer_len = b->asn_ptr - pdu->outer_ptr;
887         pdu->digest_ptr -= moved;
888
889         if (pdu->version == SNMP_V3) {
890                 if ((code = snmp_pdu_calc_digest(pdu, pdu->msg_digest)) !=
891                     SNMP_CODE_OK)
892                         return (SNMP_CODE_FAILED);
893
894                 if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0)
895                         memcpy(pdu->digest_ptr, pdu->msg_digest,
896                             sizeof(pdu->msg_digest));
897         }
898
899         return (SNMP_CODE_OK);
900 }
901
902 /*
903  * Encode a binding. Caller must ensure, that the syntax is ok for that version.
904  * Be sure not to cobber b, when something fails.
905  */
906 enum asn_err
907 snmp_binding_encode(struct asn_buf *b, const struct snmp_value *binding)
908 {
909         u_char *ptr;
910         enum asn_err err;
911         struct asn_buf save = *b;
912
913         if ((err = asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
914             ASN_TYPE_CONSTRUCTED), &ptr)) != ASN_ERR_OK) {
915                 *b = save;
916                 return (err);
917         }
918
919         if ((err = asn_put_objid(b, &binding->var)) != ASN_ERR_OK) {
920                 *b = save;
921                 return (err);
922         }
923
924         switch (binding->syntax) {
925
926           case SNMP_SYNTAX_NULL:
927                 err = asn_put_null(b);
928                 break;
929
930           case SNMP_SYNTAX_INTEGER:
931                 err = asn_put_integer(b, binding->v.integer);
932                 break;
933
934           case SNMP_SYNTAX_OCTETSTRING:
935                 err = asn_put_octetstring(b, binding->v.octetstring.octets,
936                     binding->v.octetstring.len);
937                 break;
938
939           case SNMP_SYNTAX_OID:
940                 err = asn_put_objid(b, &binding->v.oid);
941                 break;
942
943           case SNMP_SYNTAX_IPADDRESS:
944                 err = asn_put_ipaddress(b, binding->v.ipaddress);
945                 break;
946
947           case SNMP_SYNTAX_TIMETICKS:
948                 err = asn_put_uint32(b, ASN_APP_TIMETICKS, binding->v.uint32);
949                 break;
950
951           case SNMP_SYNTAX_COUNTER:
952                 err = asn_put_uint32(b, ASN_APP_COUNTER, binding->v.uint32);
953                 break;
954
955           case SNMP_SYNTAX_GAUGE:
956                 err = asn_put_uint32(b, ASN_APP_GAUGE, binding->v.uint32);
957                 break;
958
959           case SNMP_SYNTAX_COUNTER64:
960                 err = asn_put_counter64(b, binding->v.counter64);
961                 break;
962
963           case SNMP_SYNTAX_NOSUCHOBJECT:
964                 err = asn_put_exception(b, ASN_EXCEPT_NOSUCHOBJECT);
965                 break;
966
967           case SNMP_SYNTAX_NOSUCHINSTANCE:
968                 err = asn_put_exception(b, ASN_EXCEPT_NOSUCHINSTANCE);
969                 break;
970
971           case SNMP_SYNTAX_ENDOFMIBVIEW:
972                 err = asn_put_exception(b, ASN_EXCEPT_ENDOFMIBVIEW);
973                 break;
974         }
975
976         if (err != ASN_ERR_OK) {
977                 *b = save;
978                 return (err);
979         }
980
981         err = asn_commit_header(b, ptr, NULL);
982         if (err != ASN_ERR_OK) {
983                 *b = save;
984                 return (err);
985         }
986
987         return (ASN_ERR_OK);
988 }
989
990 /*
991  * Encode an PDU.
992  */
993 enum snmp_code
994 snmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b)
995 {
996         u_int idx;
997         enum snmp_code err;
998
999         if ((err = snmp_pdu_encode_header(resp_b, pdu)) != SNMP_CODE_OK)
1000                 return (err);
1001         for (idx = 0; idx < pdu->nbindings; idx++)
1002                 if (snmp_binding_encode(resp_b, &pdu->bindings[idx])
1003                     != ASN_ERR_OK)
1004                         return (SNMP_CODE_FAILED);
1005
1006         return (snmp_fix_encoding(resp_b, pdu));
1007 }
1008
1009 static void
1010 dump_binding(const struct snmp_value *b)
1011 {
1012         u_int i;
1013         char buf[ASN_OIDSTRLEN];
1014
1015         snmp_printf("%s=", asn_oid2str_r(&b->var, buf));
1016         switch (b->syntax) {
1017
1018           case SNMP_SYNTAX_NULL:
1019                 snmp_printf("NULL");
1020                 break;
1021
1022           case SNMP_SYNTAX_INTEGER:
1023                 snmp_printf("INTEGER %d", b->v.integer);
1024                 break;
1025
1026           case SNMP_SYNTAX_OCTETSTRING:
1027                 snmp_printf("OCTET STRING %lu:", b->v.octetstring.len);
1028                 for (i = 0; i < b->v.octetstring.len; i++)
1029                         snmp_printf(" %02x", b->v.octetstring.octets[i]);
1030                 break;
1031
1032           case SNMP_SYNTAX_OID:
1033                 snmp_printf("OID %s", asn_oid2str_r(&b->v.oid, buf));
1034                 break;
1035
1036           case SNMP_SYNTAX_IPADDRESS:
1037                 snmp_printf("IPADDRESS %u.%u.%u.%u", b->v.ipaddress[0],
1038                     b->v.ipaddress[1], b->v.ipaddress[2], b->v.ipaddress[3]);
1039                 break;
1040
1041           case SNMP_SYNTAX_COUNTER:
1042                 snmp_printf("COUNTER %u", b->v.uint32);
1043                 break;
1044
1045           case SNMP_SYNTAX_GAUGE:
1046                 snmp_printf("GAUGE %u", b->v.uint32);
1047                 break;
1048
1049           case SNMP_SYNTAX_TIMETICKS:
1050                 snmp_printf("TIMETICKS %u", b->v.uint32);
1051                 break;
1052
1053           case SNMP_SYNTAX_COUNTER64:
1054                 snmp_printf("COUNTER64 %lld", b->v.counter64);
1055                 break;
1056
1057           case SNMP_SYNTAX_NOSUCHOBJECT:
1058                 snmp_printf("NoSuchObject");
1059                 break;
1060
1061           case SNMP_SYNTAX_NOSUCHINSTANCE:
1062                 snmp_printf("NoSuchInstance");
1063                 break;
1064
1065           case SNMP_SYNTAX_ENDOFMIBVIEW:
1066                 snmp_printf("EndOfMibView");
1067                 break;
1068
1069           default:
1070                 snmp_printf("UNKNOWN SYNTAX %u", b->syntax);
1071                 break;
1072         }
1073 }
1074
1075 static __inline void
1076 dump_bindings(const struct snmp_pdu *pdu)
1077 {
1078         u_int i;
1079
1080         for (i = 0; i < pdu->nbindings; i++) {
1081                 snmp_printf(" [%u]: ", i);
1082                 dump_binding(&pdu->bindings[i]);
1083                 snmp_printf("\n");
1084         }
1085 }
1086
1087 static __inline void
1088 dump_notrap(const struct snmp_pdu *pdu)
1089 {
1090         snmp_printf(" request_id=%d", pdu->request_id);
1091         snmp_printf(" error_status=%d", pdu->error_status);
1092         snmp_printf(" error_index=%d\n", pdu->error_index);
1093         dump_bindings(pdu);
1094 }
1095
1096 void
1097 snmp_pdu_dump(const struct snmp_pdu *pdu)
1098 {
1099         char buf[ASN_OIDSTRLEN];
1100         const char *vers;
1101         static const char *types[] = {
1102                 [SNMP_PDU_GET] =        "GET",
1103                 [SNMP_PDU_GETNEXT] =    "GETNEXT",
1104                 [SNMP_PDU_RESPONSE] =   "RESPONSE",
1105                 [SNMP_PDU_SET] =        "SET",
1106                 [SNMP_PDU_TRAP] =       "TRAPv1",
1107                 [SNMP_PDU_GETBULK] =    "GETBULK",
1108                 [SNMP_PDU_INFORM] =     "INFORM",
1109                 [SNMP_PDU_TRAP2] =      "TRAPv2",
1110                 [SNMP_PDU_REPORT] =     "REPORT",
1111         };
1112
1113         if (pdu->version == SNMP_V1)
1114                 vers = "SNMPv1";
1115         else if (pdu->version == SNMP_V2c)
1116                 vers = "SNMPv2c";
1117         else if (pdu->version == SNMP_V3)
1118                 vers = "SNMPv3";
1119         else
1120                 vers = "v?";
1121
1122         switch (pdu->type) {
1123           case SNMP_PDU_TRAP:
1124                 snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
1125                 snmp_printf(" enterprise=%s", asn_oid2str_r(&pdu->enterprise, buf));
1126                 snmp_printf(" agent_addr=%u.%u.%u.%u", pdu->agent_addr[0],
1127                     pdu->agent_addr[1], pdu->agent_addr[2], pdu->agent_addr[3]);
1128                 snmp_printf(" generic_trap=%d", pdu->generic_trap);
1129                 snmp_printf(" specific_trap=%d", pdu->specific_trap);
1130                 snmp_printf(" time-stamp=%u\n", pdu->time_stamp);
1131                 dump_bindings(pdu);
1132                 break;
1133
1134           case SNMP_PDU_GET:
1135           case SNMP_PDU_GETNEXT:
1136           case SNMP_PDU_RESPONSE:
1137           case SNMP_PDU_SET:
1138           case SNMP_PDU_GETBULK:
1139           case SNMP_PDU_INFORM:
1140           case SNMP_PDU_TRAP2:
1141           case SNMP_PDU_REPORT:
1142                 snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
1143                 dump_notrap(pdu);
1144                 break;
1145
1146           default:
1147                 snmp_printf("bad pdu type %u\n", pdu->type);
1148                 break;
1149         }
1150 }
1151
1152 void
1153 snmp_value_free(struct snmp_value *value)
1154 {
1155         if (value->syntax == SNMP_SYNTAX_OCTETSTRING)
1156                 free(value->v.octetstring.octets);
1157         value->syntax = SNMP_SYNTAX_NULL;
1158 }
1159
1160 int
1161 snmp_value_copy(struct snmp_value *to, const struct snmp_value *from)
1162 {
1163         to->var = from->var;
1164         to->syntax = from->syntax;
1165
1166         if (from->syntax == SNMP_SYNTAX_OCTETSTRING) {
1167                 if ((to->v.octetstring.len = from->v.octetstring.len) == 0)
1168                         to->v.octetstring.octets = NULL;
1169                 else {
1170                         to->v.octetstring.octets = malloc(to->v.octetstring.len);
1171                         if (to->v.octetstring.octets == NULL)
1172                                 return (-1);
1173                         (void)memcpy(to->v.octetstring.octets,
1174                             from->v.octetstring.octets, to->v.octetstring.len);
1175                 }
1176         } else
1177                 to->v = from->v;
1178         return (0);
1179 }
1180
1181 void
1182 snmp_pdu_init_secparams(struct snmp_pdu *pdu)
1183 {
1184         int32_t rval;
1185
1186         if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH)
1187                 pdu->flags |= SNMP_MSG_AUTH_FLAG;
1188
1189         switch (pdu->user.priv_proto) {
1190         case SNMP_PRIV_DES:
1191                 memcpy(pdu->msg_salt, &pdu->engine.engine_boots,
1192                     sizeof(pdu->engine.engine_boots));
1193                 rval = random();
1194                 memcpy(pdu->msg_salt + sizeof(pdu->engine.engine_boots), &rval,
1195                     sizeof(int32_t));
1196                 pdu->flags |= SNMP_MSG_PRIV_FLAG;
1197                 break;
1198         case SNMP_PRIV_AES:
1199                 rval = random();
1200                 memcpy(pdu->msg_salt, &rval, sizeof(int32_t));
1201                 rval = random();
1202                 memcpy(pdu->msg_salt + sizeof(int32_t), &rval, sizeof(int32_t));
1203                 pdu->flags |= SNMP_MSG_PRIV_FLAG;
1204                 break;
1205         default:
1206                 break;
1207         }
1208 }
1209
1210 void
1211 snmp_pdu_free(struct snmp_pdu *pdu)
1212 {
1213         u_int i;
1214
1215         for (i = 0; i < pdu->nbindings; i++)
1216                 snmp_value_free(&pdu->bindings[i]);
1217 }
1218
1219 /*
1220  * Parse an ASCII SNMP value into the binary form
1221  */
1222 int
1223 snmp_value_parse(const char *str, enum snmp_syntax syntax, union snmp_values *v)
1224 {
1225         char *end;
1226
1227         switch (syntax) {
1228
1229           case SNMP_SYNTAX_NULL:
1230           case SNMP_SYNTAX_NOSUCHOBJECT:
1231           case SNMP_SYNTAX_NOSUCHINSTANCE:
1232           case SNMP_SYNTAX_ENDOFMIBVIEW:
1233                 if (*str != '\0')
1234                         return (-1);
1235                 return (0);
1236
1237           case SNMP_SYNTAX_INTEGER:
1238                 v->integer = strtoll(str, &end, 0);
1239                 if (*end != '\0')
1240                         return (-1);
1241                 return (0);
1242
1243           case SNMP_SYNTAX_OCTETSTRING:
1244             {
1245                 u_long len;     /* actual length of string */
1246                 u_long alloc;   /* allocate length of string */
1247                 u_char *octs;   /* actual octets */
1248                 u_long oct;     /* actual octet */
1249                 u_char *nocts;  /* to avoid memory leak */
1250                 u_char c;       /* actual character */
1251
1252 # define STUFFC(C)                                                      \
1253                 if (alloc == len) {                                     \
1254                         alloc += 100;                                   \
1255                         if ((nocts = realloc(octs, alloc)) == NULL) {   \
1256                                 free(octs);                             \
1257                                 return (-1);                            \
1258                         }                                               \
1259                         octs = nocts;                                   \
1260                 }                                                       \
1261                 octs[len++] = (C);
1262
1263                 len = alloc = 0;
1264                 octs = NULL;
1265
1266                 if (*str == '"') {
1267                         str++;
1268                         while((c = *str++) != '\0') {
1269                                 if (c == '"') {
1270                                         if (*str != '\0') {
1271                                                 free(octs);
1272                                                 return (-1);
1273                                         }
1274                                         break;
1275                                 }
1276                                 if (c == '\\') {
1277                                         switch (c = *str++) {
1278
1279                                           case '\\':
1280                                                 break;
1281                                           case 'a':
1282                                                 c = '\a';
1283                                                 break;
1284                                           case 'b':
1285                                                 c = '\b';
1286                                                 break;
1287                                           case 'f':
1288                                                 c = '\f';
1289                                                 break;
1290                                           case 'n':
1291                                                 c = '\n';
1292                                                 break;
1293                                           case 'r':
1294                                                 c = '\r';
1295                                                 break;
1296                                           case 't':
1297                                                 c = '\t';
1298                                                 break;
1299                                           case 'v':
1300                                                 c = '\v';
1301                                                 break;
1302                                           case 'x':
1303                                                 c = 0;
1304                                                 if (!isxdigit(*str))
1305                                                         break;
1306                                                 if (isdigit(*str))
1307                                                         c = *str++ - '0';
1308                                                 else if (isupper(*str))
1309                                                         c = *str++ - 'A' + 10;
1310                                                 else
1311                                                         c = *str++ - 'a' + 10;
1312                                                 if (!isxdigit(*str))
1313                                                         break;
1314                                                 if (isdigit(*str))
1315                                                         c += *str++ - '0';
1316                                                 else if (isupper(*str))
1317                                                         c += *str++ - 'A' + 10;
1318                                                 else
1319                                                         c += *str++ - 'a' + 10;
1320                                                 break;
1321                                           case '0': case '1': case '2':
1322                                           case '3': case '4': case '5':
1323                                           case '6': case '7':
1324                                                 c = *str++ - '0';
1325                                                 if (*str < '0' || *str > '7')
1326                                                         break;
1327                                                 c = *str++ - '0';
1328                                                 if (*str < '0' || *str > '7')
1329                                                         break;
1330                                                 c = *str++ - '0';
1331                                                 break;
1332                                           default:
1333                                                 break;
1334                                         }
1335                                 }
1336                                 STUFFC(c);
1337                         }
1338                 } else {
1339                         while (*str != '\0') {
1340                                 oct = strtoul(str, &end, 16);
1341                                 str = end;
1342                                 if (oct > 0xff) {
1343                                         free(octs);
1344                                         return (-1);
1345                                 }
1346                                 STUFFC(oct);
1347                                 if (*str == ':')
1348                                         str++;
1349                                 else if(*str != '\0') {
1350                                         free(octs);
1351                                         return (-1);
1352                                 }
1353                         }
1354                 }
1355                 v->octetstring.octets = octs;
1356                 v->octetstring.len = len;
1357                 return (0);
1358 # undef STUFFC
1359             }
1360
1361           case SNMP_SYNTAX_OID:
1362             {
1363                 u_long subid;
1364
1365                 v->oid.len = 0;
1366
1367                 for (;;) {
1368                         if (v->oid.len == ASN_MAXOIDLEN)
1369                                 return (-1);
1370                         subid = strtoul(str, &end, 10);
1371                         str = end;
1372                         if (subid > ASN_MAXID)
1373                                 return (-1);
1374                         v->oid.subs[v->oid.len++] = (asn_subid_t)subid;
1375                         if (*str == '\0')
1376                                 break;
1377                         if (*str != '.')
1378                                 return (-1);
1379                         str++;
1380                 }
1381                 return (0);
1382             }
1383
1384           case SNMP_SYNTAX_IPADDRESS:
1385             {
1386                 struct hostent *he;
1387                 u_long ip[4];
1388                 int n;
1389
1390                 if (sscanf(str, "%lu.%lu.%lu.%lu%n", &ip[0], &ip[1], &ip[2],
1391                     &ip[3], &n) == 4 && (size_t)n == strlen(str) &&
1392                     ip[0] <= 0xff && ip[1] <= 0xff &&
1393                     ip[2] <= 0xff && ip[3] <= 0xff) {
1394                         v->ipaddress[0] = (u_char)ip[0];
1395                         v->ipaddress[1] = (u_char)ip[1];
1396                         v->ipaddress[2] = (u_char)ip[2];
1397                         v->ipaddress[3] = (u_char)ip[3];
1398                         return (0);
1399                 }
1400
1401                 if ((he = gethostbyname(str)) == NULL)
1402                         return (-1);
1403                 if (he->h_addrtype != AF_INET)
1404                         return (-1);
1405
1406                 v->ipaddress[0] = he->h_addr[0];
1407                 v->ipaddress[1] = he->h_addr[1];
1408                 v->ipaddress[2] = he->h_addr[2];
1409                 v->ipaddress[3] = he->h_addr[3];
1410                 return (0);
1411             }
1412
1413           case SNMP_SYNTAX_COUNTER:
1414           case SNMP_SYNTAX_GAUGE:
1415           case SNMP_SYNTAX_TIMETICKS:
1416             {
1417                 uint64_t sub;
1418
1419                 sub = strtoull(str, &end, 0);
1420                 if (*end != '\0' || sub > 0xffffffff)
1421                         return (-1);
1422                 v->uint32 = (uint32_t)sub;
1423                 return (0);
1424             }
1425
1426           case SNMP_SYNTAX_COUNTER64:
1427                 v->counter64 = strtoull(str, &end, 0);
1428                 if (*end != '\0')
1429                         return (-1);
1430                 return (0);
1431         }
1432         abort();
1433 }
1434
1435 static void
1436 snmp_error_func(const char *fmt, ...)
1437 {
1438         va_list ap;
1439
1440         va_start(ap, fmt);
1441         fprintf(stderr, "SNMP: ");
1442         vfprintf(stderr, fmt, ap);
1443         fprintf(stderr, "\n");
1444         va_end(ap);
1445 }
1446
1447 static void
1448 snmp_printf_func(const char *fmt, ...)
1449 {
1450         va_list ap;
1451
1452         va_start(ap, fmt);
1453         vfprintf(stderr, fmt, ap);
1454         va_end(ap);
1455 }