Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c
105585 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
* Bsnmpget and bsnmpwalk are simple tools for querying SNMP agents,
30
* bsnmpset can be used to set MIB objects in an agent.
31
*/
32
33
#include <sys/queue.h>
34
#include <sys/types.h>
35
36
#include <assert.h>
37
#include <ctype.h>
38
#include <err.h>
39
#include <errno.h>
40
#include <stdarg.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
static const char *program_name = NULL;
54
static enum program_e {
55
BSNMPGET,
56
BSNMPWALK,
57
BSNMPSET
58
} program;
59
60
/* *****************************************************************************
61
* Common bsnmptools functions.
62
*/
63
static void
64
usage(void)
65
{
66
fprintf(stderr,
67
"Usage:\n"
68
"%s %s [-A options] [-b buffersize] [-C options] [-I options]\n"
69
"\t[-i filelist] [-l filename]%s [-o output] [-P options]\n"
70
"\t%s[-r retries] [-s [trans::][community@][server][:port]]\n"
71
"\t[-t timeout] [-U options] [-v version]%s\n",
72
program_name,
73
(program == BSNMPGET) ? "[-aDdehnK]" :
74
(program == BSNMPWALK) ? "[-dhnK]" :
75
(program == BSNMPSET) ? "[-adehnK]" :
76
"",
77
(program == BSNMPGET || program == BSNMPWALK) ?
78
" [-M max-repetitions] [-N non-repeaters]" : "",
79
(program == BSNMPGET || program == BSNMPWALK) ? "[-p pdu] " : "",
80
(program == BSNMPGET) ? " OID [OID ...]" :
81
(program == BSNMPWALK || program == BSNMPSET) ? " [OID ...]" :
82
""
83
);
84
}
85
86
static int32_t
87
parse_max_repetitions(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
88
{
89
uint32_t v;
90
91
assert(opt_arg != NULL);
92
93
v = strtoul(opt_arg, (void *) NULL, 10);
94
95
if (v > SNMP_MAX_BINDINGS) {
96
warnx("Max repetitions value greater than %d maximum allowed.",
97
SNMP_MAX_BINDINGS);
98
return (-1);
99
}
100
101
SET_MAXREP(snmptoolctx, v);
102
return (2);
103
}
104
105
static int32_t
106
parse_non_repeaters(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
107
{
108
uint32_t v;
109
110
assert(opt_arg != NULL);
111
112
v = strtoul(opt_arg, (void *) NULL, 10);
113
114
if (v > SNMP_MAX_BINDINGS) {
115
warnx("Non repeaters value greater than %d maximum allowed.",
116
SNMP_MAX_BINDINGS);
117
return (-1);
118
}
119
120
SET_NONREP(snmptoolctx, v);
121
return (2);
122
}
123
124
static int32_t
125
parse_pdu_type(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
126
{
127
assert(opt_arg != NULL);
128
129
if (strcasecmp(opt_arg, "getbulk") == 0)
130
SET_PDUTYPE(snmptoolctx, SNMP_PDU_GETBULK);
131
else if (strcasecmp(opt_arg, "getnext") == 0)
132
SET_PDUTYPE(snmptoolctx, SNMP_PDU_GETNEXT);
133
else if (strcasecmp(opt_arg, "get") == 0)
134
SET_PDUTYPE(snmptoolctx, SNMP_PDU_GET);
135
else {
136
warnx("PDU type '%s' not supported.", opt_arg);
137
return (-1);
138
}
139
140
return (2);
141
}
142
143
static int32_t
144
snmptool_parse_options(struct snmp_toolinfo *snmptoolctx, int argc, char **argv)
145
{
146
int32_t count, optnum = 0;
147
int ch;
148
const char *opts;
149
150
switch (program) {
151
case BSNMPWALK:
152
opts = "dhnKA:b:C:I:i:l:M:N:o:P:p:r:s:t:U:v:";
153
break;
154
case BSNMPGET:
155
opts = "aDdehnKA:b:C:I:i:l:M:N:o:P:p:r:s:t:U:v:";
156
break;
157
case BSNMPSET:
158
opts = "adehnKA:b:C:I:i:l:o:P:r:s:t:U:v:";
159
break;
160
default:
161
return (-1);
162
}
163
164
while ((ch = getopt(argc, argv, opts)) != EOF) {
165
switch (ch) {
166
case 'A':
167
count = parse_authentication(snmptoolctx, optarg);
168
break;
169
case 'a':
170
count = parse_skip_access(snmptoolctx);
171
break;
172
case 'b':
173
count = parse_buflen(optarg);
174
break;
175
case 'D':
176
count = parse_discovery(snmptoolctx);
177
break;
178
case 'd':
179
count = parse_debug();
180
break;
181
case 'e':
182
count = parse_errors(snmptoolctx);
183
break;
184
case 'h':
185
usage();
186
return (-2);
187
case 'C':
188
count = parse_context(snmptoolctx, optarg);
189
break;
190
case 'I':
191
count = parse_include(snmptoolctx, optarg);
192
break;
193
case 'i':
194
count = parse_file(snmptoolctx, optarg);
195
break;
196
case 'K':
197
count = parse_local_key(snmptoolctx);
198
break;
199
case 'l':
200
count = parse_local_path(optarg);
201
break;
202
case 'M':
203
count = parse_max_repetitions(snmptoolctx, optarg);
204
break;
205
case 'N':
206
count = parse_non_repeaters(snmptoolctx, optarg);
207
break;
208
case 'n':
209
count = parse_num_oids(snmptoolctx);
210
break;
211
case 'o':
212
count = parse_output(snmptoolctx, optarg);
213
break;
214
case 'P':
215
count = parse_privacy(snmptoolctx, optarg);
216
break;
217
case 'p':
218
count = parse_pdu_type(snmptoolctx, optarg);
219
break;
220
case 'r':
221
count = parse_retry(optarg);
222
break;
223
case 's':
224
count = parse_server(optarg);
225
break;
226
case 't':
227
count = parse_timeout(optarg);
228
break;
229
case 'U':
230
count = parse_user_security(snmptoolctx, optarg);
231
break;
232
case 'v':
233
count = parse_version(optarg);
234
break;
235
case '?':
236
default:
237
usage();
238
return (-1);
239
}
240
if (count < 0)
241
return (-1);
242
optnum += count;
243
}
244
245
return (optnum);
246
}
247
248
/*
249
* Read user input OID - one of following formats:
250
* 1) 1.2.1.1.2.1.0 - that is if option numeric was given;
251
* 2) string - in such case append .0 to the asn_oid subs;
252
* 3) string.1 - no additional processing required in such case.
253
*/
254
static char *
255
snmptools_parse_stroid(struct snmp_toolinfo *snmptoolctx,
256
struct snmp_object *obj, char *argv)
257
{
258
char string[MAXSTR], *str;
259
int32_t i = 0;
260
struct asn_oid in_oid;
261
262
str = argv;
263
264
if (*str == '.')
265
str++;
266
267
while (isalpha(*str) || *str == '_' || (i != 0 && isdigit(*str))) {
268
str++;
269
i++;
270
}
271
272
if (i <= 0 || i >= MAXSTR)
273
return (NULL);
274
275
memset(&in_oid, 0, sizeof(struct asn_oid));
276
if ((str = snmp_parse_suboid((argv + i), &in_oid)) == NULL) {
277
warnx("Invalid OID - %s", argv);
278
return (NULL);
279
}
280
281
strlcpy(string, argv, i + 1);
282
if (snmp_lookup_oidall(snmptoolctx, obj, string) < 0) {
283
warnx("No entry for %s in mapping lists", string);
284
return (NULL);
285
}
286
287
/* If OID given on command line append it. */
288
if (in_oid.len > 0)
289
asn_append_oid(&(obj->val.var), &in_oid);
290
else if (*str == '[') {
291
if ((str = snmp_parse_index(snmptoolctx, str + 1, obj)) == NULL)
292
return (NULL);
293
} else if (obj->val.syntax > 0 && GET_PDUTYPE(snmptoolctx) ==
294
SNMP_PDU_GET) {
295
if (snmp_suboid_append(&(obj->val.var), (asn_subid_t) 0) < 0)
296
return (NULL);
297
}
298
299
return (str);
300
}
301
302
static int32_t
303
snmptools_parse_oid(struct snmp_toolinfo *snmptoolctx,
304
struct snmp_object *obj, char *argv)
305
{
306
if (argv == NULL)
307
return (-1);
308
309
if (ISSET_NUMERIC(snmptoolctx)) {
310
if (snmp_parse_numoid(argv, &(obj->val.var)) < 0)
311
return (-1);
312
} else {
313
if (snmptools_parse_stroid(snmptoolctx, obj, argv) == NULL &&
314
snmp_parse_numoid(argv, &(obj->val.var)) < 0)
315
return (-1);
316
}
317
318
return (1);
319
}
320
321
static int32_t
322
snmptool_add_vbind(struct snmp_pdu *pdu, struct snmp_object *obj)
323
{
324
if (obj->error > 0)
325
return (0);
326
327
asn_append_oid(&(pdu->bindings[pdu->nbindings].var), &(obj->val.var));
328
pdu->nbindings++;
329
330
return (pdu->nbindings);
331
}
332
333
/* *****************************************************************************
334
* bsnmpget private functions.
335
*/
336
static int32_t
337
snmpget_verify_vbind(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu,
338
struct snmp_object *obj)
339
{
340
if (pdu->version == SNMP_V1 && obj->val.syntax ==
341
SNMP_SYNTAX_COUNTER64) {
342
warnx("64-bit counters are not supported in SNMPv1 PDU");
343
return (-1);
344
}
345
346
if (ISSET_NUMERIC(snmptoolctx) || pdu->type == SNMP_PDU_GETNEXT ||
347
pdu->type == SNMP_PDU_GETBULK)
348
return (1);
349
350
if (pdu->type == SNMP_PDU_GET && obj->val.syntax == SNMP_SYNTAX_NULL) {
351
warnx("Only leaf object values can be added to GET PDU");
352
return (-1);
353
}
354
355
return (1);
356
}
357
358
/*
359
* In case of a getbulk PDU, the error_status and error_index fields are used by
360
* libbsnmp to hold the values of the non-repeaters and max-repetitions fields
361
* that are present only in the getbulk - so before sending the PDU make sure
362
* these have correct values as well.
363
*/
364
static void
365
snmpget_fix_getbulk(struct snmp_pdu *pdu, uint32_t max_rep, uint32_t non_rep)
366
{
367
assert(pdu != NULL);
368
369
if (pdu->nbindings < non_rep)
370
pdu->error_status = pdu->nbindings;
371
else
372
pdu->error_status = non_rep;
373
374
if (max_rep > 0)
375
pdu->error_index = max_rep;
376
else
377
pdu->error_index = 1;
378
}
379
380
static int
381
snmptool_get(struct snmp_toolinfo *snmptoolctx)
382
{
383
struct snmp_pdu req, resp;
384
385
snmp_pdu_create(&req, GET_PDUTYPE(snmptoolctx));
386
387
while ((snmp_pdu_add_bindings(snmptoolctx, snmpget_verify_vbind,
388
snmptool_add_vbind, &req, SNMP_MAX_BINDINGS)) > 0) {
389
390
if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK)
391
snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx),
392
GET_NONREP(snmptoolctx));
393
394
if (snmp_dialog(&req, &resp) == -1) {
395
warn("Snmp dialog");
396
break;
397
}
398
399
if (snmp_parse_resp(&resp, &req) >= 0) {
400
snmp_output_resp(snmptoolctx, &resp, NULL);
401
snmp_pdu_free(&resp);
402
break;
403
}
404
405
snmp_output_err_resp(snmptoolctx, &resp);
406
if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK ||
407
!ISSET_RETRY(snmptoolctx)) {
408
snmp_pdu_free(&resp);
409
break;
410
}
411
412
/*
413
* Loop through the object list and set object->error to the
414
* varbinding that caused the error.
415
*/
416
if (snmp_object_seterror(snmptoolctx,
417
&(resp.bindings[resp.error_index - 1]),
418
resp.error_status) <= 0) {
419
snmp_pdu_free(&resp);
420
break;
421
}
422
423
fprintf(stderr, "Retrying...\n");
424
snmp_pdu_free(&resp);
425
snmp_pdu_create(&req, GET_PDUTYPE(snmptoolctx));
426
}
427
428
snmp_pdu_free(&req);
429
430
return (0);
431
}
432
433
434
/* *****************************************************************************
435
* bsnmpwalk private functions.
436
*/
437
/* The default tree to walk. */
438
static const struct asn_oid snmp_mibII_OID = {
439
6 , { 1, 3, 6, 1, 2, 1 }
440
};
441
442
static int32_t
443
snmpwalk_add_default(struct snmp_toolinfo *snmptoolctx __unused,
444
struct snmp_object *obj, char *string __unused)
445
{
446
asn_append_oid(&(obj->val.var), &snmp_mibII_OID);
447
return (1);
448
}
449
450
/*
451
* Prepare the next GetNext/Get PDU to send.
452
*/
453
static void
454
snmpwalk_nextpdu_create(uint32_t op, struct asn_oid *var, struct snmp_pdu *pdu)
455
{
456
snmp_pdu_create(pdu, op);
457
asn_append_oid(&(pdu->bindings[0].var), var);
458
pdu->nbindings = 1;
459
}
460
461
static int
462
snmptool_walk(struct snmp_toolinfo *snmptoolctx)
463
{
464
struct snmp_pdu req, resp;
465
struct asn_oid root; /* Keep the initial oid. */
466
int32_t outputs, rc;
467
uint32_t op;
468
469
if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK)
470
op = SNMP_PDU_GETBULK;
471
else
472
op = SNMP_PDU_GETNEXT;
473
474
snmp_pdu_create(&req, op);
475
476
while ((rc = snmp_pdu_add_bindings(snmptoolctx, NULL,
477
snmptool_add_vbind, &req, 1)) > 0) {
478
479
/* Remember the root where the walk started from. */
480
memset(&root, 0, sizeof(struct asn_oid));
481
asn_append_oid(&root, &(req.bindings[0].var));
482
483
if (op == SNMP_PDU_GETBULK)
484
snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx),
485
GET_NONREP(snmptoolctx));
486
487
outputs = 0;
488
while (snmp_dialog(&req, &resp) >= 0) {
489
if ((snmp_parse_resp(&resp, &req)) < 0) {
490
snmp_output_err_resp(snmptoolctx, &resp);
491
snmp_pdu_free(&resp);
492
outputs = -1;
493
break;
494
}
495
496
rc = snmp_output_resp(snmptoolctx, &resp, &root);
497
if (rc < 0) {
498
snmp_pdu_free(&resp);
499
outputs = -1;
500
break;
501
}
502
503
outputs += rc;
504
505
if ((u_int)rc < resp.nbindings || resp.nbindings == 0) {
506
snmp_pdu_free(&resp);
507
break;
508
}
509
510
snmpwalk_nextpdu_create(op,
511
&(resp.bindings[resp.nbindings - 1].var), &req);
512
if (op == SNMP_PDU_GETBULK)
513
snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx),
514
GET_NONREP(snmptoolctx));
515
snmp_pdu_free(&resp);
516
}
517
518
/* Just in case our root was a leaf. */
519
if (outputs == 0) {
520
snmpwalk_nextpdu_create(SNMP_PDU_GET, &root, &req);
521
if (snmp_dialog(&req, &resp) == SNMP_CODE_OK) {
522
if (snmp_parse_resp(&resp, &req) < 0)
523
snmp_output_err_resp(snmptoolctx, &resp);
524
else
525
snmp_output_resp(snmptoolctx, &resp,
526
NULL);
527
snmp_pdu_free(&resp);
528
} else
529
warn("Snmp dialog");
530
}
531
532
if (snmp_object_remove(snmptoolctx, &root) < 0) {
533
warnx("snmp_object_remove");
534
break;
535
}
536
537
snmp_pdu_free(&req);
538
snmp_pdu_create(&req, op);
539
}
540
541
snmp_pdu_free(&req);
542
543
if (rc == 0)
544
return (0);
545
else
546
return (1);
547
}
548
549
/* *****************************************************************************
550
* bsnmpset private functions.
551
*/
552
553
static int32_t
554
parse_oid_numeric(struct snmp_value *value, char *val)
555
{
556
char *endptr;
557
int32_t saved_errno;
558
asn_subid_t suboid;
559
560
do {
561
saved_errno = errno;
562
errno = 0;
563
suboid = strtoul(val, &endptr, 10);
564
if (errno != 0) {
565
warn("Value %s not supported", val);
566
errno = saved_errno;
567
return (-1);
568
}
569
errno = saved_errno;
570
if ((asn_subid_t) suboid > ASN_MAXID) {
571
warnx("Suboid %u > ASN_MAXID", suboid);
572
return (-1);
573
}
574
if (snmp_suboid_append(&(value->v.oid), suboid) < 0)
575
return (-1);
576
val = endptr + 1;
577
} while (*endptr == '.');
578
579
if (*endptr != '\0')
580
warnx("OID value %s not supported", val);
581
582
value->syntax = SNMP_SYNTAX_OID;
583
return (0);
584
}
585
586
/*
587
* Allow OID leaf in both forms:
588
* 1) 1.3.6.1.2... -> in such case call directly the function reading raw OIDs;
589
* 2) begemotSnmpdAgentFreeBSD -> lookup the ASN OID corresponding to that.
590
*/
591
static int32_t
592
parse_oid_string(struct snmp_toolinfo *snmptoolctx,
593
struct snmp_value *value, char *string)
594
{
595
struct snmp_object obj;
596
597
if (isdigit(string[0]))
598
return (parse_oid_numeric(value, string));
599
600
memset(&obj, 0, sizeof(struct snmp_object));
601
if (snmp_lookup_enumoid(snmptoolctx, &obj, string) < 0) {
602
warnx("Unknown OID enum string - %s", string);
603
return (-1);
604
}
605
606
asn_append_oid(&(value->v.oid), &(obj.val.var));
607
return (1);
608
}
609
610
static int32_t
611
parse_ip(struct snmp_value * value, char * val)
612
{
613
char *endptr, *str;
614
int32_t i;
615
uint32_t v;
616
617
str = val;
618
for (i = 0; i < 4; i++) {
619
v = strtoul(str, &endptr, 10);
620
if (v > 0xff)
621
return (-1);
622
if (*endptr != '.' && *endptr != '\0' && i != 3)
623
break;
624
str = endptr + 1;
625
value->v.ipaddress[i] = (uint8_t) v;
626
}
627
value->syntax = SNMP_SYNTAX_IPADDRESS;
628
629
return (0);
630
}
631
632
static int32_t
633
parse_int(struct snmp_value *value, char *val)
634
{
635
char *endptr;
636
int32_t v, saved_errno;
637
638
saved_errno = errno;
639
errno = 0;
640
641
v = strtol(val, &endptr, 10);
642
643
if (errno != 0) {
644
warn("Value %s not supported", val);
645
errno = saved_errno;
646
return (-1);
647
}
648
649
value->syntax = SNMP_SYNTAX_INTEGER;
650
value->v.integer = v;
651
errno = saved_errno;
652
653
return (0);
654
}
655
656
static int32_t
657
parse_int_string(struct snmp_object *object, char *val)
658
{
659
int32_t v;
660
661
if (isdigit(val[0]))
662
return ((parse_int(&(object->val), val)));
663
664
if (object->info == NULL) {
665
warnx("Unknown enumerated integer type - %s", val);
666
return (-1);
667
}
668
if ((v = enum_number_lookup(object->info->snmp_enum, val)) < 0)
669
warnx("Unknown enumerated integer type - %s", val);
670
671
object->val.v.integer = v;
672
return (1);
673
}
674
675
/*
676
* Here syntax may be one of SNMP_SYNTAX_COUNTER, SNMP_SYNTAX_GAUGE,
677
* SNMP_SYNTAX_TIMETICKS.
678
*/
679
static int32_t
680
parse_uint(struct snmp_value *value, char *val)
681
{
682
char *endptr;
683
uint32_t v = 0;
684
int32_t saved_errno;
685
686
saved_errno = errno;
687
errno = 0;
688
689
v = strtoul(val, &endptr, 10);
690
691
if (errno != 0) {
692
warn("Value %s not supported", val);
693
errno = saved_errno;
694
return (-1);
695
}
696
697
value->v.uint32 = v;
698
errno = saved_errno;
699
700
return (0);
701
}
702
703
static int32_t
704
parse_ticks(struct snmp_value *value, char *val)
705
{
706
if (parse_uint(value, val) < 0)
707
return (-1);
708
709
value->syntax = SNMP_SYNTAX_TIMETICKS;
710
return (0);
711
}
712
713
static int32_t
714
parse_gauge(struct snmp_value *value, char *val)
715
{
716
if (parse_uint(value, val) < 0)
717
return (-1);
718
719
value->syntax = SNMP_SYNTAX_GAUGE;
720
return (0);
721
}
722
723
static int32_t
724
parse_counter(struct snmp_value *value, char *val)
725
{
726
if (parse_uint(value, val) < 0)
727
return (-1);
728
729
value->syntax = SNMP_SYNTAX_COUNTER;
730
return (0);
731
}
732
733
static int32_t
734
parse_uint64(struct snmp_value *value, char *val)
735
{
736
char *endptr;
737
int32_t saved_errno;
738
uint64_t v;
739
740
saved_errno = errno;
741
errno = 0;
742
743
v = strtoull(val, &endptr, 10);
744
745
if (errno != 0) {
746
warnx("Value %s not supported", val);
747
errno = saved_errno;
748
return (-1);
749
}
750
751
value->syntax = SNMP_SYNTAX_COUNTER64;
752
value->v.counter64 = v;
753
errno = saved_errno;
754
755
return (0);
756
}
757
758
static int32_t
759
parse_syntax_val(struct snmp_value *value, enum snmp_syntax syntax, char *val)
760
{
761
switch (syntax) {
762
case SNMP_SYNTAX_INTEGER:
763
return (parse_int(value, val));
764
case SNMP_SYNTAX_IPADDRESS:
765
return (parse_ip(value, val));
766
case SNMP_SYNTAX_COUNTER:
767
return (parse_counter(value, val));
768
case SNMP_SYNTAX_GAUGE:
769
return (parse_gauge(value, val));
770
case SNMP_SYNTAX_TIMETICKS:
771
return (parse_ticks(value, val));
772
case SNMP_SYNTAX_COUNTER64:
773
return (parse_uint64(value, val));
774
case SNMP_SYNTAX_OCTETSTRING:
775
return (snmp_tc2oct(SNMP_STRING, value, val));
776
case SNMP_SYNTAX_OID:
777
return (parse_oid_numeric(value, val));
778
default:
779
/* NOTREACHED */
780
break;
781
}
782
783
return (-1);
784
}
785
786
/*
787
* Parse a command line argument of type OID=syntax:value and fill in whatever
788
* fields can be derived from the input into snmp_value structure. Reads numeric
789
* OIDs.
790
*/
791
static int32_t
792
parse_pair_numoid_val(char *str, struct snmp_value *snmp_val)
793
{
794
int32_t cnt;
795
char *ptr;
796
enum snmp_syntax syntax;
797
char oid_str[ASN_OIDSTRLEN];
798
799
ptr = str;
800
for (cnt = 0; cnt < ASN_OIDSTRLEN; cnt++)
801
if (ptr[cnt] == '=')
802
break;
803
804
if (cnt >= ASN_OIDSTRLEN) {
805
warnx("OID too long - %s", str);
806
return (-1);
807
}
808
strlcpy(oid_str, ptr, (size_t) (cnt + 1));
809
810
ptr = str + cnt + 1;
811
for (cnt = 0; cnt < MAX_CMD_SYNTAX_LEN; cnt++)
812
if(ptr[cnt] == ':')
813
break;
814
815
if (cnt >= MAX_CMD_SYNTAX_LEN) {
816
warnx("Unknown syntax in OID - %s", str);
817
return (-1);
818
}
819
820
if ((syntax = parse_syntax(ptr)) <= SNMP_SYNTAX_NULL) {
821
warnx("Unknown syntax in OID - %s", ptr);
822
return (-1);
823
}
824
825
ptr = ptr + cnt + 1;
826
for (cnt = 0; cnt < MAX_OCTSTRING_LEN; cnt++)
827
if (ptr[cnt] == '\0')
828
break;
829
830
if (ptr[cnt] != '\0') {
831
warnx("Value string too long - %s", ptr);
832
return (-1);
833
}
834
835
/*
836
* Here try parsing the OIDs and syntaxes and then check values - have
837
* to know syntax to check value boundaries.
838
*/
839
if (snmp_parse_numoid(oid_str, &(snmp_val->var)) < 0) {
840
warnx("Error parsing OID %s", oid_str);
841
return (-1);
842
}
843
844
if (parse_syntax_val(snmp_val, syntax, ptr) < 0)
845
return (-1);
846
847
return (1);
848
}
849
850
static int32_t
851
parse_syntax_strval(struct snmp_toolinfo *snmptoolctx,
852
struct snmp_object *object, char *str)
853
{
854
uint32_t len;
855
enum snmp_syntax syn;
856
857
/*
858
* Syntax string here not required - still may be present.
859
*/
860
861
if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) {
862
for (len = 0 ; *(str + len) != ':'; len++) {
863
if (*(str + len) == '\0') {
864
warnx("Syntax missing in value - %s", str);
865
return (-1);
866
}
867
}
868
if ((syn = parse_syntax(str)) <= SNMP_SYNTAX_NULL) {
869
warnx("Unknown syntax in - %s", str);
870
return (-1);
871
}
872
if (syn != object->val.syntax) {
873
if (!ISSET_ERRIGNORE(snmptoolctx)) {
874
warnx("Bad syntax in - %s", str);
875
return (-1);
876
} else
877
object->val.syntax = syn;
878
}
879
len++;
880
} else
881
len = 0;
882
883
switch (object->val.syntax) {
884
case SNMP_SYNTAX_INTEGER:
885
return (parse_int_string(object, str + len));
886
case SNMP_SYNTAX_IPADDRESS:
887
return (parse_ip(&(object->val), str + len));
888
case SNMP_SYNTAX_COUNTER:
889
return (parse_counter(&(object->val), str + len));
890
case SNMP_SYNTAX_GAUGE:
891
return (parse_gauge(&(object->val), str + len));
892
case SNMP_SYNTAX_TIMETICKS:
893
return (parse_ticks(&(object->val), str + len));
894
case SNMP_SYNTAX_COUNTER64:
895
return (parse_uint64(&(object->val), str + len));
896
case SNMP_SYNTAX_OCTETSTRING:
897
return (snmp_tc2oct(object->info->tc, &(object->val),
898
str + len));
899
case SNMP_SYNTAX_OID:
900
return (parse_oid_string(snmptoolctx, &(object->val),
901
str + len));
902
default:
903
/* NOTREACHED */
904
break;
905
}
906
907
return (-1);
908
}
909
910
static int32_t
911
parse_pair_stroid_val(struct snmp_toolinfo *snmptoolctx,
912
struct snmp_object *obj, char *argv)
913
{
914
char *ptr;
915
916
if ((ptr = snmptools_parse_stroid(snmptoolctx, obj, argv)) == NULL)
917
return (-1);
918
919
if (*ptr != '=') {
920
warnx("Value to set expected after OID");
921
return (-1);
922
}
923
924
if (parse_syntax_strval(snmptoolctx, obj, ptr + 1) < 0)
925
return (-1);
926
927
return (1);
928
}
929
930
931
static int32_t
932
snmpset_parse_oid(struct snmp_toolinfo *snmptoolctx,
933
struct snmp_object *obj, char *argv)
934
{
935
if (argv == NULL)
936
return (-1);
937
938
if (ISSET_NUMERIC(snmptoolctx)) {
939
if (parse_pair_numoid_val(argv, &(obj->val)) < 0)
940
return (-1);
941
} else {
942
if (parse_pair_stroid_val(snmptoolctx, obj, argv) < 0)
943
return (-1);
944
}
945
946
return (1);
947
}
948
949
static int32_t
950
add_ip_syntax(struct snmp_value *dst, struct snmp_value *src)
951
{
952
int8_t i;
953
954
dst->syntax = SNMP_SYNTAX_IPADDRESS;
955
for (i = 0; i < 4; i++)
956
dst->v.ipaddress[i] = src->v.ipaddress[i];
957
958
return (1);
959
}
960
961
static int32_t
962
add_octstring_syntax(struct snmp_value *dst, struct snmp_value *src)
963
{
964
if (src->v.octetstring.len > ASN_MAXOCTETSTRING) {
965
warnx("OctetString len too big - %u", src->v.octetstring.len);
966
return (-1);
967
}
968
969
if ((dst->v.octetstring.octets = malloc(src->v.octetstring.len)) ==
970
NULL) {
971
syslog(LOG_ERR, "malloc() failed - %s", strerror(errno));
972
return (-1);
973
}
974
975
memcpy(dst->v.octetstring.octets, src->v.octetstring.octets,
976
src->v.octetstring.len);
977
dst->syntax = SNMP_SYNTAX_OCTETSTRING;
978
dst->v.octetstring.len = src->v.octetstring.len;
979
980
return(0);
981
}
982
983
static int32_t
984
add_oid_syntax(struct snmp_value *dst, struct snmp_value *src)
985
{
986
asn_append_oid(&(dst->v.oid), &(src->v.oid));
987
dst->syntax = SNMP_SYNTAX_OID;
988
return (0);
989
}
990
991
/*
992
* Check syntax - if one of SNMP_SYNTAX_NULL, SNMP_SYNTAX_NOSUCHOBJECT,
993
* SNMP_SYNTAX_NOSUCHINSTANCE, SNMP_SYNTAX_ENDOFMIBVIEW or anything not known -
994
* return error.
995
*/
996
static int32_t
997
snmpset_add_value(struct snmp_value *dst, struct snmp_value *src)
998
{
999
if (dst == NULL || src == NULL)
1000
return (-1);
1001
1002
switch (src->syntax) {
1003
case SNMP_SYNTAX_INTEGER:
1004
dst->v.integer = src->v.integer;
1005
dst->syntax = SNMP_SYNTAX_INTEGER;
1006
break;
1007
case SNMP_SYNTAX_TIMETICKS:
1008
dst->v.uint32 = src->v.uint32;
1009
dst->syntax = SNMP_SYNTAX_TIMETICKS;
1010
break;
1011
case SNMP_SYNTAX_GAUGE:
1012
dst->v.uint32 = src->v.uint32;
1013
dst->syntax = SNMP_SYNTAX_GAUGE;
1014
break;
1015
case SNMP_SYNTAX_COUNTER:
1016
dst->v.uint32 = src->v.uint32;
1017
dst->syntax = SNMP_SYNTAX_COUNTER;
1018
break;
1019
case SNMP_SYNTAX_COUNTER64:
1020
dst->v.counter64 = src->v.counter64;
1021
dst->syntax = SNMP_SYNTAX_COUNTER64;
1022
break;
1023
case SNMP_SYNTAX_IPADDRESS:
1024
add_ip_syntax(dst, src);
1025
break;
1026
case SNMP_SYNTAX_OCTETSTRING:
1027
add_octstring_syntax(dst, src);
1028
break;
1029
case SNMP_SYNTAX_OID:
1030
add_oid_syntax(dst, src);
1031
break;
1032
default:
1033
warnx("Unknown syntax %d", src->syntax);
1034
return (-1);
1035
}
1036
1037
return (0);
1038
}
1039
1040
static int32_t
1041
snmpset_verify_vbind(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu,
1042
struct snmp_object *obj)
1043
{
1044
if (pdu->version == SNMP_V1 && obj->val.syntax ==
1045
SNMP_SYNTAX_COUNTER64) {
1046
warnx("64-bit counters are not supported in SNMPv1 PDU");
1047
return (-1);
1048
}
1049
1050
if (ISSET_NUMERIC(snmptoolctx) || ISSET_ERRIGNORE(snmptoolctx))
1051
return (1);
1052
1053
if (obj->info->access < SNMP_ACCESS_SET) {
1054
warnx("Object %s not accessible for set - try 'bsnmpset -a'",
1055
obj->info->string);
1056
return (-1);
1057
}
1058
1059
return (1);
1060
}
1061
1062
static int32_t
1063
snmpset_add_vbind(struct snmp_pdu *pdu, struct snmp_object *obj)
1064
{
1065
if (pdu->nbindings > SNMP_MAX_BINDINGS) {
1066
warnx("Too many OIDs for one PDU");
1067
return (-1);
1068
}
1069
1070
if (obj->error > 0)
1071
return (0);
1072
1073
if (snmpset_add_value(&(pdu->bindings[pdu->nbindings]), &(obj->val))
1074
< 0)
1075
return (-1);
1076
1077
asn_append_oid(&(pdu->bindings[pdu->nbindings].var), &(obj->val.var));
1078
pdu->nbindings++;
1079
1080
return (pdu->nbindings);
1081
}
1082
1083
static int
1084
snmptool_set(struct snmp_toolinfo *snmptoolctx)
1085
{
1086
struct snmp_pdu req, resp;
1087
1088
snmp_pdu_create(&req, SNMP_PDU_SET);
1089
1090
while ((snmp_pdu_add_bindings(snmptoolctx, snmpset_verify_vbind,
1091
snmpset_add_vbind, &req, SNMP_MAX_BINDINGS)) > 0) {
1092
if (snmp_dialog(&req, &resp)) {
1093
warn("Snmp dialog");
1094
break;
1095
}
1096
1097
if (snmp_pdu_check(&req, &resp) > 0) {
1098
if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET)
1099
snmp_output_resp(snmptoolctx, &resp, NULL);
1100
snmp_pdu_free(&resp);
1101
break;
1102
}
1103
1104
snmp_output_err_resp(snmptoolctx, &resp);
1105
if (!ISSET_RETRY(snmptoolctx)) {
1106
snmp_pdu_free(&resp);
1107
break;
1108
}
1109
1110
if (snmp_object_seterror(snmptoolctx,
1111
&(resp.bindings[resp.error_index - 1]),
1112
resp.error_status) <= 0) {
1113
snmp_pdu_free(&resp);
1114
break;
1115
}
1116
1117
fprintf(stderr, "Retrying...\n");
1118
snmp_pdu_free(&req);
1119
snmp_pdu_create(&req, SNMP_PDU_SET);
1120
}
1121
1122
snmp_pdu_free(&req);
1123
1124
return (0);
1125
}
1126
1127
/* *****************************************************************************
1128
* main
1129
*/
1130
/*
1131
* According to command line options prepare SNMP Get | GetNext | GetBulk PDU.
1132
* Wait for a response and print it.
1133
*/
1134
/*
1135
* Do a 'snmp walk' - according to command line options request for values
1136
* lexicographically subsequent and subrooted at a common node. Send a GetNext
1137
* PDU requesting the value for each next variable and print the response. Stop
1138
* when a Response PDU is received that contains the value of a variable not
1139
* subrooted at the variable the walk started.
1140
*/
1141
int
1142
main(int argc, char ** argv)
1143
{
1144
struct snmp_toolinfo snmptoolctx;
1145
int32_t oid_cnt, last_oid, opt_num;
1146
int rc = 0;
1147
1148
/* Make sure program_name is set and valid. */
1149
if (*argv == NULL)
1150
program_name = "snmptool";
1151
else {
1152
program_name = strrchr(*argv, '/');
1153
if (program_name != NULL)
1154
program_name++;
1155
else
1156
program_name = *argv;
1157
}
1158
1159
if (program_name == NULL) {
1160
fprintf(stderr, "Error: No program name?\n");
1161
exit (1);
1162
} else if (strcmp(program_name, "bsnmpget") == 0)
1163
program = BSNMPGET;
1164
else if (strcmp(program_name, "bsnmpwalk") == 0)
1165
program = BSNMPWALK;
1166
else if (strcmp(program_name, "bsnmpset") == 0)
1167
program = BSNMPSET;
1168
else {
1169
fprintf(stderr, "Unknown snmp tool name '%s'.\n", program_name);
1170
exit (1);
1171
}
1172
1173
/* Initialize. */
1174
if (snmptool_init(&snmptoolctx) < 0)
1175
exit (1);
1176
1177
if ((opt_num = snmptool_parse_options(&snmptoolctx, argc, argv)) < 0) {
1178
snmp_tool_freeall(&snmptoolctx);
1179
/* On -h (help) exit without error. */
1180
if (opt_num == -2)
1181
exit(0);
1182
else {
1183
fprintf(stderr, "Error: %s\n", snmp_client.error);
1184
exit(1);
1185
}
1186
}
1187
1188
oid_cnt = argc - opt_num - 1;
1189
if (oid_cnt == 0) {
1190
switch (program) {
1191
case BSNMPGET:
1192
if (!ISSET_EDISCOVER(&snmptoolctx) &&
1193
!ISSET_LOCALKEY(&snmptoolctx)) {
1194
fprintf(stderr, "No OID given.\n");
1195
usage();
1196
snmp_tool_freeall(&snmptoolctx);
1197
exit(1);
1198
}
1199
break;
1200
1201
case BSNMPWALK:
1202
if (snmp_object_add(&snmptoolctx, snmpwalk_add_default,
1203
NULL) < 0) {
1204
fprintf(stderr,
1205
"Error setting default subtree.\n");
1206
snmp_tool_freeall(&snmptoolctx);
1207
exit(1);
1208
}
1209
break;
1210
1211
case BSNMPSET:
1212
fprintf(stderr, "No OID given.\n");
1213
usage();
1214
snmp_tool_freeall(&snmptoolctx);
1215
exit(1);
1216
}
1217
}
1218
1219
if (snmp_import_all(&snmptoolctx) < 0) {
1220
snmp_tool_freeall(&snmptoolctx);
1221
exit(1);
1222
}
1223
1224
/* A simple sanity check - can not send GETBULK when using SNMPv1. */
1225
if (program == BSNMPGET && snmp_client.version == SNMP_V1 &&
1226
GET_PDUTYPE(&snmptoolctx) == SNMP_PDU_GETBULK) {
1227
fprintf(stderr, "Cannot send GETBULK PDU with SNMPv1.\n");
1228
snmp_tool_freeall(&snmptoolctx);
1229
exit(1);
1230
}
1231
1232
for (last_oid = argc - 1; oid_cnt > 0; last_oid--, oid_cnt--) {
1233
if ((snmp_object_add(&snmptoolctx, (program == BSNMPSET) ?
1234
snmpset_parse_oid : snmptools_parse_oid,
1235
argv[last_oid])) < 0) {
1236
fprintf(stderr, "Error parsing OID string '%s'.\n",
1237
argv[last_oid]);
1238
snmp_tool_freeall(&snmptoolctx);
1239
exit(1);
1240
}
1241
}
1242
1243
if (snmp_open(NULL, NULL, NULL, NULL)) {
1244
fprintf(stderr, "snmp_open(3): %s\n", snmp_client.error);
1245
snmp_tool_freeall(&snmptoolctx);
1246
exit(1);
1247
}
1248
1249
if (snmp_client.version == SNMP_V3 && snmp_client.engine.engine_len == 0)
1250
SET_EDISCOVER(&snmptoolctx);
1251
1252
if (ISSET_EDISCOVER(&snmptoolctx) &&
1253
snmp_discover_engine(snmptoolctx.passwd) < 0) {
1254
warn("Unknown SNMP Engine ID");
1255
rc = 1;
1256
goto cleanup;
1257
}
1258
1259
if (GET_OUTPUT(&snmptoolctx) == OUTPUT_VERBOSE ||
1260
ISSET_EDISCOVER(&snmptoolctx))
1261
snmp_output_engine();
1262
1263
if (snmp_client.version == SNMP_V3 && ISSET_LOCALKEY(&snmptoolctx) &&
1264
!ISSET_EDISCOVER(&snmptoolctx)) {
1265
if (snmp_passwd_to_keys(&snmp_client.user,
1266
snmptoolctx.passwd) != SNMP_CODE_OK ||
1267
snmp_get_local_keys(&snmp_client.user,
1268
snmp_client.engine.engine_id,
1269
snmp_client.engine.engine_len) != SNMP_CODE_OK) {
1270
warn("Failed to get keys");
1271
rc = 1;
1272
goto cleanup;
1273
}
1274
}
1275
1276
if (GET_OUTPUT(&snmptoolctx) == OUTPUT_VERBOSE ||
1277
ISSET_EDISCOVER(&snmptoolctx))
1278
snmp_output_keys();
1279
1280
if (ISSET_EDISCOVER(&snmptoolctx) && snmptoolctx.objects == 0)
1281
goto cleanup;
1282
1283
switch (program) {
1284
case BSNMPGET:
1285
rc = snmptool_get(&snmptoolctx);
1286
break;
1287
case BSNMPWALK:
1288
rc = snmptool_walk(&snmptoolctx);
1289
break;
1290
case BSNMPSET:
1291
rc = snmptool_set(&snmptoolctx);
1292
break;
1293
}
1294
1295
1296
cleanup:
1297
snmp_tool_freeall(&snmptoolctx);
1298
snmp_close();
1299
1300
exit(rc);
1301
}
1302
1303