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