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