Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c
106138 views
1
/*-
2
* Copyright (c) 2005-2006 The FreeBSD Project
3
* All rights reserved.
4
*
5
* Author: Shteryana Shopova <[email protected]>
6
*
7
* Redistribution of this software and documentation and use in source and
8
* binary forms, with or without modification, are permitted provided that
9
* the following conditions are met:
10
*
11
* 1. Redistributions of source code or documentation must retain the above
12
* copyright notice, this list of conditions and the following disclaimer.
13
* 2. Redistributions in binary form must reproduce the above copyright
14
* notice, this list of conditions and the following disclaimer in the
15
* documentation and/or other materials provided with the distribution.
16
*
17
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27
* SUCH DAMAGE.
28
*
29
* Helper functions for snmp client tools
30
*/
31
32
#include <sys/param.h>
33
#include <sys/queue.h>
34
#include <sys/uio.h>
35
36
#include <assert.h>
37
#include <ctype.h>
38
#include <err.h>
39
#include <errno.h>
40
#include <fcntl.h>
41
#include <stdio.h>
42
#include <stdlib.h>
43
#include <string.h>
44
#include <syslog.h>
45
#include <unistd.h>
46
47
#include <bsnmp/asn1.h>
48
#include <bsnmp/snmp.h>
49
#include <bsnmp/snmpclient.h>
50
#include "bsnmptc.h"
51
#include "bsnmptools.h"
52
53
/* Internal variable to turn on library debugging for testing and to
54
* find bugs. It is not exported via the header file.
55
* XXX should we cover it by some #ifdef BSNMPTOOLS_DEBUG? */
56
int _bsnmptools_debug = 0;
57
58
/* Default files to import mapping from if none explicitly provided. */
59
#define bsnmpd_defs "/usr/share/snmp/defs/tree.def"
60
#define mibII_defs "/usr/share/snmp/defs/mibII_tree.def"
61
62
/*
63
* The .iso.org.dod oid that has to be prepended to every OID when requesting
64
* a value.
65
*/
66
const struct asn_oid IsoOrgDod_OID = {
67
3, { 1, 3, 6 }
68
};
69
70
71
#define SNMP_ERR_UNKNOWN 0
72
73
/*
74
* An array of error strings corresponding to error definitions from libbsnmp.
75
*/
76
static const struct {
77
const char *str;
78
int32_t error;
79
} error_strings[] = {
80
{ "Unknown", SNMP_ERR_UNKNOWN },
81
{ "Too big ", SNMP_ERR_TOOBIG },
82
{ "No such Name", SNMP_ERR_NOSUCHNAME },
83
{ "Bad Value", SNMP_ERR_BADVALUE },
84
{ "Readonly", SNMP_ERR_READONLY },
85
{ "General error", SNMP_ERR_GENERR },
86
{ "No access", SNMP_ERR_NO_ACCESS },
87
{ "Wrong type", SNMP_ERR_WRONG_TYPE },
88
{ "Wrong length", SNMP_ERR_WRONG_LENGTH },
89
{ "Wrong encoding", SNMP_ERR_WRONG_ENCODING },
90
{ "Wrong value", SNMP_ERR_WRONG_VALUE },
91
{ "No creation", SNMP_ERR_NO_CREATION },
92
{ "Inconsistent value", SNMP_ERR_INCONS_VALUE },
93
{ "Resource unavailable", SNMP_ERR_RES_UNAVAIL },
94
{ "Commit failed", SNMP_ERR_COMMIT_FAILED },
95
{ "Undo failed", SNMP_ERR_UNDO_FAILED },
96
{ "Authorization error", SNMP_ERR_AUTH_ERR },
97
{ "Not writable", SNMP_ERR_NOT_WRITEABLE },
98
{ "Inconsistent name", SNMP_ERR_INCONS_NAME },
99
{ NULL, 0 }
100
};
101
102
/* This one and any following are exceptions. */
103
#define SNMP_SYNTAX_UNKNOWN SNMP_SYNTAX_NOSUCHOBJECT
104
105
static const struct {
106
const char *str;
107
enum snmp_syntax stx;
108
} syntax_strings[] = {
109
{ "Null", SNMP_SYNTAX_NULL },
110
{ "Integer", SNMP_SYNTAX_INTEGER },
111
{ "OctetString", SNMP_SYNTAX_OCTETSTRING },
112
{ "OID", SNMP_SYNTAX_OID },
113
{ "IpAddress", SNMP_SYNTAX_IPADDRESS },
114
{ "Counter32", SNMP_SYNTAX_COUNTER },
115
{ "Gauge", SNMP_SYNTAX_GAUGE },
116
{ "TimeTicks", SNMP_SYNTAX_TIMETICKS },
117
{ "Counter64", SNMP_SYNTAX_COUNTER64 },
118
{ "Unknown", SNMP_SYNTAX_UNKNOWN },
119
};
120
121
int
122
snmptool_init(struct snmp_toolinfo *snmptoolctx)
123
{
124
char *str;
125
size_t slen;
126
127
memset(snmptoolctx, 0, sizeof(struct snmp_toolinfo));
128
snmptoolctx->objects = 0;
129
snmptoolctx->mappings = NULL;
130
snmptoolctx->flags = SNMP_PDU_GET; /* XXX */
131
SLIST_INIT(&snmptoolctx->filelist);
132
snmp_client_init(&snmp_client);
133
SET_MAXREP(snmptoolctx, SNMP_MAX_REPETITIONS);
134
135
if (add_filename(snmptoolctx, bsnmpd_defs, &IsoOrgDod_OID, 0) < 0)
136
warnx("Error adding file %s to list", bsnmpd_defs);
137
138
if (add_filename(snmptoolctx, mibII_defs, &IsoOrgDod_OID, 0) < 0)
139
warnx("Error adding file %s to list", mibII_defs);
140
141
/* Read the environment */
142
if ((str = getenv("SNMPAUTH")) != NULL) {
143
slen = strlen(str);
144
if (slen == strlen("md5") && strcasecmp(str, "md5") == 0)
145
snmp_client.user.auth_proto = SNMP_AUTH_HMAC_MD5;
146
else if (slen == strlen("sha")&& strcasecmp(str, "sha") == 0)
147
snmp_client.user.auth_proto = SNMP_AUTH_HMAC_SHA;
148
else if (slen != 0)
149
warnx("Bad authentication type - %s in SNMPAUTH", str);
150
}
151
152
if ((str = getenv("SNMPPRIV")) != NULL) {
153
slen = strlen(str);
154
if (slen == strlen("des") && strcasecmp(str, "des") == 0)
155
snmp_client.user.priv_proto = SNMP_PRIV_DES;
156
else if (slen == strlen("aes")&& strcasecmp(str, "aes") == 0)
157
snmp_client.user.priv_proto = SNMP_PRIV_AES;
158
else if (slen != 0)
159
warnx("Bad privacy type - %s in SNMPPRIV", str);
160
}
161
162
if ((str = getenv("SNMPUSER")) != NULL) {
163
if ((slen = strlen(str)) > sizeof(snmp_client.user.sec_name)) {
164
warnx("Username too long - %s in SNMPUSER", str);
165
return (-1);
166
}
167
if (slen > 0) {
168
strlcpy(snmp_client.user.sec_name, str,
169
sizeof(snmp_client.user.sec_name));
170
snmp_client.version = SNMP_V3;
171
}
172
}
173
174
if ((str = getenv("SNMPPASSWD")) != NULL) {
175
if ((slen = strlen(str)) > MAXSTR)
176
slen = MAXSTR - 1;
177
if ((snmptoolctx->passwd = malloc(slen + 1)) == NULL) {
178
warn("malloc() failed");
179
return (-1);
180
}
181
strlcpy(snmptoolctx->passwd, str, slen + 1);
182
}
183
184
return (0);
185
}
186
187
#define OBJECT_IDX_LIST(o) o->info->table_idx->index_list
188
189
/*
190
* Walk through the file list and import string<->oid mappings from each file.
191
*/
192
int32_t
193
snmp_import_all(struct snmp_toolinfo *snmptoolctx)
194
{
195
int32_t fc;
196
struct fname *tmp;
197
198
if (snmptoolctx == NULL)
199
return (-1);
200
201
if (ISSET_NUMERIC(snmptoolctx))
202
return (0);
203
204
if ((snmptoolctx->mappings = snmp_mapping_init()) == NULL)
205
return (-1);
206
207
fc = 0;
208
if (SLIST_EMPTY(&snmptoolctx->filelist)) {
209
warnx("No files to read OID <-> string conversions from");
210
return (-1);
211
} else {
212
SLIST_FOREACH(tmp, &snmptoolctx->filelist, link) {
213
if (tmp->done)
214
continue;
215
if (snmp_import_file(snmptoolctx, tmp) < 0) {
216
fc = -1;
217
break;
218
}
219
fc++;
220
}
221
}
222
223
snmp_mapping_dump(snmptoolctx);
224
return (fc);
225
}
226
227
/*
228
* Add a filename to the file list - the initial idea of keeping a list with all
229
* files to read OIDs from was that an application might want to have loaded in
230
* memory the OIDs from a single file only and when done with them read the OIDs
231
* from another file. This is not used yet but might be a good idea at some
232
* point. Size argument is number of bytes in string including trailing '\0',
233
* not string length.
234
*/
235
int32_t
236
add_filename(struct snmp_toolinfo *snmptoolctx, const char *filename,
237
const struct asn_oid *cut, int32_t done)
238
{
239
char *fstring;
240
struct fname *entry;
241
242
if (snmptoolctx == NULL)
243
return (-1);
244
245
/* Make sure file was not in list. */
246
SLIST_FOREACH(entry, &snmptoolctx->filelist, link) {
247
if (strncmp(entry->name, filename, strlen(entry->name)) == 0)
248
return (0);
249
}
250
251
if ((fstring = strdup(filename)) == NULL) {
252
warn("strdup() failed");
253
return (-1);
254
}
255
256
if ((entry = calloc(1, sizeof(struct fname))) == NULL) {
257
warn("calloc() failed");
258
free(fstring);
259
return (-1);
260
}
261
262
if (cut != NULL)
263
asn_append_oid(&(entry->cut), cut);
264
entry->name = fstring;
265
entry->done = done;
266
SLIST_INSERT_HEAD(&snmptoolctx->filelist, entry, link);
267
268
return (1);
269
}
270
271
void
272
free_filelist(struct snmp_toolinfo *snmptoolctx)
273
{
274
struct fname *f;
275
276
if (snmptoolctx == NULL)
277
return; /* XXX error handling */
278
279
while ((f = SLIST_FIRST(&snmptoolctx->filelist)) != NULL) {
280
SLIST_REMOVE_HEAD(&snmptoolctx->filelist, link);
281
if (f->name)
282
free(f->name);
283
free(f);
284
}
285
}
286
287
static char
288
isvalid_fchar(char c, int pos)
289
{
290
if (isalpha(c)|| c == '/'|| c == '_' || c == '.' || c == '~' ||
291
(pos != 0 && isdigit(c))){
292
return (c);
293
}
294
295
if (c == '\0')
296
return (0);
297
298
if (!isascii(c) || !isprint(c))
299
warnx("Unexpected character %#2x", (u_int) c);
300
else
301
warnx("Illegal character '%c'", c);
302
303
return (-1);
304
}
305
306
/*
307
* Re-implement getsubopt from scratch, because the second argument is broken
308
* and will not compile with WARNS=5.
309
* Copied from src/contrib/bsnmp/snmpd/main.c.
310
*/
311
static int
312
getsubopt1(char **arg, const char *const *options, char **valp, char **optp)
313
{
314
static const char *const delim = ",\t ";
315
u_int i;
316
char *ptr;
317
318
*optp = NULL;
319
320
/* Skip leading junk. */
321
for (ptr = *arg; *ptr != '\0'; ptr++)
322
if (strchr(delim, *ptr) == NULL)
323
break;
324
if (*ptr == '\0') {
325
*arg = ptr;
326
return (-1);
327
}
328
*optp = ptr;
329
330
/* Find the end of the option. */
331
while (*++ptr != '\0')
332
if (strchr(delim, *ptr) != NULL || *ptr == '=')
333
break;
334
335
if (*ptr != '\0') {
336
if (*ptr == '=') {
337
*ptr++ = '\0';
338
*valp = ptr;
339
while (*ptr != '\0' && strchr(delim, *ptr) == NULL)
340
ptr++;
341
if (*ptr != '\0')
342
*ptr++ = '\0';
343
} else
344
*ptr++ = '\0';
345
}
346
347
*arg = ptr;
348
349
for (i = 0; *options != NULL; options++, i++)
350
if (strcmp(*optp, *options) == 0)
351
return (i);
352
return (-1);
353
}
354
355
static int32_t
356
parse_path(char *value)
357
{
358
int32_t i, len;
359
360
if (value == NULL)
361
return (-1);
362
363
for (len = 0; len < MAXPATHLEN; len++) {
364
i = isvalid_fchar(*(value + len), len) ;
365
366
if (i == 0)
367
break;
368
else if (i < 0)
369
return (-1);
370
}
371
372
if (len >= MAXPATHLEN || value[len] != '\0') {
373
warnx("Bad pathname - '%s'", value);
374
return (-1);
375
}
376
377
return (len);
378
}
379
380
static int32_t
381
parse_flist(struct snmp_toolinfo *snmptoolctx, char *value, char *path,
382
const struct asn_oid *cut)
383
{
384
int32_t namelen;
385
char filename[MAXPATHLEN + 1];
386
387
if (value == NULL)
388
return (-1);
389
390
do {
391
memset(filename, 0, MAXPATHLEN + 1);
392
393
if (isalpha(*value) && (path == NULL || path[0] == '\0')) {
394
strlcpy(filename, SNMP_DEFS_DIR, MAXPATHLEN + 1);
395
namelen = strlen(SNMP_DEFS_DIR);
396
} else if (path != NULL){
397
strlcpy(filename, path, MAXPATHLEN + 1);
398
namelen = strlen(path);
399
} else
400
namelen = 0;
401
402
for ( ; namelen < MAXPATHLEN; value++) {
403
if (isvalid_fchar(*value, namelen) > 0) {
404
filename[namelen++] = *value;
405
continue;
406
}
407
408
if (*value == ',' )
409
value++;
410
else if (*value == '\0')
411
;
412
else {
413
if (!isascii(*value) || !isprint(*value))
414
warnx("Unexpected character %#2x in"
415
" filename", (u_int) *value);
416
else
417
warnx("Illegal character '%c' in"
418
" filename", *value);
419
return (-1);
420
}
421
422
filename[namelen]='\0';
423
break;
424
}
425
426
if ((namelen == MAXPATHLEN) && (filename[MAXPATHLEN] != '\0')) {
427
warnx("Filename %s too long", filename);
428
return (-1);
429
}
430
431
if (add_filename(snmptoolctx, filename, cut, 0) < 0) {
432
warnx("Error adding file %s to list", filename);
433
return (-1);
434
}
435
} while (*value != '\0');
436
437
return(1);
438
}
439
440
static int32_t
441
parse_ascii(char *ascii, uint8_t *binstr, size_t binlen)
442
{
443
char dptr[3];
444
size_t count;
445
int32_t alen, i, saved_errno;
446
uint32_t val;
447
448
/* Filter 0x at the beginning */
449
if ((alen = strlen(ascii)) > 2 && ascii[0] == '0' && ascii[1] == 'x')
450
i = 2;
451
else
452
i = 0;
453
454
saved_errno = errno;
455
errno = 0;
456
for (count = 0; i < alen; i += 2) {
457
/* XXX: consider strlen(ascii) % 2 != 0 */
458
dptr[0] = ascii[i];
459
dptr[1] = ascii[i + 1];
460
dptr[2] = '\0';
461
if ((val = strtoul(dptr, NULL, 16)) > 0xFF || errno != 0) {
462
errno = saved_errno;
463
return (-1);
464
}
465
binstr[count] = (uint8_t) val;
466
if (++count >= binlen) {
467
warnx("Key %s too long - truncating to %zu octets",
468
ascii, binlen);
469
break;
470
}
471
}
472
473
return (count);
474
}
475
476
/*
477
* Functions to parse common input options for client tools and fill in the
478
* snmp_client structure.
479
*/
480
int32_t
481
parse_authentication(struct snmp_toolinfo *snmptoolctx __unused, char *opt_arg)
482
{
483
int32_t /* count, */ subopt;
484
char *val, *option;
485
const char *const subopts[] = {
486
"proto",
487
"key",
488
NULL
489
};
490
491
assert(opt_arg != NULL);
492
/* count = 1; */
493
while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
494
switch (subopt) {
495
case 0:
496
if (val == NULL) {
497
warnx("Suboption 'proto' requires an argument");
498
return (-1);
499
}
500
if (strlen(val) != 3) {
501
warnx("Unknown auth protocol - %s", val);
502
return (-1);
503
}
504
if (strncasecmp("md5", val, strlen("md5")) == 0)
505
snmp_client.user.auth_proto =
506
SNMP_AUTH_HMAC_MD5;
507
else if (strncasecmp("sha", val, strlen("sha")) == 0)
508
snmp_client.user.auth_proto =
509
SNMP_AUTH_HMAC_SHA;
510
else {
511
warnx("Unknown auth protocol - %s", val);
512
return (-1);
513
}
514
break;
515
case 1:
516
if (val == NULL) {
517
warnx("Suboption 'key' requires an argument");
518
return (-1);
519
}
520
if (parse_ascii(val, snmp_client.user.auth_key,
521
SNMP_AUTH_KEY_SIZ) < 0) {
522
warnx("Bad authentication key- %s", val);
523
return (-1);
524
}
525
break;
526
default:
527
warnx("Unknown suboption - '%s'", suboptarg);
528
return (-1);
529
}
530
/* count += 1; */
531
}
532
return (2/* count */);
533
}
534
535
int32_t
536
parse_privacy(struct snmp_toolinfo *snmptoolctx __unused, char *opt_arg)
537
{
538
int32_t /* count, */ subopt;
539
char *val, *option;
540
const char *const subopts[] = {
541
"proto",
542
"key",
543
NULL
544
};
545
546
assert(opt_arg != NULL);
547
/* count = 1; */
548
while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
549
switch (subopt) {
550
case 0:
551
if (val == NULL) {
552
warnx("Suboption 'proto' requires an argument");
553
return (-1);
554
}
555
if (strlen(val) != 3) {
556
warnx("Unknown privacy protocol - %s", val);
557
return (-1);
558
}
559
if (strncasecmp("aes", val, strlen("aes")) == 0)
560
snmp_client.user.priv_proto = SNMP_PRIV_AES;
561
else if (strncasecmp("des", val, strlen("des")) == 0)
562
snmp_client.user.priv_proto = SNMP_PRIV_DES;
563
else {
564
warnx("Unknown privacy protocol - %s", val);
565
return (-1);
566
}
567
break;
568
case 1:
569
if (val == NULL) {
570
warnx("Suboption 'key' requires an argument");
571
return (-1);
572
}
573
if (parse_ascii(val, snmp_client.user.priv_key,
574
SNMP_PRIV_KEY_SIZ) < 0) {
575
warnx("Bad privacy key- %s", val);
576
return (-1);
577
}
578
break;
579
default:
580
warnx("Unknown suboption - '%s'", suboptarg);
581
return (-1);
582
}
583
/* count += 1; */
584
}
585
return (2/* count */);
586
}
587
588
int32_t
589
parse_context(struct snmp_toolinfo *snmptoolctx __unused, char *opt_arg)
590
{
591
int32_t /* count, */ subopt;
592
char *val, *option;
593
const char *const subopts[] = {
594
"context",
595
"context-engine",
596
NULL
597
};
598
599
assert(opt_arg != NULL);
600
/* count = 1; */
601
while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
602
switch (subopt) {
603
case 0:
604
if (val == NULL) {
605
warnx("Suboption 'context' - no argument");
606
return (-1);
607
}
608
strlcpy(snmp_client.cname, val, SNMP_CONTEXT_NAME_SIZ);
609
break;
610
case 1:
611
if (val == NULL) {
612
warnx("Suboption 'context-engine' - no argument");
613
return (-1);
614
}
615
if ((int32_t)(snmp_client.clen = parse_ascii(val,
616
snmp_client.cengine, SNMP_ENGINE_ID_SIZ)) == -1) {
617
warnx("Bad EngineID - %s", val);
618
return (-1);
619
}
620
break;
621
default:
622
warnx("Unknown suboption - '%s'", suboptarg);
623
return (-1);
624
}
625
/* count += 1; */
626
}
627
return (2/* count */);
628
}
629
630
int32_t
631
parse_user_security(struct snmp_toolinfo *snmptoolctx __unused, char *opt_arg)
632
{
633
int32_t /* count, */ subopt, saved_errno;
634
char *val, *option;
635
const char *const subopts[] = {
636
"engine",
637
"engine-boots",
638
"engine-time",
639
"name",
640
NULL
641
};
642
643
assert(opt_arg != NULL);
644
/* count = 1; */
645
while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
646
switch (subopt) {
647
case 0:
648
if (val == NULL) {
649
warnx("Suboption 'engine' - no argument");
650
return (-1);
651
}
652
snmp_client.engine.engine_len = parse_ascii(val,
653
snmp_client.engine.engine_id, SNMP_ENGINE_ID_SIZ);
654
if ((int32_t)snmp_client.engine.engine_len == -1) {
655
warnx("Bad EngineID - %s", val);
656
return (-1);
657
}
658
break;
659
case 1:
660
if (val == NULL) {
661
warnx("Suboption 'engine-boots' - no argument");
662
return (-1);
663
}
664
saved_errno = errno;
665
errno = 0;
666
snmp_client.engine.engine_boots = strtoul(val, NULL, 10);
667
if (errno != 0) {
668
warn("Bad 'engine-boots' value %s", val);
669
errno = saved_errno;
670
return (-1);
671
}
672
errno = saved_errno;
673
break;
674
case 2:
675
if (val == NULL) {
676
warnx("Suboption 'engine-time' - no argument");
677
return (-1);
678
}
679
saved_errno = errno;
680
errno = 0;
681
snmp_client.engine.engine_time = strtoul(val, NULL, 10);
682
if (errno != 0) {
683
warn("Bad 'engine-time' value %s", val);
684
errno = saved_errno;
685
return (-1);
686
}
687
errno = saved_errno;
688
break;
689
case 3:
690
strlcpy(snmp_client.user.sec_name, val,
691
SNMP_ADM_STR32_SIZ);
692
break;
693
default:
694
warnx("Unknown suboption - '%s'", suboptarg);
695
return (-1);
696
}
697
/* count += 1; */
698
}
699
return (2/* count */);
700
}
701
702
int32_t
703
parse_file(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
704
{
705
assert(opt_arg != NULL);
706
707
if (parse_flist(snmptoolctx, opt_arg, NULL, &IsoOrgDod_OID) < 0)
708
return (-1);
709
710
return (2);
711
}
712
713
int32_t
714
parse_include(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
715
{
716
char path[MAXPATHLEN + 1];
717
int32_t cut_dflt, len, subopt;
718
struct asn_oid cut;
719
char *val, *option;
720
const char *const subopts[] = {
721
"cut",
722
"path",
723
"file",
724
NULL
725
};
726
727
#define INC_CUT 0
728
#define INC_PATH 1
729
#define INC_LIST 2
730
731
assert(opt_arg != NULL);
732
733
/* if (opt == 'i')
734
free_filelist(snmptoolctx, ); */
735
/*
736
* This function should be called only after getopt(3) - otherwise if
737
* no previous validation of opt_arg strlen() may not return what is
738
* expected.
739
*/
740
741
path[0] = '\0';
742
memset(&cut, 0, sizeof(struct asn_oid));
743
cut_dflt = -1;
744
745
while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
746
switch (subopt) {
747
case INC_CUT:
748
if (val == NULL) {
749
warnx("Suboption 'cut' requires an argument");
750
return (-1);
751
} else {
752
if (snmp_parse_numoid(val, &cut) < 0)
753
return (-1);
754
}
755
cut_dflt = 1;
756
break;
757
758
case INC_PATH:
759
if ((len = parse_path(val)) < 0)
760
return (-1);
761
strlcpy(path, val, len + 1);
762
break;
763
764
case INC_LIST:
765
if (val == NULL)
766
return (-1);
767
if (cut_dflt == -1)
768
len = parse_flist(snmptoolctx, val, path, &IsoOrgDod_OID);
769
else
770
len = parse_flist(snmptoolctx, val, path, &cut);
771
if (len < 0)
772
return (-1);
773
break;
774
775
default:
776
warnx("Unknown suboption - '%s'", suboptarg);
777
return (-1);
778
}
779
}
780
781
/* XXX: Fix me - returning two is wrong here */
782
return (2);
783
}
784
785
int32_t
786
parse_server(char *opt_arg)
787
{
788
assert(opt_arg != NULL);
789
790
if (snmp_parse_server(&snmp_client, opt_arg) < 0)
791
return (-1);
792
793
return (2);
794
}
795
796
int32_t
797
parse_timeout(char *opt_arg)
798
{
799
int32_t v, saved_errno;
800
801
assert(opt_arg != NULL);
802
803
saved_errno = errno;
804
errno = 0;
805
806
v = strtol(opt_arg, NULL, 10);
807
if (errno != 0) {
808
warn("Error parsing timeout value");
809
errno = saved_errno;
810
return (-1);
811
}
812
813
snmp_client.timeout.tv_sec = v;
814
errno = saved_errno;
815
return (2);
816
}
817
818
int32_t
819
parse_retry(char *opt_arg)
820
{
821
uint32_t v;
822
int32_t saved_errno;
823
824
assert(opt_arg != NULL);
825
826
saved_errno = errno;
827
errno = 0;
828
829
v = strtoul(opt_arg, NULL, 10);
830
if (errno != 0) {
831
warn("Error parsing retries count");
832
errno = saved_errno;
833
return (-1);
834
}
835
836
snmp_client.retries = v;
837
errno = saved_errno;
838
return (2);
839
}
840
841
int32_t
842
parse_version(char *opt_arg)
843
{
844
uint32_t v;
845
int32_t saved_errno;
846
847
assert(opt_arg != NULL);
848
849
saved_errno = errno;
850
errno = 0;
851
852
v = strtoul(opt_arg, NULL, 10);
853
if (errno != 0) {
854
warn("Error parsing version");
855
errno = saved_errno;
856
return (-1);
857
}
858
859
switch (v) {
860
case 1:
861
snmp_client.version = SNMP_V1;
862
break;
863
case 2:
864
snmp_client.version = SNMP_V2c;
865
break;
866
case 3:
867
snmp_client.version = SNMP_V3;
868
break;
869
default:
870
warnx("Unsupported SNMP version - %u", v);
871
errno = saved_errno;
872
return (-1);
873
}
874
875
errno = saved_errno;
876
return (2);
877
}
878
879
int32_t
880
parse_local_path(char *opt_arg)
881
{
882
assert(opt_arg != NULL);
883
884
if (strlcpy(snmp_client.local_path, opt_arg,
885
sizeof(snmp_client.local_path)) >= sizeof(snmp_client.local_path)) {
886
warnx("Filename too long - %s", opt_arg);
887
return (-1);
888
}
889
return (2);
890
}
891
892
int32_t
893
parse_buflen(char *opt_arg)
894
{
895
uint32_t size;
896
int32_t saved_errno;
897
898
assert(opt_arg != NULL);
899
900
saved_errno = errno;
901
errno = 0;
902
903
size = strtoul(opt_arg, NULL, 10);
904
if (errno != 0) {
905
warn("Error parsing buffer size");
906
errno = saved_errno;
907
return (-1);
908
}
909
910
if (size > MAX_BUFF_SIZE) {
911
warnx("Buffer size too big - %d max allowed", MAX_BUFF_SIZE);
912
errno = saved_errno;
913
return (-1);
914
}
915
916
snmp_client.txbuflen = snmp_client.rxbuflen = size;
917
errno = saved_errno;
918
return (2);
919
}
920
921
int32_t
922
parse_debug(void)
923
{
924
snmp_client.dump_pdus = 1;
925
return (1);
926
}
927
928
int32_t
929
parse_discovery(struct snmp_toolinfo *snmptoolctx)
930
{
931
SET_EDISCOVER(snmptoolctx);
932
snmp_client.version = SNMP_V3;
933
return (1);
934
}
935
936
int32_t
937
parse_local_key(struct snmp_toolinfo *snmptoolctx)
938
{
939
SET_LOCALKEY(snmptoolctx);
940
snmp_client.version = SNMP_V3;
941
return (1);
942
}
943
944
int32_t
945
parse_num_oids(struct snmp_toolinfo *snmptoolctx)
946
{
947
SET_NUMERIC(snmptoolctx);
948
return (1);
949
}
950
951
int32_t
952
parse_output(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
953
{
954
assert(opt_arg != NULL);
955
956
if (strlen(opt_arg) > strlen("verbose")) {
957
warnx( "Invalid output option - %s",opt_arg);
958
return (-1);
959
}
960
961
if (strncasecmp(opt_arg, "short", strlen(opt_arg)) == 0)
962
SET_OUTPUT(snmptoolctx, OUTPUT_SHORT);
963
else if (strncasecmp(opt_arg, "verbose", strlen(opt_arg)) == 0)
964
SET_OUTPUT(snmptoolctx, OUTPUT_VERBOSE);
965
else if (strncasecmp(opt_arg,"tabular", strlen(opt_arg)) == 0)
966
SET_OUTPUT(snmptoolctx, OUTPUT_TABULAR);
967
else if (strncasecmp(opt_arg, "quiet", strlen(opt_arg)) == 0)
968
SET_OUTPUT(snmptoolctx, OUTPUT_QUIET);
969
else {
970
warnx( "Invalid output option - %s", opt_arg);
971
return (-1);
972
}
973
974
return (2);
975
}
976
977
int32_t
978
parse_errors(struct snmp_toolinfo *snmptoolctx)
979
{
980
SET_RETRY(snmptoolctx);
981
return (1);
982
}
983
984
int32_t
985
parse_skip_access(struct snmp_toolinfo *snmptoolctx)
986
{
987
SET_ERRIGNORE(snmptoolctx);
988
return (1);
989
}
990
991
char *
992
snmp_parse_suboid(char *str, struct asn_oid *oid)
993
{
994
char *endptr;
995
asn_subid_t suboid;
996
997
if (*str == '.')
998
str++;
999
1000
if (*str < '0' || *str > '9')
1001
return (str);
1002
1003
do {
1004
suboid = strtoul(str, &endptr, 10);
1005
if ((asn_subid_t) suboid > ASN_MAXID) {
1006
warnx("Suboid %u > ASN_MAXID", suboid);
1007
return (NULL);
1008
}
1009
if (snmp_suboid_append(oid, suboid) < 0)
1010
return (NULL);
1011
str = endptr + 1;
1012
} while (*endptr == '.');
1013
1014
return (endptr);
1015
}
1016
1017
static char *
1018
snmp_int2asn_oid(char *str, struct asn_oid *oid)
1019
{
1020
char *endptr;
1021
int32_t v, saved_errno;
1022
1023
saved_errno = errno;
1024
errno = 0;
1025
1026
v = strtol(str, &endptr, 10);
1027
if (errno != 0) {
1028
warn("Integer value %s not supported", str);
1029
errno = saved_errno;
1030
return (NULL);
1031
}
1032
errno = saved_errno;
1033
1034
if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1035
return (NULL);
1036
1037
return (endptr);
1038
}
1039
1040
/* It is a bit weird to have a table indexed by OID but still... */
1041
static char *
1042
snmp_oid2asn_oid(struct snmp_toolinfo *snmptoolctx, char *str,
1043
struct asn_oid *oid)
1044
{
1045
int32_t i;
1046
char string[MAXSTR + 1], *endptr;
1047
struct snmp_object obj;
1048
1049
for (i = 0; i < MAXSTR; i++)
1050
if (isalpha (*(str + i)) == 0)
1051
break;
1052
1053
endptr = str + i;
1054
memset(&obj, 0, sizeof(struct snmp_object));
1055
if (i == 0) {
1056
if ((endptr = snmp_parse_suboid(str, &(obj.val.var))) == NULL)
1057
return (NULL);
1058
if (snmp_suboid_append(oid, (asn_subid_t) obj.val.var.len) < 0)
1059
return (NULL);
1060
} else {
1061
strlcpy(string, str, i + 1);
1062
if (snmp_lookup_enumoid(snmptoolctx, &obj, string) < 0) {
1063
warnx("Unknown string - %s", string);
1064
return (NULL);
1065
}
1066
}
1067
1068
asn_append_oid(oid, &(obj.val.var));
1069
return (endptr);
1070
}
1071
1072
static char *
1073
snmp_ip2asn_oid(char *str, struct asn_oid *oid)
1074
{
1075
uint32_t v;
1076
int32_t i;
1077
char *endptr, *ptr;
1078
1079
ptr = str;
1080
1081
for (i = 0; i < 4; i++) {
1082
v = strtoul(ptr, &endptr, 10);
1083
if (v > 0xff)
1084
return (NULL);
1085
if (*endptr != '.' && strchr("],\0", *endptr) == NULL && i != 3)
1086
return (NULL);
1087
if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1088
return (NULL);
1089
ptr = endptr + 1;
1090
}
1091
1092
return (endptr);
1093
}
1094
1095
/* 32-bit counter, gauge, timeticks. */
1096
static char *
1097
snmp_uint2asn_oid(char *str, struct asn_oid *oid)
1098
{
1099
char *endptr;
1100
uint32_t v;
1101
int32_t saved_errno;
1102
1103
saved_errno = errno;
1104
errno = 0;
1105
1106
v = strtoul(str, &endptr, 10);
1107
if (errno != 0) {
1108
warn("Integer value %s not supported", str);
1109
errno = saved_errno;
1110
return (NULL);
1111
}
1112
errno = saved_errno;
1113
if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1114
return (NULL);
1115
1116
return (endptr);
1117
}
1118
1119
static char *
1120
snmp_cnt64_2asn_oid(char *str, struct asn_oid *oid)
1121
{
1122
char *endptr;
1123
uint64_t v;
1124
int32_t saved_errno;
1125
1126
saved_errno = errno;
1127
errno = 0;
1128
1129
v = strtoull(str, &endptr, 10);
1130
1131
if (errno != 0) {
1132
warn("Integer value %s not supported", str);
1133
errno = saved_errno;
1134
return (NULL);
1135
}
1136
errno = saved_errno;
1137
if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xffffffff)) < 0)
1138
return (NULL);
1139
1140
if (snmp_suboid_append(oid, (asn_subid_t) (v >> 32)) < 0)
1141
return (NULL);
1142
1143
return (endptr);
1144
}
1145
1146
enum snmp_syntax
1147
parse_syntax(char *str)
1148
{
1149
int32_t i;
1150
1151
for (i = 0; i < SNMP_SYNTAX_UNKNOWN; i++) {
1152
if (strncmp(syntax_strings[i].str, str,
1153
strlen(syntax_strings[i].str)) == 0)
1154
return (syntax_strings[i].stx);
1155
}
1156
1157
return (SNMP_SYNTAX_NULL);
1158
}
1159
1160
static char *
1161
snmp_parse_subindex(struct snmp_toolinfo *snmptoolctx, char *str,
1162
struct index *idx, struct snmp_object *object)
1163
{
1164
char *ptr;
1165
int32_t i;
1166
enum snmp_syntax stx;
1167
char syntax[MAX_CMD_SYNTAX_LEN];
1168
1169
ptr = str;
1170
if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) {
1171
for (i = 0; i < MAX_CMD_SYNTAX_LEN ; i++) {
1172
if (*(ptr + i) == ':')
1173
break;
1174
}
1175
1176
if (i >= MAX_CMD_SYNTAX_LEN) {
1177
warnx("Unknown syntax in OID - %s", str);
1178
return (NULL);
1179
}
1180
/* Expect a syntax string here. */
1181
if ((stx = parse_syntax(str)) <= SNMP_SYNTAX_NULL) {
1182
warnx("Invalid syntax - %s",syntax);
1183
return (NULL);
1184
}
1185
1186
if (stx != idx->syntax && !ISSET_ERRIGNORE(snmptoolctx)) {
1187
warnx("Syntax mismatch - %d expected, %d given",
1188
idx->syntax, stx);
1189
return (NULL);
1190
}
1191
/*
1192
* That is where the suboid started + the syntax length + one
1193
* character for ':'.
1194
*/
1195
ptr = str + i + 1;
1196
} else
1197
stx = idx->syntax;
1198
1199
switch (stx) {
1200
case SNMP_SYNTAX_INTEGER:
1201
return (snmp_int2asn_oid(ptr, &(object->val.var)));
1202
case SNMP_SYNTAX_OID:
1203
return (snmp_oid2asn_oid(snmptoolctx, ptr,
1204
&(object->val.var)));
1205
case SNMP_SYNTAX_IPADDRESS:
1206
return (snmp_ip2asn_oid(ptr, &(object->val.var)));
1207
case SNMP_SYNTAX_COUNTER:
1208
/* FALLTHROUGH */
1209
case SNMP_SYNTAX_GAUGE:
1210
/* FALLTHROUGH */
1211
case SNMP_SYNTAX_TIMETICKS:
1212
return (snmp_uint2asn_oid(ptr, &(object->val.var)));
1213
case SNMP_SYNTAX_COUNTER64:
1214
return (snmp_cnt64_2asn_oid(ptr, &(object->val.var)));
1215
case SNMP_SYNTAX_OCTETSTRING:
1216
return (snmp_tc2oid(idx->tc, ptr, &(object->val.var)));
1217
default:
1218
/* NOTREACHED */
1219
break;
1220
}
1221
1222
return (NULL);
1223
}
1224
1225
char *
1226
snmp_parse_index(struct snmp_toolinfo *snmptoolctx, char *str,
1227
struct snmp_object *object)
1228
{
1229
char *ptr;
1230
struct index *temp;
1231
1232
if (object->info->table_idx == NULL)
1233
return (NULL);
1234
1235
ptr = NULL;
1236
STAILQ_FOREACH(temp, &(OBJECT_IDX_LIST(object)), link) {
1237
if ((ptr = snmp_parse_subindex(snmptoolctx, str, temp, object))
1238
== NULL)
1239
return (NULL);
1240
1241
if (*ptr != ',' && *ptr != ']')
1242
return (NULL);
1243
str = ptr + 1;
1244
}
1245
1246
if (ptr == NULL || *ptr != ']') {
1247
warnx("Mismatching index - %s", str);
1248
return (NULL);
1249
}
1250
1251
return (ptr + 1);
1252
}
1253
1254
/*
1255
* Fill in the struct asn_oid member of snmp_value with suboids from input.
1256
* If an error occurs - print message on stderr and return (-1).
1257
* If all is ok - return the length of the oid.
1258
*/
1259
int32_t
1260
snmp_parse_numoid(char *argv, struct asn_oid *var)
1261
{
1262
char *endptr, *str;
1263
asn_subid_t suboid;
1264
1265
str = argv;
1266
1267
if (*str == '.')
1268
str++;
1269
1270
do {
1271
if (var->len == ASN_MAXOIDLEN) {
1272
warnx("Oid too long - %u", var->len);
1273
return (-1);
1274
}
1275
1276
suboid = strtoul(str, &endptr, 10);
1277
if (suboid > ASN_MAXID) {
1278
warnx("Oid too long - %u", var->len);
1279
return (-1);
1280
}
1281
1282
var->subs[var->len++] = suboid;
1283
str = endptr + 1;
1284
} while ( *endptr == '.');
1285
1286
if (*endptr != '\0') {
1287
warnx("Invalid oid string - %s", argv);
1288
return (-1);
1289
}
1290
1291
return (var->len);
1292
}
1293
1294
/* Append a length 1 suboid to an asn_oid structure. */
1295
int32_t
1296
snmp_suboid_append(struct asn_oid *var, asn_subid_t suboid)
1297
{
1298
if (var == NULL)
1299
return (-1);
1300
1301
if (var->len >= ASN_MAXOIDLEN) {
1302
warnx("Oid too long - %u", var->len);
1303
return (-1);
1304
}
1305
1306
var->subs[var->len++] = suboid;
1307
1308
return (1);
1309
}
1310
1311
/* Pop the last suboid from an asn_oid structure. */
1312
int32_t
1313
snmp_suboid_pop(struct asn_oid *var)
1314
{
1315
asn_subid_t suboid;
1316
1317
if (var == NULL)
1318
return (-1);
1319
1320
if (var->len < 1)
1321
return (-1);
1322
1323
suboid = var->subs[--(var->len)];
1324
var->subs[var->len] = 0;
1325
1326
return (suboid);
1327
}
1328
1329
/*
1330
* Parse the command-line provided string into an OID - allocate memory for a new
1331
* snmp object, fill in its fields and insert it in the object list. A
1332
* (snmp_verify_inoid_f) function must be provided to validate the input string.
1333
*/
1334
int32_t
1335
snmp_object_add(struct snmp_toolinfo *snmptoolctx, snmp_verify_inoid_f func,
1336
char *string)
1337
{
1338
struct snmp_object *obj;
1339
1340
if (snmptoolctx == NULL)
1341
return (-1);
1342
1343
/* XXX-BZ does that chack make sense? */
1344
if (snmptoolctx->objects >= SNMP_MAX_BINDINGS) {
1345
warnx("Too many bindings in PDU - %u", snmptoolctx->objects + 1);
1346
return (-1);
1347
}
1348
1349
if ((obj = calloc(1, sizeof(struct snmp_object))) == NULL) {
1350
syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
1351
return (-1);
1352
}
1353
1354
if (func(snmptoolctx, obj, string) < 0) {
1355
warnx("Invalid OID - %s", string);
1356
free(obj);
1357
return (-1);
1358
}
1359
1360
snmptoolctx->objects++;
1361
SLIST_INSERT_HEAD(&snmptoolctx->snmp_objectlist, obj, link);
1362
1363
return (1);
1364
}
1365
1366
/* Given an OID, find it in the object list and remove it. */
1367
int32_t
1368
snmp_object_remove(struct snmp_toolinfo *snmptoolctx, struct asn_oid *oid)
1369
{
1370
struct snmp_object *temp;
1371
1372
if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist)) {
1373
warnx("Object list already empty");
1374
return (-1);
1375
}
1376
1377
1378
SLIST_FOREACH(temp, &snmptoolctx->snmp_objectlist, link)
1379
if (asn_compare_oid(&(temp->val.var), oid) == 0)
1380
break;
1381
1382
if (temp == NULL) {
1383
warnx("No such object in list");
1384
return (-1);
1385
}
1386
1387
SLIST_REMOVE(&snmptoolctx->snmp_objectlist, temp, snmp_object, link);
1388
if (temp->val.syntax == SNMP_SYNTAX_OCTETSTRING &&
1389
temp->val.v.octetstring.octets != NULL)
1390
free(temp->val.v.octetstring.octets);
1391
free(temp);
1392
1393
return (1);
1394
}
1395
1396
static void
1397
snmp_object_freeall(struct snmp_toolinfo *snmptoolctx)
1398
{
1399
struct snmp_object *o;
1400
1401
while ((o = SLIST_FIRST(&snmptoolctx->snmp_objectlist)) != NULL) {
1402
SLIST_REMOVE_HEAD(&snmptoolctx->snmp_objectlist, link);
1403
1404
if (o->val.syntax == SNMP_SYNTAX_OCTETSTRING &&
1405
o->val.v.octetstring.octets != NULL)
1406
free(o->val.v.octetstring.octets);
1407
free(o);
1408
}
1409
}
1410
1411
/* Do all possible memory release before exit. */
1412
void
1413
snmp_tool_freeall(struct snmp_toolinfo *snmptoolctx)
1414
{
1415
if (snmp_client.chost != NULL) {
1416
free(snmp_client.chost);
1417
snmp_client.chost = NULL;
1418
}
1419
1420
if (snmp_client.cport != NULL) {
1421
free(snmp_client.cport);
1422
snmp_client.cport = NULL;
1423
}
1424
1425
snmp_mapping_free(snmptoolctx);
1426
free_filelist(snmptoolctx);
1427
snmp_object_freeall(snmptoolctx);
1428
1429
if (snmptoolctx->passwd != NULL) {
1430
free(snmptoolctx->passwd);
1431
snmptoolctx->passwd = NULL;
1432
}
1433
}
1434
1435
/*
1436
* Fill all variables from the object list into a PDU. (snmp_verify_vbind_f)
1437
* function should check whether the variable is consistent in this PDU
1438
* (e.g do not add non-leaf OIDs to a GET PDU, or OIDs with read access only to
1439
* a SET PDU) - might be NULL though. (snmp_add_vbind_f) function is the
1440
* function actually adds the variable to the PDU and must not be NULL.
1441
*/
1442
int32_t
1443
snmp_pdu_add_bindings(struct snmp_toolinfo *snmptoolctx,
1444
snmp_verify_vbind_f vfunc, snmp_add_vbind_f afunc,
1445
struct snmp_pdu *pdu, int32_t maxcount)
1446
{
1447
int32_t nbindings, abind;
1448
struct snmp_object *obj;
1449
1450
if (pdu == NULL || afunc == NULL)
1451
return (-1);
1452
1453
/* Return 0 in case of no more work todo. */
1454
if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist))
1455
return (0);
1456
1457
if (maxcount < 0 || maxcount > SNMP_MAX_BINDINGS) {
1458
warnx("maxcount out of range: <0 || >SNMP_MAX_BINDINGS");
1459
return (-1);
1460
}
1461
1462
nbindings = 0;
1463
SLIST_FOREACH(obj, &snmptoolctx->snmp_objectlist, link) {
1464
if ((vfunc != NULL) && (vfunc(snmptoolctx, pdu, obj) < 0)) {
1465
nbindings = -1;
1466
break;
1467
}
1468
if ((abind = afunc(pdu, obj)) < 0) {
1469
nbindings = -1;
1470
break;
1471
}
1472
1473
if (abind > 0) {
1474
/* Do not put more varbindings than requested. */
1475
if (++nbindings >= maxcount)
1476
break;
1477
}
1478
}
1479
1480
return (nbindings);
1481
}
1482
1483
/*
1484
* Locate an object in the object list and set a corresponding error status.
1485
*/
1486
int32_t
1487
snmp_object_seterror(struct snmp_toolinfo *snmptoolctx,
1488
struct snmp_value *err_value, int32_t error_status)
1489
{
1490
struct snmp_object *obj;
1491
1492
if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist) || err_value == NULL)
1493
return (-1);
1494
1495
SLIST_FOREACH(obj, &snmptoolctx->snmp_objectlist, link)
1496
if (asn_compare_oid(&(err_value->var), &(obj->val.var)) == 0) {
1497
obj->error = error_status;
1498
return (1);
1499
}
1500
1501
return (0);
1502
}
1503
1504
/*
1505
* Check a PDU received in response to a SNMP_PDU_GET/SNMP_PDU_GETBULK request
1506
* but don't compare syntaxes - when sending a request PDU they must be null.
1507
* This is a (almost) complete copy of snmp_pdu_check() - with matching syntaxes
1508
* checks and some other checks skipped.
1509
*/
1510
int32_t
1511
snmp_parse_get_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
1512
{
1513
uint32_t i;
1514
1515
for (i = 0; i < req->nbindings; i++) {
1516
if (asn_compare_oid(&req->bindings[i].var,
1517
&resp->bindings[i].var) != 0) {
1518
warnx("Bad OID in response");
1519
return (-1);
1520
}
1521
1522
if (snmp_client.version != SNMP_V1 && (resp->bindings[i].syntax
1523
== SNMP_SYNTAX_NOSUCHOBJECT || resp->bindings[i].syntax ==
1524
SNMP_SYNTAX_NOSUCHINSTANCE))
1525
return (0);
1526
}
1527
1528
return (1);
1529
}
1530
1531
int32_t
1532
snmp_parse_getbulk_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
1533
{
1534
int32_t N, R, M, r;
1535
1536
if (req->error_status > (int32_t) resp->nbindings) {
1537
warnx("Bad number of bindings in response");
1538
return (-1);
1539
}
1540
1541
for (N = 0; N < req->error_status; N++) {
1542
if (asn_is_suboid(&req->bindings[N].var,
1543
&resp->bindings[N].var) == 0)
1544
return (0);
1545
if (resp->bindings[N].syntax == SNMP_SYNTAX_ENDOFMIBVIEW)
1546
return (0);
1547
}
1548
1549
for (R = N , r = N; R < (int32_t) req->nbindings; R++) {
1550
for (M = 0; M < req->error_index && (r + M) <
1551
(int32_t) resp->nbindings; M++) {
1552
if (asn_is_suboid(&req->bindings[R].var,
1553
&resp->bindings[r + M].var) == 0)
1554
return (0);
1555
1556
if (resp->bindings[r + M].syntax ==
1557
SNMP_SYNTAX_ENDOFMIBVIEW) {
1558
M++;
1559
break;
1560
}
1561
}
1562
r += M;
1563
}
1564
1565
return (0);
1566
}
1567
1568
int32_t
1569
snmp_parse_getnext_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
1570
{
1571
uint32_t i;
1572
1573
for (i = 0; i < req->nbindings; i++) {
1574
if (asn_is_suboid(&req->bindings[i].var, &resp->bindings[i].var)
1575
== 0)
1576
return (0);
1577
1578
if (resp->version != SNMP_V1 && resp->bindings[i].syntax ==
1579
SNMP_SYNTAX_ENDOFMIBVIEW)
1580
return (0);
1581
}
1582
1583
return (1);
1584
}
1585
1586
/*
1587
* Should be called to check a response to get/getnext/getbulk.
1588
*/
1589
int32_t
1590
snmp_parse_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
1591
{
1592
if (resp == NULL || req == NULL)
1593
return (-2);
1594
1595
if (resp->version != req->version) {
1596
warnx("Response has wrong version");
1597
return (-1);
1598
}
1599
1600
if (resp->error_status == SNMP_ERR_NOSUCHNAME) {
1601
warnx("Error - No Such Name");
1602
return (0);
1603
}
1604
1605
if (resp->error_status != SNMP_ERR_NOERROR) {
1606
warnx("Error %d in response", resp->error_status);
1607
return (-1);
1608
}
1609
1610
if (resp->nbindings != req->nbindings && req->type != SNMP_PDU_GETBULK){
1611
warnx("Bad number of bindings in response");
1612
return (-1);
1613
}
1614
1615
switch (req->type) {
1616
case SNMP_PDU_GET:
1617
return (snmp_parse_get_resp(resp,req));
1618
case SNMP_PDU_GETBULK:
1619
return (snmp_parse_getbulk_resp(resp,req));
1620
case SNMP_PDU_GETNEXT:
1621
return (snmp_parse_getnext_resp(resp,req));
1622
default:
1623
/* NOTREACHED */
1624
break;
1625
}
1626
1627
return (-2);
1628
}
1629
1630
static void
1631
snmp_output_octetstring(struct snmp_toolinfo *snmptoolctx, enum snmp_tc tc,
1632
uint32_t len, uint8_t *octets)
1633
{
1634
char *buf;
1635
1636
if (len == 0 || octets == NULL)
1637
return;
1638
1639
if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1640
fprintf(stdout, "%s : ",
1641
syntax_strings[SNMP_SYNTAX_OCTETSTRING].str);
1642
1643
if ((buf = snmp_oct2tc(tc, len, (char *) octets)) != NULL) {
1644
fprintf(stdout, "%s", buf);
1645
free(buf);
1646
}
1647
}
1648
1649
static void
1650
snmp_output_octetindex(struct snmp_toolinfo *snmptoolctx, enum snmp_tc tc,
1651
struct asn_oid *oid)
1652
{
1653
uint32_t i;
1654
uint8_t *s;
1655
1656
if ((s = malloc(oid->subs[0] + 1)) == NULL)
1657
syslog(LOG_ERR, "malloc failed - %s", strerror(errno));
1658
else {
1659
for (i = 0; i < oid->subs[0]; i++)
1660
s[i] = (u_char) (oid->subs[i + 1]);
1661
1662
snmp_output_octetstring(snmptoolctx, tc, oid->subs[0], s);
1663
free(s);
1664
}
1665
}
1666
1667
/*
1668
* Check and output syntax type and value.
1669
*/
1670
static void
1671
snmp_output_oid_value(struct snmp_toolinfo *snmptoolctx, struct asn_oid *oid)
1672
{
1673
char oid_string[ASN_OIDSTRLEN];
1674
struct snmp_object obj;
1675
1676
if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1677
fprintf(stdout, "%s : ", syntax_strings[SNMP_SYNTAX_OID].str);
1678
1679
if(!ISSET_NUMERIC(snmptoolctx)) {
1680
memset(&obj, 0, sizeof(struct snmp_object));
1681
asn_append_oid(&(obj.val.var), oid);
1682
1683
if (snmp_lookup_enumstring(snmptoolctx, &obj) > 0)
1684
fprintf(stdout, "%s" , obj.info->string);
1685
else if (snmp_lookup_oidstring(snmptoolctx, &obj) > 0)
1686
fprintf(stdout, "%s" , obj.info->string);
1687
else if (snmp_lookup_nodestring(snmptoolctx, &obj) > 0)
1688
fprintf(stdout, "%s" , obj.info->string);
1689
else {
1690
(void) asn_oid2str_r(oid, oid_string);
1691
fprintf(stdout, "%s", oid_string);
1692
}
1693
} else {
1694
(void) asn_oid2str_r(oid, oid_string);
1695
fprintf(stdout, "%s", oid_string);
1696
}
1697
}
1698
1699
static void
1700
snmp_output_int(struct snmp_toolinfo *snmptoolctx, struct enum_pairs *enums,
1701
int32_t int_val)
1702
{
1703
char *string;
1704
1705
if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1706
fprintf(stdout, "%s : ",
1707
syntax_strings[SNMP_SYNTAX_INTEGER].str);
1708
1709
if (enums != NULL && (string = enum_string_lookup(enums, int_val))
1710
!= NULL)
1711
fprintf(stdout, "%s", string);
1712
else
1713
fprintf(stdout, "%d", int_val);
1714
}
1715
1716
static void
1717
snmp_output_ipaddress(struct snmp_toolinfo *snmptoolctx, uint8_t *ip)
1718
{
1719
if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1720
fprintf(stdout, "%s : ",
1721
syntax_strings[SNMP_SYNTAX_IPADDRESS].str);
1722
1723
fprintf(stdout, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
1724
}
1725
1726
static void
1727
snmp_output_counter(struct snmp_toolinfo *snmptoolctx, uint32_t counter)
1728
{
1729
if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1730
fprintf(stdout, "%s : ",
1731
syntax_strings[SNMP_SYNTAX_COUNTER].str);
1732
1733
fprintf(stdout, "%u", counter);
1734
}
1735
1736
static void
1737
snmp_output_gauge(struct snmp_toolinfo *snmptoolctx, uint32_t gauge)
1738
{
1739
if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1740
fprintf(stdout, "%s : ", syntax_strings[SNMP_SYNTAX_GAUGE].str);
1741
1742
fprintf(stdout, "%u", gauge);
1743
}
1744
1745
static void
1746
snmp_output_ticks(struct snmp_toolinfo *snmptoolctx, uint32_t ticks)
1747
{
1748
if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1749
fprintf(stdout, "%s : ",
1750
syntax_strings[SNMP_SYNTAX_TIMETICKS].str);
1751
1752
fprintf(stdout, "%u", ticks);
1753
}
1754
1755
static void
1756
snmp_output_counter64(struct snmp_toolinfo *snmptoolctx, uint64_t counter64)
1757
{
1758
if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1759
fprintf(stdout, "%s : ",
1760
syntax_strings[SNMP_SYNTAX_COUNTER64].str);
1761
1762
fprintf(stdout,"%ju", counter64);
1763
}
1764
1765
int32_t
1766
snmp_output_numval(struct snmp_toolinfo *snmptoolctx, struct snmp_value *val,
1767
struct snmp_oid2str *entry)
1768
{
1769
if (val == NULL)
1770
return (-1);
1771
1772
if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET)
1773
fprintf(stdout, " = ");
1774
1775
switch (val->syntax) {
1776
case SNMP_SYNTAX_INTEGER:
1777
if (entry != NULL)
1778
snmp_output_int(snmptoolctx, entry->snmp_enum,
1779
val->v.integer);
1780
else
1781
snmp_output_int(snmptoolctx, NULL, val->v.integer);
1782
break;
1783
1784
case SNMP_SYNTAX_OCTETSTRING:
1785
if (entry != NULL)
1786
snmp_output_octetstring(snmptoolctx, entry->tc,
1787
val->v.octetstring.len, val->v.octetstring.octets);
1788
else
1789
snmp_output_octetstring(snmptoolctx, SNMP_STRING,
1790
val->v.octetstring.len, val->v.octetstring.octets);
1791
break;
1792
1793
case SNMP_SYNTAX_OID:
1794
snmp_output_oid_value(snmptoolctx, &(val->v.oid));
1795
break;
1796
1797
case SNMP_SYNTAX_IPADDRESS:
1798
snmp_output_ipaddress(snmptoolctx, val->v.ipaddress);
1799
break;
1800
1801
case SNMP_SYNTAX_COUNTER:
1802
snmp_output_counter(snmptoolctx, val->v.uint32);
1803
break;
1804
1805
case SNMP_SYNTAX_GAUGE:
1806
snmp_output_gauge(snmptoolctx, val->v.uint32);
1807
break;
1808
1809
case SNMP_SYNTAX_TIMETICKS:
1810
snmp_output_ticks(snmptoolctx, val->v.uint32);
1811
break;
1812
1813
case SNMP_SYNTAX_COUNTER64:
1814
snmp_output_counter64(snmptoolctx, val->v.counter64);
1815
break;
1816
1817
case SNMP_SYNTAX_NOSUCHOBJECT:
1818
fprintf(stderr, "No Such Object\n");
1819
return (val->syntax);
1820
1821
case SNMP_SYNTAX_NOSUCHINSTANCE:
1822
fprintf(stderr, "No Such Instance\n");
1823
return (val->syntax);
1824
1825
case SNMP_SYNTAX_ENDOFMIBVIEW:
1826
fprintf(stdout, "End of Mib View\n");
1827
return (val->syntax);
1828
1829
case SNMP_SYNTAX_NULL:
1830
/* NOTREACHED */
1831
fprintf(stderr, "agent returned NULL Syntax\n");
1832
return (val->syntax);
1833
1834
default:
1835
/* NOTREACHED - If here - then all went completely wrong. */
1836
fprintf(stderr, "agent returned unknown syntax\n");
1837
return (-1);
1838
}
1839
1840
fprintf(stdout, "\n");
1841
1842
return (0);
1843
}
1844
1845
static int32_t
1846
snmp_fill_object(struct snmp_toolinfo *snmptoolctx, struct snmp_object *obj,
1847
struct snmp_value *val)
1848
{
1849
int32_t rc;
1850
asn_subid_t suboid;
1851
1852
if (obj == NULL || val == NULL)
1853
return (-1);
1854
1855
if ((suboid = snmp_suboid_pop(&(val->var))) > ASN_MAXID)
1856
return (-1);
1857
1858
memset(obj, 0, sizeof(struct snmp_object));
1859
asn_append_oid(&(obj->val.var), &(val->var));
1860
obj->val.syntax = val->syntax;
1861
1862
if (obj->val.syntax > 0)
1863
rc = snmp_lookup_leafstring(snmptoolctx, obj);
1864
else
1865
rc = snmp_lookup_nonleaf_string(snmptoolctx, obj);
1866
1867
(void) snmp_suboid_append(&(val->var), suboid);
1868
(void) snmp_suboid_append(&(obj->val.var), suboid);
1869
1870
return (rc);
1871
}
1872
1873
static int32_t
1874
snmp_output_index(struct snmp_toolinfo *snmptoolctx, struct index *stx,
1875
struct asn_oid *oid)
1876
{
1877
uint8_t ip[4];
1878
uint32_t bytes = 1;
1879
uint64_t cnt64;
1880
struct asn_oid temp, out;
1881
1882
if (oid->len < bytes)
1883
return (-1);
1884
1885
memset(&temp, 0, sizeof(struct asn_oid));
1886
asn_append_oid(&temp, oid);
1887
1888
switch (stx->syntax) {
1889
case SNMP_SYNTAX_INTEGER:
1890
snmp_output_int(snmptoolctx, stx->snmp_enum, temp.subs[0]);
1891
break;
1892
1893
case SNMP_SYNTAX_OCTETSTRING:
1894
if ((temp.subs[0] > temp.len -1 ) || (temp.subs[0] >
1895
ASN_MAXOCTETSTRING))
1896
return (-1);
1897
snmp_output_octetindex(snmptoolctx, stx->tc, &temp);
1898
bytes += temp.subs[0];
1899
break;
1900
1901
case SNMP_SYNTAX_OID:
1902
if ((temp.subs[0] > temp.len -1) || (temp.subs[0] >
1903
ASN_MAXOIDLEN))
1904
return (-1);
1905
1906
bytes += temp.subs[0];
1907
memset(&out, 0, sizeof(struct asn_oid));
1908
asn_slice_oid(&out, &temp, 1, bytes);
1909
snmp_output_oid_value(snmptoolctx, &out);
1910
break;
1911
1912
case SNMP_SYNTAX_IPADDRESS:
1913
if (temp.len < 4)
1914
return (-1);
1915
for (bytes = 0; bytes < 4; bytes++)
1916
ip[bytes] = temp.subs[bytes];
1917
1918
snmp_output_ipaddress(snmptoolctx, ip);
1919
bytes = 4;
1920
break;
1921
1922
case SNMP_SYNTAX_COUNTER:
1923
snmp_output_counter(snmptoolctx, temp.subs[0]);
1924
break;
1925
1926
case SNMP_SYNTAX_GAUGE:
1927
snmp_output_gauge(snmptoolctx, temp.subs[0]);
1928
break;
1929
1930
case SNMP_SYNTAX_TIMETICKS:
1931
snmp_output_ticks(snmptoolctx, temp.subs[0]);
1932
break;
1933
1934
case SNMP_SYNTAX_COUNTER64:
1935
if (oid->len < 2)
1936
return (-1);
1937
bytes = 2;
1938
memcpy(&cnt64, temp.subs, bytes);
1939
snmp_output_counter64(snmptoolctx, cnt64);
1940
break;
1941
1942
default:
1943
return (-1);
1944
}
1945
1946
return (bytes);
1947
}
1948
1949
static int32_t
1950
snmp_output_object(struct snmp_toolinfo *snmptoolctx, struct snmp_object *o)
1951
{
1952
int32_t i, first, len;
1953
struct asn_oid oid;
1954
struct index *temp;
1955
1956
if (ISSET_NUMERIC(snmptoolctx))
1957
return (-1);
1958
1959
if (o->info->table_idx == NULL) {
1960
fprintf(stdout,"%s.%d", o->info->string,
1961
o->val.var.subs[o->val.var.len - 1]);
1962
return (1);
1963
}
1964
1965
fprintf(stdout,"%s[", o->info->string);
1966
memset(&oid, 0, sizeof(struct asn_oid));
1967
1968
len = 1;
1969
asn_slice_oid(&oid, &(o->val.var), (o->info->table_idx->var.len + len),
1970
o->val.var.len);
1971
1972
first = 1;
1973
STAILQ_FOREACH(temp, &(OBJECT_IDX_LIST(o)), link) {
1974
if(first)
1975
first = 0;
1976
else
1977
fprintf(stdout, ", ");
1978
if ((i = snmp_output_index(snmptoolctx, temp, &oid)) < 0)
1979
break;
1980
len += i;
1981
memset(&oid, 0, sizeof(struct asn_oid));
1982
asn_slice_oid(&oid, &(o->val.var),
1983
(o->info->table_idx->var.len + len), o->val.var.len + 1);
1984
}
1985
1986
fprintf(stdout,"]");
1987
return (1);
1988
}
1989
1990
void
1991
snmp_output_err_resp(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu)
1992
{
1993
struct snmp_object *object;
1994
char buf[ASN_OIDSTRLEN];
1995
1996
if (pdu == NULL || (pdu->error_index > (int32_t) pdu->nbindings)) {
1997
fprintf(stdout, "Invalid error index in PDU\n");
1998
return;
1999
}
2000
2001
if ((object = calloc(1, sizeof(struct snmp_object))) == NULL) {
2002
fprintf(stdout, "calloc: %s", strerror(errno));
2003
return;
2004
}
2005
2006
fprintf(stdout, "Agent %s:%s returned error \n", snmp_client.chost,
2007
snmp_client.cport);
2008
2009
if (!ISSET_NUMERIC(snmptoolctx) && (snmp_fill_object(snmptoolctx, object,
2010
&(pdu->bindings[pdu->error_index - 1])) > 0))
2011
snmp_output_object(snmptoolctx, object);
2012
else {
2013
asn_oid2str_r(&(pdu->bindings[pdu->error_index - 1].var), buf);
2014
fprintf(stdout,"%s", buf);
2015
}
2016
2017
fprintf(stdout," caused error - ");
2018
if ((pdu->error_status > 0) && (pdu->error_status <=
2019
SNMP_ERR_INCONS_NAME))
2020
fprintf(stdout, "%s\n", error_strings[pdu->error_status].str);
2021
else
2022
fprintf(stdout,"%s\n", error_strings[SNMP_ERR_UNKNOWN].str);
2023
2024
free(object);
2025
object = NULL;
2026
}
2027
2028
int32_t
2029
snmp_output_resp(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu,
2030
struct asn_oid *root)
2031
{
2032
struct snmp_object *object;
2033
char p[ASN_OIDSTRLEN];
2034
int32_t error;
2035
uint32_t i;
2036
2037
if ((object = calloc(1, sizeof(struct snmp_object))) == NULL)
2038
return (-1);
2039
2040
i = error = 0;
2041
while (i < pdu->nbindings) {
2042
if (root != NULL && !(asn_is_suboid(root,
2043
&(pdu->bindings[i].var))))
2044
break;
2045
2046
if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET) {
2047
if (!ISSET_NUMERIC(snmptoolctx) &&
2048
(snmp_fill_object(snmptoolctx, object,
2049
&(pdu->bindings[i])) > 0))
2050
snmp_output_object(snmptoolctx, object);
2051
else {
2052
asn_oid2str_r(&(pdu->bindings[i].var), p);
2053
fprintf(stdout, "%s", p);
2054
}
2055
}
2056
error |= snmp_output_numval(snmptoolctx, &(pdu->bindings[i]),
2057
object->info);
2058
i++;
2059
}
2060
2061
free(object);
2062
object = NULL;
2063
2064
if (error)
2065
return (-1);
2066
2067
return (i);
2068
}
2069
2070
void
2071
snmp_output_engine(void)
2072
{
2073
uint32_t i;
2074
char *cptr, engine[2 * SNMP_ENGINE_ID_SIZ + 2];
2075
2076
cptr = engine;
2077
for (i = 0; i < snmp_client.engine.engine_len; i++)
2078
cptr += sprintf(cptr, "%.2x", snmp_client.engine.engine_id[i]);
2079
*cptr++ = '\0';
2080
2081
fprintf(stdout, "Engine ID 0x%s\n", engine);
2082
fprintf(stdout, "Boots : %u\t\tTime : %d\n",
2083
snmp_client.engine.engine_boots,
2084
snmp_client.engine.engine_time);
2085
}
2086
2087
void
2088
snmp_output_keys(void)
2089
{
2090
uint32_t i, keylen = 0;
2091
char *cptr, extkey[2 * SNMP_AUTH_KEY_SIZ + 2];
2092
2093
fprintf(stdout, "Localized keys for %s\n", snmp_client.user.sec_name);
2094
if (snmp_client.user.auth_proto == SNMP_AUTH_HMAC_MD5) {
2095
fprintf(stdout, "MD5 : 0x");
2096
keylen = SNMP_AUTH_HMACMD5_KEY_SIZ;
2097
} else if (snmp_client.user.auth_proto == SNMP_AUTH_HMAC_SHA) {
2098
fprintf(stdout, "SHA : 0x");
2099
keylen = SNMP_AUTH_HMACSHA_KEY_SIZ;
2100
}
2101
if (snmp_client.user.auth_proto != SNMP_AUTH_NOAUTH) {
2102
cptr = extkey;
2103
for (i = 0; i < keylen; i++)
2104
cptr += sprintf(cptr, "%.2x",
2105
snmp_client.user.auth_key[i]);
2106
*cptr++ = '\0';
2107
fprintf(stdout, "%s\n", extkey);
2108
}
2109
2110
if (snmp_client.user.priv_proto == SNMP_PRIV_DES) {
2111
fprintf(stdout, "DES : 0x");
2112
keylen = SNMP_PRIV_DES_KEY_SIZ;
2113
} else if (snmp_client.user.priv_proto == SNMP_PRIV_AES) {
2114
fprintf(stdout, "AES : 0x");
2115
keylen = SNMP_PRIV_AES_KEY_SIZ;
2116
}
2117
if (snmp_client.user.priv_proto != SNMP_PRIV_NOPRIV) {
2118
cptr = extkey;
2119
for (i = 0; i < keylen; i++)
2120
cptr += sprintf(cptr, "%.2x",
2121
snmp_client.user.priv_key[i]);
2122
*cptr++ = '\0';
2123
fprintf(stdout, "%s\n", extkey);
2124
}
2125
}
2126
2127