Index: vendor/1.14/gensnmpdef/gensnmpdef.1 =================================================================== --- vendor/1.14/gensnmpdef/gensnmpdef.1 (nonexistent) +++ vendor/1.14/gensnmpdef/gensnmpdef.1 (revision 359491) @@ -0,0 +1,85 @@ +.\" +.\" Copyright (C) 2004-2006 +.\" Hartmut Brandt. +.\" All rights reserved. +.\" +.\" Author: Harti Brandt +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Begemot: gensnmpdef.1 383 2006-05-30 07:40:49Z brandt_h $ +.\" +.Dd May 28, 2006 +.Dt GENSNMPDEF 1 +.Os +.Sh NAME +.Nm gensnmpdef +.Nd "generate a MIB description file from MIBs" +.Sh SYNOPSIS +.Nm +.Op Fl hEe +.Op Fl c Ar cut +.Ar name Op Ar ... +.Sh DESCRIPTION +The +.Nm +utility is used to create an initial MIB description file from +one or more MIBs. +The description file must be edited to be actually useful +for feeding it into +.Xr gensnmptree 1 . +.Pp +The following options are available: +.Bl -tag -width indent +.It Fl c Ar cut +Specify the number of initial sub-oids that should be omitted +from the tree in the output. +.Xr gensnmptree 1 +automatically adds 1.3.6 in front of all OIDs so the default value +of 3 is just correct in most cases. +.It Fl E +Generate typedefs for named enumerations. +These are enumerations defined via the TEXTUAL-CONVENTION macro. +The normal tree output is suppressed. +.It Fl e +Generate typedefs for unnamed enumerations. +These are enumerations defined in the SYNTAX clause of an OBJECT-TYPE macro. +The name of the enumeration is formed by appending the string +.Ql Type +to the name of the object. +The normal tree output is suppressed. +.It Fl h +Print a short help text and exit. +.El +.Pp +.Nm +does no attempt on sorting the OID tree so in case of complex and +non-standard MIBs it is necessary to sort the tree in the resulting definition +file by hand. +.Sh SEE ALSO +.Xr snmpd 1 +.Sh AUTHORS +.An Hartmut Brandt Aq harti@FreeBSD.org +.Sh BUGS +The utility is by no means bullet-proof and may fail for complex +or non-standard MIBs. +Its output is expected to be edited by hand. Property changes on: vendor/1.14/gensnmpdef/gensnmpdef.1 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/gensnmpdef/gensnmpdef.c =================================================================== --- vendor/1.14/gensnmpdef/gensnmpdef.c (nonexistent) +++ vendor/1.14/gensnmpdef/gensnmpdef.c (revision 359491) @@ -0,0 +1,588 @@ +/* + * Copyright (C) 2004-2006 + * Hartmut Brandt. + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: gensnmpdef.c 383 2006-05-30 07:40:49Z brandt_h $ + */ +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static const char usgtxt[] = +"Usage: gensnmpdef [-hEe] [-c ] MIB [MIB ...]\n" +"Options:\n" +" -c specify the number of initial sub-oids to cut from the oids\n" +" -E extract named enum types. Print a typedef for all enums defined\n" +" in syntax clauses of normal objects. Suppress normal output.\n" +" -e extract unnamed enum types. Print a typedef for all enums defined\n" +" as textual conventions. Suppress normal output.\n" +" -h print this help\n" +"MIBs are searched according to the libsmi(3) search rules and can\n" +"be specified either by path or module name\n"; + +static SmiNode *last_node; +static u_int cut = 3; + +struct tdef { + char *name; + SLIST_ENTRY(tdef) link; +}; + +static SLIST_HEAD(, tdef) tdefs = SLIST_HEAD_INITIALIZER(tdefs); +static int do_typedef = 0; + +static void print_node(SmiNode *n, u_int level); + +static void +save_node(SmiNode *n) +{ + if (n != NULL) + last_node = n; +} + +static void +pindent(u_int level) +{ + if (level >= cut) + printf("%*s", (level - cut) * 2, ""); +} + +static void +print_name(SmiNode *n) +{ + char *p; + + for (p = n->name; *p != '\0'; p++) { + if (*p == '-') + printf("_"); + else + printf("%c", *p); + } +} + +static u_int +close_node(u_int n, u_int level) +{ + while (n--) { + pindent(level); + level--; + if (level >= cut) + printf(")\n"); + } + return (level); +} + +static u_int +open_node(const SmiNode *n, u_int level, SmiNode **last) +{ + SmiNode *n1; + u_int i; + + if (*last != NULL) { + for (i = 0; i < (*last)->oidlen - 1; i++) { + if (i >= n->oidlen) { + level = close_node((*last)->oidlen - + n->oidlen, level); + break; + } + if ((*last)->oid[i] != n->oid[i]) + break; + } + if (i < (*last)->oidlen - 1) + level = close_node((*last)->oidlen - 1 - i, + level - 1) + 1; + } + + while (level < n->oidlen - 1) { + if (level >= cut) { + n1 = smiGetNodeByOID(level + 1, n->oid); + if (n1 == NULL) + continue; + pindent(level); + printf("(%u", n->oid[level]); + printf(" "); + print_name(n1); + printf("\n"); + } + level++; + } + return (level); +} + +static const char *const type_names[] = { + [SMI_BASETYPE_UNKNOWN] = "UNKNOWN_TYPE", + [SMI_BASETYPE_INTEGER32] = "INTEGER", + [SMI_BASETYPE_OCTETSTRING] = "OCTETSTRING", + [SMI_BASETYPE_OBJECTIDENTIFIER] = "OID", + [SMI_BASETYPE_UNSIGNED32] = "UNSIGNED32", + [SMI_BASETYPE_INTEGER64] = "INTEGER64", + [SMI_BASETYPE_UNSIGNED64] = "UNSIGNED64", + [SMI_BASETYPE_FLOAT32] = "FLOAT32", + [SMI_BASETYPE_FLOAT64] = "FLOAT64", + [SMI_BASETYPE_FLOAT128] = "FLOAT128", + [SMI_BASETYPE_ENUM] = "ENUM", + [SMI_BASETYPE_BITS] = "BITS", +}; + +static const char *const type_map[] = { + "Gauge32", "GAUGE", + "Gauge", "GAUGE", + "TimeTicks", "TIMETICKS", + "Counter32", "COUNTER", + "Counter", "COUNTER", + "Counter64", "COUNTER64", + "Integer32", "INTEGER32", + "IpAddress", "IPADDRESS", + NULL +}; + +static void +print_enum(SmiType *t) +{ + SmiNamedNumber *nnum; + + printf(" ("); + for (nnum = smiGetFirstNamedNumber(t); nnum != NULL; + nnum = smiGetNextNamedNumber(nnum)) + printf(" %ld %s", nnum->value.value.integer32, nnum->name); + printf(" )"); +} + +static void +print_type(SmiNode *n) +{ + SmiType *type; + u_int m; + + type = smiGetNodeType(n); + assert(type != NULL); + + if (type->name != NULL) { + for (m = 0; type_map[m] != NULL; m += 2) + if (strcmp(type_map[m], type->name) == 0) { + printf("%s", type_map[m + 1]); + return; + } + } + printf("%s", type_names[type->basetype]); + + if (type->basetype == SMI_BASETYPE_ENUM || + type->basetype == SMI_BASETYPE_BITS) + print_enum(type); + + else if (type->basetype == SMI_BASETYPE_OCTETSTRING && + type->name != NULL) + printf(" | %s", type->name); +} + +static void +print_access(SmiAccess a) +{ + if (a == SMI_ACCESS_READ_ONLY) + printf(" GET"); + else if (a == SMI_ACCESS_READ_WRITE) + printf(" GET SET"); +} + +static void +print_scalar(SmiNode *n, u_int level) +{ + SmiNode *p; + + assert (n->nodekind == SMI_NODEKIND_SCALAR); + + save_node(n); + + pindent(level); + printf("(%u ", n->oid[level]); + print_name(n); + printf(" "); + print_type(n); + + /* generate the operation from the parent node name */ + p = smiGetParentNode(n); + printf(" op_%s", p->name); + + print_access(n->access); + + printf(")\n"); +} + +static void +print_notification(SmiNode *n, u_int level) +{ + + assert (n->nodekind == SMI_NODEKIND_NOTIFICATION); + + save_node(n); + + pindent(level); + printf("(%u ", n->oid[level]); + print_name(n); + printf(" OID"); + + printf(" op_%s)\n", n->name); +} + +static void +print_col(SmiNode *n, u_int level) +{ + assert (n->nodekind == SMI_NODEKIND_COLUMN); + + save_node(n); + + pindent(level); + printf("(%u ", n->oid[level]); + print_name(n); + printf(" "); + print_type(n); + print_access(n->access); + printf(")\n"); +} + +static void +print_index(SmiNode *row) +{ + SmiElement *e; + + e = smiGetFirstElement(row); + while (e != NULL) { + printf(" "); + print_type(smiGetElementNode(e)); + e = smiGetNextElement(e); + } +} + +static void +print_table(SmiNode *n, u_int level) +{ + SmiNode *row, *col, *rel; + + assert (n->nodekind == SMI_NODEKIND_TABLE); + + save_node(n); + + pindent(level); + printf("(%u ", n->oid[level]); + print_name(n); + printf("\n"); + + row = smiGetFirstChildNode(n); + if (row->nodekind != SMI_NODEKIND_ROW) + errx(1, "%s: kind %u, not row", __func__, row->nodekind); + + save_node(n); + + pindent(level + 1); + printf("(%u ", row->oid[level + 1]); + print_name(row); + printf(" :"); + + /* index */ + rel = smiGetRelatedNode(row); + switch (row->indexkind) { + + case SMI_INDEX_INDEX: + print_index(row); + break; + + case SMI_INDEX_AUGMENT: + if (rel == NULL) + errx(1, "%s: cannot find augemented table", row->name); + print_index(rel); + break; + + default: + errx(1, "%s: cannot handle index kind %u", row->name, + row->indexkind); + } + + printf(" op_%s", n->name); + printf("\n"); + + col = smiGetFirstChildNode(row); + while (col != NULL) { + print_col(col, level + 2); + col = smiGetNextChildNode(col); + } + pindent(level + 1); + printf(")\n"); + + pindent(level); + printf(")\n"); +} + +static void +print_it(SmiNode *n, u_int level) +{ + switch (n->nodekind) { + + case SMI_NODEKIND_NODE: + print_node(n, level); + break; + + case SMI_NODEKIND_SCALAR: + print_scalar(n, level); + break; + + case SMI_NODEKIND_TABLE: + print_table(n, level); + break; + + case SMI_NODEKIND_COMPLIANCE: + case SMI_NODEKIND_GROUP: + save_node(n); + break; + + case SMI_NODEKIND_NOTIFICATION: + print_notification(n, level); + break; + + default: + errx(1, "cannot handle %u nodes", n->nodekind); + } +} + +static void +print_node(SmiNode *n, u_int level) +{ + assert (n->nodekind == SMI_NODEKIND_NODE); + + save_node(n); + + pindent(level); + printf("(%u ", n->oid[level]); + print_name(n); + printf("\n"); + + n = smiGetFirstChildNode(n); + while (n != NULL) { + print_it(n, level + 1); + n = smiGetNextChildNode(n); + } + pindent(level); + printf(")\n"); +} + +static void +save_typdef(char *name) +{ + struct tdef *t; + + t = calloc(1, sizeof(struct tdef)); + if (t == NULL) + err(1, NULL); + + t->name = name; + SLIST_INSERT_HEAD(&tdefs, t, link); +} + +static void +tdefs_cleanup(void) +{ + struct tdef *t; + + while ((t = SLIST_FIRST(&tdefs)) != NULL) { + SLIST_REMOVE_HEAD(&tdefs, link); + free(t); + } +} + +static void +print_enum_typedef(SmiType *t) +{ + SmiNamedNumber *nnum; + + for (nnum = smiGetFirstNamedNumber(t); nnum != NULL; + nnum = smiGetNextNamedNumber(nnum)) { + printf("\t%ld %s\n" , nnum->value.value.integer32, nnum->name); + } +} + +static void +print_stype(SmiNode *n) +{ + SmiType *type; + struct tdef *t = NULL; + + type = smiGetNodeType(n); + assert(type != NULL); + + if (type->basetype == SMI_BASETYPE_ENUM) { + if (do_typedef == 'e' && type->name != NULL) { + SLIST_FOREACH(t, &tdefs, link) { + if (strcmp(t->name, type->name) == 0) + return; + } + save_typdef(type->name); + printf("typedef %s ENUM (\n", type->name); + } else if (do_typedef == 'E' && type->name == NULL) + printf("typedef %sType ENUM (\n", n->name); + else + return; + + print_enum_typedef(type); + printf(")\n\n"); + + } else if (type->basetype == SMI_BASETYPE_BITS) { + if (do_typedef == 'e' && type->name != NULL) { + SLIST_FOREACH(t, &tdefs, link) { + if (strcmp(t->name, type->name) == 0) + return; + } + save_typdef(type->name); + printf("typedef %s BITS (\n", type->name); + } else if (do_typedef == 'E' && type->name == NULL) + printf("typedef %sType BITS (\n", n->name); + else + return; + + print_enum_typedef(type); + printf(")\n\n"); + } +} + +static void +print_typdefs(SmiNode *n) +{ + SmiNode *p; + + p = n; + n = smiGetFirstChildNode(n); + while (n != NULL) { + switch (n->nodekind) { + case SMI_NODEKIND_SCALAR: + case SMI_NODEKIND_COLUMN: + print_stype(n); + break; + case SMI_NODEKIND_COMPLIANCE: + case SMI_NODEKIND_GROUP: + save_node(n); + return; + default: + break; + } + n = smiGetNextChildNode(n); + } + + save_node(p); +} + +int +main(int argc, char *argv[]) +{ + int opt; + int flags; + SmiModule **mods; + char *name; + SmiNode *n, *last; + u_int level; + long u; + char *end; + + smiInit(NULL); + + while ((opt = getopt(argc, argv, "c:Eeh")) != -1) + switch (opt) { + + case 'c': + errno = 0; + u = strtol(optarg, &end, 10); + if (errno != 0) + err(1, "argument to -c"); + if (*end != '\0') + err(1, "%s: not a number", optarg); + if (u < 0 || u > 5) + err(1, "%s: out of range", optarg); + cut = (u_int)u; + break; + + case 'E': + do_typedef = 'E'; + break; + + case 'e': + do_typedef = 'e'; + break; + + case 'h': + fprintf(stderr, usgtxt); + exit(0); + } + + argc -= optind; + argv += optind; + + flags = smiGetFlags(); + flags |= SMI_FLAG_ERRORS; + smiSetFlags(flags); + + mods = malloc(sizeof(mods[0]) * argc); + if (mods == NULL) + err(1, NULL); + + for (opt = 0; opt < argc; opt++) { + if ((name = smiLoadModule(argv[opt])) == NULL) + err(1, "%s: cannot load", argv[opt]); + mods[opt] = smiGetModule(name); + } + level = 0; + last = NULL; + for (opt = 0; opt < argc; opt++) { + if (mods[opt] == NULL) /* smiGetModule failed above */ + continue; + n = smiGetFirstNode(mods[opt], SMI_NODEKIND_ANY); + if (n == NULL) + continue; + for (;;) { + if (do_typedef == 0) { + level = open_node(n, level, &last); + print_it(n, level); + last = n; + } else + print_typdefs(n); + + if (last_node == NULL || + (n = smiGetNextNode(last_node, SMI_NODEKIND_ANY)) + == NULL) + break; + } + } + if (last != NULL && do_typedef == 0) + level = close_node(last->oidlen - 1, level - 1); + else if (do_typedef != 0) + tdefs_cleanup(); + + return (0); +} Property changes on: vendor/1.14/gensnmpdef/gensnmpdef.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/gensnmptree/gensnmptree.1 =================================================================== --- vendor/1.14/gensnmptree/gensnmptree.1 (nonexistent) +++ vendor/1.14/gensnmptree/gensnmptree.1 (revision 359491) @@ -0,0 +1,252 @@ +.\" +.\" Copyright (c) 2001-2005 +.\" Fraunhofer Institute for Open Communication Systems (FhG Fokus). +.\" All rights reserved. +.\" Copyright (c) 2006,2018 +.\" Hartmut Brandt +.\" All rights reserved. +.\" +.\" Author: Harti Brandt +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Begemot: gensnmptree.1 383 2006-05-30 07:40:49Z brandt_h $ +.\" +.Dd April 2, 2019 +.Dt GENSNMPTREE 1 +.Os +.Sh NAME +.Nm gensnmptree +.Nd "generate C and header files from a MIB description file" +.Sh SYNOPSIS +.Nm +.Op Fl dEeFfhlt +.Op Fl I Ar directory +.Op Fl i Ar infile +.Op Fl p Ar prefix +.Op Ar name Ar ... +.Sh DESCRIPTION +The +.Nm +utility is used to either generate C language tables and header files from +a MIB description or to numeric OIDs from MIB descriptions. +The first form is used only for maintaining the +.Xr bsnmpd 1 +daemon or for module writers. +The second form may be used by SNMP client program writers. +.Pp +If none of the options +.Fl e , +.Fl E +or +.Fl t +are used +.Nm +reads a MIB description from its standard input and creates two files: a +C-file +.Ar prefix Ns tree.c +containing a table used by +.Xr bsnmpd 1 +during PDU processing +and a header file +.Ar prefix Ns tree.h +containing appropriate declarations of the callback functions used in this +table, the table itself and definitions for all enums. +.Pp +The following options are available: +.Bl -tag -width ".Fl E" +.It Fl d +Switch on debugging. +.It Fl E +Extract enumerations and bit constructs. +In this mode the tool emits +a header file that contains for each type given on the command line a +C-enum definition and a preprocessor define that may be used to map +values to strings. +.It Fl e +.Nm +expects MIB variable names (only the last component) on its command line. +It reads a MIB specification from standard input and for each MIB variable +name emits three C preprocessor defines on its standard output: +.Bl -tag -width ".Va OIDLEN_ Ns Ar Name" +.It Va OIDX_ Ns Ar name +This define can be used to initialize a +.Va struct asn_oid +in the following way: +.Pp +.Dl const struct asn_oid oid_sysDescr = OIDX_sysDescr; +.It Va OIDLEN_ Ns Ar name +is the length of the OID. +.It Va OID_ Ns Ar name +is the last component of the OID. +.El +.It Fl F +emit definitions for C-functions includeable in a C-file that do some basic +stuff on enums like value checking and conversion between value and strings. +.It Fl f +emit definitions for inline C-functions that do some basic +stuff on enums like value checking and conversion between value and strings. +.It Fl h +Print a short help page. +.It Fl I Ar directory +Add the named directory to the include path just before the standard include +directories. +.It Fl i Ar infile +Read from the named file instead of standard input. +.It Fl l +Generate local preprocessor includes. +This is used for bootstrapping +.Xr bsnmpd 1 . +.It Fl t +Instead of normal output print the resulting tree. +.It Fl p Ar prefix +Prefix the file names and the table name with +.Ar prefix . +.El +.Sh MIBS +The syntax of the MIB description file can formally be specified as follows: +.Bd -unfilled -offset indent + file := top | top file + + top := tree | typedef | include + + tree := head elements ')' + + entry := head ':' index STRING elements ')' + + leaf := head type STRING ACCESS ')' + + column := head type ACCESS ')' + + type := BASETYPE | BASETYPE '|' subtype | enum | bits + + subtype := STRING + + enum := ENUM '(' value ')' + + bits := BITS '(' value ')' + + value := INT STRING | INT STRING value + + head := '(' INT STRING + + elements := EMPTY | elements element + + element := tree | leaf | column + + index := type | index type + + typedef := 'typedef' STRING type + + include := 'include' filespec + + filespec := '"' STRING '"' | '<' STRING '>' +.Ed +.Pp +.Ar BASETYPE +specifies a SNMP data type and may be one of +.Bl -bullet -offset indent -compact +.It +NULL +.It +INTEGER +.It +INTEGER32 (same as INTEGER) +.It +UNSIGNED32 (same as GAUGE) +.It +OCTETSTRING +.It +IPADDRESS +.It +OID +.It +TIMETICKS +.It +COUNTER +.It +GAUGE +.It +COUNTER64 +.El +.Pp +.Ar ACCESS +specifies the accessibility of the MIB variable (which operation can be +performed) and is one of +.Bl -bullet -offset indent -compact +.It +GET +.It +SET +.El +.Pp +.Ar INT +is a decimal integer and +.Ar STRING +is any string starting with a letter or underscore and consisting of +letters, digits, underscores and minuses, that is not one of the keywords. +.Pp +The +.Ar typedef +directive associates a type with a single name. +.Pp +The +.Ar include +directive is replaced by the contents of the named file. +.Sh EXAMPLES +The following MIB description describes the system group: +.Bd -literal -offset indent +include "tc.def" + +typedef AdminStatus ENUM ( + 1 up + 2 down +) + +(1 internet + (2 mgmt + (1 mibII + (1 system + (1 sysDescr OCTETSTRING op_system_group GET) + (2 sysObjectId OID op_system_group GET) + (3 sysUpTime TIMETICKS op_system_group GET) + (4 sysContact OCTETSTRING op_system_group GET SET) + (5 sysName OCTETSTRING op_system_group GET SET) + (6 sysLocation OCTETSTRING op_system_group GET SET) + (7 sysServices INTEGER op_system_group GET) + (8 sysORLastChange TIMETICKS op_system_group GET) + (9 sysORTable + (1 sysOREntry : INTEGER op_or_table + (1 sysORIndex INTEGER) + (2 sysORID OID GET) + (3 sysORDescr OCTETSTRING GET) + (4 sysORUpTime TIMETICKS GET) + )) + ) + ) + ) +) +.Ed +.Sh SEE ALSO +.Xr bsnmpd 1 +.Sh AUTHORS +.An Hartmut Brandt Aq harti@FreeBSD.org Property changes on: vendor/1.14/gensnmptree/gensnmptree.1 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/gensnmptree/gensnmptree.c =================================================================== --- vendor/1.14/gensnmptree/gensnmptree.c (nonexistent) +++ vendor/1.14/gensnmptree/gensnmptree.c (revision 359491) @@ -0,0 +1,1818 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Copyright (c) 2004-2006,2018 + * Hartmut Brandt. + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: gensnmptree.c 383 2006-05-30 07:40:49Z brandt_h $ + * + * Generate OID table from table description. + * + * Syntax is: + * --------- + * file := top | top file + * + * top := tree | typedef | include + * + * tree := head elements ')' + * + * entry := head ':' index STRING elements ')' + * + * leaf := head type STRING ACCESS ')' + * + * column := head type ACCESS ')' + * + * type := BASETYPE | BASETYPE '|' subtype | enum | bits + * + * subtype := STRING + * + * enum := ENUM '(' value ')' + * + * bits := BITS '(' value ')' + * + * value := optminus INT STRING | optminus INT STRING value + * + * optminus := '-' | EMPTY + * + * head := '(' INT STRING + * + * elements := EMPTY | elements element + * + * element := tree | leaf | column + * + * index := type | index type + * + * typedef := 'typedef' STRING type + * + * include := 'include' filespec + * + * filespec := '"' STRING '"' | '<' STRING '>' + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_ERR_H +#include +#endif +#include +#include "support.h" +#include "asn1.h" +#include "snmp.h" +#include "snmpagent.h" + +/* + * Constant prefix for all OIDs + */ +static const asn_subid_t prefix[] = { 1, 3, 6 }; +#define PREFIX_LEN (sizeof(prefix) / sizeof(prefix[0])) + +u_int tree_size; +static const char *file_prefix = ""; + +/* if true generate local include paths */ +static int localincs = 0; + +/* if true print tokens */ +static int debug; + +static const char usgtxt[] = "\ +Generate SNMP tables.\n\ +usage: gensnmptree [-dEeFfhlt] [-I directory] [-i infile] [-p prefix]\n\ + [name]...\n\ +options:\n\ + -d debug mode\n\ + -E extract the named or all enums and bits only\n\ + -e extract the named oids or enums\n\ + -F generate functions for -E into a .c file\n\ + -f generate functions for -E into the header\n\ + -h print this info\n\ + -I directory add directory to include path\n\ + -i ifile read from the named file instead of stdin\n\ + -l generate local include directives\n\ + -p prefix prepend prefix to file and variable names\n\ + -t generate a .def file\n\ +"; + +/** + * Program operation. + */ +enum op { + /** generate the tree */ + OP_GEN, + + /** extract OIDs */ + OP_EXTRACT, + + /** print the parsed tree */ + OP_TREE, + + /** extract enums */ + OP_ENUMS, +}; + +/** + * Which functions to create. + */ +enum gen_funcs { + /** none */ + GEN_FUNCS_NONE, + + /** functions for header files */ + GEN_FUNCS_H, + + /** functions for C files */ + GEN_FUNCS_C, +}; + +/* + * A node in the OID tree + */ +enum ntype { + NODE_LEAF = 1, + NODE_TREE, + NODE_ENTRY, + NODE_COLUMN +}; + +enum { + FL_GET = 0x01, + FL_SET = 0x02, +}; + +struct node; +TAILQ_HEAD(node_list, node); + +struct node { + enum ntype type; + asn_subid_t id; /* last element of OID */ + char *name; /* name of node */ + TAILQ_ENTRY(node) link; + u_int lno; /* starting line number */ + u_int flags; /* allowed operations */ + + union { + struct tree { + struct node_list subs; + } tree; + + struct entry { + uint32_t index; /* index for table entry */ + char *func; /* function for tables */ + struct node_list subs; + char *subtypes[SNMP_INDEXES_MAX]; + } entry; + + struct leaf { + enum snmp_syntax syntax; /* syntax for this leaf */ + char *func; /* function name */ + char *subtype; /* subtype */ + } leaf; + + struct column { + enum snmp_syntax syntax; /* syntax for this column */ + char *subtype; /* subtype */ + } column; + } u; +}; + +struct func { + const char *name; + LIST_ENTRY(func) link; +}; + +static LIST_HEAD(, func) funcs = LIST_HEAD_INITIALIZER(funcs); + +struct enums { + const char *name; + long value; + TAILQ_ENTRY(enums) link; +}; + +struct type { + const char *name; + const char *from_fname; + u_int from_lno; + u_int syntax; + int is_enum; + int is_bits; + TAILQ_HEAD(, enums) enums; + LIST_ENTRY(type) link; +}; + +static LIST_HEAD(, type) types = LIST_HEAD_INITIALIZER(types); + +static void report(const char *, ...) __dead2 __printflike(1, 2); +static void report_node(const struct node *, const char *, ...) + __dead2 __printflike(2, 3); + +/************************************************************ + * + * Allocate memory and panic just in the case... + */ +static void * +xalloc(size_t size) +{ + void *ptr; + + if ((ptr = calloc(1, size)) == NULL) + err(1, "allocing %zu bytes", size); + + return (ptr); +} + +static char * +savestr(const char *s) +{ + + if (s == NULL) + return (NULL); + return (strcpy(xalloc(strlen(s) + 1), s)); +} + +/************************************************************ + * + * Input stack + */ +struct input { + FILE *fp; + u_int lno; + char *fname; + char *path; + LIST_ENTRY(input) link; +}; +static LIST_HEAD(, input) inputs = LIST_HEAD_INITIALIZER(inputs); +static struct input *input = NULL; + +#define MAX_PATHS 100 +static u_int npaths = 2; +static u_int stdpaths = 2; +static const char *paths[MAX_PATHS + 1] = { + "/usr/share/snmp/defs", + "/usr/local/share/snmp/defs", + NULL +}; + +static int pbchar = -1; + +static void +path_new(const char *path) +{ + if (npaths >= MAX_PATHS) + report("too many -I directives"); + memmove(&paths[npaths - stdpaths + 1], &paths[npaths - stdpaths], + sizeof(path[0]) * stdpaths); + paths[npaths - stdpaths] = savestr(path); + npaths++; +} + +static void +input_new(FILE *fp, const char *path, const char *fname) +{ + struct input *ip; + + ip = xalloc(sizeof(*ip)); + ip->fp = fp; + ip->lno = 1; + ip->fname = savestr(fname); + ip->path = savestr(path); + LIST_INSERT_HEAD(&inputs, ip, link); + + input = ip; +} + +static void +input_close(void) +{ + + if (input == NULL) + return; + fclose(input->fp); + free(input->fname); + free(input->path); + LIST_REMOVE(input, link); + free(input); + + input = LIST_FIRST(&inputs); +} + +static FILE * +tryopen(const char *path, const char *fname) +{ + char *fn; + FILE *fp; + + if (path == NULL) + fn = savestr(fname); + else { + fn = xalloc(strlen(path) + strlen(fname) + 2); + sprintf(fn, "%s/%s", path, fname); + } + fp = fopen(fn, "r"); + free(fn); + return (fp); +} + +static void +input_fopen(const char *fname, int loc) +{ + FILE *fp; + char *path; + u_int p; + + if (fname[0] == '/') { + if ((fp = tryopen(NULL, fname)) != NULL) { + input_new(fp, NULL, fname); + return; + } + + } else { + if (loc) { + if (input == NULL) + path = NULL; + else + path = input->path; + + if ((fp = tryopen(path, fname)) != NULL) { + input_new(fp, NULL, fname); + return; + } + } + + for (p = 0; paths[p] != NULL; p++) + if ((fp = tryopen(paths[p], fname)) != NULL) { + input_new(fp, paths[p], fname); + return; + } + } + report("cannot open '%s'", fname); +} + +static int +tgetc(void) +{ + int c; + + if (pbchar != -1) { + c = pbchar; + pbchar = -1; + return (c); + } + + for (;;) { + if (input == NULL) + return (EOF); + + if ((c = getc(input->fp)) != EOF) + return (c); + + input_close(); + } +} + +static void +tungetc(int c) +{ + + if (pbchar != -1) + abort(); + pbchar = c; +} + +/************************************************************ + * + * Parsing input + */ +enum tok { + TOK_EOF = 0200, /* end-of-file seen */ + TOK_NUM, /* number */ + TOK_STR, /* string */ + TOK_ACCESS, /* access operator */ + TOK_TYPE, /* type operator */ + TOK_ENUM, /* enum token (kind of a type) */ + TOK_TYPEDEF, /* typedef directive */ + TOK_DEFTYPE, /* defined type */ + TOK_INCLUDE, /* include directive */ + TOK_FILENAME, /* filename ("foo.bar" or ) */ + TOK_BITS, /* bits token (kind of a type) */ +}; + +static const struct { + const char *str; + enum tok tok; + u_int val; +} keywords[] = { + { "GET", TOK_ACCESS, FL_GET }, + { "SET", TOK_ACCESS, FL_SET }, + { "NULL", TOK_TYPE, SNMP_SYNTAX_NULL }, + { "INTEGER", TOK_TYPE, SNMP_SYNTAX_INTEGER }, + { "INTEGER32", TOK_TYPE, SNMP_SYNTAX_INTEGER }, + { "UNSIGNED32", TOK_TYPE, SNMP_SYNTAX_GAUGE }, + { "OCTETSTRING", TOK_TYPE, SNMP_SYNTAX_OCTETSTRING }, + { "IPADDRESS", TOK_TYPE, SNMP_SYNTAX_IPADDRESS }, + { "OID", TOK_TYPE, SNMP_SYNTAX_OID }, + { "TIMETICKS", TOK_TYPE, SNMP_SYNTAX_TIMETICKS }, + { "COUNTER", TOK_TYPE, SNMP_SYNTAX_COUNTER }, + { "GAUGE", TOK_TYPE, SNMP_SYNTAX_GAUGE }, + { "COUNTER64", TOK_TYPE, SNMP_SYNTAX_COUNTER64 }, + { "ENUM", TOK_ENUM, SNMP_SYNTAX_INTEGER }, + { "BITS", TOK_BITS, SNMP_SYNTAX_OCTETSTRING }, + { "typedef", TOK_TYPEDEF, 0 }, + { "include", TOK_INCLUDE, 0 }, + { NULL, 0, 0 } +}; + +/* arbitrary upper limit on node names and function names */ +#define MAXSTR 1000 +static char str[MAXSTR]; +static u_long val; /* integer values */ +static int saved_token = -1; + +/* + * Report an error and exit. + */ +static void +report(const char *fmt, ...) +{ + va_list ap; + int c; + + va_start(ap, fmt); + fprintf(stderr, "line %u: ", input->lno); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + fprintf(stderr, "context: \""); + while ((c = tgetc()) != EOF && c != '\n') + fprintf(stderr, "%c", c); + fprintf(stderr, "\n"); + va_end(ap); + exit(1); +} +static void +report_node(const struct node *np, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "line %u, node %s: ", np->lno, np->name); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + exit(1); +} + +/* + * Return a fresh copy of the string constituting the current token. + */ +static char * +savetok(void) +{ + return (savestr(str)); +} + +/* + * Get the next token from input. + */ +static int +gettoken_internal(void) +{ + int c; + struct type *t; + + if (saved_token != -1) { + c = saved_token; + saved_token = -1; + return (c); + } + + again: + /* + * Skip any whitespace before the next token + */ + while ((c = tgetc()) != EOF) { + if (c == '\n') + input->lno++; + if (!isspace(c)) + break; + } + if (c == EOF) + return (TOK_EOF); + if (!isascii(c)) + report("unexpected character %#2x", (u_int)c); + + /* + * Skip comments + */ + if (c == '#') { + while ((c = tgetc()) != EOF) { + if (c == '\n') { + input->lno++; + goto again; + } + } + report("unexpected EOF in comment"); + } + + /* + * Single character tokens + */ + if (strchr("():|-", c) != NULL) + return (c); + + if (c == '"' || c == '<') { + int end = c; + size_t n = 0; + + val = 1; + if (c == '<') { + val = 0; + end = '>'; + } + + while ((c = tgetc()) != EOF) { + if (c == end) + break; + if (n == sizeof(str) - 1) { + str[n++] = '\0'; + report("filename too long '%s...'", str); + } + str[n++] = c; + } + str[n++] = '\0'; + return (TOK_FILENAME); + } + + /* + * Sort out numbers + */ + if (isdigit(c)) { + size_t n = 0; + str[n++] = c; + while ((c = tgetc()) != EOF) { + if (!isdigit(c)) { + tungetc(c); + break; + } + if (n == sizeof(str) - 1) { + str[n++] = '\0'; + report("number too long '%s...'", str); + } + str[n++] = c; + } + str[n++] = '\0'; + sscanf(str, "%lu", &val); + return (TOK_NUM); + } + + /* + * So that has to be a string. + */ + if (isalpha(c) || c == '_') { + size_t n = 0; + str[n++] = c; + while ((c = tgetc()) != EOF) { + if (!isalnum(c) && c != '_' && c != '-') { + tungetc(c); + break; + } + if (n == sizeof(str) - 1) { + str[n++] = '\0'; + report("string too long '%s...'", str); + } + str[n++] = c; + } + str[n++] = '\0'; + + /* + * Keywords + */ + for (c = 0; keywords[c].str != NULL; c++) + if (strcmp(keywords[c].str, str) == 0) { + val = keywords[c].val; + return (keywords[c].tok); + } + + LIST_FOREACH(t, &types, link) { + if (strcmp(t->name, str) == 0) { + val = t->syntax; + return (TOK_DEFTYPE); + } + } + return (TOK_STR); + } + if (isprint(c)) + errx(1, "%u: unexpected character '%c'", input->lno, c); + else + errx(1, "%u: unexpected character 0x%02x", input->lno, + (u_int)c); +} +static int +gettoken(void) +{ + int tok = gettoken_internal(); + + if (debug) { + switch (tok) { + + case TOK_EOF: + fprintf(stderr, "EOF "); + break; + + case TOK_NUM: + fprintf(stderr, "NUM(%lu) ", val); + break; + + case TOK_STR: + fprintf(stderr, "STR(%s) ", str); + break; + + case TOK_ACCESS: + fprintf(stderr, "ACCESS(%lu) ", val); + break; + + case TOK_TYPE: + fprintf(stderr, "TYPE(%lu) ", val); + break; + + case TOK_ENUM: + fprintf(stderr, "ENUM "); + break; + + case TOK_BITS: + fprintf(stderr, "BITS "); + break; + + case TOK_TYPEDEF: + fprintf(stderr, "TYPEDEF "); + break; + + case TOK_DEFTYPE: + fprintf(stderr, "DEFTYPE(%s,%lu) ", str, val); + break; + + case TOK_INCLUDE: + fprintf(stderr, "INCLUDE "); + break; + + case TOK_FILENAME: + fprintf(stderr, "FILENAME "); + break; + + default: + if (tok < TOK_EOF) { + if (isprint(tok)) + fprintf(stderr, "'%c' ", tok); + else if (tok == '\n') + fprintf(stderr, "\n"); + else + fprintf(stderr, "%02x ", tok); + } else + abort(); + break; + } + } + return (tok); +} + +/** + * Pushback a token + */ +static void +pushback(enum tok tok) +{ + + if (saved_token != -1) + abort(); + saved_token = tok; +} + +/* + * Create a new type + */ +static struct type * +make_type(const char *s) +{ + struct type *t; + + t = xalloc(sizeof(*t)); + t->name = savestr(s); + t->is_enum = 0; + t->syntax = SNMP_SYNTAX_NULL; + t->from_fname = savestr(input->fname); + t->from_lno = input->lno; + TAILQ_INIT(&t->enums); + LIST_INSERT_HEAD(&types, t, link); + + return (t); +} + +/* + * Parse a type. We've seen the ENUM or type keyword already. Leave next + * token. + */ +static u_int +parse_type(enum tok *tok, struct type *t, const char *vname, char **subtype) +{ + u_int syntax; + struct enums *e; + + syntax = val; + if (subtype != NULL) + *subtype = NULL; + + if (*tok == TOK_ENUM || *tok == TOK_BITS) { + if (t == NULL && vname != NULL) { + t = make_type(vname); + t->is_enum = (*tok == TOK_ENUM); + t->is_bits = (*tok == TOK_BITS); + t->syntax = syntax; + } + if (gettoken() != '(') + report("'(' expected after ENUM"); + + if ((*tok = gettoken()) == TOK_EOF) + report("unexpected EOF in ENUM"); + do { + e = NULL; + if (t != NULL) { + e = xalloc(sizeof(*e)); + } + if (*tok == '-') { + if ((*tok = gettoken()) == TOK_EOF) + report("unexpected EOF in ENUM"); + e->value = -(long)val; + } else + e->value = val; + + if (*tok != TOK_NUM) + report("need value for ENUM/BITS"); + if (gettoken() != TOK_STR) + report("need string in ENUM/BITS"); + e->name = savetok(); + TAILQ_INSERT_TAIL(&t->enums, e, link); + if ((*tok = gettoken()) == TOK_EOF) + report("unexpected EOF in ENUM/BITS"); + } while (*tok != ')'); + *tok = gettoken(); + + } else if (*tok == TOK_DEFTYPE) { + *tok = gettoken(); + + } else { + if ((*tok = gettoken()) == '|') { + if (gettoken() != TOK_STR) + report("subtype expected after '|'"); + if (subtype != NULL) + *subtype = savetok(); + *tok = gettoken(); + } + } + + return (syntax); +} + +/* + * Parse the next node (complete with all subnodes) + */ +static struct node * +parse(enum tok tok) +{ + struct node *node; + struct node *sub; + u_int index_count; + + node = xalloc(sizeof(struct node)); + node->lno = input->lno; + node->flags = 0; + + if (tok != '(') + report("'(' expected at begin of node"); + if (gettoken() != TOK_NUM) + report("node id expected after opening '('"); + if (val > ASN_MAXID) + report("subid too large '%lu'", val); + node->id = (asn_subid_t)val; + if (gettoken() != TOK_STR) + report("node name expected after '(' ID"); + node->name = savetok(); + + if ((tok = gettoken()) == TOK_TYPE || tok == TOK_DEFTYPE || + tok == TOK_ENUM || tok == TOK_BITS) { + /* LEAF or COLUM */ + char *subtype; + u_int syntax = parse_type(&tok, NULL, node->name, &subtype); + + if (tok == TOK_STR) { + /* LEAF */ + node->type = NODE_LEAF; + node->u.leaf.func = savetok(); + node->u.leaf.syntax = syntax; + node->u.leaf.subtype = subtype; + tok = gettoken(); + } else { + /* COLUMN */ + node->type = NODE_COLUMN; + node->u.column.syntax = syntax; + node->u.column.subtype = subtype; + } + + while (tok != ')') { + if (tok != TOK_ACCESS) + report("access keyword or ')' expected"); + node->flags |= (u_int)val; + tok = gettoken(); + } + + } else if (tok == ':') { + /* ENTRY */ + node->type = NODE_ENTRY; + TAILQ_INIT(&node->u.entry.subs); + + index_count = 0; + node->u.entry.index = 0; + tok = gettoken(); + while (tok == TOK_TYPE || tok == TOK_DEFTYPE || + tok == TOK_ENUM || tok == TOK_BITS) { + char *subtype; + u_int syntax = parse_type(&tok, NULL, node->name, + &subtype); + if (index_count == SNMP_INDEXES_MAX) + report("too many table indexes"); + node->u.entry.subtypes[index_count++] = subtype; + node->u.entry.index |= + syntax << (SNMP_INDEX_SHIFT * index_count); + } + node->u.entry.index |= index_count; + if (index_count == 0) + report("need at least one index"); + if (tok != TOK_STR) + report("function name expected"); + + node->u.entry.func = savetok(); + + tok = gettoken(); + + while (tok != ')') { + sub = parse(tok); + TAILQ_INSERT_TAIL(&node->u.entry.subs, sub, link); + tok = gettoken(); + } + + } else { + /* subtree */ + node->type = NODE_TREE; + TAILQ_INIT(&node->u.tree.subs); + + while (tok != ')') { + sub = parse(tok); + TAILQ_INSERT_TAIL(&node->u.tree.subs, sub, link); + tok = gettoken(); + } + } + return (node); +} + +/* + * Parse a top level element. Return the tree if it was a tree, NULL + * otherwise. + */ +static struct node * +parse_top(enum tok tok) +{ + struct type *t; + + if (tok == '(') + return (parse(tok)); + + if (tok == TOK_TYPEDEF) { + if (gettoken() != TOK_STR) + report("type name expected after typedef"); + + t = make_type(str); + + tok = gettoken(); + t->is_enum = (tok == TOK_ENUM); + t->is_bits = (tok == TOK_BITS); + + t->syntax = parse_type(&tok, t, NULL, NULL); + pushback(tok); + + return (NULL); + } + + if (tok == TOK_INCLUDE) { + if (gettoken() != TOK_FILENAME) + report("filename expected in include directive"); + + input_fopen(str, val); + return (NULL); + } + + report("'(' or 'typedef' expected"); +} + +/* + * Generate the C-code table part for one node. + */ +static void +gen_node(FILE *fp, const struct node *np, struct asn_oid *oid, u_int idx, + const char *func) +{ + u_int n; + struct node *sub; + u_int syntax; + + if (oid->len == ASN_MAXOIDLEN) + report_node(np, "OID too long"); + oid->subs[oid->len++] = np->id; + + if (np->type == NODE_TREE) { + TAILQ_FOREACH(sub, &np->u.tree.subs, link) + gen_node(fp, sub, oid, 0, NULL); + oid->len--; + return; + } + if (np->type == NODE_ENTRY) { + TAILQ_FOREACH(sub, &np->u.entry.subs, link) + gen_node(fp, sub, oid, np->u.entry.index, + np->u.entry.func); + oid->len--; + return; + } + + /* leaf or column */ + if ((np->flags & (FL_GET|FL_SET)) == 0) { + oid->len--; + return; + } + + fprintf(fp, " {{ %u, {", oid->len); + for (n = 0; n < oid->len; n++) + fprintf(fp, " %u,", oid->subs[n]); + fprintf(fp, " }}, \"%s\", ", np->name); + + if (np->type == NODE_COLUMN) { + syntax = np->u.column.syntax; + fprintf(fp, "SNMP_NODE_COLUMN, "); + } else { + syntax = np->u.leaf.syntax; + fprintf(fp, "SNMP_NODE_LEAF, "); + } + + switch (syntax) { + + case SNMP_SYNTAX_NULL: + fprintf(fp, "SNMP_SYNTAX_NULL, "); + break; + + case SNMP_SYNTAX_INTEGER: + fprintf(fp, "SNMP_SYNTAX_INTEGER, "); + break; + + case SNMP_SYNTAX_OCTETSTRING: + fprintf(fp, "SNMP_SYNTAX_OCTETSTRING, "); + break; + + case SNMP_SYNTAX_IPADDRESS: + fprintf(fp, "SNMP_SYNTAX_IPADDRESS, "); + break; + + case SNMP_SYNTAX_OID: + fprintf(fp, "SNMP_SYNTAX_OID, "); + break; + + case SNMP_SYNTAX_TIMETICKS: + fprintf(fp, "SNMP_SYNTAX_TIMETICKS, "); + break; + + case SNMP_SYNTAX_COUNTER: + fprintf(fp, "SNMP_SYNTAX_COUNTER, "); + break; + + case SNMP_SYNTAX_GAUGE: + fprintf(fp, "SNMP_SYNTAX_GAUGE, "); + break; + + case SNMP_SYNTAX_COUNTER64: + fprintf(fp, "SNMP_SYNTAX_COUNTER64, "); + break; + + case SNMP_SYNTAX_NOSUCHOBJECT: + case SNMP_SYNTAX_NOSUCHINSTANCE: + case SNMP_SYNTAX_ENDOFMIBVIEW: + abort(); + } + + if (np->type == NODE_COLUMN) + fprintf(fp, "%s, ", func); + else + fprintf(fp, "%s, ", np->u.leaf.func); + + fprintf(fp, "0"); + if (np->flags & FL_SET) + fprintf(fp, "|SNMP_NODE_CANSET"); + fprintf(fp, ", %#x, NULL, NULL },\n", idx); + oid->len--; + return; +} + +/* + * Generate the header file with the function declarations. + */ +static void +gen_header(FILE *fp, const struct node *np, u_int oidlen, const char *func) +{ + char f[MAXSTR + 4]; + struct node *sub; + struct func *ptr; + + oidlen++; + if (np->type == NODE_TREE) { + TAILQ_FOREACH(sub, &np->u.tree.subs, link) + gen_header(fp, sub, oidlen, NULL); + return; + } + if (np->type == NODE_ENTRY) { + TAILQ_FOREACH(sub, &np->u.entry.subs, link) + gen_header(fp, sub, oidlen, np->u.entry.func); + return; + } + + if((np->flags & (FL_GET|FL_SET)) == 0) + return; + + if (np->type == NODE_COLUMN) { + if (func == NULL) + errx(1, "column without function (%s) - probably " + "outside of a table", np->name); + sprintf(f, "%s", func); + } else + sprintf(f, "%s", np->u.leaf.func); + + LIST_FOREACH(ptr, &funcs, link) + if (strcmp(ptr->name, f) == 0) + break; + + if (ptr == NULL) { + ptr = xalloc(sizeof(*ptr)); + ptr->name = savestr(f); + LIST_INSERT_HEAD(&funcs, ptr, link); + + fprintf(fp, "int %s(struct snmp_context *, " + "struct snmp_value *, u_int, u_int, " + "enum snmp_op);\n", f); + } + + fprintf(fp, "# define LEAF_%s %u\n", np->name, np->id); +} + +/* + * Generate the OID table. + */ +static void +gen_table(FILE *fp, const struct node *node) +{ + struct asn_oid oid; + + fprintf(fp, "#include \n"); + fprintf(fp, "#include \n"); +#ifdef HAVE_STDINT_H + fprintf(fp, "#include \n"); +#endif + if (localincs) { + fprintf(fp, "#include \"asn1.h\"\n"); + fprintf(fp, "#include \"snmp.h\"\n"); + fprintf(fp, "#include \"snmpagent.h\"\n"); + } else { + fprintf(fp, "#include \n"); + fprintf(fp, "#include \n"); + fprintf(fp, "#include \n"); + } + fprintf(fp, "#include \"%stree.h\"\n", file_prefix); + fprintf(fp, "\n"); + + fprintf(fp, "const struct snmp_node %sctree[] = {\n", file_prefix); + + oid.len = PREFIX_LEN; + memcpy(oid.subs, prefix, sizeof(prefix)); + gen_node(fp, node, &oid, 0, NULL); + + fprintf(fp, "};\n\n"); +} + +static void +print_syntax(u_int syntax) +{ + u_int i; + + for (i = 0; keywords[i].str != NULL; i++) + if (keywords[i].tok == TOK_TYPE && + keywords[i].val == syntax) { + printf(" %s", keywords[i].str); + return; + } + abort(); +} + +/* + * Generate a tree definition file + */ +static void +gen_tree(const struct node *np, int level) +{ + const struct node *sp; + u_int i; + + printf("%*s(%u %s", 2 * level, "", np->id, np->name); + + switch (np->type) { + + case NODE_LEAF: + print_syntax(np->u.leaf.syntax); + if (np->u.leaf.subtype != NULL) + printf(" | %s", np->u.leaf.subtype); + printf(" %s%s%s)\n", np->u.leaf.func, + (np->flags & FL_GET) ? " GET" : "", + (np->flags & FL_SET) ? " SET" : ""); + break; + + case NODE_TREE: + if (TAILQ_EMPTY(&np->u.tree.subs)) { + printf(")\n"); + } else { + printf("\n"); + TAILQ_FOREACH(sp, &np->u.tree.subs, link) + gen_tree(sp, level + 1); + printf("%*s)\n", 2 * level, ""); + } + break; + + case NODE_ENTRY: + printf(" :"); + + for (i = 0; i < SNMP_INDEX_COUNT(np->u.entry.index); i++) { + print_syntax(SNMP_INDEX(np->u.entry.index, i)); + if (np->u.entry.subtypes[i] != NULL) + printf(" | %s", np->u.entry.subtypes[i]); + } + printf(" %s\n", np->u.entry.func); + TAILQ_FOREACH(sp, &np->u.entry.subs, link) + gen_tree(sp, level + 1); + printf("%*s)\n", 2 * level, ""); + break; + + case NODE_COLUMN: + print_syntax(np->u.column.syntax); + if (np->u.column.subtype != NULL) + printf(" | %s", np->u.column.subtype); + printf("%s%s)\n", (np->flags & FL_GET) ? " GET" : "", + (np->flags & FL_SET) ? " SET" : ""); + break; + } +} + +static int +extract(FILE *fp, const struct node *np, struct asn_oid *oid, const char *obj, + const struct asn_oid *idx, const char *iname) +{ + struct node *sub; + u_long n; + + if (oid->len == ASN_MAXOIDLEN) + report_node(np, "OID too long"); + oid->subs[oid->len++] = np->id; + + if (strcmp(obj, np->name) == 0) { + if (oid->len + idx->len >= ASN_MAXOIDLEN) + report_node(np, "OID too long"); + fprintf(fp, "#define OID_%s%s\t%u\n", np->name, + iname ? iname : "", np->id); + fprintf(fp, "#define OIDLEN_%s%s\t%u\n", np->name, + iname ? iname : "", oid->len + idx->len); + fprintf(fp, "#define OIDX_%s%s\t{ %u, {", np->name, + iname ? iname : "", oid->len + idx->len); + for (n = 0; n < oid->len; n++) + fprintf(fp, " %u,", oid->subs[n]); + for (n = 0; n < idx->len; n++) + fprintf(fp, " %u,", idx->subs[n]); + fprintf(fp, " } }\n"); + return (0); + } + + if (np->type == NODE_TREE) { + TAILQ_FOREACH(sub, &np->u.tree.subs, link) + if (!extract(fp, sub, oid, obj, idx, iname)) + return (0); + } else if (np->type == NODE_ENTRY) { + TAILQ_FOREACH(sub, &np->u.entry.subs, link) + if (!extract(fp, sub, oid, obj, idx, iname)) + return (0); + } + oid->len--; + return (1); +} + +static int +gen_extract(FILE *fp, const struct node *root, char *object) +{ + struct asn_oid oid; + struct asn_oid idx; + char *s, *e, *end, *iname; + u_long ul; + int ret; + + /* look whether the object to extract has an index part */ + idx.len = 0; + iname = NULL; + s = strchr(object, '.'); + if (s != NULL) { + iname = malloc(strlen(s) + 1); + if (iname == NULL) + err(1, "cannot allocated index"); + + strcpy(iname, s); + for (e = iname; *e != '\0'; e++) + if (*e == '.') + *e = '_'; + + *s++ = '\0'; + while (s != NULL) { + if (*s == '\0') + errx(1, "bad index syntax"); + if ((e = strchr(s, '.')) != NULL) + *e++ = '\0'; + + errno = 0; + ul = strtoul(s, &end, 0); + if (*end != '\0') + errx(1, "bad index syntax '%s'", end); + if (errno != 0) + err(1, "bad index syntax"); + + if (idx.len == ASN_MAXOIDLEN) + errx(1, "index oid too large"); + idx.subs[idx.len++] = ul; + + s = e; + } + } + + oid.len = PREFIX_LEN; + memcpy(oid.subs, prefix, sizeof(prefix)); + ret = extract(fp, root, &oid, object, &idx, iname); + if (iname != NULL) + free(iname); + + return (ret); +} + + +static void +check_sub_order(const struct node *np, const struct node_list *subs) +{ + int first; + const struct node *sub; + asn_subid_t maxid = 0; + + /* ensure, that subids are ordered */ + first = 1; + TAILQ_FOREACH(sub, subs, link) { + if (!first && sub->id <= maxid) + report_node(np, "subids not ordered at %s", sub->name); + maxid = sub->id; + first = 0; + } +} + +/* + * Do some sanity checks on the tree definition and do some computations. + */ +static void +check_tree(struct node *np) +{ + struct node *sub; + + if (np->type == NODE_LEAF || np->type == NODE_COLUMN) { + if ((np->flags & (FL_GET|FL_SET)) != 0) + tree_size++; + return; + } + + if (np->type == NODE_ENTRY) { + check_sub_order(np, &np->u.entry.subs); + + /* ensure all subnodes are columns */ + TAILQ_FOREACH(sub, &np->u.entry.subs, link) { + if (sub->type != NODE_COLUMN) + report_node(np, "entry subnode '%s' is not " + "a column", sub->name); + check_tree(sub); + } + } else { + check_sub_order(np, &np->u.tree.subs); + + TAILQ_FOREACH(sub, &np->u.tree.subs, link) + check_tree(sub); + } +} + +static void +merge_subs(struct node_list *s1, struct node_list *s2) +{ + struct node *n1, *n2; + + while (!TAILQ_EMPTY(s2)) { + n2 = TAILQ_FIRST(s2); + TAILQ_REMOVE(s2, n2, link); + + TAILQ_FOREACH(n1, s1, link) + if (n1->id >= n2->id) + break; + if (n1 == NULL) + TAILQ_INSERT_TAIL(s1, n2, link); + else if (n1->id > n2->id) + TAILQ_INSERT_BEFORE(n1, n2, link); + else { + if (n1->type == NODE_TREE && n2->type == NODE_TREE) { + if (strcmp(n1->name, n2->name) != 0) + errx(1, "trees to merge must have " + "same name '%s' '%s'", n1->name, + n2->name); + merge_subs(&n1->u.tree.subs, &n2->u.tree.subs); + free(n2); + } else if (n1->type == NODE_ENTRY && + n2->type == NODE_ENTRY) { + if (strcmp(n1->name, n2->name) != 0) + errx(1, "entries to merge must have " + "same name '%s' '%s'", n1->name, + n2->name); + if (n1->u.entry.index != n2->u.entry.index) + errx(1, "entries to merge must have " + "same index '%s'", n1->name); + if (strcmp(n1->u.entry.func, + n2->u.entry.func) != 0) + errx(1, "entries to merge must have " + "same op '%s'", n1->name); + merge_subs(&n1->u.entry.subs, + &n2->u.entry.subs); + free(n2); + } else + errx(1, "entities to merge must be both " + "trees or both entries: %s, %s", + n1->name, n2->name); + } + } +} + +static void +merge(struct node **root, struct node *t) +{ + + if (*root == NULL) { + *root = t; + return; + } + if (t == NULL) + return; + + /* both must be trees */ + if ((*root)->type != NODE_TREE) + errx(1, "root is not a tree"); + if (t->type != NODE_TREE) + errx(1, "can merge only with tree"); + if ((*root)->id != t->id) + errx(1, "trees to merge must have same id"); + + merge_subs(&(*root)->u.tree.subs, &t->u.tree.subs); +} + +static void +unminus(FILE *fp, const char *s) +{ + + while (*s != '\0') { + if (*s == '-') + fprintf(fp, "_"); + else + fprintf(fp, "%c", *s); + s++; + } +} + +/** + * Generate helper functions for an enum. + * + * We always generate a switch statement for the isok function. The compiler + * optimizes this into range checks if possible. + * + * \param fp file to write to + * \param t type + * \param ccode generate externally visible non-inline functions + */ +static void +gen_enum_funcs(FILE *fp, const struct type *t, int ccode) +{ + fprintf(fp, "\n"); + + if (!ccode) + fprintf(fp, "static inline "); + fprintf(fp, "int\n"); + fprintf(fp, "isok_%s(enum %s s)\n", t->name, t->name); + fprintf(fp, "{\n"); + fprintf(fp, " switch (s) {\n"); + + const struct enums *e; + TAILQ_FOREACH(e, &t->enums, link) { + fprintf(fp, "\t case %s_", t->name); + unminus(fp, e->name); + fprintf(fp, ":\n"); + } + + fprintf(fp, " return (1);\n"); + fprintf(fp, " }\n"); + fprintf(fp, " return (0);\n"); + fprintf(fp, "}\n\n"); + + if (!ccode) + fprintf(fp, "static inline "); + fprintf(fp, "const char *\n"); + fprintf(fp, "tostr_%s(enum %s s)\n", t->name, t->name); + fprintf(fp, "{\n"); + fprintf(fp, " static const char *vals[] = { STRING_%s };\n", t->name); + fprintf(fp, "\n"); + fprintf(fp, " if (isok_%s(s))\n", t->name); + fprintf(fp, " return (vals[(int)s - STROFF_%s]);\n", t->name); + fprintf(fp, " return (\"%s???\");\n", t->name); + fprintf(fp, "}\n\n"); + + if (!ccode) + fprintf(fp, "static inline "); + fprintf(fp, "int\n"); + fprintf(fp, "fromstr_%s(const char *str, enum %s *s)\n", + t->name, t->name); + fprintf(fp, "{\n"); + fprintf(fp, " static const char *vals[] = { STRING_%s };\n", t->name); + fprintf(fp, "\n"); + fprintf(fp, " for (size_t i = 0; i < sizeof(vals)/sizeof(vals[0]); i++) {\n"); + fprintf(fp, " if (vals[i] != NULL && strcmp(vals[i], str) == 0) {\n"); + fprintf(fp, " *s = i + STROFF_%s;\n", t->name); + fprintf(fp, " return (1);\n"); + fprintf(fp, " }\n"); + fprintf(fp, " }\n"); + fprintf(fp, " return (0);\n"); + fprintf(fp, "}\n"); +} + +/** + * Generate a definition for the enum packed into a guard against multiple + * definitions. + * + * \param fp file to write definition to + * \param t type + * \param dof generate functions too + */ +static void +gen_enum(FILE *fp, const struct type *t, int dof) +{ + const struct enums *e; + long min = LONG_MAX; + + fprintf(fp, "\n"); + fprintf(fp, "#ifndef %s_defined__\n", t->name); + fprintf(fp, "#define %s_defined__\n", t->name); + fprintf(fp, "/*\n"); + fprintf(fp, " * From %s:%u\n", t->from_fname, t->from_lno); + fprintf(fp, " */\n"); + fprintf(fp, "enum %s {\n", t->name); + TAILQ_FOREACH(e, &t->enums, link) { + fprintf(fp, "\t%s_", t->name); + unminus(fp, e->name); + fprintf(fp, " = %ld,\n", e->value); + if (e->value < min) + min = e->value; + } + fprintf(fp, "};\n"); + fprintf(fp, "#define STROFF_%s %ld\n", t->name, min); + fprintf(fp, "#define STRING_%s \\\n", t->name); + TAILQ_FOREACH(e, &t->enums, link) { + fprintf(fp, "\t[%ld] = \"%s_", e->value - min, t->name); + unminus(fp, e->name); + fprintf(fp, "\",\\\n"); + } + fprintf(fp, "\n"); + if (dof) { + fprintf(fp, "#ifdef SNMPENUM_FUNCS\n"); + fprintf(fp, "\n"); + gen_enum_funcs(fp, t, 0); + fprintf(fp, "\n"); + fprintf(fp, "#endif\n"); + fprintf(fp, "\n"); + } + fprintf(fp, "#endif /* %s_defined__ */\n", t->name); +} + +/** + * Generate helper functions for an enum. This generates code for a c file. + * + * \param fp file to write to + * \param name enum name + */ +static int +gen_enum_funcs_str(FILE *fp, const char *name) +{ + const struct type *t; + + LIST_FOREACH(t, &types, link) + if ((t->is_enum || t->is_bits) && strcmp(t->name, name) == 0) { + gen_enum_funcs(fp, t, 1); + return (0); + } + + return (-1); +} + +/** + * Generate helper functions for all enums. + * + * \param fp file to write to + * \param ccode generate externally visible non-inline functions + */ +static void +gen_all_enum_funcs(FILE *fp, int ccode) +{ + const struct type *t; + + LIST_FOREACH(t, &types, link) + if (t->is_enum || t->is_bits) + gen_enum_funcs(fp, t, ccode); +} + +static void +gen_enums(FILE *fp, int dof) +{ + const struct type *t; + + LIST_FOREACH(t, &types, link) + if (t->is_enum || t->is_bits) + gen_enum(fp, t, dof); +} + +/** + * Extract a given enum to the specified file and optionally generate static + * inline helper functions for them. + * + * \param fp file to print on + * \param name name of the enum + * \param gen_funcs generate the functions too + * + * \return 0 if found, -1 otherwise + */ +static int +extract_enum(FILE *fp, const char *name, int gen_funcs) +{ + const struct type *t; + + LIST_FOREACH(t, &types, link) + if ((t->is_enum || t->is_bits) && strcmp(t->name, name) == 0) { + gen_enum(fp, t, gen_funcs); + return (0); + } + return (-1); +} + +/** + * Extract all enums to the given file and optionally generate static inline + * helper functions for them. + * + * \param fp file to print on + * \param gen_funcs generate the functions too + */ +static void +extract_all_enums(FILE *fp, int gen_funcs) +{ + const struct type *t; + + LIST_FOREACH(t, &types, link) + if (t->is_enum || t->is_bits) + gen_enum(fp, t, gen_funcs); +} + +/** + * Extract enums and optionally generate some helper functions for them. + * + * \param argc number of arguments + * \param argv arguments (enum names) + * \param gen_funcs which functions to generate + */ +static void +make_enums(int argc, char *argv[], enum gen_funcs gen_funcs) +{ + if (gen_funcs == GEN_FUNCS_C) { + if (argc == 0) + gen_all_enum_funcs(stdout, 1); + else { + for (int i = 0; i < argc; i++) + if (gen_enum_funcs_str(stdout, argv[i])) + errx(1, "enum not found: %s", argv[i]); + } + } else { + if (argc == 0) + extract_all_enums(stdout, gen_funcs == GEN_FUNCS_H); + else { + for (int i = 0; i < argc; i++) + if (extract_enum(stdout, argv[i], + gen_funcs == GEN_FUNCS_H)) + errx(1, "enum not found: %s", argv[i]); + } + } +} + +/** + * Produce the operation tables for the daemon or a module. + * + * \param root tree root + * \param gen_funcs generate enum funcs + */ +static void +make_table(const struct node *root, int gen_funcs) +{ + FILE *fp; + + char fname[MAXPATHLEN + 1]; + sprintf(fname, "%stree.h", file_prefix); + if ((fp = fopen(fname, "w")) == NULL) + err(1, "%s: ", fname); + gen_header(fp, root, PREFIX_LEN, NULL); + + fprintf(fp, "\n#ifdef SNMPTREE_TYPES\n"); + gen_enums(fp, gen_funcs); + fprintf(fp, "\n#endif /* SNMPTREE_TYPES */\n\n"); + + fprintf(fp, "#define %sCTREE_SIZE %u\n", file_prefix, tree_size); + fprintf(fp, "extern const struct snmp_node %sctree[];\n", file_prefix); + + fclose(fp); + + sprintf(fname, "%stree.c", file_prefix); + if ((fp = fopen(fname, "w")) == NULL) + err(1, "%s: ", fname); + gen_table(fp, root); + fclose(fp); +} + +int +main(int argc, char *argv[]) +{ + enum op op = OP_GEN; + enum gen_funcs gen_funcs = GEN_FUNCS_NONE; + + char *infile = NULL; + + int opt; + while ((opt = getopt(argc, argv, "dEeFfhI:i:lp:t")) != EOF) + switch (opt) { + + case 'd': + debug = 1; + break; + + case 'E': + if (op != OP_GEN && op != OP_ENUMS) + errx(1, "-E conflicts with earlier options"); + op = OP_ENUMS; + break; + + case 'e': + if (op != OP_GEN && op != OP_EXTRACT) + errx(1, "-e conflicts with earlier options"); + op = OP_EXTRACT; + break; + + case 'F': + if (gen_funcs != GEN_FUNCS_NONE && + gen_funcs != GEN_FUNCS_C) + errx(1, "-F conflicts with -f"); + gen_funcs = GEN_FUNCS_C; + break; + + case 'f': + if (gen_funcs != GEN_FUNCS_NONE && + gen_funcs != GEN_FUNCS_H) + errx(1, "-f conflicts with -F"); + gen_funcs = GEN_FUNCS_H; + break; + + case 'h': + fprintf(stderr, "%s", usgtxt); + exit(0); + + case 'I': + path_new(optarg); + break; + + case 'i': + infile = optarg; + break; + + case 'l': + localincs = 1; + break; + + case 'p': + file_prefix = optarg; + if (strlen(file_prefix) + strlen("tree.c") > + MAXPATHLEN) + errx(1, "prefix too long"); + break; + + case 't': + if (op != OP_GEN && op != OP_TREE) + errx(1, "-t conflicts with earlier options"); + op = OP_TREE; + break; + } + + argc -= optind; + argv += optind; + + /* open input */ + if (infile == NULL) { + input_new(stdin, NULL, ""); + } else { + FILE *fp; + if ((fp = fopen(infile, "r")) == NULL) + err(1, "%s", infile); + input_new(fp, NULL, infile); + } + + /* parse and check input */ + struct node *root = parse_top(gettoken()); + + int tok; + while ((tok = gettoken()) != TOK_EOF) + merge(&root, parse_top(tok)); + + if (root) + check_tree(root); + + /* do what the user has requested */ + switch (op) { + + case OP_EXTRACT: + if (argc == 0) + errx(1, "-e requires arguments"); + + for (int i = 0; i < argc; i++) + if (gen_extract(stdout, root, argv[i])) + errx(1, "object not found: %s", argv[i]); + return (0); + + case OP_ENUMS: + make_enums(argc, argv, gen_funcs); + return (0); + + case OP_TREE: + if (argc != 0) + errx(1, "-t allows no arguments"); + gen_tree(root, 0); + return (0); + + case OP_GEN: + if (argc != 0) + errx(1, "tree generation allows no arguments"); + make_table(root, gen_funcs == GEN_FUNCS_H); + return (0); + } +} Property changes on: vendor/1.14/gensnmptree/gensnmptree.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/lib/asn1.c =================================================================== --- vendor/1.14/lib/asn1.c (nonexistent) +++ vendor/1.14/lib/asn1.c (revision 359491) @@ -0,0 +1,1045 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/lib/asn1.c,v 1.31 2005/10/06 07:14:58 brandt_h Exp $ + * + * ASN.1 for SNMP. + */ +#include +#include +#include +#include +#include +#ifdef HAVE_STDINT_H +#include +#elif defined(HAVE_INTTYPES_H) +#include +#endif +#include + +#include "support.h" +#include "asn1.h" + +static void asn_error_func(const struct asn_buf *, const char *, ...); + +void (*asn_error)(const struct asn_buf *, const char *, ...) = asn_error_func; + +/* + * Read the next header. This reads the tag (note, that only single + * byte tags are supported for now) and the length field. The length field + * is restricted to a 32-bit value. + * All errors of this function stop the decoding. + */ +enum asn_err +asn_get_header(struct asn_buf *b, u_char *type, asn_len_t *len) +{ + u_int length; + + if (b->asn_len == 0) { + asn_error(b, "no identifier for header"); + return (ASN_ERR_EOBUF); + } + *type = *b->asn_cptr; + if ((*type & ASN_TYPE_MASK) > 0x1e) { + asn_error(b, "tags > 0x1e not supported (%#x)", + *type & ASN_TYPE_MASK); + return (ASN_ERR_FAILED); + } + b->asn_cptr++; + b->asn_len--; + if (b->asn_len == 0) { + asn_error(b, "no length field"); + return (ASN_ERR_EOBUF); + } + if (*b->asn_cptr & 0x80) { + length = *b->asn_cptr++ & 0x7f; + b->asn_len--; + if (length == 0) { + asn_error(b, "indefinite length not supported"); + return (ASN_ERR_FAILED); + } + if (length > ASN_MAXLENLEN) { + asn_error(b, "long length too long (%u)", length); + return (ASN_ERR_FAILED); + } + if (length > b->asn_len) { + asn_error(b, "long length truncated"); + return (ASN_ERR_EOBUF); + } + *len = 0; + while (length--) { + *len = (*len << 8) | *b->asn_cptr++; + b->asn_len--; + } + } else { + *len = *b->asn_cptr++; + b->asn_len--; + } + +#ifdef BOGUS_CVE_2019_5610_FIX + /* + * This is the fix from CVE-2019-5610. + * + * This is the wrong place. Each of the asn functions should check + * that it has enough info for its own work. + */ + if (*len > b->asn_len) { + asn_error(b, "lenen %u exceeding asn_len %u", *len, b->asn_len); + return (ASN_ERR_EOBUF); + } +#endif + return (ASN_ERR_OK); +} + +/* + * Write a length field (restricted to values < 2^32-1) and return the + * number of bytes this field takes. If ptr is NULL, the length is computed + * but nothing is written. If the length would be too large return 0. + */ +static u_int +asn_put_len(u_char *ptr, asn_len_t len) +{ + u_int lenlen, lenlen1; + asn_len_t tmp; + + if (len > ASN_MAXLEN) { + asn_error(NULL, "encoding length too long: (%u)", len); + return (0); + } + + if (len <= 127) { + if (ptr) + *ptr++ = (u_char)len; + return (1); + } else { + lenlen = 0; + /* compute number of bytes for value (is at least 1) */ + for (tmp = len; tmp != 0; tmp >>= 8) + lenlen++; + if (ptr != NULL) { + *ptr++ = (u_char)lenlen | 0x80; + lenlen1 = lenlen; + while (lenlen1-- > 0) { + ptr[lenlen1] = len & 0xff; + len >>= 8; + } + } + return (lenlen + 1); + } +} + +/* + * Write a header (tag and length fields). + * Tags are restricted to one byte tags (value <= 0x1e) and the + * lenght field to 16-bit. All errors stop the encoding. + */ +enum asn_err +asn_put_header(struct asn_buf *b, u_char type, asn_len_t len) +{ + u_int lenlen; + + /* tag field */ + if ((type & ASN_TYPE_MASK) > 0x1e) { + asn_error(NULL, "types > 0x1e not supported (%#x)", + type & ASN_TYPE_MASK); + return (ASN_ERR_FAILED); + } + if (b->asn_len == 0) + return (ASN_ERR_EOBUF); + + *b->asn_ptr++ = type; + b->asn_len--; + + /* length field */ + if ((lenlen = asn_put_len(NULL, len)) == 0) + return (ASN_ERR_FAILED); + if (b->asn_len < lenlen) + return (ASN_ERR_EOBUF); + + (void)asn_put_len(b->asn_ptr, len); + b->asn_ptr += lenlen; + b->asn_len -= lenlen; + return (ASN_ERR_OK); +} + + +/* + * This constructs a temporary sequence header with space for the maximum + * length field (three byte). Set the pointer that ptr points to to the + * start of the encoded header. This is used for a later call to + * asn_commit_header which will fix-up the length field and move the + * value if needed. All errors should stop the encoding. + */ +#define TEMP_LEN (1 + ASN_MAXLENLEN + 1) +enum asn_err +asn_put_temp_header(struct asn_buf *b, u_char type, u_char **ptr) +{ + int ret; + + if (b->asn_len < TEMP_LEN) + return (ASN_ERR_EOBUF); + *ptr = b->asn_ptr; + if ((ret = asn_put_header(b, type, ASN_MAXLEN)) == ASN_ERR_OK) + assert(b->asn_ptr == *ptr + TEMP_LEN); + return (ret); +} +enum asn_err +asn_commit_header(struct asn_buf *b, u_char *ptr, size_t *moved) +{ + asn_len_t len; + u_int lenlen, shift; + + /* compute length of encoded value without header */ + len = b->asn_ptr - (ptr + TEMP_LEN); + + /* insert length. may not fail. */ + lenlen = asn_put_len(ptr + 1, len); + if (lenlen > TEMP_LEN - 1) + return (ASN_ERR_FAILED); + + if (lenlen < TEMP_LEN - 1) { + /* shift value down */ + shift = (TEMP_LEN - 1) - lenlen; + memmove(ptr + 1 + lenlen, ptr + TEMP_LEN, len); + b->asn_ptr -= shift; + b->asn_len += shift; + if (moved != NULL) + *moved = shift; + } + return (ASN_ERR_OK); +} +#undef TEMP_LEN + +/* + * BER integer. This may be used to get a signed 64 bit integer at maximum. + * The maximum length should be checked by the caller. This cannot overflow + * if the caller ensures that len is at maximum 8. + * + * + */ +static enum asn_err +asn_get_real_integer(struct asn_buf *b, asn_len_t len, int64_t *vp) +{ + uint64_t val; + int neg = 0; + enum asn_err err; + + if (b->asn_len < len) { + asn_error(b, "truncated integer"); + return (ASN_ERR_EOBUF); + } + if (len == 0) { + asn_error(b, "zero-length integer"); + *vp = 0; + return (ASN_ERR_BADLEN); + } + err = ASN_ERR_OK; + if (len > 8) { + asn_error(b, "integer too long"); + err = ASN_ERR_RANGE; + } else if (len > 1 && + ((*b->asn_cptr == 0x00 && (b->asn_cptr[1] & 0x80) == 0) || + (*b->asn_cptr == 0xff && (b->asn_cptr[1] & 0x80) == 0x80))) { + asn_error(b, "non-minimal integer"); + err = ASN_ERR_BADLEN; + } + + if (*b->asn_cptr & 0x80) + neg = 1; + val = 0; + while (len--) { + val <<= 8; + val |= neg ? (u_char)~*b->asn_cptr : *b->asn_cptr; + b->asn_len--; + b->asn_cptr++; + } + if (neg) { + *vp = -(int64_t)val - 1; + } else + *vp = (int64_t)val; + return (err); +} + +/* + * Write a signed integer with the given type. The caller has to ensure + * that the actual value is ok for this type. + */ +static enum asn_err +asn_put_real_integer(struct asn_buf *b, u_char type, int64_t ival) +{ + int i, neg = 0; +# define OCTETS 8 + u_char buf[OCTETS]; + uint64_t val; + enum asn_err ret; + + if (ival < 0) { + /* this may fail if |INT64_MIN| > |INT64_MAX| and + * the value is between * INT64_MIN <= ival < -(INT64_MAX+1) */ + val = (uint64_t)-(ival + 1); + neg = 1; + } else + val = (uint64_t)ival; + + /* split the value into octets */ + for (i = OCTETS - 1; i >= 0; i--) { + buf[i] = val & 0xff; + if (neg) + buf[i] = ~buf[i]; + val >>= 8; + } + /* no leading 9 zeroes or ones */ + for (i = 0; i < OCTETS - 1; i++) + if (!((buf[i] == 0xff && (buf[i + 1] & 0x80) != 0) || + (buf[i] == 0x00 && (buf[i + 1] & 0x80) == 0))) + break; + if ((ret = asn_put_header(b, type, OCTETS - i))) + return (ret); + if (OCTETS - (u_int)i > b->asn_len) + return (ASN_ERR_EOBUF); + + while (i < OCTETS) { + *b->asn_ptr++ = buf[i++]; + b->asn_len--; + } + return (ASN_ERR_OK); +# undef OCTETS +} + + +/* + * The same for unsigned 64-bitters. Here we have the problem, that overflow + * can happen, because the value maybe 9 bytes long. In this case the + * first byte must be 0. + */ +static enum asn_err +asn_get_real_unsigned(struct asn_buf *b, asn_len_t len, uint64_t *vp) +{ + *vp = 0; + if (b->asn_len < len) { + asn_error(b, "truncated integer"); + return (ASN_ERR_EOBUF); + } + if (len == 0) { + /* X.690: 8.3.1 */ + asn_error(b, "zero-length integer"); + return (ASN_ERR_BADLEN); + } + if (len > 1 && *b->asn_cptr == 0x00 && (b->asn_cptr[1] & 0x80) == 0) { + /* X.690: 8.3.2 */ + asn_error(b, "non-minimal unsigned"); + b->asn_cptr += len; + b->asn_len -= len; + return (ASN_ERR_BADLEN); + + } + + enum asn_err err = ASN_ERR_OK; + + if ((*b->asn_cptr & 0x80) || len > 9 || + (len == 9 && *b->asn_cptr != 0)) { + /* negative integer or too larger */ + *vp = 0xffffffffffffffffULL; + asn_error(b, "unsigned too large or negative"); + b->asn_cptr += len; + b->asn_len -= len; + return (ASN_ERR_RANGE); + } + + while (len--) { + *vp = (*vp << 8) | *b->asn_cptr++; + b->asn_len--; + } + return (err); +} + + +/* + * Values with the msb on need 9 octets. + */ +static int +asn_put_real_unsigned(struct asn_buf *b, u_char type, uint64_t val) +{ + int i; +# define OCTETS 9 + u_char buf[OCTETS]; + enum asn_err ret; + + /* split the value into octets */ + for (i = OCTETS - 1; i >= 0; i--) { + buf[i] = val & 0xff; + val >>= 8; + } + /* no leading 9 zeroes */ + for (i = 0; i < OCTETS - 1; i++) + if (!(buf[i] == 0x00 && (buf[i + 1] & 0x80) == 0)) + break; + if ((ret = asn_put_header(b, type, OCTETS - i))) + return (ret); + if (OCTETS - (u_int)i > b->asn_len) + return (ASN_ERR_EOBUF); + + while (i < OCTETS) { + *b->asn_ptr++ = buf[i++]; + b->asn_len--; + } +#undef OCTETS + return (ASN_ERR_OK); +} + +/* + * The ASN.1 INTEGER type is restricted to 32-bit signed by the SMI. + */ +enum asn_err +asn_get_integer_raw(struct asn_buf *b, asn_len_t len, int32_t *vp) +{ + int64_t val; + enum asn_err ret; + + if ((ret = asn_get_real_integer(b, len, &val)) == ASN_ERR_OK) { + if (len > 4) { + asn_error(b, "integer too long"); + ret = ASN_ERR_BADLEN; + } else if (val > INT32_MAX || val < INT32_MIN) { + /* may not happen */ + asn_error(b, "integer out of range"); + ret = ASN_ERR_RANGE; + } + *vp = (int32_t)val; + } + return (ret); +} + +enum asn_err +asn_get_integer(struct asn_buf *b, int32_t *vp) +{ + asn_len_t len; + u_char type; + enum asn_err err; + + if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK) + return (err); + if (type != ASN_TYPE_INTEGER) { + asn_error(b, "bad type for integer (%u)", type); + return (ASN_ERR_TAG); + } + + return (asn_get_integer_raw(b, len, vp)); +} + +enum asn_err +asn_put_integer(struct asn_buf *b, int32_t val) +{ + return (asn_put_real_integer(b, ASN_TYPE_INTEGER, val)); +} + +/* + * OCTETSTRING + * + * <0x04> + * + * Get an octetstring. noctets must point to the buffer size and on + * return will contain the size of the octetstring, regardless of the + * buffer size. + */ +enum asn_err +asn_get_octetstring_raw(struct asn_buf *b, asn_len_t len, u_char *octets, + u_int *noctets) +{ + enum asn_err err = ASN_ERR_OK; + + if (*noctets < len) { + asn_error(b, "octetstring truncated"); + err = ASN_ERR_RANGE; + } + if (b->asn_len < len) { + asn_error(b, "truncatet octetstring"); + return (ASN_ERR_EOBUF); + } + if (*noctets < len) + memcpy(octets, b->asn_cptr, *noctets); + else + memcpy(octets, b->asn_cptr, len); + *noctets = len; + b->asn_cptr += len; + b->asn_len -= len; + return (err); +} + +enum asn_err +asn_get_octetstring(struct asn_buf *b, u_char *octets, u_int *noctets) +{ + enum asn_err err; + u_char type; + asn_len_t len; + + if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK) + return (err); + if (type != ASN_TYPE_OCTETSTRING) { + asn_error(b, "bad type for octetstring (%u)", type); + return (ASN_ERR_TAG); + } + return (asn_get_octetstring_raw(b, len, octets, noctets)); +} + +enum asn_err +asn_put_octetstring(struct asn_buf *b, const u_char *octets, u_int noctets) +{ + enum asn_err ret; + + if ((ret = asn_put_header(b, ASN_TYPE_OCTETSTRING, noctets)) != ASN_ERR_OK) + return (ret); + if (b->asn_len < noctets) + return (ASN_ERR_EOBUF); + + memcpy(b->asn_ptr, octets, noctets); + b->asn_ptr += noctets; + b->asn_len -= noctets; + return (ASN_ERR_OK); +} + +/* + * NULL + * + * <0x05> <0x00> + */ +enum asn_err +asn_get_null_raw(struct asn_buf *b, asn_len_t len) +{ + if (len != 0) { + if (b->asn_len < len) { + asn_error(b, "truncated NULL"); + return (ASN_ERR_EOBUF); + } + asn_error(b, "bad length for NULL (%u)", len); + b->asn_len -= len; + b->asn_ptr += len; + return (ASN_ERR_BADLEN); + } + return (ASN_ERR_OK); +} + +enum asn_err +asn_get_null(struct asn_buf *b) +{ + u_char type; + asn_len_t len; + enum asn_err err; + + if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK) + return (err); + if (type != ASN_TYPE_NULL) { + asn_error(b, "bad type for NULL (%u)", type); + return (ASN_ERR_TAG); + } + return (asn_get_null_raw(b, len)); +} + +enum asn_err +asn_put_null(struct asn_buf *b) +{ + return (asn_put_header(b, ASN_TYPE_NULL, 0)); +} + +enum asn_err +asn_put_exception(struct asn_buf *b, u_int except) +{ + return (asn_put_header(b, ASN_CLASS_CONTEXT | except, 0)); +} + +/* + * OBJID + * + * <0x06> + */ +enum asn_err +asn_get_objid_raw(struct asn_buf *b, asn_len_t len, struct asn_oid *oid) +{ + asn_subid_t subid; + enum asn_err err; + + if (b->asn_len < len) { + asn_error(b, "truncated OBJID"); + return (ASN_ERR_EOBUF); + } + oid->len = 0; + if (len == 0) { + asn_error(b, "short OBJID"); + oid->subs[oid->len++] = 0; + oid->subs[oid->len++] = 0; + return (ASN_ERR_BADLEN); + } + err = ASN_ERR_OK; + while (len != 0) { + if (oid->len == ASN_MAXOIDLEN) { + asn_error(b, "OID too long (%u)", oid->len); + b->asn_cptr += len; + b->asn_len -= len; + return (ASN_ERR_BADLEN); + } + subid = 0; + do { + if (len == 0) { + asn_error(b, "unterminated subid"); + return (ASN_ERR_EOBUF); + } + if (subid > (ASN_MAXID >> 7)) { + asn_error(b, "OID subid too larger"); + err = ASN_ERR_RANGE; + } + subid = (subid << 7) | (*b->asn_cptr & 0x7f); + len--; + b->asn_len--; + } while (*b->asn_cptr++ & 0x80); + if (oid->len == 0) { + if (subid < 80) { + oid->subs[oid->len++] = subid / 40; + oid->subs[oid->len++] = subid % 40; + } else { + oid->subs[oid->len++] = 2; + oid->subs[oid->len++] = subid - 80; + } + } else { + oid->subs[oid->len++] = subid; + } + } + return (err); + +} + +enum asn_err +asn_get_objid(struct asn_buf *b, struct asn_oid *oid) +{ + u_char type; + asn_len_t len; + enum asn_err err; + + if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK) + return (err); + if (type != ASN_TYPE_OBJID) { + asn_error(b, "bad type for OBJID (%u)", type); + return (ASN_ERR_TAG); + } + return (asn_get_objid_raw(b, len, oid)); +} + +enum asn_err +asn_put_objid(struct asn_buf *b, const struct asn_oid *oid) +{ + asn_subid_t first, sub; + enum asn_err err, err1; + u_int i, oidlen; + asn_len_t len; + + err = ASN_ERR_OK; + if (oid->len == 0) { + /* illegal */ + asn_error(NULL, "short oid"); + err = ASN_ERR_RANGE; + first = 0; + oidlen = 2; + } else if (oid->len == 1) { + /* illegal */ + asn_error(NULL, "short oid"); + if (oid->subs[0] > 2) + asn_error(NULL, "oid[0] too large (%u)", oid->subs[0]); + err = ASN_ERR_RANGE; + first = oid->subs[0] * 40; + oidlen = 2; + } else { + if (oid->len > ASN_MAXOIDLEN) { + asn_error(NULL, "oid too long %u", oid->len); + err = ASN_ERR_RANGE; + } + if (oid->subs[0] > 2 || + (oid->subs[0] < 2 && oid->subs[1] >= 40) || + (oid->subs[0] == 2 && oid->subs[1] > ASN_MAXID - 2 * 40)) { + asn_error(NULL, "oid out of range (%u,%u)", + oid->subs[0], oid->subs[1]); + err = ASN_ERR_RANGE; + } + first = 40 * oid->subs[0] + oid->subs[1]; + oidlen = oid->len; + } + len = 0; + for (i = 1; i < oidlen; i++) { + sub = (i == 1) ? first : oid->subs[i]; + if (sub > ASN_MAXID) { + asn_error(NULL, "oid subid too large"); + err = ASN_ERR_RANGE; + } + len += (sub <= 0x7f) ? 1 + : (sub <= 0x3fff) ? 2 + : (sub <= 0x1fffff) ? 3 + : (sub <= 0xfffffff) ? 4 + : 5; + } + if ((err1 = asn_put_header(b, ASN_TYPE_OBJID, len)) != ASN_ERR_OK) + return (err1); + if (b->asn_len < len) + return (ASN_ERR_EOBUF); + + for (i = 1; i < oidlen; i++) { + sub = (i == 1) ? first : oid->subs[i]; + if (sub <= 0x7f) { + *b->asn_ptr++ = sub; + b->asn_len--; + } else if (sub <= 0x3fff) { + *b->asn_ptr++ = (sub >> 7) | 0x80; + *b->asn_ptr++ = sub & 0x7f; + b->asn_len -= 2; + } else if (sub <= 0x1fffff) { + *b->asn_ptr++ = (sub >> 14) | 0x80; + *b->asn_ptr++ = ((sub >> 7) & 0x7f) | 0x80; + *b->asn_ptr++ = sub & 0x7f; + b->asn_len -= 3; + } else if (sub <= 0xfffffff) { + *b->asn_ptr++ = (sub >> 21) | 0x80; + *b->asn_ptr++ = ((sub >> 14) & 0x7f) | 0x80; + *b->asn_ptr++ = ((sub >> 7) & 0x7f) | 0x80; + *b->asn_ptr++ = sub & 0x7f; + b->asn_len -= 4; + } else { + *b->asn_ptr++ = (sub >> 28) | 0x80; + *b->asn_ptr++ = ((sub >> 21) & 0x7f) | 0x80; + *b->asn_ptr++ = ((sub >> 14) & 0x7f) | 0x80; + *b->asn_ptr++ = ((sub >> 7) & 0x7f) | 0x80; + *b->asn_ptr++ = sub & 0x7f; + b->asn_len -= 5; + } + } + return (err); +} +/* + * SEQUENCE header + * + * <0x10|0x20> + */ +enum asn_err +asn_get_sequence(struct asn_buf *b, asn_len_t *len) +{ + u_char type; + enum asn_err err; + + if ((err = asn_get_header(b, &type, len)) != ASN_ERR_OK) + return (err); + if (type != (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED)) { + asn_error(b, "bad sequence type %u", type); + return (ASN_ERR_TAG); + } + if (*len > b->asn_len) { + asn_error(b, "truncated sequence"); + return (ASN_ERR_EOBUF); + } + return (ASN_ERR_OK); +} + +/* + * Application types + * + * 0x40 4 MSB 2MSB 2LSB LSB + */ +enum asn_err +asn_get_ipaddress_raw(struct asn_buf *b, asn_len_t len, u_char *addr) +{ + u_int i; + + if (b->asn_len < len) { + asn_error(b, "truncated ip-address"); + return (ASN_ERR_EOBUF); + } + if (len < 4) { + asn_error(b, "short length for ip-Address %u", len); + for (i = 0; i < len; i++) + *addr++ = *b->asn_cptr++; + while (i++ < len) + *addr++ = 0; + b->asn_len -= len; + return (ASN_ERR_BADLEN); + } + for (i = 0; i < 4; i++) + *addr++ = *b->asn_cptr++; + b->asn_cptr += len - 4; + b->asn_len -= len; + return (ASN_ERR_OK); +} + +enum asn_err +asn_get_ipaddress(struct asn_buf *b, u_char *addr) +{ + u_char type; + asn_len_t len; + enum asn_err err; + + if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK) + return (err); + if (type != (ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS)) { + asn_error(b, "bad type for ip-address %u", type); + return (ASN_ERR_TAG); + } + return (asn_get_ipaddress_raw(b, len, addr)); +} + +enum asn_err +asn_put_ipaddress(struct asn_buf *b, const u_char *addr) +{ + enum asn_err err; + + if ((err = asn_put_header(b, ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS, + 4)) != ASN_ERR_OK) + return (err); + if (b->asn_len < 4) + return (ASN_ERR_EOBUF); + + memcpy(b->asn_ptr, addr, 4); + b->asn_ptr += 4; + b->asn_len -= 4; + return (ASN_ERR_OK); +} + + +/* + * UNSIGNED32 + * + * 0x42|0x41 ... + */ +enum asn_err +asn_get_uint32_raw(struct asn_buf *b, asn_len_t len, uint32_t *vp) +{ + uint64_t v; + enum asn_err err; + + if ((err = asn_get_real_unsigned(b, len, &v)) == ASN_ERR_OK) { + if (v > UINT32_MAX) { + asn_error(b, "uint32 too large %llu", v); + err = ASN_ERR_RANGE; + } + *vp = (uint32_t)v; + } + return (err); +} + +enum asn_err +asn_put_uint32(struct asn_buf *b, u_char type, uint32_t val) +{ + uint64_t v = val; + + return (asn_put_real_unsigned(b, ASN_CLASS_APPLICATION|type, v)); +} + +/* + * COUNTER64 + * 0x46 ... + */ +enum asn_err +asn_get_counter64_raw(struct asn_buf *b, asn_len_t len, uint64_t *vp) +{ + return (asn_get_real_unsigned(b, len, vp)); +} + +enum asn_err +asn_put_counter64(struct asn_buf *b, uint64_t val) +{ + return (asn_put_real_unsigned(b, + ASN_CLASS_APPLICATION | ASN_APP_COUNTER64, val)); +} + +/* + * TimeTicks + * 0x43 ... + */ +enum asn_err +asn_get_timeticks(struct asn_buf *b, uint32_t *vp) +{ + asn_len_t len; + u_char type; + enum asn_err err; + + if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK) + return (err); + if (type != (ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS)) { + asn_error(b, "bad type for timeticks %u", type); + return (ASN_ERR_TAG); + } + return (asn_get_uint32_raw(b, len, vp)); +} + +enum asn_err +asn_put_timeticks(struct asn_buf *b, uint32_t val) +{ + uint64_t v = val; + + return (asn_put_real_unsigned(b, + ASN_CLASS_APPLICATION | ASN_APP_TIMETICKS, v)); +} + +/* + * Construct a new OID by taking a range of sub ids of the original oid. + */ +void +asn_slice_oid(struct asn_oid *dest, const struct asn_oid *src, + u_int from, u_int to) +{ + if (from >= to) { + dest->len = 0; + return; + } + dest->len = to - from; + memcpy(dest->subs, &src->subs[from], dest->len * sizeof(dest->subs[0])); +} + +/* + * Append from to to + */ +void +asn_append_oid(struct asn_oid *to, const struct asn_oid *from) +{ + memcpy(&to->subs[to->len], &from->subs[0], + from->len * sizeof(from->subs[0])); + to->len += from->len; +} + +/* + * Skip a value + */ +enum asn_err +asn_skip(struct asn_buf *b, asn_len_t len) +{ + if (b->asn_len < len) + return (ASN_ERR_EOBUF); + b->asn_cptr += len; + b->asn_len -= len; + return (ASN_ERR_OK); +} + +/* + * Add a padding + */ +enum asn_err +asn_pad(struct asn_buf *b, asn_len_t len) +{ + if (b->asn_len < len) + return (ASN_ERR_EOBUF); + b->asn_ptr += len; + b->asn_len -= len; + + return (ASN_ERR_OK); +} + +/* + * Compare two OIDs. + * + * o1 < o2 : -1 + * o1 > o2 : +1 + * o1 = o2 : 0 + */ +int +asn_compare_oid(const struct asn_oid *o1, const struct asn_oid *o2) +{ + u_long i; + + for (i = 0; i < o1->len && i < o2->len; i++) { + if (o1->subs[i] < o2->subs[i]) + return (-1); + if (o1->subs[i] > o2->subs[i]) + return (+1); + } + if (o1->len < o2->len) + return (-1); + if (o1->len > o2->len) + return (+1); + return (0); +} + +/* + * Check whether an OID is a sub-string of another OID. + */ +int +asn_is_suboid(const struct asn_oid *o1, const struct asn_oid *o2) +{ + u_long i; + + for (i = 0; i < o1->len; i++) + if (i >= o2->len || o1->subs[i] != o2->subs[i]) + return (0); + return (1); +} + +/* + * Put a string representation of an oid into a user buffer. This buffer + * is assumed to be at least ASN_OIDSTRLEN characters long. + * + * sprintf is assumed not to fail here. + */ +char * +asn_oid2str_r(const struct asn_oid *oid, char *buf) +{ + u_int len, i; + char *ptr; + + if ((len = oid->len) > ASN_MAXOIDLEN) + len = ASN_MAXOIDLEN; + buf[0] = '\0'; + for (i = 0, ptr = buf; i < len; i++) { + if (i > 0) + *ptr++ = '.'; + ptr += sprintf(ptr, "%u", oid->subs[i]); + } + return (buf); +} + +/* + * Make a string from an OID in a private buffer. + */ +char * +asn_oid2str(const struct asn_oid *oid) +{ + static char str[ASN_OIDSTRLEN]; + + return (asn_oid2str_r(oid, str)); +} + + +static void +asn_error_func(const struct asn_buf *b, const char *err, ...) +{ + va_list ap; + u_long i; + + fprintf(stderr, "ASN.1: "); + va_start(ap, err); + vfprintf(stderr, err, ap); + va_end(ap); + + if (b != NULL) { + fprintf(stderr, " at"); + for (i = 0; b->asn_len > i; i++) + fprintf(stderr, " %02x", b->asn_cptr[i]); + } + fprintf(stderr, "\n"); +} Property changes on: vendor/1.14/lib/asn1.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/lib/bsnmpclient.3 =================================================================== --- vendor/1.14/lib/bsnmpclient.3 (nonexistent) +++ vendor/1.14/lib/bsnmpclient.3 (revision 359491) @@ -0,0 +1,751 @@ +.\" +.\" Copyright (c) 2004-2005 +.\" Hartmut Brandt. +.\" All rights reserved. +.\" Copyright (c) 2001-2003 +.\" Fraunhofer Institute for Open Communication Systems (FhG Fokus). +.\" All rights reserved. +.\" +.\" Author: Harti Brandt +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Begemot: bsnmp/lib/bsnmpclient.3,v 1.12 2005/10/04 08:46:50 brandt_h Exp $ +.\" +.Dd March 31, 2020 +.Dt BSNMPCLIENT 3 +.Os +.Sh NAME +.Nm snmp_client , +.Nm snmp_client_init , +.Nm snmp_client_set_host , +.Nm snmp_client_set_port , +.Nm snmp_send_cb_f , +.Nm snmp_timeout_cb_f , +.Nm snmp_timeout_start_f , +.Nm snmp_timeout_stop_f , +.Nm snmp_open , +.Nm snmp_close , +.Nm snmp_pdu_create , +.Nm snmp_add_binding , +.Nm snmp_pdu_check , +.Nm snmp_pdu_send , +.Nm snmp_oid_append , +.Nm snmp_parse_server , +.Nm snmp_receive , +.Nm snmp_table_cb_f , +.Nm snmp_table_fetch , +.Nm snmp_table_fetch_async , +.Nm snmp_dialog , +.Nm snmp_discover_engine +.Nd "SNMP client library" +.Sh LIBRARY +Begemot SNMP library +.Pq libbsnmp, -lbsnmp +.Sh SYNOPSIS +.In asn1.h +.In snmp.h +.In snmpclient.h +.Ft typedef void +.Fn (*snmp_send_cb_f) "struct snmp_pdu *req" "struct snmp_pdu *resp" "void *uarg" +.Ft typedef void +.Fn (*snmp_timeout_cb_f) "void *uarg" +.Ft typedef void * +.Fn (*snmp_timeout_start_f) "struct timeval *timeout" "snmp_timeout_cb_f callback" "void *uarg" +.Ft typedef void +.Fn (*snmp_timeout_stop_f) "void *timeout_id" +.Vt extern struct snmp_client snmp_client ; +.Ft void +.Fn snmp_client_init "struct snmp_client *client" +.Ft int +.Fn snmp_client_set_host "struct snmp_client *client" "const char *host" +.Ft int +.Fn snmp_client_set_port "struct snmp_client *client" "const char *port" +.Ft int +.Fn snmp_open "const char *host" "const char *port" "const char *read_community" "const char *write_community" +.Ft void +.Fn snmp_close "void" +.Ft void +.Fn snmp_pdu_create "struct snmp_pdu *pdu" "u_int op" +.Ft int +.Fn snmp_add_binding "struct snmp_pdu *pdu" "..." +.Ft int +.Fn snmp_pdu_check "const struct snmp_pdu *req" "const struct snmp_pdu *resp" +.Ft int32_t +.Fn snmp_pdu_send "struct snmp_pdu *pdu" "snmp_send_cb_f func" "void *uarg" +.Ft int +.Fn snmp_oid_append "struct asn_oid *oid" "const char *fmt" "..." +.Ft int +.Fn snmp_parse_server "struct snmp_client *sc" "const char *str" +.Ft int +.Fn snmp_receive "int blocking" +.Ft typedef void +.Fn (*snmp_table_cb_f) "void *list" "void *arg" "int res" +.Ft int +.Fn snmp_table_fetch "const struct snmp_table *descr" "void *list" +.Ft int +.Fn snmp_table_fetch_async "const struct snmp_table *descr" "void *list" "snmp_table_cb_f callback" "void *uarg" +.Ft int +.Fn snmp_dialog "struct snmp_pdu *req" "struct snmp_pdu *resp" +.Ft int +.Fn snmp_discover_engine "void" +.Sh DESCRIPTION +The SNMP library contains routines to easily build SNMP client applications +that use SNMP versions 1, 2 or 3. +Most of the routines use a +.Vt struct snmp_client : +.Bd -literal -offset indent +struct snmp_client { + enum snmp_version version; + int trans; /* which transport to use */ + + /* these two are read-only for the application */ + char *cport; /* port number as string */ + char *chost; /* host name or IP address as string */ + + char read_community[SNMP_COMMUNITY_MAXLEN + 1]; + char write_community[SNMP_COMMUNITY_MAXLEN + 1]; + + /* SNMPv3 specific fields */ + int32_t identifier; + int32_t security_model; + struct snmp_engine engine; + struct snmp_user user; + + /* SNMPv3 Access control - VACM*/ + uint32_t clen; + uint8_t cengine[SNMP_ENGINE_ID_SIZ]; + char cname[SNMP_CONTEXT_NAME_SIZ]; + + struct timeval timeout; + u_int retries; + + int dump_pdus; + + size_t txbuflen; + size_t rxbuflen; + + int fd; + + int32_t next_reqid; + int32_t max_reqid; + int32_t min_reqid; + + char error[SNMP_STRERROR_LEN]; + + snmp_timeout_start_f timeout_start; + snmp_timeout_stop_f timeout_stop; + + char local_path[sizeof(SNMP_LOCAL_PATH)]; +}; +.Ed +.Pp +The fields of this structure are described below. +.Bl -tag -width "timeout_start" +.It Va version +This is the version of SNMP to use. +See +.Xr bsnmplib 3 +for applicable values. +The default version is +.Li SNMP_V2c . +.It Va trans +If this is +.Dv SNMP_TRANS_LOC_DGRAM +a local datagram socket is used. +If it is +.Dv SNMP_TRANS_LOC_STREAM +a local stream socket is used. +For +.Dv SNMP_TRANS_UDP +a UDPv4 socket and for +.Dv SNMP_TRANS_UDP6 +a UDPv6 socket is created. +It uses the +.Va chost +field as the path to the server's socket for local sockets. +.It Va cport +The SNMP agent's UDP port number. +This may be a symbolic port number (from +.Pa /etc/services ) +or a numeric port number. +If this field is +.Li NULL +(the default) the standard SNMP port is used. +This field should not be changed directly but rather by calling +.Fn snmp_client_set_port . +.It Va chost +The SNMP agent's host name, IP address or +.Ux +domain socket path name. +If this is +.Li NULL +(the default) +.Li localhost +is assumed. +This field should not be changed directly but rather through calling +.Fn snmp_client_set_host . +.It Va read_community +This is the community name to be used for all requests except SET requests. +The default is +.Sq public . +.It Va write_community +The community name to be used for SET requests. +The default is +.Sq private . +.It Va identifier +The message identifier value to be used with SNMPv3 PDUs. Incremented with +each transmitted PDU. +.It Va security_model +The security model to be used with SNMPv3 PDUs. Currently only User-Based +Security model specified by RFC 3414 (value 3) is supported. +.It Va engine +The authoritive SNMP engine parameters to be used with SNMPv3 PDUs. +.It Va user +The USM SNMP user credentials to be used with SNMPv3 PDUs. +.It Va clen +The length of the context engine id to be used with SNMPv3 PDUs. +.It Va cengine +The context engine id to be used with SNMPv3 PDUs. Default is empty. +.It Va cname +The context name to be used with SNMPv3 PDUs. Default is +.Sq "" . +.It Va timeout +The maximum time to wait for responses to requests. +If the time elapses, the request is resent up to +.Va retries +times. +The default is 3 seconds. +.It Va retries +Number of times a request PDU is to be resent. +If set to 0, the request is sent only once. +The default is 3 retransmissions. +.It Va dump_pdus +If set to a non-zero value all received and sent PDUs are dumped via +.Xr snmp_pdu_dump 3 . +The default is not to dump PDUs. +.It Va txbuflen +The encoding buffer size to be allocated for transmitted PDUs. +The default is 10000 octets. +.It Va rxbuflen +The decoding buffer size to be allocated for received PDUs. +This is the size of the maximum PDU that can be received. +The default is 10000 octets. +.It Va fd +After calling +.Fn snmp_open +this is the file socket file descriptor used for sending and receiving PDUs. +.It Va next_reqid +The request id of the next PDU to send. +Used internal by the library. +.It Va max_reqid +The maximum request id to use for outgoing PDUs. +The default is +.Li INT32_MAX . +.It Va min_reqid +The minimum request id to use for outgoing PDUs. +Request ids are allocated linearily starting at +.Va min_reqid +up to +.Va max_reqid . +.It Va error +If an error happens, this field is set to a printable string describing the +error. +.It Va timeout_start +This field must point to a function setting up a one shot timeout. +After the timeout has elapsed, the given callback function must be called +with the user argument. +The +.Fn timeout_start +function must return a +.Vt void * +identifying the timeout. +.It Va timeout_stop +This field must be set to a function that stops a running timeout. +The function will be called with the return value of the corresponding +.Fn timeout_start +function. +.It Va local_path +If in local socket mode, the name of the clients socket. +Not needed by the application. +.El +.Pp +In the current implementation there is a global variable +.Pp +.D1 Vt extern struct snmp_client snmp_client ; +.Pp +that is used by all the library functions. +The first call into the library must be a call to +.Fn snmp_client_init +to initialize this global variable to the default values. +After this call and before calling +.Fn snmp_open +the fields of the variable may be modified by the user. +The modification of the +.Va chost +and +.Va cport +fields should be done only via the functions +.Fn snmp_client_set_host +and +.Fn snmp_client_set_port . +.Pp +The function +.Fn snmp_open +creates a UDP or +.Ux +domain socket and connects it to the agent's IP address and port. +If any of the arguments of the call is not +.Li NULL +the corresponding field in the global +.Va snmp_client +is set from the argument. +Otherwise the values that are already in that variable are used. +The function +.Fn snmp_close +closes the socket, stops all timeouts and frees all dynamically allocated +resources. +.Pp +The next three functions are used to create request PDUs. +The function +.Fn snmp_pdu_create +initializes a PDU of type +.Va op . +It does not allocate space for the PDU itself. +This is the responsibility of the caller. +.Fn snmp_add_binding +adds bindings to the PDU and returns the (zero based) index of the first new +binding. +The arguments are pairs of pointer to the OIDs and syntax constants, +terminated by a NULL. +The call +.Bd -literal -offset indent +snmp_add_binding(&pdu, + &oid1, SNMP_SYNTAX_INTEGER, + &oid2, SNMP_SYNTAX_OCTETSTRING, + NULL); +.Ed +.Pp +adds two new bindings to the PDU and returns the index of the first one. +It is the responsibility of the caller to set the value part of the binding +if necessary. +The functions returns -1 if the maximum number of bindings is exhausted. +The function +.Fn snmp_oid_append +can be used to construct variable OIDs for requests. +It takes a pointer to an +.Vt struct asn_oid +that is to be constructed, a format string, and a number of arguments +the type of which depends on the format string. +The format string is interpreted +character by character in the following way: +.Bl -tag -width ".It Li ( Va N Ns Li )" +.It Li i +This format expects an argument of type +.Vt asn_subid_t +and appends this as a single integer to the OID. +.It Li a +This format expects an argument of type +.Vt struct in_addr +and appends to four parts of the IP address to the OID. +.It Li s +This format expects an argument of type +.Vt const char * +and appends the length of the string (as computed by +.Xr strlen 3 ) +and each of the characters in the string to the OID. +.It ( Va N Ns ) +This format expects no argument. +.Va N +must be a decimal number and is stored into an internal variable +.Va size . +.It Li b +This format expects an argument of type +.Vt const char * +and appends +.Va size +characters from the string to the OID. +The string may contain +.Li NUL +characters. +.It Li c +This format expects two arguments: one of type +.Vt size_t +and one of type +.Vt const u_char * . +The first argument gives the number of bytes to append to the OID from the string +pointed to by the second argument. +.El +.Pp +The function +.Fn snmp_pdu_check +may be used to check a response PDU. +A number of checks are performed +(error code, equal number of bindings, syntaxes and values for SET PDUs). +The function returns +1 if everything is ok, 0 if a NOSUCHNAME or similar +error was detected, -1 if the response PDU had fatal errors +and -2 if +.Fa resp +is +.Li NULL +(a timeout occurred). +.Pp +The function +.Fn snmp_pdu_send +encodes and sends the given PDU. +It records the PDU together with the callback +and user pointers in an internal list and arranges for retransmission if no +response is received. +When a response is received or the retransmission count +is exceeded the callback +.Fa func +is called with the original request PDU, the response PDU and the user argument +.Fa uarg . +If the retransmit count is exceeded, +.Fa func +is called with the original request PDU, the response pointer set to +.Li NULL +and the user argument +.Fa uarg . +The caller should not free the request PDU until the callback function is +called. +The callback function must free the request PDU and the response PDU (if not +.Li NULL ). +.Pp +The function +.Fn snmp_receive +tries to receive a PDU. +If the argument is zero, the function polls to see +whether a packet is available, if the argument is non-zero, the function blocks +until the next packet is received. +The packet is delivered via the usual callback +mechanism (non-response packets are silently dropped). +The function returns 0, if a packet was received and successfully dispatched, +-1 if an error occurred or no packet was available (in polling mode). +.Pp +The next two functions are used to retrieve tables from SNMP agents. +They use +the following input structure, that describes the table: +.Bd -literal -offset indent +struct snmp_table { + struct asn_oid table; + struct asn_oid last_change; + u_int max_iter; + size_t entry_size; + u_int index_size; + uint64_t req_mask; + + struct snmp_table_entry { + asn_subid_t subid; + enum snmp_syntax syntax; + off_t offset; + } entries[]; +}; +.Ed +.Pp +The fields of this structure have the following meaning: +.Bl -tag -width "last_change" +.It Va table +This is the base OID of the table. +.It Va last_change +Some tables have a scalar variable of type TIMETICKS attached to them, +that holds the time when the table was last changed. +This OID should be the OID of this variable (without the \&.0 index). +When the table is retrieved +with multiple GET requests, and the variable changes between two request, +the table fetch is restarted. +.It Va max_iter +Maximum number of tries to fetch the table. +.It Va entry_size +The table fetching routines return a list of structures one for each table +row. +This variable is the size of one structure and used to +.Xr malloc 3 +the structure. +.It Va index_size +This is the number of index columns in the table. +.It Va req_mask +This is a bit mask with a 1 for each table column that is required. +Bit 0 corresponds to the first element (index 0) in the array +.Va entries , +bit 1 to the second (index 1) and so on. +SNMP tables may be sparse. +For sparse columns the bit should not be set. +If the bit for a given column is set and +the column value cannot be retrieved for a given row, the table fetch is +restarted assuming that the table is currently being modified by the agent. +The bits for the index columns are ignored. +.It Va entries +This is a variable sized array of column descriptors. +This array is terminated by an element with syntax +.Li SNMP_SYNTAX_NULL . +The first +.Va index_size +elements describe all the index columns of the table, the rest are normal +columns. +If for the column at +.Ql entries[N] +the expression +.Ql req_mask & (1 << N) +yields true, the column is considered a required column. +The fields of this the array elements have the following meaning: +.Bl -tag -width "syntax" +.It Va subid +This is the OID subid of the column. +This is ignored for index entries. +Index entries are decoded according to the +.Va syntax +field. +.It Va syntax +This is the syntax of the column or index. +A syntax of +.Li SNMP_SYNTAX_NULL +terminates the array. +.It Va offset +This is the starting offset of the value of the column in the return structures. +This field can be set with the ISO-C +.Fn offsetof +macro. +.El +.El +.Pp +Both table fetching functions return TAILQ (see +.Xr queue 3 ) +of structures--one for each table row. +These structures must start with a +.Fn TAILQ_ENTRY +and a +.Vt uint64_t +and are allocated via +.Xr malloc 3 . +The +.Fa list +argument of the table functions must point to a +.Fn TAILQ_HEAD . +The +.Vt uint64_t +fields, usually called +.Va found +is used to indicate which of the columns have been found for the given +row. +It is encoded like the +.Fa req_mask +field. +.Pp +The function +.Fn snmp_table_fetch +synchronously fetches the given table. +If everything is ok 0 is returned. +Otherwise the function returns -1 and sets an appropriate error string. +The function +.Fn snmp_table_fetch_async +fetches the tables asynchronously. +If either the entire table is fetch, or +an error occurs the callback function +.Fa callback +is called with the callers arguments +.Fa list +and +.Fa uarg +and a parameter that is either 0 if the table was fetched, or +-1 if there was an error. +The function itself returns -1 if it could not +initialize fetching of the table. +.Pp +The following table description is used to fetch the ATM interface table: +.Bd -literal -offset indent +/* + * ATM interface table + */ +struct atmif { + TAILQ_ENTRY(atmif) link; + uint64_t found; + int32_t index; + u_char *ifname; + size_t ifnamelen; + uint32_t node_id; + uint32_t pcr; + int32_t media; + uint32_t vpi_bits; + uint32_t vci_bits; + uint32_t max_vpcs; + uint32_t max_vccs; + u_char *esi; + size_t esilen; + int32_t carrier; +}; +TAILQ_HEAD(atmif_list, atmif); + +/* list of all ATM interfaces */ +struct atmif_list atmif_list; + +static const struct snmp_table atmif_table = { + OIDX_begemotAtmIfTable, + OIDX_begemotAtmIfTableLastChange, 2, + sizeof(struct atmif), + 1, 0x7ffULL, + { + { 0, SNMP_SYNTAX_INTEGER, + offsetof(struct atmif, index) }, + { 1, SNMP_SYNTAX_OCTETSTRING, + offsetof(struct atmif, ifname) }, + { 2, SNMP_SYNTAX_GAUGE, + offsetof(struct atmif, node_id) }, + { 3, SNMP_SYNTAX_GAUGE, + offsetof(struct atmif, pcr) }, + { 4, SNMP_SYNTAX_INTEGER, + offsetof(struct atmif, media) }, + { 5, SNMP_SYNTAX_GAUGE, + offsetof(struct atmif, vpi_bits) }, + { 6, SNMP_SYNTAX_GAUGE, + offsetof(struct atmif, vci_bits) }, + { 7, SNMP_SYNTAX_GAUGE, + offsetof(struct atmif, max_vpcs) }, + { 8, SNMP_SYNTAX_GAUGE, + offsetof(struct atmif, max_vccs) }, + { 9, SNMP_SYNTAX_OCTETSTRING, + offsetof(struct atmif, esi) }, + { 10, SNMP_SYNTAX_INTEGER, + offsetof(struct atmif, carrier) }, + { 0, SNMP_SYNTAX_NULL, 0 } + } +}; + +\&... + if (snmp_table_fetch(&atmif_table, &atmif_list) != 0) + errx(1, "AtmIf table: %s", snmp_client.error); +\&... +.Ed +.Pp +The function +.Fn snmp_dialog +is used to execute a synchonuous dialog with the agent. +The request PDU +.Fa req +is sent and the function blocks until the response PDU is received. +Note, +that asynchonuous receives are handled (i.e. callback functions of other send +calls or table fetches may be called while in the function). +The response PDU is returned in +.Fa resp . +If no response could be received after all timeouts and retries, the function +returns -1. +If a response was received 0 is returned. +.Pp +The function +.Fn snmp_discover_engine +is used to discover the authoritative snmpEngineId of a remote SNMPv3 agent. +A request PDU with empty USM user name is sent and the client's engine +parameters are set according to the snmpEngine parameters received in the +response PDU. +If the client is configured to use authentication and/or privacy and the +snmpEngineBoots and/or snmpEngineTime in the response had zero values, an +additional request (possibly encrypted) with the appropriate user credentials +is sent to fetch the missing values. +Note, that the function blocks until the discovery process is completed. +If no response could be received after all timeouts and retries, or the +response contained errors the function returns -1. +If the discovery process was completed 0 is returned. +.Pp +The function +.Fn snmp_parse_server +is used to parse an SNMP server specification string and fill in the +fields of a +.Vt struct snmp_client . +The syntax of a server specification is +.Pp +.D1 [trans::][community@][server][:port] +.Pp +where +.Va trans +is the transport name (one of +.Qq udp , +.Qq udp6 , +.Qq stream +or +.Qq dgram ) , +.Va community +is the string to be used for both the read and the write community, +.Va server +is the server's host name in case of UDP and the path name in case +of a local socket, and +.Va port +is the port in case of UDP transport. +The function returns 0 in the case of success and return -1 and sets +the error string in case of an error. +.Pp +The function +.Fn snmp_parse_serverr +fills the transport, the port number and the community strings with +reasonable default values when they are not specified. +The default transport +is +.Dv SNMP_TRANS_UDP . +If the host name contains a slash the default is modified to +.Dv SNMP_TRANS_LOC_DGRAM . +If the host name looks like a numeric IPv6 address the default is +.Dv SNMP_TRANS_UDP6 . +For numeric IPv6 addresses the transport name udp is automatically +translated as +.Dv SNMP_TRANS_UDP6 . +The default port number (for +.Dv udp +or +.Dv udp6 ) +is +.Qq snmp . +The default read community is +.Qq public +and the default write community +.Qq private . +.Pp +.Fn snmp_parse_server +recognizes path names, host names and numerical IPv4 and IPv6 addresses. +A string consisting of digits and periods is assumed to be an IPv4 address +and must be parseable by +.Fn inet_aton 3 . +An IPv6 address is any string enclosed in square brackets. +It must be parseable with +.Fn gethostinfo 3 . +.Pp +The port number for +.Fn snmp_parse_server +can be specified numerically or symbolically. +It is ignored for local sockets. +.Sh DIAGNOSTICS +If an error occurs in any of the functions an error indication as described +above is returned. +Additionally the function sets a printable error string in the +.Va error +field of +.Va snmp_client . +.Sh SEE ALSO +.Xr gensnmptree 1 , +.Xr bsnmpd 1 , +.Xr bsnmpagent 3 , +.Xr bsnmplib 3 +.Sh STANDARDS +This implementation conforms to the applicable IETF RFCs and ITU-T +recommendations. +.Sh AUTHORS +.An Hartmut Brandt Aq harti@FreeBSD.org +.An Kendy Kutzner Aq kutzner@fokus.gmd.de Property changes on: vendor/1.14/lib/bsnmpclient.3 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/lib/snmp.h =================================================================== --- vendor/1.14/lib/snmp.h (nonexistent) +++ vendor/1.14/lib/snmp.h (revision 359491) @@ -0,0 +1,287 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Copyright (c) 2010 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Shteryana Sotirova Shopova + * under sponsorship from the FreeBSD Foundation. + * + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/lib/snmp.h,v 1.30 2004/08/06 08:46:54 brandt Exp $ + * + * Header file for SNMP functions. + */ +#ifndef snmp_h_ +#define snmp_h_ + +#include + +#define BSNMP_MAJOR 1 +#define BSNMP_MINOR 13 + +#define SNMP_COMMUNITY_MAXLEN 128 +#define SNMP_MAX_BINDINGS 100 +#define SNMP_CONTEXT_NAME_SIZ (32 + 1) +#define SNMP_ENGINE_ID_SIZ 32 +#define SNMP_TIME_WINDOW 150 + +enum snmp_syntax { + SNMP_SYNTAX_NULL = 0, + SNMP_SYNTAX_INTEGER, /* == INTEGER32 */ + SNMP_SYNTAX_OCTETSTRING, + SNMP_SYNTAX_OID, + SNMP_SYNTAX_IPADDRESS, + SNMP_SYNTAX_COUNTER, + SNMP_SYNTAX_GAUGE, /* == UNSIGNED32 */ + SNMP_SYNTAX_TIMETICKS, + + /* v2 additions */ + SNMP_SYNTAX_COUNTER64, + SNMP_SYNTAX_NOSUCHOBJECT, /* exception */ + SNMP_SYNTAX_NOSUCHINSTANCE, /* exception */ + SNMP_SYNTAX_ENDOFMIBVIEW, /* exception */ +}; + +struct snmp_value { + struct asn_oid var; + enum snmp_syntax syntax; + union snmp_values { + int32_t integer; /* also integer32 */ + struct { + u_int len; + u_char *octets; + } octetstring; + struct asn_oid oid; + u_char ipaddress[4]; + uint32_t uint32; /* also gauge32, counter32, + unsigned32, timeticks */ + uint64_t counter64; + } v; +}; + +enum snmp_version { + SNMP_Verr = 0, + SNMP_V1 = 1, + SNMP_V2c = 2, + SNMP_V3, +}; + +#define SNMP_MPM_SNMP_V1 0 +#define SNMP_MPM_SNMP_V2c 1 +#define SNMP_MPM_SNMP_V3 3 + +#define SNMP_ADM_STR32_SIZ (32 + 1) +#define SNMP_AUTH_KEY_SIZ 40 +#define SNMP_PRIV_KEY_SIZ 32 +#define SNMP_USM_AUTH_SIZE 12 +#define SNMP_USM_PRIV_SIZE 8 +#define SNMP_AUTH_HMACMD5_KEY_SIZ 16 +#define SNMP_AUTH_HMACSHA_KEY_SIZ 20 +#define SNMP_PRIV_AES_KEY_SIZ 16 +#define SNMP_PRIV_DES_KEY_SIZ 8 + + +enum snmp_secmodel { + SNMP_SECMODEL_ANY = 0, + SNMP_SECMODEL_SNMPv1 = 1, + SNMP_SECMODEL_SNMPv2c = 2, + SNMP_SECMODEL_USM = 3, + SNMP_SECMODEL_UNKNOWN +}; + +enum snmp_usm_level { + SNMP_noAuthNoPriv = 1, + SNMP_authNoPriv = 2, + SNMP_authPriv = 3 +}; + +enum snmp_authentication { + SNMP_AUTH_NOAUTH = 0, + SNMP_AUTH_HMAC_MD5, + SNMP_AUTH_HMAC_SHA +}; + +enum snmp_privacy { + SNMP_PRIV_NOPRIV = 0, + SNMP_PRIV_DES = 1, + SNMP_PRIV_AES +}; + +struct snmp_engine { + uint8_t engine_id[SNMP_ENGINE_ID_SIZ]; + uint32_t engine_len; + int32_t engine_boots; + int32_t engine_time; + int32_t max_msg_size; +}; + +struct snmp_user { + char sec_name[SNMP_ADM_STR32_SIZ]; + enum snmp_authentication auth_proto; + enum snmp_privacy priv_proto; + uint8_t auth_key[SNMP_AUTH_KEY_SIZ]; + uint8_t priv_key[SNMP_PRIV_KEY_SIZ]; +}; + +struct snmp_pdu { + char community[SNMP_COMMUNITY_MAXLEN + 1]; + enum snmp_version version; + u_int type; + + /* SNMPv3 PDU header fields */ + int32_t identifier; + uint8_t flags; + int32_t security_model; + struct snmp_engine engine; + + /* Associated USM user parameters */ + struct snmp_user user; + uint8_t msg_digest[SNMP_USM_AUTH_SIZE]; + uint8_t msg_salt[SNMP_USM_PRIV_SIZE]; + + /* View-based Access Model */ + /* XXX: put in separate structure - conflicts with struct snmp_context */ + uint32_t context_engine_len; + uint8_t context_engine[SNMP_ENGINE_ID_SIZ]; + char context_name[SNMP_CONTEXT_NAME_SIZ]; + + /* trap only */ + struct asn_oid enterprise; + u_char agent_addr[4]; + int32_t generic_trap; + int32_t specific_trap; + uint32_t time_stamp; + + /* others */ + int32_t request_id; + int32_t error_status; + int32_t error_index; + + /* fixes for encoding */ + size_t outer_len; + asn_len_t scoped_len; + u_char *outer_ptr; + u_char *digest_ptr; + u_char *encrypted_ptr; + u_char *scoped_ptr; + u_char *pdu_ptr; + u_char *vars_ptr; + + + struct snmp_value bindings[SNMP_MAX_BINDINGS]; + u_int nbindings; +}; +#define snmp_v1_pdu snmp_pdu + +#define SNMP_PDU_GET 0 +#define SNMP_PDU_GETNEXT 1 +#define SNMP_PDU_RESPONSE 2 +#define SNMP_PDU_SET 3 +#define SNMP_PDU_TRAP 4 /* v1 */ +#define SNMP_PDU_GETBULK 5 /* v2 */ +#define SNMP_PDU_INFORM 6 /* v2 */ +#define SNMP_PDU_TRAP2 7 /* v2 */ +#define SNMP_PDU_REPORT 8 /* v2 */ + +#define SNMP_ERR_NOERROR 0 +#define SNMP_ERR_TOOBIG 1 +#define SNMP_ERR_NOSUCHNAME 2 /* v1 */ +#define SNMP_ERR_BADVALUE 3 /* v1 */ +#define SNMP_ERR_READONLY 4 /* v1 */ +#define SNMP_ERR_GENERR 5 +#define SNMP_ERR_NO_ACCESS 6 /* v2 */ +#define SNMP_ERR_WRONG_TYPE 7 /* v2 */ +#define SNMP_ERR_WRONG_LENGTH 8 /* v2 */ +#define SNMP_ERR_WRONG_ENCODING 9 /* v2 */ +#define SNMP_ERR_WRONG_VALUE 10 /* v2 */ +#define SNMP_ERR_NO_CREATION 11 /* v2 */ +#define SNMP_ERR_INCONS_VALUE 12 /* v2 */ +#define SNMP_ERR_RES_UNAVAIL 13 /* v2 */ +#define SNMP_ERR_COMMIT_FAILED 14 /* v2 */ +#define SNMP_ERR_UNDO_FAILED 15 /* v2 */ +#define SNMP_ERR_AUTH_ERR 16 /* v2 */ +#define SNMP_ERR_NOT_WRITEABLE 17 /* v2 */ +#define SNMP_ERR_INCONS_NAME 18 /* v2 */ + +#define SNMP_TRAP_COLDSTART 0 +#define SNMP_TRAP_WARMSTART 1 +#define SNMP_TRAP_LINKDOWN 2 +#define SNMP_TRAP_LINKUP 3 +#define SNMP_TRAP_AUTHENTICATION_FAILURE 4 +#define SNMP_TRAP_EGP_NEIGHBOR_LOSS 5 +#define SNMP_TRAP_ENTERPRISE 6 + +enum snmp_code { + SNMP_CODE_OK = 0, + SNMP_CODE_FAILED, + SNMP_CODE_BADVERS, + SNMP_CODE_BADLEN, + SNMP_CODE_BADENC, + SNMP_CODE_OORANGE, + SNMP_CODE_BADSECLEVEL, + SNMP_CODE_NOTINTIME, + SNMP_CODE_BADUSER, + SNMP_CODE_BADENGINE, + SNMP_CODE_BADDIGEST, + SNMP_CODE_EDECRYPT +}; + +#define SNMP_MSG_AUTH_FLAG 0x1 +#define SNMP_MSG_PRIV_FLAG 0x2 +#define SNMP_MSG_REPORT_FLAG 0x4 +#define SNMP_MSG_AUTODISCOVER 0x80 + +void snmp_value_free(struct snmp_value *); +int snmp_value_parse(const char *, enum snmp_syntax, union snmp_values *); +int snmp_value_copy(struct snmp_value *, const struct snmp_value *); + +void snmp_pdu_free(struct snmp_pdu *); +void snmp_pdu_init_secparams(struct snmp_pdu *); +enum snmp_code snmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *); +enum snmp_code snmp_pdu_decode_header(struct asn_buf *, struct snmp_pdu *); +enum snmp_code snmp_pdu_decode_scoped(struct asn_buf *, struct snmp_pdu *, int32_t *); +enum snmp_code snmp_pdu_encode(struct snmp_pdu *, struct asn_buf *); +enum snmp_code snmp_pdu_decode_secmode(struct asn_buf *, struct snmp_pdu *); + +int snmp_pdu_snoop(const struct asn_buf *); + +void snmp_pdu_dump(const struct snmp_pdu *pdu); + +enum snmp_code snmp_passwd_to_keys(struct snmp_user *, char *); +enum snmp_code snmp_get_local_keys(struct snmp_user *, uint8_t *, uint32_t); +enum snmp_code snmp_calc_keychange(struct snmp_user *, uint8_t *); + +extern void (*snmp_error)(const char *, ...); +extern void (*snmp_printf)(const char *, ...); + +#define TRUTH_MK(F) ((F) ? 1 : 2) +#define TRUTH_GET(T) (((T) == 1) ? 1 : 0) +#define TRUTH_OK(T) ((T) == 1 || (T) == 2) + +#endif Property changes on: vendor/1.14/lib/snmp.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/lib/snmpclient.c =================================================================== --- vendor/1.14/lib/snmpclient.c (nonexistent) +++ vendor/1.14/lib/snmpclient.c (revision 359491) @@ -0,0 +1,2298 @@ +/* + * Copyright (c) 2004-2005,2018-2019 + * Hartmut Brandt. + * All rights reserved. + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * Kendy Kutzner + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/lib/snmpclient.c,v 1.36 2005/10/06 07:14:58 brandt_h Exp $ + * + * Support functions for SNMP clients. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_STDINT_H +#include +#elif defined(HAVE_INTTYPES_H) +#include +#endif +#include +#ifdef HAVE_ERR_H +#include +#endif + +#include + +#include "support.h" +#include "asn1.h" +#include "snmp.h" +#include "snmpclient.h" +#include "snmppriv.h" + +#define DEBUG_PARSE 0 + +/* global context */ +struct snmp_client snmp_client; + +/* List of all outstanding requests */ +struct sent_pdu { + int reqid; + struct snmp_pdu *pdu; + struct timeval time; + u_int retrycount; + snmp_send_cb_f callback; + void *arg; + void *timeout_id; + LIST_ENTRY(sent_pdu) entries; +}; +LIST_HEAD(sent_pdu_list, sent_pdu); + +static struct sent_pdu_list sent_pdus; + +/* + * Prototype table entry. All C-structure produced by the table function must + * start with these two fields. This relies on the fact, that all TAILQ_ENTRY + * are compatible with each other in the sense implied by ANSI-C. + */ +struct entry { + TAILQ_ENTRY(entry) link; + uint64_t found; +}; +TAILQ_HEAD(table, entry); + +/* + * working list entry. This list is used to hold the Index part of the + * table row's. The entry list and the work list parallel each other. + */ +struct work { + TAILQ_ENTRY(work) link; + struct asn_oid index; +}; +TAILQ_HEAD(worklist, work); + +/* + * Table working data + */ +struct tabwork { + const struct snmp_table *descr; + struct table *table; + struct worklist worklist; + uint32_t last_change; + int first; + u_int iter; + snmp_table_cb_f callback; + void *arg; + struct snmp_pdu pdu; +}; + +/* + * Set the error string + */ +static void +seterr(struct snmp_client *sc, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vsnprintf(sc->error, sizeof(sc->error), fmt, ap); + va_end(ap); +} + +/* + * Free the entire table and work list. If table is NULL only the worklist + * is freed. + */ +static void +table_free(struct tabwork *work, int all) +{ + struct work *w; + struct entry *e; + const struct snmp_table_entry *d; + u_int i; + + while ((w = TAILQ_FIRST(&work->worklist)) != NULL) { + TAILQ_REMOVE(&work->worklist, w, link); + free(w); + } + + if (all == 0) + return; + + while ((e = TAILQ_FIRST(work->table)) != NULL) { + for (i = 0; work->descr->entries[i].syntax != SNMP_SYNTAX_NULL; + i++) { + d = &work->descr->entries[i]; + if (d->syntax == SNMP_SYNTAX_OCTETSTRING && + (e->found & ((uint64_t)1 << i))) + free(*(void **)(void *) + ((u_char *)e + d->offset)); + } + TAILQ_REMOVE(work->table, e, link); + free(e); + } +} + +/* + * Find the correct table entry for the given variable. If non exists, + * create one. + */ +static struct entry * +table_find(struct tabwork *work, const struct asn_oid *var) +{ + struct entry *e, *e1; + struct work *w, *w1; + u_int i, p, j; + size_t len; + u_char *ptr; + struct asn_oid oid; + + /* get index */ + asn_slice_oid(&oid, var, work->descr->table.len + 2, var->len); + + e = TAILQ_FIRST(work->table); + w = TAILQ_FIRST(&work->worklist); + while (e != NULL) { + if (asn_compare_oid(&w->index, &oid) == 0) + return (e); + e = TAILQ_NEXT(e, link); + w = TAILQ_NEXT(w, link); + } + + /* Not found create new one */ + if ((e = malloc(work->descr->entry_size)) == NULL) { + seterr(&snmp_client, "no memory for table entry"); + return (NULL); + } + if ((w = malloc(sizeof(*w))) == NULL) { + seterr(&snmp_client, "no memory for table entry"); + free(e); + return (NULL); + } + w->index = oid; + memset(e, 0, work->descr->entry_size); + + /* decode index */ + p = work->descr->table.len + 2; + for (i = 0; i < work->descr->index_size; i++) { + switch (work->descr->entries[i].syntax) { + + case SNMP_SYNTAX_INTEGER: + if (var->len < p + 1) { + seterr(&snmp_client, "bad index: need integer"); + goto err; + } + if (var->subs[p] > INT32_MAX) { + seterr(&snmp_client, + "bad index: integer too large"); + goto err; + } + *(int32_t *)(void *)((u_char *)e + + work->descr->entries[i].offset) = var->subs[p++]; + break; + + case SNMP_SYNTAX_OCTETSTRING: + if (var->len < p + 1) { + seterr(&snmp_client, + "bad index: need string length"); + goto err; + } + len = var->subs[p++]; + if (var->len < p + len) { + seterr(&snmp_client, + "bad index: string too short"); + goto err; + } + if ((ptr = malloc(len + 1)) == NULL) { + seterr(&snmp_client, + "no memory for index string"); + goto err; + } + for (j = 0; j < len; j++) { + if (var->subs[p] > UCHAR_MAX) { + seterr(&snmp_client, + "bad index: char too large"); + free(ptr); + goto err; + } + ptr[j] = var->subs[p++]; + } + ptr[j] = '\0'; + *(u_char **)(void *)((u_char *)e + + work->descr->entries[i].offset) = ptr; + *(size_t *)(void *)((u_char *)e + + work->descr->entries[i].offset + sizeof(u_char *)) + = len; + break; + + case SNMP_SYNTAX_OID: + if (var->len < p + 1) { + seterr(&snmp_client, + "bad index: need oid length"); + goto err; + } + oid.len = var->subs[p++]; + if (var->len < p + oid.len) { + seterr(&snmp_client, + "bad index: oid too short"); + goto err; + } + for (j = 0; j < oid.len; j++) + oid.subs[j] = var->subs[p++]; + *(struct asn_oid *)(void *)((u_char *)e + + work->descr->entries[i].offset) = oid; + break; + + case SNMP_SYNTAX_IPADDRESS: + if (var->len < p + 4) { + seterr(&snmp_client, + "bad index: need ip-address"); + goto err; + } + for (j = 0; j < 4; j++) { + if (var->subs[p] > 0xff) { + seterr(&snmp_client, + "bad index: ipaddress too large"); + goto err; + } + ((u_char *)e + + work->descr->entries[i].offset)[j] = + var->subs[p++]; + } + break; + + case SNMP_SYNTAX_GAUGE: + if (var->len < p + 1) { + seterr(&snmp_client, + "bad index: need unsigned"); + goto err; + } + if (var->subs[p] > UINT32_MAX) { + seterr(&snmp_client, + "bad index: unsigned too large"); + goto err; + } + *(uint32_t *)(void *)((u_char *)e + + work->descr->entries[i].offset) = var->subs[p++]; + break; + + case SNMP_SYNTAX_COUNTER: + case SNMP_SYNTAX_TIMETICKS: + case SNMP_SYNTAX_COUNTER64: + case SNMP_SYNTAX_NULL: + case SNMP_SYNTAX_NOSUCHOBJECT: + case SNMP_SYNTAX_NOSUCHINSTANCE: + case SNMP_SYNTAX_ENDOFMIBVIEW: + abort(); + } + e->found |= (uint64_t)1 << i; + } + + /* link into the correct place */ + e1 = TAILQ_FIRST(work->table); + w1 = TAILQ_FIRST(&work->worklist); + while (e1 != NULL) { + if (asn_compare_oid(&w1->index, &w->index) > 0) + break; + e1 = TAILQ_NEXT(e1, link); + w1 = TAILQ_NEXT(w1, link); + } + if (e1 == NULL) { + TAILQ_INSERT_TAIL(work->table, e, link); + TAILQ_INSERT_TAIL(&work->worklist, w, link); + } else { + TAILQ_INSERT_BEFORE(e1, e, link); + TAILQ_INSERT_BEFORE(w1, w, link); + } + + return (e); + + err: + /* + * Error happend. Free all octet string index parts and the entry + * itself. + */ + for (i = 0; i < work->descr->index_size; i++) { + if (work->descr->entries[i].syntax == SNMP_SYNTAX_OCTETSTRING && + (e->found & ((uint64_t)1 << i))) + free(*(void **)(void *)((u_char *)e + + work->descr->entries[i].offset)); + } + free(e); + free(w); + return (NULL); +} + +/* + * Assign the value + */ +static int +table_value(const struct snmp_table *descr, struct entry *e, + const struct snmp_value *b) +{ + u_int i; + u_char *ptr; + + for (i = descr->index_size; + descr->entries[i].syntax != SNMP_SYNTAX_NULL; i++) + if (descr->entries[i].subid == + b->var.subs[descr->table.len + 1]) + break; + if (descr->entries[i].syntax == SNMP_SYNTAX_NULL) + return (0); + + /* check syntax */ + if (b->syntax != descr->entries[i].syntax) { + seterr(&snmp_client, "bad syntax (%u instead of %u)", b->syntax, + descr->entries[i].syntax); + return (-1); + } + + switch (b->syntax) { + + case SNMP_SYNTAX_INTEGER: + *(int32_t *)(void *)((u_char *)e + descr->entries[i].offset) = + b->v.integer; + break; + + case SNMP_SYNTAX_OCTETSTRING: + if ((ptr = malloc(b->v.octetstring.len + 1)) == NULL) { + seterr(&snmp_client, "no memory for string"); + return (-1); + } + memcpy(ptr, b->v.octetstring.octets, b->v.octetstring.len); + ptr[b->v.octetstring.len] = '\0'; + *(u_char **)(void *)((u_char *)e + descr->entries[i].offset) = + ptr; + *(size_t *)(void *)((u_char *)e + descr->entries[i].offset + + sizeof(u_char *)) = b->v.octetstring.len; + break; + + case SNMP_SYNTAX_OID: + *(struct asn_oid *)(void *)((u_char *)e + descr->entries[i].offset) = + b->v.oid; + break; + + case SNMP_SYNTAX_IPADDRESS: + memcpy((u_char *)e + descr->entries[i].offset, + b->v.ipaddress, 4); + break; + + case SNMP_SYNTAX_COUNTER: + case SNMP_SYNTAX_GAUGE: + case SNMP_SYNTAX_TIMETICKS: + *(uint32_t *)(void *)((u_char *)e + descr->entries[i].offset) = + b->v.uint32; + break; + + case SNMP_SYNTAX_COUNTER64: + *(uint64_t *)(void *)((u_char *)e + descr->entries[i].offset) = + b->v.counter64; + break; + + case SNMP_SYNTAX_NULL: + case SNMP_SYNTAX_NOSUCHOBJECT: + case SNMP_SYNTAX_NOSUCHINSTANCE: + case SNMP_SYNTAX_ENDOFMIBVIEW: + abort(); + } + e->found |= (uint64_t)1 << i; + + return (0); +} + +/* + * Initialize the first PDU to send + */ +static void +table_init_pdu(const struct snmp_table *descr, struct snmp_pdu *pdu) +{ + if (snmp_client.version == SNMP_V1) + snmp_pdu_create(pdu, SNMP_PDU_GETNEXT); + else { + snmp_pdu_create(pdu, SNMP_PDU_GETBULK); + pdu->error_index = 10; + } + if (descr->last_change.len != 0) { + pdu->bindings[pdu->nbindings].syntax = SNMP_SYNTAX_NULL; + pdu->bindings[pdu->nbindings].var = descr->last_change; + pdu->nbindings++; + if (pdu->version != SNMP_V1) + pdu->error_status++; + } + pdu->bindings[pdu->nbindings].var = descr->table; + pdu->bindings[pdu->nbindings].syntax = SNMP_SYNTAX_NULL; + pdu->nbindings++; +} + +/* + * Return code: + * 0 - End Of Table + * -1 - Error + * -2 - Last change changed - again + * +1 - ok, continue + */ +static int +table_check_response(struct tabwork *work, const struct snmp_pdu *resp) +{ + const struct snmp_value *b; + struct entry *e; + + if (resp->error_status != SNMP_ERR_NOERROR) { + if (snmp_client.version == SNMP_V1 && + resp->error_status == SNMP_ERR_NOSUCHNAME && + resp->error_index == + ((work->descr->last_change.len == 0) ? 1 : 2)) + /* EOT */ + return (0); + /* Error */ + seterr(&snmp_client, "error fetching table: status=%d index=%d", + resp->error_status, resp->error_index); + return (-1); + } + + for (b = resp->bindings; b < resp->bindings + resp->nbindings; b++) { + if (work->descr->last_change.len != 0 && b == resp->bindings) { + if (!asn_is_suboid(&work->descr->last_change, &b->var) || + b->var.len != work->descr->last_change.len + 1 || + b->var.subs[work->descr->last_change.len] != 0) { + seterr(&snmp_client, + "last_change: bad response"); + return (-1); + } + if (b->syntax != SNMP_SYNTAX_TIMETICKS) { + seterr(&snmp_client, + "last_change: bad syntax %u", b->syntax); + return (-1); + } + if (work->first) { + work->last_change = b->v.uint32; + work->first = 0; + + } else if (work->last_change != b->v.uint32) { + if (++work->iter >= work->descr->max_iter) { + seterr(&snmp_client, + "max iteration count exceeded"); + return (-1); + } + table_free(work, 1); + return (-2); + } + + continue; + } + if (!asn_is_suboid(&work->descr->table, &b->var) || + b->syntax == SNMP_SYNTAX_ENDOFMIBVIEW) + return (0); + + if ((e = table_find(work, &b->var)) == NULL) + return (-1); + if (table_value(work->descr, e, b)) + return (-1); + } + return (+1); +} + +/* + * Check table consistency + */ +static int +table_check_cons(struct tabwork *work) +{ + struct entry *e; + + TAILQ_FOREACH(e, work->table, link) + if ((e->found & work->descr->req_mask) != + work->descr->req_mask) { + if (work->descr->last_change.len == 0) { + if (++work->iter >= work->descr->max_iter) { + seterr(&snmp_client, + "max iteration count exceeded"); + return (-1); + } + return (-2); + } + seterr(&snmp_client, "inconsistency detected %llx %llx", + e->found, work->descr->req_mask); + return (-1); + } + return (0); +} + +/* + * Fetch a table. Returns 0 if ok, -1 on errors. + * This is the synchronous variant. + */ +int +snmp_table_fetch(const struct snmp_table *descr, void *list) +{ + struct snmp_pdu resp; + struct tabwork work; + int ret; + + work.descr = descr; + work.table = (struct table *)list; + work.iter = 0; + TAILQ_INIT(work.table); + TAILQ_INIT(&work.worklist); + work.callback = NULL; + work.arg = NULL; + + again: + /* + * We come to this label when the code detects that the table + * has changed while fetching it. + */ + work.first = 1; + work.last_change = 0; + table_init_pdu(descr, &work.pdu); + + for (;;) { + if (snmp_dialog(&work.pdu, &resp)) { + table_free(&work, 1); + return (-1); + } + if ((ret = table_check_response(&work, &resp)) == 0) { + snmp_pdu_free(&resp); + break; + } + if (ret == -1) { + snmp_pdu_free(&resp); + table_free(&work, 1); + return (-1); + } + if (ret == -2) { + snmp_pdu_free(&resp); + goto again; + } + + work.pdu.bindings[work.pdu.nbindings - 1].var = + resp.bindings[resp.nbindings - 1].var; + + snmp_pdu_free(&resp); + } + + if ((ret = table_check_cons(&work)) == -1) { + table_free(&work, 1); + return (-1); + } + if (ret == -2) { + table_free(&work, 1); + goto again; + } + /* + * Free index list + */ + table_free(&work, 0); + return (0); +} + +/* + * Callback for table + */ +static void +table_cb(struct snmp_pdu *req __unused, struct snmp_pdu *resp, void *arg) +{ + struct tabwork *work = arg; + int ret; + + if (resp == NULL) { + /* timeout */ + seterr(&snmp_client, "no response to fetch table request"); + table_free(work, 1); + work->callback(work->table, work->arg, -1); + free(work); + return; + } + + if ((ret = table_check_response(work, resp)) == 0) { + /* EOT */ + snmp_pdu_free(resp); + + if ((ret = table_check_cons(work)) == -1) { + /* error happend */ + table_free(work, 1); + work->callback(work->table, work->arg, -1); + free(work); + return; + } + if (ret == -2) { + /* restart */ + again: + table_free(work, 1); + work->first = 1; + work->last_change = 0; + table_init_pdu(work->descr, &work->pdu); + if (snmp_pdu_send(&work->pdu, table_cb, work) == -1) { + work->callback(work->table, work->arg, -1); + free(work); + return; + } + return; + } + /* + * Free index list + */ + table_free(work, 0); + work->callback(work->table, work->arg, 0); + free(work); + return; + } + + if (ret == -1) { + /* error */ + snmp_pdu_free(resp); + table_free(work, 1); + work->callback(work->table, work->arg, -1); + free(work); + return; + } + + if (ret == -2) { + /* again */ + snmp_pdu_free(resp); + goto again; + } + + /* next part */ + + work->pdu.bindings[work->pdu.nbindings - 1].var = + resp->bindings[resp->nbindings - 1].var; + + snmp_pdu_free(resp); + + if (snmp_pdu_send(&work->pdu, table_cb, work) == -1) { + table_free(work, 1); + work->callback(work->table, work->arg, -1); + free(work); + return; + } +} + +int +snmp_table_fetch_async(const struct snmp_table *descr, void *list, + snmp_table_cb_f func, void *arg) +{ + struct tabwork *work; + + if ((work = malloc(sizeof(*work))) == NULL) { + seterr(&snmp_client, "%s", strerror(errno)); + return (-1); + } + + work->descr = descr; + work->table = (struct table *)list; + work->iter = 0; + TAILQ_INIT(work->table); + TAILQ_INIT(&work->worklist); + + work->callback = func; + work->arg = arg; + + /* + * Start by sending the first PDU + */ + work->first = 1; + work->last_change = 0; + table_init_pdu(descr, &work->pdu); + + if (snmp_pdu_send(&work->pdu, table_cb, work) == -1) { + free(work); + work = NULL; + return (-1); + } + return (0); +} + +/* + * Append an index to an oid + */ +int +snmp_oid_append(struct asn_oid *oid, const char *fmt, ...) +{ + va_list va; + int size; + char *nextptr; + const u_char *str; + size_t len; + struct in_addr ina; + int ret; + + va_start(va, fmt); + + size = 0; + + ret = 0; + while (*fmt != '\0') { + switch (*fmt++) { + case 'i': + /* just an integer more */ + if (oid->len + 1 > ASN_MAXOIDLEN) { + warnx("%s: OID too long for integer", __func__); + ret = -1; + break; + } + oid->subs[oid->len++] = va_arg(va, asn_subid_t); + break; + + case 'a': + /* append an IP address */ + if (oid->len + 4 > ASN_MAXOIDLEN) { + warnx("%s: OID too long for ip-addr", __func__); + ret = -1; + break; + } + ina = va_arg(va, struct in_addr); + ina.s_addr = ntohl(ina.s_addr); + oid->subs[oid->len++] = (ina.s_addr >> 24) & 0xff; + oid->subs[oid->len++] = (ina.s_addr >> 16) & 0xff; + oid->subs[oid->len++] = (ina.s_addr >> 8) & 0xff; + oid->subs[oid->len++] = (ina.s_addr >> 0) & 0xff; + break; + + case 's': + /* append a null-terminated string, + * length is computed */ + str = (const u_char *)va_arg(va, const char *); + len = strlen((const char *)str); + if (oid->len + len + 1 > ASN_MAXOIDLEN) { + warnx("%s: OID too long for string", __func__); + ret = -1; + break; + } + oid->subs[oid->len++] = len; + while (len--) + oid->subs[oid->len++] = *str++; + break; + + case '(': + /* the integer value between ( and ) is stored + * in size */ + size = strtol(fmt, &nextptr, 10); + if (*nextptr != ')') + abort(); + fmt = ++nextptr; + break; + + case 'b': + /* append `size` characters */ + str = (const u_char *)va_arg(va, const char *); + if (oid->len + size > ASN_MAXOIDLEN) { + warnx("%s: OID too long for string", __func__); + ret = -1; + break; + } + while (size--) + oid->subs[oid->len++] = *str++; + break; + + case 'c': + /* get size and the octets from the arguments */ + size = va_arg(va, size_t); + str = va_arg(va, const u_char *); + if (oid->len + size + 1 > ASN_MAXOIDLEN) { + warnx("%s: OID too long for string", __func__); + ret = -1; + break; + } + oid->subs[oid->len++] = size; + while (size--) + oid->subs[oid->len++] = *str++; + break; + + default: + abort(); + } + } + va_end(va); + return (ret); +} + +/* + * Initialize a client structure + */ +void +snmp_client_init(struct snmp_client *c) +{ + memset(c, 0, sizeof(*c)); + + c->version = SNMP_V2c; + c->trans = SNMP_TRANS_UDP; + c->chost = NULL; + c->cport = NULL; + + strcpy(c->read_community, "public"); + strcpy(c->write_community, "private"); + + c->security_model = SNMP_SECMODEL_USM; + strcpy(c->cname, ""); + + c->timeout.tv_sec = 3; + c->timeout.tv_usec = 0; + c->retries = 3; + c->dump_pdus = 0; + c->txbuflen = c->rxbuflen = 10000; + + c->fd = -1; + + c->max_reqid = INT32_MAX; + c->min_reqid = 0; + c->next_reqid = 0; + + c->engine.max_msg_size = 1500; /* XXX */ +} + + +/* + * Open UDP client socket + */ +static int +open_client_udp(const char *host, const char *port) +{ + int error; + char *ptr; + struct addrinfo hints, *res0, *res; + + /* copy host- and portname */ + if (snmp_client.chost == NULL) { + if ((snmp_client.chost = malloc(1 + sizeof(DEFAULT_HOST))) + == NULL) { + seterr(&snmp_client, "%s", strerror(errno)); + return (-1); + } + strcpy(snmp_client.chost, DEFAULT_HOST); + } + if (host != NULL) { + if ((ptr = malloc(1 + strlen(host))) == NULL) { + seterr(&snmp_client, "%s", strerror(errno)); + return (-1); + } + free(snmp_client.chost); + snmp_client.chost = ptr; + strcpy(snmp_client.chost, host); + } + if (snmp_client.cport == NULL) { + if ((snmp_client.cport = malloc(1 + sizeof(DEFAULT_PORT))) + == NULL) { + seterr(&snmp_client, "%s", strerror(errno)); + return (-1); + } + strcpy(snmp_client.cport, DEFAULT_PORT); + } + if (port != NULL) { + if ((ptr = malloc(1 + strlen(port))) == NULL) { + seterr(&snmp_client, "%s", strerror(errno)); + return (-1); + } + free(snmp_client.cport); + snmp_client.cport = ptr; + strcpy(snmp_client.cport, port); + } + + /* open connection */ + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME; + hints.ai_family = snmp_client.trans == SNMP_TRANS_UDP ? AF_INET : + AF_INET6; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = 0; + error = getaddrinfo(snmp_client.chost, snmp_client.cport, &hints, &res0); + if (error != 0) { + seterr(&snmp_client, "%s: %s", snmp_client.chost, + gai_strerror(error)); + return (-1); + } + res = res0; + for (;;) { + if ((snmp_client.fd = socket(res->ai_family, res->ai_socktype, + res->ai_protocol)) == -1) { + if ((res = res->ai_next) == NULL) { + seterr(&snmp_client, "%s", strerror(errno)); + freeaddrinfo(res0); + return (-1); + } + } else if (connect(snmp_client.fd, res->ai_addr, + res->ai_addrlen) == -1) { + if ((res = res->ai_next) == NULL) { + seterr(&snmp_client, "%s", strerror(errno)); + freeaddrinfo(res0); + (void)close(snmp_client.fd); + snmp_client.fd = -1; + return (-1); + } + } else + break; + } + freeaddrinfo(res0); + return (0); +} + +static void +remove_local(void) +{ + (void)remove(snmp_client.local_path); +} + +/* + * Open local socket + */ +static int +open_client_local(const char *path) +{ + struct sockaddr_un sa; + char *ptr; + int stype; + + if (snmp_client.chost == NULL) { + if ((snmp_client.chost = malloc(1 + sizeof(DEFAULT_LOCAL))) + == NULL) { + seterr(&snmp_client, "%s", strerror(errno)); + return (-1); + } + strcpy(snmp_client.chost, DEFAULT_LOCAL); + } + if (path != NULL) { + if ((ptr = malloc(1 + strlen(path))) == NULL) { + seterr(&snmp_client, "%s", strerror(errno)); + return (-1); + } + free(snmp_client.chost); + snmp_client.chost = ptr; + strcpy(snmp_client.chost, path); + } + + if (snmp_client.trans == SNMP_TRANS_LOC_DGRAM) + stype = SOCK_DGRAM; + else + stype = SOCK_STREAM; + + if ((snmp_client.fd = socket(PF_LOCAL, stype, 0)) == -1) { + seterr(&snmp_client, "%s", strerror(errno)); + return (-1); + } + + snprintf(snmp_client.local_path, sizeof(snmp_client.local_path), + "%s", SNMP_LOCAL_PATH); + + if (mktemp(snmp_client.local_path) == NULL) { + seterr(&snmp_client, "%s", strerror(errno)); + (void)close(snmp_client.fd); + snmp_client.fd = -1; + return (-1); + } + + sa.sun_family = AF_LOCAL; + sa.sun_len = sizeof(sa); + strcpy(sa.sun_path, snmp_client.local_path); + + if (bind(snmp_client.fd, (struct sockaddr *)&sa, sizeof(sa)) == -1) { + seterr(&snmp_client, "%s", strerror(errno)); + (void)close(snmp_client.fd); + snmp_client.fd = -1; + (void)remove(snmp_client.local_path); + return (-1); + } + atexit(remove_local); + + sa.sun_family = AF_LOCAL; + sa.sun_len = offsetof(struct sockaddr_un, sun_path) + + strlen(snmp_client.chost); + strncpy(sa.sun_path, snmp_client.chost, sizeof(sa.sun_path) - 1); + sa.sun_path[sizeof(sa.sun_path) - 1] = '\0'; + + if (connect(snmp_client.fd, (struct sockaddr *)&sa, sa.sun_len) == -1) { + seterr(&snmp_client, "%s", strerror(errno)); + (void)close(snmp_client.fd); + snmp_client.fd = -1; + (void)remove(snmp_client.local_path); + return (-1); + } + return (0); +} + +/* + * SNMP_OPEN + */ +int +snmp_open(const char *host, const char *port, const char *readcomm, + const char *writecomm) +{ + struct timeval tout; + + /* still open ? */ + if (snmp_client.fd != -1) { + errno = EBUSY; + seterr(&snmp_client, "%s", strerror(errno)); + return (-1); + } + + /* copy community strings */ + if (readcomm != NULL) + strlcpy(snmp_client.read_community, readcomm, + sizeof(snmp_client.read_community)); + if (writecomm != NULL) + strlcpy(snmp_client.write_community, writecomm, + sizeof(snmp_client.write_community)); + + switch (snmp_client.trans) { + + case SNMP_TRANS_UDP: + case SNMP_TRANS_UDP6: + if (open_client_udp(host, port) != 0) + return (-1); + break; + + case SNMP_TRANS_LOC_DGRAM: + case SNMP_TRANS_LOC_STREAM: + if (open_client_local(host) != 0) + return (-1); + break; + + default: + seterr(&snmp_client, "bad transport mapping"); + return (-1); + } + tout.tv_sec = 0; + tout.tv_usec = 0; + if (setsockopt(snmp_client.fd, SOL_SOCKET, SO_SNDTIMEO, + &tout, sizeof(struct timeval)) == -1) { + seterr(&snmp_client, "%s", strerror(errno)); + (void)close(snmp_client.fd); + snmp_client.fd = -1; + if (snmp_client.local_path[0] != '\0') + (void)remove(snmp_client.local_path); + return (-1); + } + + /* initialize list */ + LIST_INIT(&sent_pdus); + + return (0); +} + + +/* + * SNMP_CLOSE + * + * closes connection to snmp server + * - function cannot fail + * - clears connection + * - clears list of sent pdus + * + * input: + * void + * return: + * void + */ +void +snmp_close(void) +{ + struct sent_pdu *p1; + + if (snmp_client.fd != -1) { + (void)close(snmp_client.fd); + snmp_client.fd = -1; + if (snmp_client.local_path[0] != '\0') + (void)remove(snmp_client.local_path); + } + while(!LIST_EMPTY(&sent_pdus)){ + p1 = LIST_FIRST(&sent_pdus); + if (p1->timeout_id != NULL) + snmp_client.timeout_stop(p1->timeout_id); + LIST_REMOVE(p1, entries); + free(p1); + } + free(snmp_client.chost); + free(snmp_client.cport); +} + +/* + * initialize a snmp_pdu structure + */ +void +snmp_pdu_create(struct snmp_pdu *pdu, u_int op) +{ + memset(pdu, 0, sizeof(struct snmp_pdu)); + + if (op == SNMP_PDU_SET) + strlcpy(pdu->community, snmp_client.write_community, + sizeof(pdu->community)); + else + strlcpy(pdu->community, snmp_client.read_community, + sizeof(pdu->community)); + + pdu->type = op; + pdu->version = snmp_client.version; + pdu->error_status = 0; + pdu->error_index = 0; + pdu->nbindings = 0; + + if (snmp_client.version != SNMP_V3) + return; + + pdu->identifier = ++snmp_client.identifier; + pdu->engine.max_msg_size = snmp_client.engine.max_msg_size; + pdu->flags = 0; + pdu->security_model = snmp_client.security_model; + + if (snmp_client.security_model == SNMP_SECMODEL_USM) { + memcpy(&pdu->engine, &snmp_client.engine, sizeof(pdu->engine)); + memcpy(&pdu->user, &snmp_client.user, sizeof(pdu->user)); + snmp_pdu_init_secparams(pdu); + } else + seterr(&snmp_client, "unknown security model"); + + if (snmp_client.clen > 0) { + memcpy(pdu->context_engine, snmp_client.cengine, + snmp_client.clen); + pdu->context_engine_len = snmp_client.clen; + } else { + memcpy(pdu->context_engine, snmp_client.engine.engine_id, + snmp_client.engine.engine_len); + pdu->context_engine_len = snmp_client.engine.engine_len; + } + + strlcpy(pdu->context_name, snmp_client.cname, + sizeof(pdu->context_name)); +} + +/* add pairs of (struct asn_oid, enum snmp_syntax) to an existing pdu */ +/* added 10/04/02 by kek: check for MAX_BINDINGS */ +int +snmp_add_binding(struct snmp_v1_pdu *pdu, ...) +{ + va_list ap; + const struct asn_oid *oid; + u_int ret; + + va_start(ap, pdu); + + ret = pdu->nbindings; + while ((oid = va_arg(ap, const struct asn_oid *)) != NULL) { + if (pdu->nbindings >= SNMP_MAX_BINDINGS){ + va_end(ap); + return (-1); + } + pdu->bindings[pdu->nbindings].var = *oid; + pdu->bindings[pdu->nbindings].syntax = + va_arg(ap, enum snmp_syntax); + pdu->nbindings++; + } + va_end(ap); + return (ret); +} + + +static int32_t +snmp_next_reqid(struct snmp_client * c) +{ + int32_t i; + + i = c->next_reqid; + if (c->next_reqid >= c->max_reqid) + c->next_reqid = c->min_reqid; + else + c->next_reqid++; + return (i); +} + +/* + * Send request and return request id. + */ +static int32_t +snmp_send_packet(struct snmp_pdu * pdu) +{ + u_char *buf; + struct asn_buf b; + ssize_t ret; + + if ((buf = calloc(1, snmp_client.txbuflen)) == NULL) { + seterr(&snmp_client, "%s", strerror(errno)); + return (-1); + } + + pdu->request_id = snmp_next_reqid(&snmp_client); + + b.asn_ptr = buf; + b.asn_len = snmp_client.txbuflen; + if (snmp_pdu_encode(pdu, &b)) { + seterr(&snmp_client, "%s", strerror(errno)); + free(buf); + return (-1); + } + + if (snmp_client.dump_pdus) + snmp_pdu_dump(pdu); + + if ((ret = send(snmp_client.fd, buf, b.asn_ptr - buf, 0)) == -1) { + seterr(&snmp_client, "%s", strerror(errno)); + free(buf); + return (-1); + } + free(buf); + + return (pdu->request_id); +} + +/* + * to be called when a snmp request timed out + */ +static void +snmp_timeout(void * listentry_ptr) +{ + struct sent_pdu *listentry = listentry_ptr; + +#if 0 + warnx("snmp request %i timed out, attempt (%i/%i)", + listentry->reqid, listentry->retrycount, snmp_client.retries); +#endif + + listentry->retrycount++; + if (listentry->retrycount > snmp_client.retries) { + /* there is no answer at all */ + LIST_REMOVE(listentry, entries); + listentry->callback(listentry->pdu, NULL, listentry->arg); + free(listentry); + } else { + /* try again */ + /* new request with new request ID */ + listentry->reqid = snmp_send_packet(listentry->pdu); + listentry->timeout_id = + snmp_client.timeout_start(&snmp_client.timeout, + snmp_timeout, listentry); + } +} + +int32_t +snmp_pdu_send(struct snmp_pdu *pdu, snmp_send_cb_f func, void *arg) +{ + struct sent_pdu *listentry; + int32_t id; + + if ((listentry = malloc(sizeof(struct sent_pdu))) == NULL) { + seterr(&snmp_client, "%s", strerror(errno)); + return (-1); + } + + /* here we really send */ + if ((id = snmp_send_packet(pdu)) == -1) { + free(listentry); + return (-1); + } + + /* add entry to list of sent PDUs */ + listentry->pdu = pdu; + if (gettimeofday(&listentry->time, NULL) == -1) + warn("gettimeofday() failed"); + + listentry->reqid = pdu->request_id; + listentry->callback = func; + listentry->arg = arg; + listentry->retrycount=1; + listentry->timeout_id = + snmp_client.timeout_start(&snmp_client.timeout, snmp_timeout, + listentry); + + LIST_INSERT_HEAD(&sent_pdus, listentry, entries); + + return (id); +} + +/* + * Receive an SNMP packet. + * + * tv controls how we wait for a packet: if tv is a NULL pointer, + * the receive blocks forever, if tv points to a structure with all + * members 0 the socket is polled, in all other cases tv specifies the + * maximum time to wait for a packet. + * + * Return: + * -1 on errors + * 0 on timeout + * +1 if packet received + */ +static int +snmp_receive_packet(struct snmp_pdu *pdu, struct timeval *tv) +{ + int dopoll, setpoll; + int flags; + int saved_errno; + u_char *buf; + int ret; + struct asn_buf abuf; + int32_t ip; +#ifdef bsdi + int optlen; +#else + socklen_t optlen; +#endif + + if ((buf = calloc(1, snmp_client.rxbuflen)) == NULL) { + seterr(&snmp_client, "%s", strerror(errno)); + return (-1); + } + dopoll = setpoll = 0; + flags = 0; + if (tv != NULL) { + /* poll or timeout */ + if (tv->tv_sec != 0 || tv->tv_usec != 0) { + /* wait with timeout */ + if (setsockopt(snmp_client.fd, SOL_SOCKET, SO_RCVTIMEO, + tv, sizeof(*tv)) == -1) { + seterr(&snmp_client, "setsockopt: %s", + strerror(errno)); + free(buf); + return (-1); + } + optlen = sizeof(*tv); + if (getsockopt(snmp_client.fd, SOL_SOCKET, SO_RCVTIMEO, + tv, &optlen) == -1) { + seterr(&snmp_client, "getsockopt: %s", + strerror(errno)); + free(buf); + return (-1); + } + /* at this point tv_sec and tv_usec may appear + * as 0. This happens for timeouts lesser than + * the clock granularity. The kernel rounds these to + * 0 and this would result in a blocking receive. + * Instead of an else we check tv_sec and tv_usec + * again below and if this rounding happens, + * switch to a polling receive. */ + } + if (tv->tv_sec == 0 && tv->tv_usec == 0) { + /* poll */ + dopoll = 1; + if ((flags = fcntl(snmp_client.fd, F_GETFL, 0)) == -1) { + seterr(&snmp_client, "fcntl: %s", + strerror(errno)); + free(buf); + return (-1); + } + if (!(flags & O_NONBLOCK)) { + setpoll = 1; + flags |= O_NONBLOCK; + if (fcntl(snmp_client.fd, F_SETFL, flags) == -1) { + seterr(&snmp_client, "fcntl: %s", + strerror(errno)); + free(buf); + return (-1); + } + } + } + } + ret = recv(snmp_client.fd, buf, snmp_client.rxbuflen, 0); + saved_errno = errno; + if (tv != NULL) { + if (dopoll) { + if (setpoll) { + flags &= ~O_NONBLOCK; + (void)fcntl(snmp_client.fd, F_SETFL, flags); + } + } else { + tv->tv_sec = 0; + tv->tv_usec = 0; + (void)setsockopt(snmp_client.fd, SOL_SOCKET, SO_RCVTIMEO, + tv, sizeof(*tv)); + } + } + if (ret == -1) { + free(buf); + if (errno == EAGAIN || errno == EWOULDBLOCK) + return (0); + seterr(&snmp_client, "recv: %s", strerror(saved_errno)); + return (-1); + } + if (ret == 0) { + /* this happens when we have a streaming socket and the + * remote side has closed it */ + free(buf); + seterr(&snmp_client, "recv: socket closed by peer"); + errno = EPIPE; + return (-1); + } + + abuf.asn_ptr = buf; + abuf.asn_len = ret; + + memset(pdu, 0, sizeof(*pdu)); + if (snmp_client.security_model == SNMP_SECMODEL_USM) { + memcpy(&pdu->engine, &snmp_client.engine, sizeof(pdu->engine)); + memcpy(&pdu->user, &snmp_client.user, sizeof(pdu->user)); + snmp_pdu_init_secparams(pdu); + } + + if (SNMP_CODE_OK != (ret = snmp_pdu_decode(&abuf, pdu, &ip))) { + seterr(&snmp_client, "snmp_decode_pdu: failed %d", ret); + free(buf); + return (-1); + } + + free(buf); + if (snmp_client.dump_pdus) + snmp_pdu_dump(pdu); + + snmp_client.engine.engine_time = pdu->engine.engine_time; + snmp_client.engine.engine_boots = pdu->engine.engine_boots; + + return (+1); +} + +static int +snmp_deliver_packet(struct snmp_pdu * resp) +{ + struct sent_pdu *listentry; + + if (resp->type != SNMP_PDU_RESPONSE) { + warn("ignoring snmp pdu %u", resp->type); + return (-1); + } + + LIST_FOREACH(listentry, &sent_pdus, entries) + if (listentry->reqid == resp->request_id) + break; + if (listentry == NULL) + return (-1); + + LIST_REMOVE(listentry, entries); + listentry->callback(listentry->pdu, resp, listentry->arg); + + snmp_client.timeout_stop(listentry->timeout_id); + + free(listentry); + return (0); +} + +int +snmp_receive(int blocking) +{ + int ret; + + struct timeval tv; + struct snmp_pdu * resp; + + memset(&tv, 0, sizeof(tv)); + + resp = malloc(sizeof(struct snmp_pdu)); + if (resp == NULL) { + seterr(&snmp_client, "no memory for returning PDU"); + return (-1) ; + } + + if ((ret = snmp_receive_packet(resp, blocking ? NULL : &tv)) <= 0) { + free(resp); + return (ret); + } + ret = snmp_deliver_packet(resp); + snmp_pdu_free(resp); + free(resp); + return (ret); +} + + +/* + * Check a GETNEXT response. Here we have three possible outcomes: -1 an + * unexpected error happened. +1 response is ok and is within the table 0 + * response is ok, but is behind the table or error is NOSUCHNAME. The req + * should point to a template PDU which contains the base OIDs and the + * syntaxes. This is really only useful to sweep non-sparse tables. + */ +static int +ok_getnext(const struct snmp_pdu * req, const struct snmp_pdu * resp) +{ + u_int i; + + if (resp->version != req->version) { + warnx("SNMP GETNEXT: response has wrong version"); + return (-1); + } + + if (resp->error_status == SNMP_ERR_NOSUCHNAME) + return (0); + + if (resp->error_status != SNMP_ERR_NOERROR) { + warnx("SNMP GETNEXT: error %d", resp->error_status); + return (-1); + } + if (resp->nbindings != req->nbindings) { + warnx("SNMP GETNEXT: bad number of bindings in response"); + return (-1); + } + for (i = 0; i < req->nbindings; i++) { + if (!asn_is_suboid(&req->bindings[i].var, + &resp->bindings[i].var)) { + if (i != 0) + warnx("SNMP GETNEXT: inconsistent table " + "response"); + return (0); + } + if (resp->version != SNMP_V1 && + resp->bindings[i].syntax == SNMP_SYNTAX_ENDOFMIBVIEW) + return (0); + + if (resp->bindings[i].syntax != req->bindings[i].syntax) { + warnx("SNMP GETNEXT: bad syntax in response"); + return (0); + } + } + return (1); +} + +/* + * Check a GET response. Here we have three possible outcomes: -1 an + * unexpected error happened. +1 response is ok. 0 NOSUCHNAME The req should + * point to a template PDU which contains the OIDs and the syntaxes. This + * is only useful for SNMPv1 or single object GETS. + */ +static int +ok_get(const struct snmp_pdu * req, const struct snmp_pdu * resp) +{ + u_int i; + + if (resp->version != req->version) { + warnx("SNMP GET: response has wrong version"); + return (-1); + } + + if (resp->error_status == SNMP_ERR_NOSUCHNAME) + return (0); + + if (resp->error_status != SNMP_ERR_NOERROR) { + warnx("SNMP GET: error %d", resp->error_status); + return (-1); + } + + if (resp->nbindings != req->nbindings) { + warnx("SNMP GET: bad number of bindings in response"); + return (-1); + } + for (i = 0; i < req->nbindings; i++) { + if (asn_compare_oid(&req->bindings[i].var, + &resp->bindings[i].var) != 0) { + warnx("SNMP GET: bad OID in response"); + return (-1); + } + if (snmp_client.version != SNMP_V1 && + (resp->bindings[i].syntax == SNMP_SYNTAX_NOSUCHOBJECT || + resp->bindings[i].syntax == SNMP_SYNTAX_NOSUCHINSTANCE)) + return (0); + if (resp->bindings[i].syntax != req->bindings[i].syntax) { + warnx("SNMP GET: bad syntax in response"); + return (-1); + } + } + return (1); +} + +/* + * Check the response to a SET PDU. We check: - the error status must be 0 - + * the number of bindings must be equal in response and request - the + * syntaxes must be the same in response and request - the OIDs must be the + * same in response and request + */ +static int +ok_set(const struct snmp_pdu * req, const struct snmp_pdu * resp) +{ + u_int i; + + if (resp->version != req->version) { + warnx("SNMP SET: response has wrong version"); + return (-1); + } + + if (resp->error_status == SNMP_ERR_NOSUCHNAME) { + warnx("SNMP SET: error %d", resp->error_status); + return (0); + } + if (resp->error_status != SNMP_ERR_NOERROR) { + warnx("SNMP SET: error %d", resp->error_status); + return (-1); + } + + if (resp->nbindings != req->nbindings) { + warnx("SNMP SET: bad number of bindings in response"); + return (-1); + } + for (i = 0; i < req->nbindings; i++) { + if (asn_compare_oid(&req->bindings[i].var, + &resp->bindings[i].var) != 0) { + warnx("SNMP SET: wrong OID in response to SET"); + return (-1); + } + if (resp->bindings[i].syntax != req->bindings[i].syntax) { + warnx("SNMP SET: bad syntax in response"); + return (-1); + } + } + return (1); +} + +/* + * Simple checks for response PDUs against request PDUs. Return values: 1=ok, + * 0=nosuchname or similar, -1=failure, -2=no response at all + */ +int +snmp_pdu_check(const struct snmp_pdu *req, + const struct snmp_pdu *resp) +{ + if (resp == NULL) + return (-2); + + switch (req->type) { + + case SNMP_PDU_GET: + return (ok_get(req, resp)); + + case SNMP_PDU_SET: + return (ok_set(req, resp)); + + case SNMP_PDU_GETNEXT: + return (ok_getnext(req, resp)); + + } + errx(1, "%s: bad pdu type %i", __func__, req->type); +} + +int +snmp_dialog(struct snmp_v1_pdu *req, struct snmp_v1_pdu *resp) +{ + struct timeval tv = snmp_client.timeout; + struct timeval end; + struct snmp_pdu pdu; + int ret; + int32_t reqid; + u_int i; + + /* + * Make a copy of the request and replace the syntaxes by NULL + * if this is a GET,GETNEXT or GETBULK. + */ + pdu = *req; + if (pdu.type == SNMP_PDU_GET || pdu.type == SNMP_PDU_GETNEXT || + pdu.type == SNMP_PDU_GETBULK) { + for (i = 0; i < pdu.nbindings; i++) + pdu.bindings[i].syntax = SNMP_SYNTAX_NULL; + } + + for (i = 0; i <= snmp_client.retries; i++) { + (void)gettimeofday(&end, NULL); + timeradd(&end, &snmp_client.timeout, &end); + if ((reqid = snmp_send_packet(&pdu)) == -1) + return (-1); + for (;;) { + (void)gettimeofday(&tv, NULL); + if (timercmp(&end, &tv, <=)) + break; + timersub(&end, &tv, &tv); + if ((ret = snmp_receive_packet(resp, &tv)) == 0) + /* timeout */ + break; + + if (ret > 0) { + if (reqid == resp->request_id) + return (0); + /* not for us */ + (void)snmp_deliver_packet(resp); + } + if (ret < 0 && errno == EPIPE) + /* stream closed */ + return (-1); + } + } + errno = ETIMEDOUT; + seterr(&snmp_client, "retry count exceeded"); + return (-1); +} + +int +snmp_discover_engine(char *passwd) +{ + char cname[SNMP_ADM_STR32_SIZ]; + enum snmp_authentication cap; + enum snmp_privacy cpp; + struct snmp_pdu req, resp; + + if (snmp_client.version != SNMP_V3) + seterr(&snmp_client, "wrong version"); + + strlcpy(cname, snmp_client.user.sec_name, sizeof(cname)); + cap = snmp_client.user.auth_proto; + cpp = snmp_client.user.priv_proto; + + snmp_client.engine.engine_len = 0; + snmp_client.engine.engine_boots = 0; + snmp_client.engine.engine_time = 0; + snmp_client.user.auth_proto = SNMP_AUTH_NOAUTH; + snmp_client.user.priv_proto = SNMP_PRIV_NOPRIV; + memset(snmp_client.user.sec_name, 0, sizeof(snmp_client.user.sec_name)); + + snmp_pdu_create(&req, SNMP_PDU_GET); + + if (snmp_dialog(&req, &resp) == -1) + return (-1); + + if (resp.version != req.version) { + seterr(&snmp_client, "wrong version"); + return (-1); + } + + if (resp.error_status != SNMP_ERR_NOERROR) { + seterr(&snmp_client, "Error %d in responce", resp.error_status); + return (-1); + } + + snmp_client.engine.engine_len = resp.engine.engine_len; + snmp_client.engine.max_msg_size = resp.engine.max_msg_size; + memcpy(snmp_client.engine.engine_id, resp.engine.engine_id, + resp.engine.engine_len); + + strlcpy(snmp_client.user.sec_name, cname, + sizeof(snmp_client.user.sec_name)); + snmp_client.user.auth_proto = cap; + snmp_client.user.priv_proto = cpp; + + if (snmp_client.user.auth_proto == SNMP_AUTH_NOAUTH) + return (0); + + if (passwd == NULL || + snmp_passwd_to_keys(&snmp_client.user, passwd) != SNMP_CODE_OK || + snmp_get_local_keys(&snmp_client.user, snmp_client.engine.engine_id, + snmp_client.engine.engine_len) != SNMP_CODE_OK) + return (-1); + + if (resp.engine.engine_boots != 0) + snmp_client.engine.engine_boots = resp.engine.engine_boots; + + if (resp.engine.engine_time != 0) { + snmp_client.engine.engine_time = resp.engine.engine_time; + return (0); + } + + snmp_pdu_free(&req); + + snmp_pdu_create(&req, SNMP_PDU_GET); + req.engine.engine_boots = 0; + req.engine.engine_time = 0; + + if (snmp_dialog(&req, &resp) == -1) + return (-1); + + if (resp.version != req.version) { + seterr(&snmp_client, "wrong version"); + return (-1); + } + + if (resp.error_status != SNMP_ERR_NOERROR) { + seterr(&snmp_client, "Error %d in responce", resp.error_status); + return (-1); + } + + snmp_client.engine.engine_boots = resp.engine.engine_boots; + snmp_client.engine.engine_time = resp.engine.engine_time; + + snmp_pdu_free(&req); + snmp_pdu_free(&resp); + + return (0); +} + +int +snmp_client_set_host(struct snmp_client *cl, const char *h) +{ + char *np; + + if (h == NULL) { + if (cl->chost != NULL) + free(cl->chost); + cl->chost = NULL; + } else { + if ((np = malloc(strlen(h) + 1)) == NULL) + return (-1); + strcpy(np, h); + if (cl->chost != NULL) + free(cl->chost); + cl->chost = np; + } + return (0); +} + +int +snmp_client_set_port(struct snmp_client *cl, const char *p) +{ + char *np; + + if (p == NULL) { + if (cl->cport != NULL) + free(cl->cport); + cl->cport = NULL; + } else { + if ((np = malloc(strlen(p) + 1)) == NULL) + return (-1); + strcpy(np, p); + if (cl->cport != NULL) + free(cl->cport); + cl->cport = np; + } + return (0); +} + +static const char *const trans_list[] = { + [SNMP_TRANS_UDP] = "udp::", + [SNMP_TRANS_LOC_DGRAM] = "dgram::", + [SNMP_TRANS_LOC_STREAM] = "stream::", + [SNMP_TRANS_UDP6] = "udp6::", +}; + +/** + * Try to get a transport identifier which is a leading alphanumeric string + * terminated by a double colon. The string may not be empty. The transport + * identifier is optional. Unknown transport identifiers are reject. + * Be careful: a double colon can also occur in a numeric IPv6 address. + * + * \param sc client struct to set errors + * \param strp possible start of transport; updated to point to + * the next character to parse + * + * \return transport identifier + */ +static inline int +get_transp(struct snmp_client *sc, const char **strp) +{ + const char *p; + size_t i; + + for (i = 0; i < nitems(trans_list); i++) { + p = strstr(*strp, trans_list[i]); + if (p == *strp) { + *strp += strlen(trans_list[i]); + return ((int)i); + } + } + + p = strstr(*strp, "::"); + if (p == *strp) { + seterr(sc, "empty transport specifier"); + return (-1); + } + if (p == NULL) + /* by default assume UDP */ + return (SNMP_TRANS_UDP); + + /* ignore :: after [ */ + const char *ob = strchr(*strp, '['); + if (ob != NULL && p > ob) + /* by default assume UDP */ + return (SNMP_TRANS_UDP); + + seterr(sc, "unknown transport specifier '%.*s'", p - *strp, *strp); + return (-1); +} + +/** + * Try to get community string. Eat everything up to the last @ (if there is + * any) but only if it is not longer than SNMP_COMMUNITY_MAXLEN. Empty + * community strings are legal. + * + * \param sc client struct to set errors + * \param strp possible start of community; updated to the point to + * the next character to parse + * + * \return end of community; equals *strp if there is none; NULL if there + * was an error + */ +static inline const char * +get_comm(struct snmp_client *sc, const char **strp) +{ + const char *p = strrchr(*strp, '@'); + + if (p == NULL) + /* no community string */ + return (*strp); + + if (p - *strp > SNMP_COMMUNITY_MAXLEN) { + seterr(sc, "community string too long '%.*s'", + p - *strp, *strp); + return (NULL); + } + + *strp = p + 1; + return (p); +} + +/** + * Try to get an IPv6 address. This starts with an [ and should end with an ] + * and everything between should be not longer than INET6_ADDRSTRLEN and + * parseable by inet_pton(). + * + * \param sc client struct to set errors + * \param strp possible start of IPv6 address (the '['); updated to point to + * the next character to parse (the one after the closing ']') + * + * \return end of address (equals *strp + 1 if there is none) or NULL + * on errors + */ +static inline const char * +get_ipv6(struct snmp_client *sc, const char **strp) +{ + char str[INET6_ADDRSTRLEN + IF_NAMESIZE]; + struct addrinfo hints, *res; + int error; + + if (**strp != '[') + return (*strp + 1); + + const char *p = *strp + 1; + while (*p != ']' ) { + if (*p == '\0') { + seterr(sc, "unterminated IPv6 address '%.*s'", + p - *strp, *strp); + return (NULL); + } + p++; + } + + if (p - *strp > INET6_ADDRSTRLEN + IF_NAMESIZE) { + seterr(sc, "IPv6 address too long '%.*s'", p - *strp, *strp); + return (NULL); + } + + strncpy(str, *strp + 1, p - (*strp + 1)); + str[p - (*strp + 1)] = '\0'; + + memset(&hints, 0, sizeof(hints)); + hints.ai_flags = AI_CANONNAME | AI_NUMERICHOST; + hints.ai_family = AF_INET6; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + error = getaddrinfo(str, NULL, &hints, &res); + if (error != 0) { + seterr(sc, "%s: %s", str, gai_strerror(error)); + return (NULL); + } + freeaddrinfo(res); + *strp = p + 1; + return (p); +} + +/** + * Try to get an IPv4 address. This starts with a digit and consists of digits + * and dots, is not longer INET_ADDRSTRLEN and must be parseable by + * inet_aton(). + * + * \param sc client struct to set errors + * \param strp possible start of IPv4 address; updated to point to the + * next character to parse + * + * \return end of address (equals *strp if there is none) or NULL + * on errors + */ +static inline const char * +get_ipv4(struct snmp_client *sc, const char **strp) +{ + const char *p = *strp; + + while (isascii(*p) && (isdigit(*p) || *p == '.')) + p++; + + if (p - *strp > INET_ADDRSTRLEN) { + seterr(sc, "IPv4 address too long '%.*s'", p - *strp, *strp); + return (NULL); + } + if (*strp == p) + return *strp; + + char str[INET_ADDRSTRLEN + 1]; + strncpy(str, *strp, p - *strp); + str[p - *strp] = '\0'; + + struct in_addr addr; + if (inet_aton(str, &addr) != 1) { + seterr(sc, "illegal IPv4 address '%s'", str); + return (NULL); + } + + *strp = p; + return (p); +} + +/** + * Try to get a hostname. This includes everything up to but not including + * the last colon (if any). There is no length restriction. + * + * \param sc client struct to set errors + * \param strp possible start of hostname; updated to point to the next + * character to parse (the trailing NUL character or the last + * colon) + * + * \return end of address (equals *strp if there is none) + */ +static inline const char * +get_host(struct snmp_client *sc __unused, const char **strp) +{ + const char *p = strrchr(*strp, ':'); + + if (p == NULL) { + *strp += strlen(*strp); + return (*strp); + } + + *strp = p; + return (p); +} + +/** + * Try to get a port number. This start with a colon and extends to the end + * of string. The port number must not be empty. + * + * \param sc client struct to set errors + * \param strp possible start of port specification; if this points to a + * colon there is a port specification + * + * \return end of port number (equals *strp if there is none); NULL + * if there is no port number + */ +static inline const char * +get_port(struct snmp_client *sc, const char **strp) +{ + if (**strp != ':') + return (*strp + 1); + + if ((*strp)[1] == '\0') { + seterr(sc, "empty port name"); + return (NULL); + } + + *strp += strlen(*strp); + return (*strp); +} + +/** + * Save the string in the range given by two pointers. + * + * \param sc client struct to set errors + * \param s begin and end pointers + * + * \return freshly allocated copy of the string between s[0] and s[1] + */ +static inline char * +save_str(struct snmp_client *sc, const char *const s[2]) +{ + char *m; + + if ((m = malloc(s[1] - s[0] + 1)) == NULL) { + seterr(sc, "%s: %s", __func__, strerror(errno)); + return (NULL); + } + strncpy(m, s[0], s[1] - s[0]); + m[s[1] - s[0]] = '\0'; + + return (m); +} + +/** + * Parse a server specification. All parts are optional: + * + * [::][@][][:] + * + * The transport string consists of letters, digits or '_' and starts with + * a letter or digit. It is terminated by two colons and may not be empty. + * + * The community string is terminated by the last '@' and does not exceed + * SNMP_COMMUNITY_MAXLEN. It may be empty. + * + * The host or ip is either an IPv4 address (as parsed by inet_pton()), an + * IPv6 address in '[' and ']' and parseable by inet_aton() or a hostname + * terminated by the last colon or by the NUL character. + * + * The port number may be specified numerically or symbolically and starts + * with the last colon. + * + * The functions sets the chost, cport, trans, read_community and + * write_community fields on success and the error field on errors. + * The chost and cport fields are allocated by malloc(3), their previous + * content is deallocated by free(3). + * + * The function explicitly allows mismatches between the transport and + * the address type in order to support IPv4 in IPv6 addresses. + * + * \param sc client struct to fill + * \param str string to parse + * + * \return 0 on success and -1 on errors + */ +int +snmp_parse_server(struct snmp_client *sc, const char *str) +{ + const char *const orig = str; + + /* parse input */ + int def_trans = 0, trans = get_transp(sc, &str); + if (trans < 0) + return (-1); + /* choose automatically */ + if (orig == str) + def_trans = 1; + + const char *const comm[2] = { + str, + get_comm(sc, &str), + }; + if (comm[1] == NULL) + return (-1); + + const char *const ipv6[2] = { + str + 1, + get_ipv6(sc, &str), + }; + if (ipv6[1] == NULL) + return (-1); + + const char *ipv4[2] = { + str, + str, + }; + + const char *host[2] = { + str, + str, + }; + + if (ipv6[0] == ipv6[1]) { + ipv4[1] = get_ipv4(sc, &str); + + if (ipv4[0] == ipv4[1]) + host[1] = get_host(sc, &str); + } + + const char *port[2] = { + str + 1, + get_port(sc, &str), + }; + if (port[1] == NULL) + return (-1); + + if (*str != '\0') { + seterr(sc, "junk at end of server specification '%s'", str); + return (-1); + } + +#if DEBUG_PARSE + printf("transp: %d (def=%d)\n", trans, def_trans); + printf("comm: %zu %zu\n", comm[0] - orig, comm[1] - orig); + printf("ipv6: %zu %zu\n", ipv6[0] - orig, ipv6[1] - orig); + printf("ipv4: %zu %zu\n", ipv4[0] - orig, ipv4[1] - orig); + printf("host: %zu %zu\n", host[0] - orig, host[1] - orig); + printf("port: %zu %zu\n", port[0] - orig, port[1] - orig); +#endif + + /* analyse and allocate */ + char *chost; + + if (ipv6[0] != ipv6[1]) { + if ((chost = save_str(sc, ipv6)) == NULL) + return (-1); + if (def_trans || trans == SNMP_TRANS_UDP) + /* assume the user meant udp6:: */ + trans = SNMP_TRANS_UDP6; + } else if (ipv4[0] != ipv4[1]) { + if ((chost = save_str(sc, ipv4)) == NULL) + return (-1); + if (def_trans) + trans = SNMP_TRANS_UDP; + } else { + if ((chost = save_str(sc, host)) == NULL) + return (-1); + + if (def_trans) { + /* + * Default transport is UDP unless the host contains + * a slash in which case we default to DGRAM. + */ + for (const char *p = host[0]; p < host[1]; p++) + if (*p == '/') { + trans = SNMP_TRANS_LOC_DGRAM; + break; + } + } + } + + char *cport; + + if (port[0] == port[1] && ( + trans == SNMP_TRANS_UDP || trans == SNMP_TRANS_UDP6)) { + /* If port was not specified, use "snmp" name by default */ + cport = strdup("snmp"); + } else + cport = save_str(sc, port); + + if (cport == NULL) { + free(chost); + return (-1); + } + + /* commit */ + sc->trans = trans; + + /* + * If community string was specified and it is empty, overwrite it. + * If it was not specified, use default. + */ + if (comm[0] != comm[1] || strrchr(comm[0], '@') != NULL) { + strncpy(sc->read_community, comm[0], comm[1] - comm[0]); + sc->read_community[comm[1] - comm[0]] = '\0'; + strncpy(sc->write_community, comm[0], comm[1] - comm[0]); + sc->write_community[comm[1] - comm[0]] = '\0'; + } + + free(sc->chost); + sc->chost = chost; + free(sc->cport); + sc->cport = cport; + +#if DEBUG_PARSE + printf("Committed values:\n"); + printf("trans: %d\n", sc->trans); + printf("comm: '%s'/'%s'\n", sc->read_community, sc->write_community); + printf("host: '%s'\n", sc->chost); + printf("port: '%s'\n", sc->cport); +#endif + return (0); +} Property changes on: vendor/1.14/lib/snmpclient.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/lib/snmpclient.h =================================================================== --- vendor/1.14/lib/snmpclient.h (nonexistent) +++ vendor/1.14/lib/snmpclient.h (revision 359491) @@ -0,0 +1,202 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * Kendy Kutzner + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/lib/snmpclient.h,v 1.19 2005/05/23 11:10:14 brandt_h Exp $ + */ +#ifndef _BSNMP_SNMPCLIENT_H +#define _BSNMP_SNMPCLIENT_H + +#include +#include +#include +#include +#include + + +#define SNMP_STRERROR_LEN 200 + +#define SNMP_LOCAL_PATH "/tmp/snmpXXXXXXXXXXXXXX" + +/* + * transport methods + */ +#define SNMP_TRANS_UDP 0 +#define SNMP_TRANS_LOC_DGRAM 1 +#define SNMP_TRANS_LOC_STREAM 2 +#define SNMP_TRANS_UDP6 3 + +/* type of callback function for responses + * this callback function is responsible for free() any memory associated with + * any of the PDUs. Therefor it may call snmp_pdu_free() */ +typedef void (*snmp_send_cb_f)(struct snmp_pdu *, struct snmp_pdu *, void *); + +/* type of callback function for timeouts */ +typedef void (*snmp_timeout_cb_f)(void * ); + +/* timeout start function */ +typedef void *(*snmp_timeout_start_f)(struct timeval *timeout, + snmp_timeout_cb_f callback, void *); + +/* timeout stop function */ +typedef void (*snmp_timeout_stop_f)(void *timeout_id); + +/* + * Client context. + */ +struct snmp_client { + enum snmp_version version; + int trans; /* which transport to use */ + + /* these two are read-only for the application */ + char *cport; /* port number as string */ + char *chost; /* host name or IP address as string */ + + char read_community[SNMP_COMMUNITY_MAXLEN + 1]; + char write_community[SNMP_COMMUNITY_MAXLEN + 1]; + + /* SNMPv3 specific fields */ + int32_t identifier; + int32_t security_model; + struct snmp_engine engine; + struct snmp_user user; + + /* SNMPv3 Access control - VACM*/ + uint32_t clen; + uint8_t cengine[SNMP_ENGINE_ID_SIZ]; + char cname[SNMP_CONTEXT_NAME_SIZ]; + + struct timeval timeout; + u_int retries; + + int dump_pdus; + + size_t txbuflen; + size_t rxbuflen; + + int fd; + + int32_t next_reqid; + int32_t max_reqid; + int32_t min_reqid; + + char error[SNMP_STRERROR_LEN]; + + snmp_timeout_start_f timeout_start; + snmp_timeout_stop_f timeout_stop; + + char local_path[sizeof(SNMP_LOCAL_PATH)]; +}; + +/* the global context */ +extern struct snmp_client snmp_client; + +/* initizialies a snmp_client structure */ +void snmp_client_init(struct snmp_client *); + +/* initialize fields */ +int snmp_client_set_host(struct snmp_client *, const char *); +int snmp_client_set_port(struct snmp_client *, const char *); + +/* open connection to snmp server (hostname or portname can be NULL) */ +int snmp_open(const char *_hostname, const char *_portname, + const char *_read_community, const char *_write_community); + +/* close connection */ +void snmp_close(void); + +/* initialize a snmp_pdu structure */ +void snmp_pdu_create(struct snmp_pdu *, u_int _op); + +/* add pairs of (struct asn_oid *, enum snmp_syntax) to an existing pdu */ +int snmp_add_binding(struct snmp_pdu *, ...); + +/* check wheater the answer is valid or not */ +int snmp_pdu_check(const struct snmp_pdu *_req, const struct snmp_pdu *_resp); + +int32_t snmp_pdu_send(struct snmp_pdu *_pdu, snmp_send_cb_f _func, void *_arg); + +/* append an index to an oid */ +int snmp_oid_append(struct asn_oid *_oid, const char *_fmt, ...); + +/* receive a packet */ +int snmp_receive(int _blocking); + +/* + * This structure is used to describe an SNMP table that is to be fetched. + * The C-structure that is produced by the fetch function must start with + * a TAILQ_ENTRY and an u_int64_t. + */ +struct snmp_table { + /* base OID of the table */ + struct asn_oid table; + /* type OID of the LastChange variable for the table if any */ + struct asn_oid last_change; + /* maximum number of iterations if table has changed */ + u_int max_iter; + /* size of the C-structure */ + size_t entry_size; + /* number of index fields */ + u_int index_size; + /* bit mask of required fields */ + uint64_t req_mask; + + /* indexes and columns to fetch. Ended by a NULL syntax entry */ + struct snmp_table_entry { + /* the column sub-oid, ignored for index fields */ + asn_subid_t subid; + /* the syntax of the column or index */ + enum snmp_syntax syntax; + /* offset of the field into the C-structure. For octet strings + * this points to an u_char * followed by a size_t */ + off_t offset; +#if defined(__GNUC__) && __GNUC__ < 3 + } entries[0]; +#else + } entries[]; +#endif +}; + +/* callback type for table fetch */ +typedef void (*snmp_table_cb_f)(void *_list, void *_arg, int _res); + +/* fetch a table. The argument points to a TAILQ_HEAD */ +int snmp_table_fetch(const struct snmp_table *descr, void *); +int snmp_table_fetch_async(const struct snmp_table *, void *, + snmp_table_cb_f, void *); + +/* send a request and wait for the response */ +int snmp_dialog(struct snmp_pdu *_req, struct snmp_pdu *_resp); + +/* discover an authorative snmpEngineId */ +int snmp_discover_engine(char *); + +/* parse a server specification */ +int snmp_parse_server(struct snmp_client *, const char *); + +#endif /* _BSNMP_SNMPCLIENT_H */ Property changes on: vendor/1.14/lib/snmpclient.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/lib/snmpcrypto.c =================================================================== --- vendor/1.14/lib/snmpcrypto.c (nonexistent) +++ vendor/1.14/lib/snmpcrypto.c (revision 359491) @@ -0,0 +1,435 @@ +/*- + * Copyright (c) 2010 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Shteryana Sotirova Shopova under + * sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: head/contrib/bsnmp/lib/snmpcrypto.c 339270 2018-10-09 21:28:26Z gjb $ + */ +#include +#include +#include +#include +#include +#include +#ifdef HAVE_STDINT_H +#include +#elif defined(HAVE_INTTYPES_H) +#include +#endif +#include +#include +#include +#include + +#ifdef HAVE_LIBCRYPTO +#include +#endif + +#include "asn1.h" +#include "snmp.h" +#include "snmppriv.h" + +#define SNMP_PRIV_AES_IV_SIZ 16 +#define SNMP_EXTENDED_KEY_SIZ 64 +#define SNMP_AUTH_KEY_LOOPCNT 1048576 +#define SNMP_AUTH_BUF_SIZE 72 + +#ifdef HAVE_LIBCRYPTO + +static const uint8_t ipad = 0x36; +static const uint8_t opad = 0x5c; + +static int32_t +snmp_digest_init(const struct snmp_user *user, EVP_MD_CTX *ctx, + const EVP_MD **dtype, uint32_t *keylen) +{ + if (user->auth_proto == SNMP_AUTH_HMAC_MD5) { + *dtype = EVP_md5(); + *keylen = SNMP_AUTH_HMACMD5_KEY_SIZ; + } else if (user->auth_proto == SNMP_AUTH_HMAC_SHA) { + *dtype = EVP_sha1(); + *keylen = SNMP_AUTH_HMACSHA_KEY_SIZ; + } else if (user->auth_proto == SNMP_AUTH_NOAUTH) + return (0); + else { + snmp_error("unknown authentication option - %d", + user->auth_proto); + return (-1); + } + + if (EVP_DigestInit(ctx, *dtype) != 1) + return (-1); + + return (1); +} + +enum snmp_code +snmp_pdu_calc_digest(const struct snmp_pdu *pdu, uint8_t *digest) +{ + uint8_t md[EVP_MAX_MD_SIZE], extkey[SNMP_EXTENDED_KEY_SIZ]; + uint8_t key1[SNMP_EXTENDED_KEY_SIZ], key2[SNMP_EXTENDED_KEY_SIZ]; + uint32_t i, keylen, olen; + int32_t err; + const EVP_MD *dtype; + EVP_MD_CTX *ctx; + + ctx = EVP_MD_CTX_new(); + if (ctx == NULL) + return (SNMP_CODE_FAILED); + err = snmp_digest_init(&pdu->user, ctx, &dtype, &keylen); + if (err <= 0) + EVP_MD_CTX_free(ctx); + if (err < 0) + return (SNMP_CODE_BADDIGEST); + else if (err == 0) + return (SNMP_CODE_OK); + + memset(pdu->digest_ptr, 0, sizeof(pdu->msg_digest)); + memcpy(extkey, pdu->user.auth_key, keylen); + memset(extkey + keylen, 0, sizeof(extkey) - keylen); + + for (i = 0; i < SNMP_EXTENDED_KEY_SIZ; i++) { + key1[i] = extkey[i] ^ ipad; + key2[i] = extkey[i] ^ opad; + } + + if (EVP_DigestUpdate(ctx, key1, SNMP_EXTENDED_KEY_SIZ) != 1 || + EVP_DigestUpdate(ctx, pdu->outer_ptr, pdu->outer_len) != 1 || + EVP_DigestFinal(ctx, md, &olen) != 1) + goto failed; + + if (EVP_DigestInit(ctx, dtype) != 1 || + EVP_DigestUpdate(ctx, key2, SNMP_EXTENDED_KEY_SIZ) != 1 || + EVP_DigestUpdate(ctx, md, olen) != 1 || + EVP_DigestFinal(ctx, md, &olen) != 1) + goto failed; + + if (olen < SNMP_USM_AUTH_SIZE) { + snmp_error("bad digest size - %d", olen); + EVP_MD_CTX_free(ctx); + return (SNMP_CODE_BADDIGEST); + } + + memcpy(digest, md, SNMP_USM_AUTH_SIZE); + EVP_MD_CTX_free(ctx); + return (SNMP_CODE_OK); + +failed: + EVP_MD_CTX_free(ctx); + return (SNMP_CODE_BADDIGEST); +} + +static int32_t +snmp_pdu_cipher_init(const struct snmp_pdu *pdu, int32_t len, + const EVP_CIPHER **ctype, uint8_t *piv) +{ + int i; + uint32_t netint; + + if (pdu->user.priv_proto == SNMP_PRIV_DES) { + if (len % 8 != 0) + return (-1); + *ctype = EVP_des_cbc(); + memcpy(piv, pdu->msg_salt, sizeof(pdu->msg_salt)); + for (i = 0; i < 8; i++) + piv[i] = piv[i] ^ pdu->user.priv_key[8 + i]; + } else if (pdu->user.priv_proto == SNMP_PRIV_AES) { + *ctype = EVP_aes_128_cfb128(); + netint = htonl(pdu->engine.engine_boots); + memcpy(piv, &netint, sizeof(netint)); + piv += sizeof(netint); + netint = htonl(pdu->engine.engine_time); + memcpy(piv, &netint, sizeof(netint)); + piv += sizeof(netint); + memcpy(piv, pdu->msg_salt, sizeof(pdu->msg_salt)); + } else if (pdu->user.priv_proto == SNMP_PRIV_NOPRIV) + return (0); + else { + snmp_error("unknown privacy option - %d", pdu->user.priv_proto); + return (-1); + } + + return (1); +} + +enum snmp_code +snmp_pdu_encrypt(const struct snmp_pdu *pdu) +{ + int32_t err, olen; + uint8_t iv[SNMP_PRIV_AES_IV_SIZ]; + const EVP_CIPHER *ctype; + EVP_CIPHER_CTX *ctx; + + err = snmp_pdu_cipher_init(pdu, pdu->scoped_len, &ctype, iv); + if (err < 0) + return (SNMP_CODE_EDECRYPT); + else if (err == 0) + return (SNMP_CODE_OK); + + ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) + return (SNMP_CODE_FAILED); + if (EVP_EncryptInit(ctx, ctype, pdu->user.priv_key, iv) != 1) + goto failed; + + if (EVP_EncryptUpdate(ctx, pdu->scoped_ptr, &olen, pdu->scoped_ptr, + pdu->scoped_len) != 1 || + EVP_EncryptFinal(ctx, pdu->scoped_ptr + olen, &olen) != 1) + goto failed; + + EVP_CIPHER_CTX_free(ctx); + return (SNMP_CODE_OK); + +failed: + EVP_CIPHER_CTX_free(ctx); + return (SNMP_CODE_FAILED); +} + +enum snmp_code +snmp_pdu_decrypt(const struct snmp_pdu *pdu) +{ + int32_t err, olen; + uint8_t iv[SNMP_PRIV_AES_IV_SIZ]; + const EVP_CIPHER *ctype; + EVP_CIPHER_CTX *ctx; + + err = snmp_pdu_cipher_init(pdu, pdu->scoped_len, &ctype, iv); + if (err < 0) + return (SNMP_CODE_EDECRYPT); + else if (err == 0) + return (SNMP_CODE_OK); + + ctx = EVP_CIPHER_CTX_new(); + if (ctx == NULL) + return (SNMP_CODE_FAILED); + if (EVP_DecryptInit(ctx, ctype, pdu->user.priv_key, iv) != 1 || + EVP_CIPHER_CTX_set_padding(ctx, 0) != 1) + goto failed; + + if (EVP_DecryptUpdate(ctx, pdu->scoped_ptr, &olen, pdu->scoped_ptr, + pdu->scoped_len) != 1 || + EVP_DecryptFinal(ctx, pdu->scoped_ptr + olen, &olen) != 1) + goto failed; + + EVP_CIPHER_CTX_free(ctx); + return (SNMP_CODE_OK); + +failed: + EVP_CIPHER_CTX_free(ctx); + return (SNMP_CODE_EDECRYPT); +} + +/* [RFC 3414] - A.2. Password to Key Algorithm */ +enum snmp_code +snmp_passwd_to_keys(struct snmp_user *user, char *passwd) +{ + int err, loop, i, pwdlen; + uint32_t keylen, olen; + const EVP_MD *dtype; + EVP_MD_CTX *ctx; + uint8_t authbuf[SNMP_AUTH_BUF_SIZE]; + + if (passwd == NULL || user == NULL) + return (SNMP_CODE_FAILED); + + ctx = EVP_MD_CTX_new(); + if (ctx == NULL) + return (SNMP_CODE_FAILED); + + err = snmp_digest_init(user, ctx, &dtype, &keylen); + if (err <= 0) + EVP_MD_CTX_free(ctx); + if (err < 0) + return (SNMP_CODE_BADDIGEST); + else if (err == 0) + return (SNMP_CODE_OK); + + memset(user->auth_key, 0, sizeof(user->auth_key)); + pwdlen = strlen(passwd); + + for (loop = 0; loop < SNMP_AUTH_KEY_LOOPCNT; loop += i) { + for (i = 0; i < SNMP_EXTENDED_KEY_SIZ; i++) + authbuf[i] = passwd[(loop + i) % pwdlen]; + if (EVP_DigestUpdate(ctx, authbuf, SNMP_EXTENDED_KEY_SIZ) != 1) + goto failed; + } + + if (EVP_DigestFinal(ctx, user->auth_key, &olen) != 1) + goto failed; + + EVP_MD_CTX_free(ctx); + return (SNMP_CODE_OK); + +failed: + EVP_MD_CTX_free(ctx); + return (SNMP_CODE_BADDIGEST); +} + +/* [RFC 3414] - 2.6. Key Localization Algorithm */ +enum snmp_code +snmp_get_local_keys(struct snmp_user *user, uint8_t *eid, uint32_t elen) +{ + int err; + uint32_t keylen, olen; + const EVP_MD *dtype; + EVP_MD_CTX *ctx; + uint8_t authbuf[SNMP_AUTH_BUF_SIZE]; + + if (user == NULL || eid == NULL || elen > SNMP_ENGINE_ID_SIZ) + return (SNMP_CODE_FAILED); + + ctx = EVP_MD_CTX_new(); + if (ctx == NULL) + return (SNMP_CODE_FAILED); + + memset(user->priv_key, 0, sizeof(user->priv_key)); + memset(authbuf, 0, sizeof(authbuf)); + + err = snmp_digest_init(user, ctx, &dtype, &keylen); + if (err <= 0) + EVP_MD_CTX_free(ctx); + if (err < 0) + return (SNMP_CODE_BADDIGEST); + else if (err == 0) + return (SNMP_CODE_OK); + + memcpy(authbuf, user->auth_key, keylen); + memcpy(authbuf + keylen, eid, elen); + memcpy(authbuf + keylen + elen, user->auth_key, keylen); + + if (EVP_DigestUpdate(ctx, authbuf, 2 * keylen + elen) != 1 || + EVP_DigestFinal(ctx, user->auth_key, &olen) != 1) { + EVP_MD_CTX_free(ctx); + return (SNMP_CODE_BADDIGEST); + } + EVP_MD_CTX_free(ctx); + + if (user->priv_proto != SNMP_PRIV_NOPRIV) + memcpy(user->priv_key, user->auth_key, sizeof(user->priv_key)); + + return (SNMP_CODE_OK); +} + +enum snmp_code +snmp_calc_keychange(struct snmp_user *user, uint8_t *keychange) +{ + int32_t err, rvalue[SNMP_AUTH_HMACSHA_KEY_SIZ / 4]; + uint32_t i, keylen, olen; + const EVP_MD *dtype; + EVP_MD_CTX *ctx; + + ctx = EVP_MD_CTX_new(); + if (ctx == NULL) + return (SNMP_CODE_FAILED); + + err = snmp_digest_init(user, ctx, &dtype, &keylen); + if (err <= 0) + EVP_MD_CTX_free(ctx); + if (err < 0) + return (SNMP_CODE_BADDIGEST); + else if (err == 0) + return (SNMP_CODE_OK); + + for (i = 0; i < keylen / 4; i++) + rvalue[i] = random(); + + memcpy(keychange, user->auth_key, keylen); + memcpy(keychange + keylen, rvalue, keylen); + + if (EVP_DigestUpdate(ctx, keychange, 2 * keylen) != 1 || + EVP_DigestFinal(ctx, keychange, &olen) != 1) { + EVP_MD_CTX_free(ctx); + return (SNMP_CODE_BADDIGEST); + } + + EVP_MD_CTX_free(ctx); + return (SNMP_CODE_OK); +} + +#else /* !HAVE_LIBCRYPTO */ + +enum snmp_code +snmp_pdu_calc_digest(const struct snmp_pdu *pdu, uint8_t *digest __unused) +{ + if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH) + return (SNMP_CODE_BADSECLEVEL); + + + return (SNMP_CODE_OK); +} + +enum snmp_code +snmp_pdu_encrypt(const struct snmp_pdu *pdu) +{ + if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV) + return (SNMP_CODE_BADSECLEVEL); + + return (SNMP_CODE_OK); +} + +enum snmp_code +snmp_pdu_decrypt(const struct snmp_pdu *pdu) +{ + if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV) + return (SNMP_CODE_BADSECLEVEL); + + return (SNMP_CODE_OK); +} + +enum snmp_code +snmp_passwd_to_keys(struct snmp_user *user, char *passwd __unused) +{ + if (user->auth_proto == SNMP_AUTH_NOAUTH && + user->priv_proto == SNMP_PRIV_NOPRIV) + return (SNMP_CODE_OK); + + errno = EPROTONOSUPPORT; + + return (SNMP_CODE_FAILED); +} + +enum snmp_code +snmp_get_local_keys(struct snmp_user *user, uint8_t *eid __unused, + uint32_t elen __unused) +{ + if (user->auth_proto == SNMP_AUTH_NOAUTH && + user->priv_proto == SNMP_PRIV_NOPRIV) + return (SNMP_CODE_OK); + + errno = EPROTONOSUPPORT; + + return (SNMP_CODE_FAILED); +} + +enum snmp_code +snmp_calc_keychange(struct snmp_user *user __unused, + uint8_t *keychange __unused) +{ + errno = EPROTONOSUPPORT; + return (SNMP_CODE_FAILED); +} + +#endif /* HAVE_LIBCRYPTO */ Property changes on: vendor/1.14/lib/snmpcrypto.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/lib/tc.def =================================================================== --- vendor/1.14/lib/tc.def (nonexistent) +++ vendor/1.14/lib/tc.def (revision 359491) @@ -0,0 +1,56 @@ +#- +# Copyright (C) 2010 The FreeBSD Foundation +# All rights reserved. +# +# This software was developed by Shteryana Sotirova Shopova under +# sponsorship from the FreeBSD Foundation. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +typedef RowStatus ENUM ( + 1 active + 2 notInService + 3 notReady + 4 createAndGo + 5 createAndWait + 6 destroy +) + +typedef StorageType ENUM ( + 1 other + 2 volatile + 3 nonVolatile + 4 permanent + 5 readOnly +) + +typedef InetAddressType ENUM ( + 0 unknown + 1 ipv4 + 2 ipv6 + 3 ipv4z + 4 ipv6z + 16 dns +) Property changes on: vendor/1.14/lib/tc.def ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/lib/asn1.3 =================================================================== --- vendor/1.14/lib/asn1.3 (nonexistent) +++ vendor/1.14/lib/asn1.3 (revision 359491) @@ -0,0 +1,492 @@ +.\" +.\" Copyright (c) 2004-2005 +.\" Hartmut Brandt. +.\" All rights reserved. +.\" Copyright (c) 2001-2003 +.\" Fraunhofer Institute for Open Communication Systems (FhG Fokus). +.\" All rights reserved. +.\" +.\" Author: Harti Brandt +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Begemot: bsnmp/lib/asn1.3,v 1.9 2005/10/04 08:46:49 brandt_h Exp $ +.\" +.Dd October 4, 2005 +.Dt ASN1 3 +.Os +.Sh NAME +.Nm asn_get_header , +.Nm asn_put_header , +.Nm asn_put_temp_header , +.Nm asn_commit_header , +.Nm asn_get_integer_raw , +.Nm asn_get_integer , +.Nm asn_put_integer , +.Nm asn_get_octetstring_raw , +.Nm asn_get_octetstring , +.Nm asn_put_octetstring , +.Nm asn_get_null_raw , +.Nm asn_get_null , +.Nm asn_put_null , +.Nm asn_put_exception , +.Nm asn_get_objid_raw , +.Nm asn_get_objid , +.Nm asn_put_objid , +.Nm asn_get_sequence , +.Nm asn_get_ipaddress_raw , +.Nm asn_get_ipaddress , +.Nm asn_put_ipaddress , +.Nm asn_get_uint32_raw , +.Nm asn_put_uint32 , +.Nm asn_get_counter64_raw , +.Nm asn_put_counter64 , +.Nm asn_get_timeticks , +.Nm asn_put_timeticks , +.Nm asn_skip , +.Nm asn_slice_oid , +.Nm asn_append_oid , +.Nm asn_compare_oid , +.Nm asn_is_suboid , +.Nm asn_oid2str_r , +.Nm asn_oid2str +.Nd "ASN.1 library for SNMP" +.Sh LIBRARY +Begemot SNMP library +.Pq libbsnmp, -lbsnmp +.Sh SYNOPSIS +.In bsnmp/asn1.h +.Ft enum asn_err +.Fn asn_get_header "struct asn_buf *buf" "u_char *type" "asn_len_t *lenp" +.Ft enum asn_err +.Fn asn_put_header "struct asn_buf *buf" "u_char type" "asn_len_t len" +.Ft enum asn_err +.Fn asn_put_temp_header "struct asn_buf *buf" "u_char type" "u_char **ptr" +.Ft enum asn_err +.Fn asn_commit_header "struct asn_buf *buf" "u_char *ptr" +.Ft enum asn_err +.Fn asn_get_integer_raw "struct asn_buf *buf" "asn_len_t len" "int32_t *res" +.Ft enum asn_err +.Fn asn_get_integer "struct asn_buf *buf" "int32_t *res" +.Ft enum asn_err +.Fn asn_put_integer "struct asn_buf *buf" "int32_t arg" +.Ft enum asn_err +.Fn asn_get_octetstring_raw "struct asn_buf *buf" "asn_len_t len" "u_char *out" "u_int *outsize" +.Ft enum asn_err +.Fn asn_get_octetstring "struct asn_buf *buf" "u_char *out" "u_int *outsize" +.Ft enum asn_err +.Fn asn_put_octetstring "struct asn_buf *buf" "const u_char *str" "u_int strsize" +.Ft enum asn_err +.Fn asn_get_null_raw "struct asn_buf *buf" "asn_len_t len" +.Ft enum asn_err +.Fn asn_get_null "struct asn_buf *buf" +.Ft enum asn_err +.Fn asn_put_null "struct asn_buf *buf" +.Ft enum asn_err +.Fn asn_put_exception "struct asn_buf *buf" "u_int type" +.Ft enum asn_err +.Fn asn_get_objid_raw "struct asn_buf *buf" "asn_len_t len" "struct asn_oid *oid" +.Ft enum asn_err +.Fn asn_get_objid "struct asn_buf *buf" "struct asn_oid *oid" +.Ft enum asn_err +.Fn asn_put_objid "struct asn_buf *buf" "const struct asn_oid *oid" +.Ft enum asn_err +.Fn asn_get_sequence "struct asn_buf *buf" "asn_len_t *lenp" +.Ft enum asn_err +.Fn asn_get_ipaddress_raw "struct asn_buf *buf" "asn_len_t len" "u_char *ipa" +.Ft enum asn_err +.Fn asn_get_ipaddress "struct asn_buf *buf" "u_char *ipa" +.Ft enum asn_err +.Fn asn_put_ipaddress "struct asn_buf *buf" "const u_char *ipa" +.Ft enum asn_err +.Fn asn_get_uint32_raw "struct asn_buf *buf" "asn_len_t len" "u_int32_t *res" +.Ft enum asn_err +.Fn asn_put_uint32 "struct asn_buf *buf" "u_char type" "u_int32_t val" +.Ft enum asn_err +.Fn asn_get_counter64_raw "struct asn_buf *buf" "asn_len_t len" "u_int64_t *res" +.Ft enum asn_err +.Fn asn_put_counter64 "struct asn_buf *buf" "u_int64_t val" +.Ft enum asn_err +.Fn asn_get_timeticks "struct asn_buf *buf" "u_int32_t *valp" +.Ft enum asn_err +.Fn asn_put_timeticks "struct asn_buf *buf" "u_int32_t val" +.Ft enum asn_err +.Fn asn_skip "struct asn_buf *buf" "asn_len_t len" +.Ft void +.Fn asn_slice_oid "struct asn_oid *dest" "const struct asn_oid *src" "u_int from" "u_int to" +.Ft void +.Fn asn_append_oid "struct asn_oid *to" "const struct asn_oid *from" +.Ft int +.Fn asn_compare_oid "const struct asn_oid *oid1" "const struct asn_oid *oid2" +.Ft int +.Fn asn_is_suboid "const struct asn_oid *oid1" "const struct asn_oid *oid2" +.Ft char * +.Fn asn_oid2str_r "const struct asn_oid *oid" "char *buf" +.Ft char * +.Fn asn_oid2str "const struct asn_oid *oid" +.Sh DESCRIPTION +The ASN.1 library contains routines to handle ASN.1 encoding for SNMP. +It supports only the restricted form of ASN.1 as required by SNMP. +There are two basic structures used throughout the library: +.Bd -literal -offset indent +/* these restrictions are in the SMI */ +#define ASN_MAXID 0xffffffff +#define ASN_MAXOIDLEN 128 + +/* type of subidentifiers */ +typedef u_int32_t asn_subid_t; + +struct asn_oid { + u_int len; + asn_subid_t subs[ASN_MAXOIDLEN]; +}; +.Ed +.Pp +This structure represents an OID with the restrictions defined in the SNMP +SMI. +.Fa len +holds the current length of the OID and +.Fa subs +holds the elements of the OID. +.Bd -literal -offset indent +struct asn_buf { + union { + u_char *ptr; + const u_char *cptr; + } asn_u; + size_t asn_len; +}; +#define asn_cptr asn_u.cptr +#define asn_ptr asn_u.ptr +.Ed +.Pp +This structure is used to encode and decode ASN.1. +It describes the output +buffer for encoding routines and the input buffer for decoding routines. +For encoding +.Fa asn_len +holds the number of remaining free octets in the buffer. +The first free byte is pointed to by +.Fa asn_ptr . +For decoding +.Fa asn_len +holds the number of remaining bytes to decode. +The next byte to decode is pointed to by +.Fa asn_cptr . +.Pp +Most of the functions return an error code +.Fa "enum asn_error" : +.Bd -literal -offset indent +enum asn_err { + /* conversion was ok */ + ASN_ERR_OK = 0, + /* conversion failed and stopped */ + ASN_ERR_FAILED = 1 | 0x1000, + /* length field bad, value skipped */ + ASN_ERR_BADLEN = 2, + /* out of buffer, stopped */ + ASN_ERR_EOBUF = 3 | 0x1000, + /* length ok, but value is out of range */ + ASN_ERR_RANGE = 4, + /* not the expected tag, stopped */ + ASN_ERR_TAG = 5 | 0x1000, +}; +#define ASN_ERR_STOPPED(E) (((E) & 0x1000) != 0) +.Ed +.Pp +If +.Fn ASN_ERR_STOPPED +returns true, the error was fatal and processing has stopped at the point +of error. +.Pp +The function +.Fn asn_get_header +reads the next header from the input octet stream. +It returns the tag in the variable pointed to by +.Fa type +(note that only single byte tags are supported) and the decoded length field +in the value pointed to by +.Fa lenp +(this is restricted to a unsigned 32-bit value). +All errors in this function are fatal and stop processing. +.Pp +The function +.Fn asn_put_header +writes an ASN.1 header. +.Fa type +is the tag to write and is restricted to one byte tags (i.e., tags +lesser or equal than 0x30). +.Fa len +is the length of the value and is restricted to 16-bit. +.Pp +The functions +.Fn asn_put_temp_header +and +.Fn asn_commit_header +are used to write a header when the length of the value is not known in +advance, for example, for sequences. +.Fn asn_put_temp_header +writes a header with the given tag +.Fa type +and space for the maximum supported length field and sets the pointer pointed +to by +.Fa ptr +to the begin of this length field. +This pointer must then be fed into +.Fn asn_commit_header +directly after writing the value to the buffer. +The function will compute the +length, insert it into the right place and shift the value if the resulting +length field is shorter than the estimated one. +.Pp +The function +.Fn asn_get_integer_raw +is used to decode a signed integer value (32-bit). +It assumes, that the +header of the integer has been decoded already. +.Fa len +is the length obtained from the ASN.1 header and the integer will be returned +in the value pointed to by +.Fa res . +.Pp +The function +.Fn asn_get_integer +decodes a complete 32-bit signed integer including the header. +If the tag is wrong +.Li ASN_ERR_TAG +is returned. +The function +.Fn asn_put_integer +encodes a 32-bit signed integer. +.Pp +The function +.Fn asn_get_octetstring_raw +decodes the value field of an ASN.1 octet string. +The length obtained from the header must be fed into the +.Fa len +argument and +.Fa out +must point to a buffer to receive the octet string. +On entry to the function +.Fa outsize +must point to the size of the buffer. +On exit +.Fa outsize +will point to the number of octets decoded (if no error occurs this will be +equal to +.Fa len ). +The function +.Fn asn_get_octetstring +decodes an octetstring including the header. +.Fa out +must point to a buffer to receive the string, +.Fa outsize +must point to the size of the buffer. +On exit of the function +.Fa outsize +will point to the number of octets decoded. +The function +.Fn asn_put_octetstring +encodes an octetstring (including the header). +.Fa str +points to the string to encode and +.Fa strsize +is the length of the string (the string may contain embedded +.Li NUL Ns s). +.Pp +The function +.Fn asn_get_null_raw +decodes a null value. +.Fa len +is the length obtained from the header and must be 0. +The function +.Fn asn_get_null +decodes a null including the header and the function +.Fn asn_put_null +encodes a null. +.Pp +The function +.Fn asn_put_exception +is used to encode an SNMPv2 exception. +The exception type is +.Fa type . +.Pp +The function +.Fn asn_get_objid_raw +is used to decode an OID value. +.Fa len +must be the value length obtained from the header and +.Fa oid +will receive the decoded OID. +The function +.Fn asn_get_objid +decodes a complete OID (including the header) and the function +.Fn asn_put_objid +encodes a complete OID. +.Pp +The function +.Fn asn_get_sequence +decodes a sequence header. +The length of the sequence value will be stored in the value pointed to by +.Fa lenp . +.Pp +The function +.Fn asn_get_ipaddress_raw +decodes an IP address value. +.Fa len +is the length from the header and must be 4. +.Fa ipa +will receive the decoded IP address and must point to a buffer of at least +four bytes. +The function +.Fn asn_get_ipaddress +decodes a complete IP address (including the header) and +.Fn asn_put_ipaddress +encodes an IP address. +.Pp +The function +.Fn asn_get_uint32_raw +decodes an unsigned 32-bit integer value. +.Fa len +is the length from the header and +.Fa res +will get the decoded value. +The function +.Fn asn_put_uint32 +encodes an unsigned 32-bit integer value and inserts the tag given in +.Fa type +into the header. +.Pp +The function +.Fn asn_get_counter64_raw +decodes an unsigned 64-bit integer value. +.Fa len +must be the value length from the header. +The resulting value is stored into the variable pointed to by +.Fa res . +The function +.Fn asn_put_counter64 +encodes a complete unsigned 64-bit value. +.Pp +The function +.Fn asn_get_timeticks +decodes an ASN.1 object of type +.Li TIMETICKS +and the function +.Fn asn_put_timeticks +encodes such an object. +.Pp +The function +.Fn asn_skip +can be used to skip +.Fa len +bytes in the input buffer. +.Pp +The function +.Fn asn_slice_oid +splits a part out from an OID. +It takes all the subids from the OID pointed to by +.Fa src +starting with the subid at position +.Fa from +(the first subid being subid 0) up to, but not including, subid +.Fa to +and generates a new OID in +.Fa dest . +If +.Fa to +is less or equal to +.Fa from +the resulting OID will have a length of zero. +.Pp +The function +.Fn asn_append_oid +appends the OID +.Fa from +to the OID +.Fa to +given that the resulting OID is not too long. +If the maximum length is exceeded the result is undefined. +.Pp +The function +.Fn asn_compare_oid +compares two oids and returns the values +.Li -1 , +.Li 0 or +.Li +1 +when +.Fa oid1 +is lesser than, equal, or larger than +.Fa oid2 +resp. +.Pp +The function +.Fn asn_is_suboid +returns 1 if +.Fa oid1 +is equal to the leading part of +.Fa oid2 . +It returns 0 otherwise. +.Pp +The function +.Fn asn_oid2str_r +makes a printable string from +.Fa oid . +The buffer pointed to by +.Fa str +must be large enough to hold the result. +The constant +.Li ASN_OIDSTRLEN +is defined to be the length of the maximum string generated by this function +(including the trailing NUL). +The function +.Fn asn_oid2str +makes a printable string from +.Fa oid +into a private buffer that is overwritten by each call. +.Sh DIAGNOSTICS +When an error occurs in any of the function the function pointed to +by the global pointer +.Bd -literal -offset indent +extern void (*asn_error)(const struct asn_buf *, const char *, ...); +.Ed +.Pp +is called with the current buffer (this may be +.Li NULL ) +and a +.Xr printf 3 +style format string. +There is a default error handler in the library that prints a message +starting with +.Sq ASN.1: +followed by the error message and an optional dump of the buffer. +.Sh SEE ALSO +.Xr gensnmptree 1 , +.Xr bsnmpd 1 , +.Xr bsnmpagent 3 , +.Xr bsnmpclient 3 , +.Xr bsnmplib 3 +.Sh STANDARDS +This implementation conforms to the applicable IETF RFCs and ITU-T +recommendations. +.Sh AUTHORS +.An Hartmut Brandt Aq harti@FreeBSD.org Property changes on: vendor/1.14/lib/asn1.3 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/lib/asn1.h =================================================================== --- vendor/1.14/lib/asn1.h (nonexistent) +++ vendor/1.14/lib/asn1.h (revision 359491) @@ -0,0 +1,183 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/lib/asn1.h,v 1.20 2005/10/05 16:43:11 brandt_h Exp $ + * + * ASN.1 for SNMP + */ +#ifndef asn1_h_ +#define asn1_h_ + +#include + +struct asn_buf { + union { + u_char *ptr; + const u_char *cptr; + } asn_u; + size_t asn_len; +}; +#define asn_cptr asn_u.cptr +#define asn_ptr asn_u.ptr + +/* these restrictions are in the SMI */ +#define ASN_MAXID 0xffffffff +#define ASN_MAXOIDLEN 128 + +/* the string needed for this (with trailing zero) */ +#define ASN_OIDSTRLEN (ASN_MAXOIDLEN * (10 + 1) - 1 + 1) + +/* type of subidentifiers */ +typedef uint32_t asn_subid_t; + +struct asn_oid { + u_int len; + asn_subid_t subs[ASN_MAXOIDLEN]; +}; + +enum asn_err { + /* conversion was ok */ + ASN_ERR_OK = 0, + /* conversion failed and stopped */ + ASN_ERR_FAILED = 1 | 0x1000, + /* length field bad, value skipped */ + ASN_ERR_BADLEN = 2, + /* out of buffer, stopped */ + ASN_ERR_EOBUF = 3 | 0x1000, + /* length ok, but value is out of range */ + ASN_ERR_RANGE = 4, + /* not the expected tag, stopped */ + ASN_ERR_TAG = 5 | 0x1000, +}; +#define ASN_ERR_STOPPED(E) (((E) & 0x1000) != 0) + +/* type for the length field of encoded values. The length is restricted + * to 65535, but using uint16_t would give conversion warnings on gcc */ +typedef uint32_t asn_len_t; /* could be also uint16_t */ + +/* maximal length of a long length field without the length of the length */ +#define ASN_MAXLEN 65535 +#define ASN_MAXLENLEN 2 /* number of bytes in a length */ + +/* maximum size of an octet string as per SMIv2 */ +#define ASN_MAXOCTETSTRING 65535 + +extern void (*asn_error)(const struct asn_buf *, const char *, ...); + +enum asn_err asn_get_header(struct asn_buf *, u_char *, asn_len_t *); +enum asn_err asn_put_header(struct asn_buf *, u_char, asn_len_t); + +enum asn_err asn_put_temp_header(struct asn_buf *, u_char, u_char **); +enum asn_err asn_commit_header(struct asn_buf *, u_char *, size_t *); + +enum asn_err asn_get_integer_raw(struct asn_buf *, asn_len_t, int32_t *); +enum asn_err asn_get_integer(struct asn_buf *, int32_t *); +enum asn_err asn_put_integer(struct asn_buf *, int32_t); + +enum asn_err asn_get_octetstring_raw(struct asn_buf *, asn_len_t, u_char *, u_int *); +enum asn_err asn_get_octetstring(struct asn_buf *, u_char *, u_int *); +enum asn_err asn_put_octetstring(struct asn_buf *, const u_char *, u_int); + +enum asn_err asn_get_null_raw(struct asn_buf *b, asn_len_t); +enum asn_err asn_get_null(struct asn_buf *); +enum asn_err asn_put_null(struct asn_buf *); + +enum asn_err asn_put_exception(struct asn_buf *, u_int); + +enum asn_err asn_get_objid_raw(struct asn_buf *, asn_len_t, struct asn_oid *); +enum asn_err asn_get_objid(struct asn_buf *, struct asn_oid *); +enum asn_err asn_put_objid(struct asn_buf *, const struct asn_oid *); + +enum asn_err asn_get_sequence(struct asn_buf *, asn_len_t *); + +enum asn_err asn_get_ipaddress_raw(struct asn_buf *, asn_len_t, u_char *); +enum asn_err asn_get_ipaddress(struct asn_buf *, u_char *); +enum asn_err asn_put_ipaddress(struct asn_buf *, const u_char *); + +enum asn_err asn_get_uint32_raw(struct asn_buf *, asn_len_t, uint32_t *); +enum asn_err asn_put_uint32(struct asn_buf *, u_char, uint32_t); + +enum asn_err asn_get_counter64_raw(struct asn_buf *, asn_len_t, uint64_t *); +enum asn_err asn_put_counter64(struct asn_buf *, uint64_t); + +enum asn_err asn_get_timeticks(struct asn_buf *, uint32_t *); +enum asn_err asn_put_timeticks(struct asn_buf *, uint32_t); + +enum asn_err asn_skip(struct asn_buf *, asn_len_t); +enum asn_err asn_pad(struct asn_buf *, asn_len_t); + +/* + * Utility functions for OIDs + */ +/* get a sub-OID from the middle of another OID */ +void asn_slice_oid(struct asn_oid *, const struct asn_oid *, u_int, u_int); + +/* append an OID to another one */ +void asn_append_oid(struct asn_oid *, const struct asn_oid *); + +/* compare two OIDs */ +int asn_compare_oid(const struct asn_oid *, const struct asn_oid *); + +/* check whether the first is a suboid of the second one */ +int asn_is_suboid(const struct asn_oid *, const struct asn_oid *); + +/* format an OID into a user buffer of size ASN_OIDSTRLEN */ +char *asn_oid2str_r(const struct asn_oid *, char *); + +/* format an OID into a private static buffer */ +char *asn_oid2str(const struct asn_oid *); + +enum { + ASN_TYPE_BOOLEAN = 0x01, + ASN_TYPE_INTEGER = 0x02, + ASN_TYPE_BITSTRING = 0x03, + ASN_TYPE_OCTETSTRING = 0x04, + ASN_TYPE_NULL = 0x05, + ASN_TYPE_OBJID = 0x06, + ASN_TYPE_SEQUENCE = 0x10, + + ASN_TYPE_CONSTRUCTED = 0x20, + ASN_CLASS_UNIVERSAL = 0x00, + ASN_CLASS_APPLICATION = 0x40, + ASN_CLASS_CONTEXT = 0x80, + ASN_CLASS_PRIVATE = 0xc0, + ASN_TYPE_MASK = 0x1f, + + ASN_APP_IPADDRESS = 0x00, + ASN_APP_COUNTER = 0x01, + ASN_APP_GAUGE = 0x02, + ASN_APP_TIMETICKS = 0x03, + ASN_APP_OPAQUE = 0x04, /* not implemented */ + ASN_APP_COUNTER64 = 0x06, + + ASN_EXCEPT_NOSUCHOBJECT = 0x00, + ASN_EXCEPT_NOSUCHINSTANCE = 0x01, + ASN_EXCEPT_ENDOFMIBVIEW = 0x02, +}; + +#endif Property changes on: vendor/1.14/lib/asn1.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/lib/bsnmpagent.3 =================================================================== --- vendor/1.14/lib/bsnmpagent.3 (nonexistent) +++ vendor/1.14/lib/bsnmpagent.3 (revision 359491) @@ -0,0 +1,444 @@ +.\" +.\" Copyright (c) 2004-2005 +.\" Hartmut Brandt. +.\" All rights reserved. +.\" Copyright (c) 2001-2003 +.\" Fraunhofer Institute for Open Communication Systems (FhG Fokus). +.\" All rights reserved. +.\" +.\" Author: Harti Brandt +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Begemot: bsnmp/lib/bsnmpagent.3,v 1.10 2005/10/04 08:46:49 brandt_h Exp $ +.\" +.Dd October 4, 2005 +.Dt BSNMPAGENT 3 +.Os +.Sh NAME +.Nm bsnmpagent , +.Nm snmp_depop_t , +.Nm snmp_op_t , +.Nm tree , +.Nm tree_size , +.Nm snmp_trace , +.Nm snmp_debug , +.Nm snmp_get , +.Nm snmp_getnext , +.Nm snmp_getbulk , +.Nm snmp_set , +.Nm snmp_make_errresp , +.Nm snmp_dep_lookup , +.Nm snmp_init_context , +.Nm snmp_dep_commit , +.Nm snmp_dep_rollback , +.Nm snmp_dep_finish +.Nd "SNMP agent library" +.Sh LIBRARY +Begemot SNMP library +.Pq libbsnmp, -lbsnmp +.Sh SYNOPSIS +.In asn1.h +.In snmp.h +.In snmpagent.h +.Ft typedef int +.Fn (*snmp_depop_t) "struct snmp_context *ctx" "struct snmp_dependency *dep" "enum snmp_depop op" +.Ft typedef int +.Fn (*snmp_op_t) "struct snmp_context *ctx" "struct snmp_value *val" "u_int len" "u_int idx" "enum snmp_op op" +.Vt extern struct snmp_node *tree ; +.Vt extern u_int tree_size ; +.Vt extern u_int snmp_trace ; +.Vt extern void (*snmp_debug)(const char *fmt, ...) ; +.Ft enum snmp_ret +.Fn snmp_get "struct snmp_pdu *pdu" "struct asn_buf *resp_b" "struct snmp_pdu *resp" "void *data" +.Ft enum snmp_ret +.Fn snmp_getnext "struct snmp_pdu *pdu" "struct asn_buf *resp_b" "struct snmp_pdu *resp" "void *data" +.Ft enum snmp_ret +.Fn snmp_getbulk "struct snmp_pdu *pdu" "struct asn_buf *resp_b" "struct snmp_pdu *resp" "void *data" +.Ft enum snmp_ret +.Fn snmp_set "struct snmp_pdu *pdu" "struct asn_buf *resp_b" "struct snmp_pdu *resp" "void *data" +.Ft enum snmp_ret +.Fn snmp_make_errresp "const struct snmp_pdu *pdu" "struct asn_buf *req_b" "struct asn_buf *resp_b" +.Ft struct snmp_dependency * +.Fn snmp_dep_lookup "struct snmp_context *ctx" "const struct asn_oid *base" "const struct asn_oid *idx" "size_t alloc" "snmp_depop_t func" +.Ft struct snmp_context * +.Fn snmp_init_context "void" +.Ft int +.Fn snmp_dep_commit "struct snmp_context *ctx" +.Ft int +.Fn snmp_dep_rollback "struct snmp_context *ctx" +.Ft void +.Fn snmp_dep_finish "struct snmp_context *ctx" +.Sh DESCRIPTION +The SNMP library contains routines to easily build SNMP agent applications +that use SNMP versions 1 or 2. +Note, however, that it may be even easier to build an +.Xr bsnmpd 1 +loadable module, that handles the new MIB (see +.Xr snmpmod 3 ) . +.Pp +Most of the agent routines operate on a global array that the describes the +complete MIB served by the agent. +This array is held in the two variables: +.Bd -literal -offset indent +extern struct snmp_node *tree; +extern u_int tree_size; +.Ed +.Pp +The elements of the array are of type +.Vt struct snmp_node : +.Bd -literal -offset indent +typedef int (*snmp_op_t)(struct snmp_context *, struct snmp_value *, + u_int, u_int, enum snmp_op); + +struct snmp_node { + struct asn_oid oid; + const char *name; /* name of the leaf */ + enum snmp_node_type type; /* type of this node */ + enum snmp_syntax syntax; + snmp_op_t op; + u_int flags; + u_int32_t index; /* index data */ + void *data; /* application data */ + void *tree_data; /* application data */ +}; +.Ed +.Pp +The fields of this structure are described below. +.Bl -tag -width "syntax" +.It Va oid +Base OID of the scalar or table column. +.It Va name +Name of this variable. +.It Va type +Type of this variable. +One of: +.Bd -literal -offset indent +enum snmp_node_type { + SNMP_NODE_LEAF = 1, + SNMP_NODE_COLUMN +}; +.Ed +.It Va syntax +The SNMP syntax of this variable. +.It Va op +The user supplied handler for this variable. +The handler is called with the following arguments: +.Bl -tag -width "ctx" +.It Fa ctx +A pointer to the context (see below). +.Li NULL . +.It Fa val +The value to be set or retrieved. +For GETNEXT and GETBULK operations the oid in +this value is the current OID. +The function (called in this case only for +table rows) must find the lexically next existing OID within the same column and +set the oid and value subfields accordingly. +If the table column is exhausted the +function must return +.Li SNMP_ERR_NOSUCHNAME . +For all other operations the oid in +.Fa val +is the oid to fetch or set. +.It Fa len +The length of the base oid without index. +.It Fa idx +For table columns this is the index expression from the node (see below). +.It Fa op +This is the operation to execute, one of: +.Bd -literal -offset indent +enum snmp_op { + SNMP_OP_GET = 1, + SNMP_OP_GETNEXT, + SNMP_OP_SET, + SNMP_OP_COMMIT, + SNMP_OP_ROLLBACK, +}; +.Ed +.El +.Pp +The user handler must return an appropriate SNMP v2 error code. +If the original +PDU was a version 1 PDU, the error code is mapped automatically. +.It Va flags +Currently only the flag +.Li SNMP_NODE_CANSET is defined and set for nodes, that can be written or +created. +.It Va index +This word describes the index for table columns. +Each part of the index takes 4 bits starting at bit 4. +Bits 0 to 3 hold the number of index parts. +This arrangement allows for tables with up to seven indexes. +Each bit group contains the syntax for the index part. +There are a number of macros to help in parsing this field: +.Bd -literal -offset indent +#define SNMP_INDEXES_MAX 7 +#define SNMP_INDEX_SHIFT 4 +#define SNMP_INDEX_MASK 0xf +#define SNMP_INDEX_COUNT(V) ((V) & SNMP_INDEX_MASK) +#define SNMP_INDEX(V,I) \e + (((V) >> (((I) + 1) * SNMP_INDEX_SHIFT)) & \e + SNMP_INDEX_MASK) +.Ed +.It Va data +This field may contain arbitrary data and is not used by the library. +.El +.Pp +The easiest way to construct the node table is +.Xr gensnmptree 1 . +Note, that one must be careful when changing the tree while executing a SET +operation. +Consult the sources for +.Xr bsnmpd 1 . +.Pp +The global variable +.Va snmp_trace +together with the function pointed to by +.Va snmp_debug +help in debugging the library and the agent. +.Va snmp_trace is a bit mask with the following bits: +.Bd -literal -offset indent +enum { + SNMP_TRACE_GET, + SNMP_TRACE_GETNEXT, + SNMP_TRACE_SET, + SNMP_TRACE_DEPEND, + SNMP_TRACE_FIND, +}; +.Ed +.Pp +Setting a bit to true causes the library to call +.Fn snmp_debug +in strategic places with a debug string. +The library contains a default +implementation for the debug function that prints a message to standard error. +.Pp +Many of the functions use a so called context: +.Bd -literal -offset indent +struct snmp_context { + u_int var_index; + struct snmp_scratch *scratch; + struct snmp_dependency *dep; + void *data; /* user data */ + enum snmp_ret code; /* return code */ +}; + +struct snmp_scratch { + void *ptr1; + void *ptr2; + uint32_t int1; + uint32_t int2; +}; +.Ed +.Pp +The fields are used as follows: +.Bl -tag -width ".It Va var_index" +.It Va va_index +For the node operation callback this is the +index of the variable binding that should be returned if an error occurs. +Set by the library. +In all other functions this is undefined. +.It Va scratch +For the node operation callback this is a pointer to a per variable binding +scratch area that can be used to implement the commit and rollback. +Set by the library. +.It Va dep +In the dependency callback function (see below) this is a pointer to the +current dependency. +Set by the library. +.It Va data +This is the +.Fa data +argument from the call to the library and is not used by the library. +.El +.Pp +The next three functions execute different kinds of GET requests. +The function +.Fn snmp_get +executes an SNMP GET operation, the function +.Fn snmp_getnext +executes an SNMP GETNEXT operation and the function +.Fn snmp_getbulk +executes an SNMP GETBULK operation. +For all three functions the response PDU is constructed and encoded +on the fly. +If everything is ok, the response PDU is returned in +.Fa resp +and +.Fa resp_b . +The caller must call +.Fn snmp_pdu_free +to free the response PDU in this case. +One of the following values may be returned: +.Bl -tag -width ".It Li SNMP_RET_ERR" +.It Li SNMP_RET_OK +Operation successful, response PDU may be sent. +.It Li SNMP_RET_IGN +Operation failed, no response PDU constructed. +Request is ignored. +.It Li SNMP_RET_ERR +Error in operation. +The error code and index have been set in +.Fa pdu . +No response PDU has been constructed. +The caller may construct an error response PDU via +.Fn snmp_make_errresp . +.El +.Pp +The function +.Fn snmp_set +executes an SNMP SET operation. +The arguments are the same as for the previous +three functions. +The operation of this functions is, however, much more complex. +.Pp +The SET operation occurs in several stages: +.Bl -enum -offset indent +.It +For each binding search the corresponding nodes, check that the +variable is writeable and the syntax is ok. +The writeable check can be done only for scalars. +For columns it must be done in the node's operation callback function. +.It +For each binding call the node's operation callback with function SNMP_OP_SET. +The callback may create dependencies or finalizers (see below). +For simple +scalars the scratch area may be enough to handle commit and rollback, for +interdependent table columns dependencies may be necessary. +.It +If the previous step fails at any point, the node's operation callback +functions are called for all bindings for which SNMP_OP_SET was executed +with SNMP_OP_ROLLBACK, in the opposite order. +This allows all variables to undo the effect of the SET operation. +After this all the dependencies are freed +and the finalizers are executed with a fail flag of 1. +Then the function +returns to the caller with an appropriate error indication. +.It +If the SET step was successful for all bindings, the dependency callbacks +are executed in the order in which the dependencies were created with an +operation of SNMP_DEPOP_COMMIT. +If any of the dependencies fails, all the +committed dependencies are called again in the opposite order +with SNMP_DEPOP_ROLLBACK. +Than for all bindings from the last to the first +the node's operation callback is called with SNMP_OP_ROLLBACK to undo +the effect of SNMP_OP_SET. +At the end the dependencies are freed and the finalizers are called with +a fail flag of 1 and the function returns to the caller with an appropriate +error indication. +.It +If the dependency commits were successful, for each binding the node's +operation callback is called with SNMP_OP_COMMIT. +Any error returned from +the callbacks is ignored (an error message is generated via +.Fn snmp_error ). +.It +Now the dependencies are freed and the finalizers are called +with a fail flag of 0. +For each dependency just before freeing it +its callback is called with +.Li SNMP_DEPOP_FINISH. +Then the function returns +.Li SNMP_ERR_OK . +.El +.Pp +There are to mechanisms to help in complex SET operations: dependencies and +finalizers. +A dependency is used if several bindings depend on each other. +A typical example is the creation of a conceptual row, which requires +the setting of several columns to succeed. +A dependency is identified by +two OIDs. +In the table case, the first oid is typically the table's base OID +and the second one the index. +Both of these can easily be generated from the +variables OID with +.Fn asn_slice_oid . +The function +.Fn snmp_dep_lookup +tries to find a dependency based on these two OIDs and, if it cannot find one +creates a new one. +This means for the table example, that the function +returns the same dependency for each of the columns of the same table row. +This allows during the SNMP_OP_SET processing to collect all information +about the row into the dependency. +The arguments to +.Fn snmp_dep_lookup +are: the two OIDs to identify the dependency (they are copied into newly +created dependencies), the size of the structure to allocate and +the dependency callback. +.Pp +When all SNMP_OP_SET operations have succeeded the dependencies are executed. +At this stage the dependency callback has all information about the given +table row that was available in this SET PDU and can operate accordingly. +.Pp +It is guaranteed that each dependency callback is executed at minimum once +- with an operation of +.Li SNMP_OP_ROLLBACK . +This ensures that all dynamically allocated resources in a callback can be +freed correctly. +.Pp +The function +.Fn snmp_make_errresp +makes an error response if an operation has failed. +It takes the original request PDU (it will look only on the error code and +index fields), the buffer containing the original PDU and a buffer for the +error PDU. +It copies the bindings field from the original PDUs buffer directly to +the response PDU and thus does not depend on the decodability of this field. +It may return the same values as the operation functions. +.Pp +The next four functions allow some parts of the SET operation to be executed. +This is only used in +.Xr bsnmpd 1 +to implement the configuration as a single transaction. +The function +.Fn snmp_init_context +creates and initializes a context. +The function +.Fn snmp_dep_commit +executes SNMP_DEPOP_COMMIT for all dependencies in the context stopping at +the first error. +The function +.Fn snmp_dep_rollback +executes SNMP_DEPOP_ROLLBACK starting at the previous of the current +dependency in the context. +The function +.Fn snmp_dep_finish +executes SNMP_DEPOP_FINISH for all dependencies. +.Sh DIAGNOSTICS +If an error occurs in any of the function an error indication as described +above is returned. +Additionally the functions may call snmp_error on unexpected errors. +.Sh SEE ALSO +.Xr gensnmptree 1 , +.Xr bsnmpd 1 , +.Xr bsnmpclient 3 , +.Xr bsnmplib 3 , +.Xr snmpmod 3 +.Sh STANDARDS +This implementation conforms to the applicable IETF RFCs and ITU-T +recommendations. +.Sh AUTHORS +.An Hartmut Brandt Aq harti@FreeBSD.org Property changes on: vendor/1.14/lib/bsnmpagent.3 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/lib/bsnmplib.3 =================================================================== --- vendor/1.14/lib/bsnmplib.3 (nonexistent) +++ vendor/1.14/lib/bsnmplib.3 (revision 359491) @@ -0,0 +1,514 @@ +.\" +.\" Copyright (c) 2010 The FreeBSD Foundation +.\" All rights reserved. +.\" +.\" Portions of this documentation were written by Shteryana Sotirova Shopova +.\" under sponsorship from the FreeBSD Foundation. +.\" +.\" Copyright (c) 2004-2005 +.\" Hartmut Brandt. +.\" All rights reserved. +.\" Copyright (c) 2001-2003 +.\" Fraunhofer Institute for Open Communication Systems (FhG Fokus). +.\" All rights reserved. +.\" +.\" Author: Harti Brandt +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Begemot: bsnmp/lib/bsnmplib.3,v 1.9 2005/10/04 08:46:51 brandt_h Exp $ +.\" +.Dd December 31, 2016 +.Dt BSNMPLIB 3 +.Os +.Sh NAME +.Nm snmp_value_free , +.Nm snmp_value_parse , +.Nm snmp_value_copy , +.Nm snmp_pdu_free , +.Nm snmp_pdu_decode , +.Nm snmp_pdu_encode , +.Nm snmp_pdu_decode_header , +.Nm snmp_pdu_decode_scoped , +.Nm snmp_pdu_decode_secmode , +.Nm snmp_pdu_init_secparams , +.Nm snmp_pdu_dump , +.Nm snmp_passwd_to_keys , +.Nm snmp_get_local_keys , +.Nm snmp_calc_keychange , +.Nm TRUTH_MK , +.Nm TRUTH_GET , +.Nm TRUTH_OK +.Nd "SNMP decoding and encoding library" +.Sh LIBRARY +Begemot SNMP library +.Pq libbsnmp, -lbsnmp +.Sh SYNOPSIS +.In bsnmp/asn1.h +.In bsnmp/snmp.h +.Ft void +.Fn snmp_value_free "struct snmp_value *value" +.Ft int +.Fn snmp_value_parse "const char *buf" "enum snmp_syntax" "union snmp_values *value" +.Ft int +.Fn snmp_value_copy "struct snmp_value *to" "const struct snmp_value *from" +.Ft void +.Fn snmp_pdu_free "struct snmp_pdu *value" +.Ft enum snmp_code +.Fn snmp_pdu_decode "struct asn_buf *buf" "struct snmp_pdu *pdu" "int32_t *ip" +.Ft enum snmp_code +.Fn snmp_pdu_encode "struct snmp_pdu *pdu" "struct asn_buf *buf" +.Ft enum snmp_code +.Fn snmp_pdu_decode_header "struct snmp_pdu *pdu" "struct asn_buf *buf" +.Ft enum snmp_code +.Fn snmp_pdu_decode_scoped "struct asn_buf *buf" "struct snmp_pdu *pdu" "int32_t *ip" +.Ft enum snmp_code +.Fn snmp_pdu_decode_secmode "struct asn_buf *buf" "struct snmp_pdu *pdu" +.Ft void +.Fn snmp_pdu_init_secparams "struct snmp_pdu *pdu" +.Ft void +.Fn snmp_pdu_dump "const struct snmp_pdu *pdu" +.Ft enum snmp_code +.Fn snmp_passwd_to_keys "struct snmp_user *user" "char *passwd" +.Ft enum snmp_code +.Fn snmp_get_local_keys "struct snmp_user *user" "uint8_t *eid" "uint32_t elen" +.Ft enum snmp_code +.Fn snmp_calc_keychange "struct snmp_user *user" "uint8_t *keychange" +.Ft int +.Fn TRUTH_MK "F" +.Ft int +.Fn TRUTH_GET "T" +.Ft int +.Fn TRUTH_OK "T" +.Sh DESCRIPTION +The SNMP library contains routines to handle SNMP version 1, 2 and 3 PDUs. +There are several basic structures used throughout the library: +.Bd -literal -offset indent +struct snmp_value { + struct asn_oid var; + enum snmp_syntax syntax; + union snmp_values { + int32_t integer;/* also integer32 */ + struct { + u_int len; + u_char *octets; + } octetstring; + struct asn_oid oid; + u_char ipaddress[4]; + uint32_t uint32; /* also gauge32, counter32, + unsigned32, timeticks */ + uint64_t counter64; + } v; +}; +.Ed +.Pp +This structure represents one variable binding from an SNMP PDU. +The field +.Fa var +is the ASN.1 of the variable that is bound. +.Fa syntax +contains either the syntax code of the value or an exception code for SNMPv2 +and may be one of: +.Bd -literal -offset indent +enum snmp_syntax { + SNMP_SYNTAX_NULL = 0, + SNMP_SYNTAX_INTEGER, /* == INTEGER32 */ + SNMP_SYNTAX_OCTETSTRING, + SNMP_SYNTAX_OID, + SNMP_SYNTAX_IPADDRESS, + SNMP_SYNTAX_COUNTER, + SNMP_SYNTAX_GAUGE, /* == UNSIGNED32 */ + SNMP_SYNTAX_TIMETICKS, + + /* v2 additions */ + SNMP_SYNTAX_COUNTER64, + /* exceptions */ + SNMP_SYNTAX_NOSUCHOBJECT, + SNMP_SYNTAX_NOSUCHINSTANCE, + SNMP_SYNTAX_ENDOFMIBVIEW, +}; +.Ed +The field +.Fa v +holds the actual value depending on +.Fa syntax . +Note, that if +.Fa syntax +is +.Li SNMP_SYNTAX_OCTETSTRING +and +.Fa v.octetstring.len +is not zero, +.Fa v.octetstring.octets +points to a string allocated by +.Xr malloc 3 . +.Bd -literal -offset indent +#define SNMP_ENGINE_ID_SIZ 32 + +struct snmp_engine { + uint8_t engine_id[SNMP_ENGINE_ID_SIZ]; + uint32_t engine_len; + int32_t engine_boots; + int32_t engine_time; + int32_t max_msg_size; +}; +.Ed +.Pp +This structure represents an SNMP engine as specified by the SNMP Management +Architecture described in RFC 3411. +.Bd -literal -offset indent +#define SNMP_ADM_STR32_SIZ (32 + 1) +#define SNMP_AUTH_KEY_SIZ 40 +#define SNMP_PRIV_KEY_SIZ 32 + +enum snmp_usm_level { + SNMP_noAuthNoPriv = 1, + SNMP_authNoPriv = 2, + SNMP_authPriv = 3 +}; + +struct snmp_user { + char sec_name[SNMP_ADM_STR32_SIZ]; + enum snmp_authentication auth_proto; + enum snmp_privacy priv_proto; + uint8_t auth_key[SNMP_AUTH_KEY_SIZ]; + uint8_t priv_key[SNMP_PRIV_KEY_SIZ]; +}; +.Ed +.Pp +This structure represents an SNMPv3 user as specified by the User-based +Security Model (USM) described in RFC 3414. The field +.Fa sec_name +is a human readable string containing the security user name. +.Fa auth_proto +contains the id of the authentication protocol in use by the user and may be one +of: +.Bd -literal -offset indent +enum snmp_authentication { + SNMP_AUTH_NOAUTH = 0, + SNMP_AUTH_HMAC_MD5, + SNMP_AUTH_HMAC_SHA +}; +.Ed +.Fa priv_proto +contains the id of the privacy protocol in use by the user and may be one +of: +.Bd -literal -offset indent +enum snmp_privacy { + SNMP_PRIV_NOPRIV = 0, + SNMP_PRIV_DES = 1, + SNMP_PRIV_AES +}; +.Ed +.Fa auth_key +and +.Fa priv_key +contain the authentication and privacy keys for the user. +.Bd -literal -offset indent +#define SNMP_COMMUNITY_MAXLEN 128 +#define SNMP_MAX_BINDINGS 100 +#define SNMP_CONTEXT_NAME_SIZ (32 + 1) +#define SNMP_TIME_WINDOW 150 + +#define SNMP_USM_AUTH_SIZE 12 +#define SNMP_USM_PRIV_SIZE 8 + +#define SNMP_MSG_AUTH_FLAG 0x1 +#define SNMP_MSG_PRIV_FLAG 0x2 +#define SNMP_MSG_REPORT_FLAG 0x4 + +#define SNMP_MPM_SNMP_V1 0 +#define SNMP_MPM_SNMP_V2c 1 +#define SNMP_MPM_SNMP_V3 3 + +struct snmp_pdu { + char community[SNMP_COMMUNITY_MAXLEN + 1]; + enum snmp_version version; + u_int type; + + /* SNMPv3 PDU header fields */ + int32_t identifier; + uint8_t flags; + int32_t security_model; + struct snmp_engine engine; + + /* Associated USM user parameters */ + struct snmp_user user; + uint8_t msg_digest[SNMP_USM_AUTH_SIZE]; + uint8_t msg_salt[SNMP_USM_PRIV_SIZE]; + + /* View-based Access Model */ + uint32_t context_engine_len; + uint8_t context_engine[SNMP_ENGINE_ID_SIZ]; + char context_name[SNMP_CONTEXT_NAME_SIZ]; + + /* trap only */ + struct asn_oid enterprise; + u_char agent_addr[4]; + int32_t generic_trap; + int32_t specific_trap; + uint32_t time_stamp; + + /* others */ + int32_t request_id; + int32_t error_status; + int32_t error_index; + + /* fixes for encoding */ + size_t outer_len; + size_t scoped_len; + u_char *outer_ptr; + u_char *digest_ptr; + u_char *encrypted_ptr; + u_char *scoped_ptr; + u_char *pdu_ptr; + u_char *vars_ptr; + + + struct snmp_value bindings[SNMP_MAX_BINDINGS]; + u_int nbindings; +}; +.Ed +This structure contains a decoded SNMP PDU. +.Fa version +is one of +.Bd -literal -offset indent +enum snmp_version { + SNMP_Verr = 0, + SNMP_V1 = 1, + SNMP_V2c, + SNMP_V3 +}; +.Ed +and +.Fa type +is the type of the PDU. +.Fa security_model +is the security model used for SNMPv3 PDUs. The only supported +value currently is 3 (User-based Security Model). Additional values for any, +unknown, SNMPv1 and SNMPv2c security models are also enumerated +.Bd -literal -offset indent +enum snmp_secmodel { + SNMP_SECMODEL_ANY = 0, + SNMP_SECMODEL_SNMPv1 = 1, + SNMP_SECMODEL_SNMPv2c = 2, + SNMP_SECMODEL_USM = 3, + SNMP_SECMODEL_UNKNOWN +}; +.Ed +.Pp +The function +.Fn snmp_value_free +is used to free all the dynamic allocated contents of an SNMP value. +It does not free the structure pointed to by +.Fa value +itself. +.Pp +The function +.Fn snmp_value_parse +parses the ASCII representation of an SNMP value into its binary form. +This function is mainly used by the configuration file reader of +.Xr bsnmpd 1 . +.Pp +The function +.Fn snmp_value_copy +makes a deep copy of the value pointed to by +.Fa from +to the structure pointed to by +.Fa to . +It assumes that +.Fa to +is uninitialized and will overwrite its previous contents. +It does not itself allocate the structure pointed to by +.Fa to . +.Pp +The function +.Fn snmp_pdu_free +frees all the dynamically allocated components of the PDU. +It does not itself free the structure pointed to by +.Fa pdu . +.Pp +The function +.Fn snmp_pdu_decode +decodes the PDU pointed to by +.Fa buf +and stores the result into +.Fa pdu . +If an error occurs in a variable binding the (1 based) index of this binding +is stored in the variable pointed to by +.Fa ip . +.Pp +The function +.Fn snmp_pdu_encode +encodes the PDU +.Fa pdu +into the an octetstring in buffer, and if authentication and privacy are used, +calculates a message digest and encrypts the PDU data in the buffer +.Fa buf . +.Pp +The function +.Fn snmp_pdu_decode_header +decodes the header of the PDU pointed to by +.Fa buf . +The uncoded PDU contents remain in the buffer. +.Pp +The function +.Fn snmp_pdu_decode_scoped +decodes the scoped PDU pointed to by +.Fa buf . +.Pp +The function +.Fn snmp_pdu_decode_secmode +verifies the authentication parameter contained in the PDU (if present) and +if the PDU is encrypted, decrypts the PDU contents pointed to by +.Fa buf . +If successful, a plain text scoped PDU is stored in the buffer. +.Pp +The function +.Fn snmp_pdu_init_secparams +calculates the initialization vector for the privacy protocol in use before +the PDU pointed to by +.Fa pdu +may be encrypted or decrypted. +.Pp +The function +.Fn snmp_pdu_dump +dumps the PDU in a human readable form by calling +.Fn snmp_printf . +.Pp +The function +.Fn snmp_passwd_to_keys +calculates a binary private authentication key corresponding to a plain text human +readable password string. The calculated key is placed in the +.Fa auth_key +field of the +.Fa user . +.Pp +The function +.Fn snmp_get_local_keys +calculates a localazied authentication and privacy keys for a specified SNMPv3 +engine. The calculateds keys are placed in the +.Fa auth_key +and +.Fa priv_key +fields of the +.Fa user . +.Pp +The function +.Fn snmp_calc_keychange +calculates a binary key change octet string based on the contents of an old and +a new binary localized key. The rezult is placed in the buffer pointer to by +.Fa keychange +and may be used by an SNMPv3 user who wishes to change his/her password +or localized key. +.Pp +The function +.Fn TRUTH_MK +takes a C truth value (zero or non-zero) and makes an SNMP truth value (2 or 1). +The function +.Fn TRUTH_GET +takes an SNMP truth value and makes a C truth value (0 or 1). +The function +.Fn TRUTH_OK +checks, whether its argument is a legal SNMP truth value. +.Sh DIAGNOSTICS +When an error occurs in any of the function the function pointed to +by the global pointer +.Bd -literal -offset indent +extern void (*snmp_error)(const char *, ...); +.Ed +.Pp +with a +.Xr printf 3 +style format string. +There is a default error handler in the library that prints a message +starting with +.Sq SNMP: +followed by the error message to standard error. +.Pp +The function pointed to by +.Bd -literal -offset indent +extern void (*snmp_printf)(const char *, ...); +.Ed +.Pp +is called by the +.Fn snmp_pdu_dump +function. +The default handler is +.Xr printf 3 . +.Sh ERRORS +.Fn snmp_pdu_decode +will return one of the following return codes: +.Bl -tag -width Er +.It Bq Er SNMP_CODE_OK +Success. +.It Bq Er SNMP_CODE_FAILED +The ASN.1 coding was wrong. +.It Bq Er SNMP_CODE_BADLEN +A variable binding value had a wrong length field. +.It Bq Er SNMP_CODE_OORANGE +A variable binding value was out of the allowed range. +.It Bq Er SNMP_CODE_BADVERS +The PDU is of an unsupported version. +.It Bq Er SNMP_CODE_BADENQ +There was an ASN.1 value with an unsupported tag. +.It Bq Er SNMP_CODE_BADSECLEVEL +The requested securityLevel contained in the PDU is not supported. +.It Bq Er SNMP_CODE_BADDIGEST +The PDU authentication parameter received in the PDU did not match the +calculated message digest. +.It Bq Er SNMP_CODE_EDECRYPT +Error occurred while trying to decrypt the PDU. +.El +.Pp +.Fn snmp_pdu_encode +will return one of the following return codes: +.Bl -tag -width Er +.It Bq Er SNMP_CODE_OK +Success. +.It Bq Er SNMP_CODE_FAILED +Encoding failed. +.El +.Sh SEE ALSO +.Xr gensnmptree 1 , +.Xr bsnmpd 1 , +.Xr bsnmpagent 3 , +.Xr bsnmpclient 3 , +.Xr bsnmplib 3 +.Sh CAVEAT +The SNMPv3 message digests, encryption and decryption, and key routines use +the cryptographic functions from +.Xr crypto 3 . +The library may optionally be built without references to the +.Xr crypto 3 +library. In such case only plain text SNMPv3 PDUs without message digests +may be proccessed correctly. +.Sh STANDARDS +This implementation conforms to the applicable IETF RFCs and ITU-T +recommendations. +.Sh AUTHORS +The Begemot SNMP library was originally written by +.An Hartmut Brandt Aq harti@FreeBSD.org +.Pp +.An Shteryana Shopova Aq syrinx@FreeBSD.org +added support for the SNMPv3 message proccessing and User-Based +Security model message authentication and privacy. Property changes on: vendor/1.14/lib/bsnmplib.3 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/lib/snmp.c =================================================================== --- vendor/1.14/lib/snmp.c (nonexistent) +++ vendor/1.14/lib/snmp.c (revision 359491) @@ -0,0 +1,1448 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Copyright (c) 2010 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Shteryana Sotirova Shopova + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/lib/snmp.c,v 1.40 2005/10/04 14:32:42 brandt_h Exp $ + * + * SNMP + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_STDINT_H +#include +#elif defined(HAVE_INTTYPES_H) +#include +#endif +#include +#include + +#include "asn1.h" +#include "snmp.h" +#include "snmppriv.h" + +static void snmp_error_func(const char *, ...); +static void snmp_printf_func(const char *, ...); + +void (*snmp_error)(const char *, ...) = snmp_error_func; +void (*snmp_printf)(const char *, ...) = snmp_printf_func; + +/* + * Get the next variable binding from the list. + * ASN errors on the sequence or the OID are always fatal. + */ +static enum asn_err +get_var_binding(struct asn_buf *b, struct snmp_value *binding) +{ + u_char type; + asn_len_t len, trailer; + enum asn_err err; + + if (asn_get_sequence(b, &len) != ASN_ERR_OK) { + snmp_error("cannot parse varbind header"); + return (ASN_ERR_FAILED); + } + + /* temporary truncate the length so that the parser does not + * eat up bytes behind the sequence in the case the encoding is + * wrong of inner elements. */ + trailer = b->asn_len - len; + b->asn_len = len; + + if (asn_get_objid(b, &binding->var) != ASN_ERR_OK) { + snmp_error("cannot parse binding objid"); + return (ASN_ERR_FAILED); + } + if (asn_get_header(b, &type, &len) != ASN_ERR_OK) { + snmp_error("cannot parse binding value header"); + return (ASN_ERR_FAILED); + } + + switch (type) { + + case ASN_TYPE_NULL: + binding->syntax = SNMP_SYNTAX_NULL; + err = asn_get_null_raw(b, len); + break; + + case ASN_TYPE_INTEGER: + binding->syntax = SNMP_SYNTAX_INTEGER; + err = asn_get_integer_raw(b, len, &binding->v.integer); + break; + + case ASN_TYPE_OCTETSTRING: + binding->syntax = SNMP_SYNTAX_OCTETSTRING; + binding->v.octetstring.octets = malloc(len); + if (binding->v.octetstring.octets == NULL) { + snmp_error("%s", strerror(errno)); + return (ASN_ERR_FAILED); + } + binding->v.octetstring.len = len; + err = asn_get_octetstring_raw(b, len, + binding->v.octetstring.octets, + &binding->v.octetstring.len); + if (ASN_ERR_STOPPED(err)) { + free(binding->v.octetstring.octets); + binding->v.octetstring.octets = NULL; + } + break; + + case ASN_TYPE_OBJID: + binding->syntax = SNMP_SYNTAX_OID; + err = asn_get_objid_raw(b, len, &binding->v.oid); + break; + + case ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS: + binding->syntax = SNMP_SYNTAX_IPADDRESS; + err = asn_get_ipaddress_raw(b, len, binding->v.ipaddress); + break; + + case ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS: + binding->syntax = SNMP_SYNTAX_TIMETICKS; + err = asn_get_uint32_raw(b, len, &binding->v.uint32); + break; + + case ASN_CLASS_APPLICATION|ASN_APP_COUNTER: + binding->syntax = SNMP_SYNTAX_COUNTER; + err = asn_get_uint32_raw(b, len, &binding->v.uint32); + break; + + case ASN_CLASS_APPLICATION|ASN_APP_GAUGE: + binding->syntax = SNMP_SYNTAX_GAUGE; + err = asn_get_uint32_raw(b, len, &binding->v.uint32); + break; + + case ASN_CLASS_APPLICATION|ASN_APP_COUNTER64: + binding->syntax = SNMP_SYNTAX_COUNTER64; + err = asn_get_counter64_raw(b, len, &binding->v.counter64); + break; + + case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHOBJECT: + binding->syntax = SNMP_SYNTAX_NOSUCHOBJECT; + err = asn_get_null_raw(b, len); + break; + + case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHINSTANCE: + binding->syntax = SNMP_SYNTAX_NOSUCHINSTANCE; + err = asn_get_null_raw(b, len); + break; + + case ASN_CLASS_CONTEXT | ASN_EXCEPT_ENDOFMIBVIEW: + binding->syntax = SNMP_SYNTAX_ENDOFMIBVIEW; + err = asn_get_null_raw(b, len); + break; + + default: + if ((err = asn_skip(b, len)) == ASN_ERR_OK) + err = ASN_ERR_TAG; + snmp_error("bad binding value type 0x%x", type); + break; + } + + if (ASN_ERR_STOPPED(err)) { + snmp_error("cannot parse binding value"); + return (err); + } + + if (b->asn_len != 0) + snmp_error("ignoring junk at end of binding"); + + b->asn_len = trailer; + + return (err); +} + +/* + * Parse the different PDUs contents. Any ASN error in the outer components + * are fatal. Only errors in variable values may be tolerated. If all + * components can be parsed it returns either ASN_ERR_OK or the first + * error that was found. + */ +enum asn_err +snmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp) +{ + if (pdu->type == SNMP_PDU_TRAP) { + if (asn_get_objid(b, &pdu->enterprise) != ASN_ERR_OK) { + snmp_error("cannot parse trap enterprise"); + return (ASN_ERR_FAILED); + } + if (asn_get_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK) { + snmp_error("cannot parse trap agent address"); + return (ASN_ERR_FAILED); + } + if (asn_get_integer(b, &pdu->generic_trap) != ASN_ERR_OK) { + snmp_error("cannot parse 'generic-trap'"); + return (ASN_ERR_FAILED); + } + if (asn_get_integer(b, &pdu->specific_trap) != ASN_ERR_OK) { + snmp_error("cannot parse 'specific-trap'"); + return (ASN_ERR_FAILED); + } + if (asn_get_timeticks(b, &pdu->time_stamp) != ASN_ERR_OK) { + snmp_error("cannot parse trap 'time-stamp'"); + return (ASN_ERR_FAILED); + } + } else { + if (asn_get_integer(b, &pdu->request_id) != ASN_ERR_OK) { + snmp_error("cannot parse 'request-id'"); + return (ASN_ERR_FAILED); + } + if (asn_get_integer(b, &pdu->error_status) != ASN_ERR_OK) { + snmp_error("cannot parse 'error_status'"); + return (ASN_ERR_FAILED); + } + if (asn_get_integer(b, &pdu->error_index) != ASN_ERR_OK) { + snmp_error("cannot parse 'error_index'"); + return (ASN_ERR_FAILED); + } + } + + if (asn_get_sequence(b, lenp) != ASN_ERR_OK) { + snmp_error("cannot get varlist header"); + return (ASN_ERR_FAILED); + } + + return (ASN_ERR_OK); +} + +static enum asn_err +parse_pdus(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip) +{ + asn_len_t len, trailer; + struct snmp_value *v; + enum asn_err err, err1; + + err = snmp_parse_pdus_hdr(b, pdu, &len); + if (ASN_ERR_STOPPED(err)) + return (err); + + trailer = b->asn_len - len; + + v = pdu->bindings; + err = ASN_ERR_OK; + while (b->asn_len != 0) { + if (pdu->nbindings == SNMP_MAX_BINDINGS) { + snmp_error("too many bindings (> %u) in PDU", + SNMP_MAX_BINDINGS); + return (ASN_ERR_FAILED); + } + err1 = get_var_binding(b, v); + if (ASN_ERR_STOPPED(err1)) + return (ASN_ERR_FAILED); + if (err1 != ASN_ERR_OK && err == ASN_ERR_OK) { + err = err1; + *ip = pdu->nbindings + 1; + } + pdu->nbindings++; + v++; + } + + b->asn_len = trailer; + + return (err); +} + + +static enum asn_err +parse_secparams(struct asn_buf *b, struct snmp_pdu *pdu) +{ + asn_len_t octs_len; + u_char buf[256]; /* XXX: calc max possible size here */ + struct asn_buf tb; + + memset(buf, 0, 256); + tb.asn_ptr = buf; + tb.asn_len = 256; + u_int len = 256; + + if (asn_get_octetstring(b, buf, &len) != ASN_ERR_OK) { + snmp_error("cannot parse usm header"); + return (ASN_ERR_FAILED); + } + tb.asn_len = len; + + if (asn_get_sequence(&tb, &octs_len) != ASN_ERR_OK) { + snmp_error("cannot decode usm header"); + return (ASN_ERR_FAILED); + } + + octs_len = SNMP_ENGINE_ID_SIZ; + if (asn_get_octetstring(&tb, (u_char *)&pdu->engine.engine_id, + &octs_len) != ASN_ERR_OK) { + snmp_error("cannot decode msg engine id"); + return (ASN_ERR_FAILED); + } + pdu->engine.engine_len = octs_len; + + if (asn_get_integer(&tb, &pdu->engine.engine_boots) != ASN_ERR_OK) { + snmp_error("cannot decode msg engine boots"); + return (ASN_ERR_FAILED); + } + + if (asn_get_integer(&tb, &pdu->engine.engine_time) != ASN_ERR_OK) { + snmp_error("cannot decode msg engine time"); + return (ASN_ERR_FAILED); + } + + octs_len = SNMP_ADM_STR32_SIZ - 1; + if (asn_get_octetstring(&tb, (u_char *)&pdu->user.sec_name, &octs_len) + != ASN_ERR_OK) { + snmp_error("cannot decode msg user name"); + return (ASN_ERR_FAILED); + } + pdu->user.sec_name[octs_len] = '\0'; + + octs_len = sizeof(pdu->msg_digest); + if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_digest, &octs_len) != + ASN_ERR_OK || ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0 && + octs_len != sizeof(pdu->msg_digest))) { + snmp_error("cannot decode msg authentication param"); + return (ASN_ERR_FAILED); + } + + octs_len = sizeof(pdu->msg_salt); + if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_salt, &octs_len) != + ASN_ERR_OK ||((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && + octs_len != sizeof(pdu->msg_salt))) { + snmp_error("cannot decode msg authentication param"); + return (ASN_ERR_FAILED); + } + + if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) { + pdu->digest_ptr = b->asn_ptr - SNMP_USM_AUTH_SIZE; + pdu->digest_ptr -= octs_len + ASN_MAXLENLEN; + } + + return (ASN_ERR_OK); +} + +static enum snmp_code +pdu_encode_secparams(struct asn_buf *b, struct snmp_pdu *pdu) +{ + u_char buf[256], *sptr; + struct asn_buf tb; + size_t auth_off, moved = 0; + + auth_off = 0; + memset(buf, 0, 256); + tb.asn_ptr = buf; + tb.asn_len = 256; + + if (asn_put_temp_header(&tb, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED), + &sptr) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + if (asn_put_octetstring(&tb, (u_char *)pdu->engine.engine_id, + pdu->engine.engine_len) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + if (asn_put_integer(&tb, pdu->engine.engine_boots) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + if (asn_put_integer(&tb, pdu->engine.engine_time) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + if (asn_put_octetstring(&tb, (u_char *)pdu->user.sec_name, + strlen(pdu->user.sec_name)) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) { + auth_off = sizeof(buf) - tb.asn_len + ASN_MAXLENLEN; + if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest, + sizeof(pdu->msg_digest)) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + } else { + if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest, 0) + != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + } + + if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0) { + if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt, + sizeof(pdu->msg_salt)) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + } else { + if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt, 0) + != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + } + + if (asn_commit_header(&tb, sptr, &moved) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) + pdu->digest_ptr = b->asn_ptr + auth_off - moved; + + if (asn_put_octetstring(b, buf, sizeof(buf) - tb.asn_len) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + pdu->digest_ptr += ASN_MAXLENLEN; + + if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && asn_put_temp_header(b, + ASN_TYPE_OCTETSTRING, &pdu->encrypted_ptr) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + return (SNMP_CODE_OK); +} + +/* + * Decode the PDU except for the variable bindings itself. + * If decoding fails because of a bad binding, but the rest can be + * decoded, ip points to the index of the failed variable (errors + * OORANGE, BADLEN or BADVERS). + */ +enum snmp_code +snmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip) +{ + enum snmp_code code; + + if ((code = snmp_pdu_decode_header(b, pdu)) != SNMP_CODE_OK) + return (code); + + if (pdu->version == SNMP_V3) { + if (pdu->security_model != SNMP_SECMODEL_USM) + return (SNMP_CODE_FAILED); + if ((code = snmp_pdu_decode_secmode(b, pdu)) != SNMP_CODE_OK) + return (code); + } + + code = snmp_pdu_decode_scoped(b, pdu, ip); + + switch (code) { + case SNMP_CODE_FAILED: + snmp_pdu_free(pdu); + break; + + case SNMP_CODE_BADENC: + if (pdu->version == SNMP_Verr) + return (SNMP_CODE_BADVERS); + + default: + break; + } + + return (code); +} + +enum snmp_code +snmp_pdu_decode_header(struct asn_buf *b, struct snmp_pdu *pdu) +{ + int32_t version; + u_int octs_len; + asn_len_t len; + + pdu->outer_ptr = b->asn_ptr; + pdu->outer_len = b->asn_len; + + if (asn_get_sequence(b, &len) != ASN_ERR_OK) { + snmp_error("cannot decode pdu header"); + return (SNMP_CODE_FAILED); + } + if (b->asn_len < len) { + snmp_error("outer sequence value too short"); + return (SNMP_CODE_FAILED); + } + if (b->asn_len != len) { + snmp_error("ignoring trailing junk in message"); + b->asn_len = len; + } + + if (asn_get_integer(b, &version) != ASN_ERR_OK) { + snmp_error("cannot decode version"); + return (SNMP_CODE_FAILED); + } + + if (version == 0) + pdu->version = SNMP_V1; + else if (version == 1) + pdu->version = SNMP_V2c; + else if (version == 3) + pdu->version = SNMP_V3; + else { + pdu->version = SNMP_Verr; + snmp_error("unsupported SNMP version"); + return (SNMP_CODE_BADENC); + } + + if (pdu->version == SNMP_V3) { + if (asn_get_sequence(b, &len) != ASN_ERR_OK) { + snmp_error("cannot decode pdu global data header"); + return (SNMP_CODE_FAILED); + } + + if (asn_get_integer(b, &pdu->identifier) != ASN_ERR_OK) { + snmp_error("cannot decode msg indetifier"); + return (SNMP_CODE_FAILED); + } + + if (asn_get_integer(b, &pdu->engine.max_msg_size) + != ASN_ERR_OK) { + snmp_error("cannot decode msg size"); + return (SNMP_CODE_FAILED); + } + + octs_len = 1; + if (asn_get_octetstring(b, (u_char *)&pdu->flags, + &octs_len) != ASN_ERR_OK) { + snmp_error("cannot decode msg flags"); + return (SNMP_CODE_FAILED); + } + + if (asn_get_integer(b, &pdu->security_model) != ASN_ERR_OK) { + snmp_error("cannot decode msg size"); + return (SNMP_CODE_FAILED); + } + + if (pdu->security_model != SNMP_SECMODEL_USM) + return (SNMP_CODE_FAILED); + + if (parse_secparams(b, pdu) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + } else { + octs_len = SNMP_COMMUNITY_MAXLEN; + if (asn_get_octetstring(b, (u_char *)pdu->community, + &octs_len) != ASN_ERR_OK) { + snmp_error("cannot decode community"); + return (SNMP_CODE_FAILED); + } + pdu->community[octs_len] = '\0'; + } + + return (SNMP_CODE_OK); +} + +enum snmp_code +snmp_pdu_decode_scoped(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip) +{ + u_char type; + asn_len_t len, trailer; + enum asn_err err; + + if (pdu->version == SNMP_V3) { + if (asn_get_sequence(b, &len) != ASN_ERR_OK) { + snmp_error("cannot decode scoped pdu header"); + return (SNMP_CODE_FAILED); + } + + len = SNMP_ENGINE_ID_SIZ; + if (asn_get_octetstring(b, (u_char *)&pdu->context_engine, + &len) != ASN_ERR_OK) { + snmp_error("cannot decode msg context engine"); + return (SNMP_CODE_FAILED); + } + pdu->context_engine_len = len; + + len = SNMP_CONTEXT_NAME_SIZ; + if (asn_get_octetstring(b, (u_char *)&pdu->context_name, + &len) != ASN_ERR_OK) { + snmp_error("cannot decode msg context name"); + return (SNMP_CODE_FAILED); + } + pdu->context_name[len] = '\0'; + } + + if (asn_get_header(b, &type, &len) != ASN_ERR_OK) { + snmp_error("cannot get pdu header"); + return (SNMP_CODE_FAILED); + } + if ((type & ~ASN_TYPE_MASK) != + (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) { + snmp_error("bad pdu header tag"); + return (SNMP_CODE_FAILED); + } + pdu->type = type & ASN_TYPE_MASK; + + switch (pdu->type) { + + case SNMP_PDU_GET: + case SNMP_PDU_GETNEXT: + case SNMP_PDU_RESPONSE: + case SNMP_PDU_SET: + break; + + case SNMP_PDU_TRAP: + if (pdu->version != SNMP_V1) { + snmp_error("bad pdu type %u", pdu->type); + return (SNMP_CODE_FAILED); + } + break; + + case SNMP_PDU_GETBULK: + case SNMP_PDU_INFORM: + case SNMP_PDU_TRAP2: + case SNMP_PDU_REPORT: + if (pdu->version == SNMP_V1) { + snmp_error("bad pdu type %u", pdu->type); + return (SNMP_CODE_FAILED); + } + break; + + default: + snmp_error("bad pdu type %u", pdu->type); + return (SNMP_CODE_FAILED); + } + + trailer = b->asn_len - len; + b->asn_len = len; + + err = parse_pdus(b, pdu, ip); + if (ASN_ERR_STOPPED(err)) + return (SNMP_CODE_FAILED); + + if (b->asn_len != 0) + snmp_error("ignoring trailing junk after pdu"); + + b->asn_len = trailer; + + return (SNMP_CODE_OK); +} + +enum snmp_code +snmp_pdu_decode_secmode(struct asn_buf *b, struct snmp_pdu *pdu) +{ + u_char type; + enum snmp_code code; + uint8_t digest[SNMP_USM_AUTH_SIZE]; + + if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH && + (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0) + return (SNMP_CODE_BADSECLEVEL); + + if ((code = snmp_pdu_calc_digest(pdu, digest)) != + SNMP_CODE_OK) + return (SNMP_CODE_FAILED); + + if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH && + memcmp(digest, pdu->msg_digest, sizeof(pdu->msg_digest)) != 0) + return (SNMP_CODE_BADDIGEST); + + if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV && (asn_get_header(b, &type, + &pdu->scoped_len) != ASN_ERR_OK || type != ASN_TYPE_OCTETSTRING)) { + snmp_error("cannot decode encrypted pdu"); + return (SNMP_CODE_FAILED); + } + pdu->scoped_ptr = b->asn_ptr; + + if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV && + (pdu->flags & SNMP_MSG_PRIV_FLAG) == 0) + return (SNMP_CODE_BADSECLEVEL); + + if ((code = snmp_pdu_decrypt(pdu)) != SNMP_CODE_OK) + return (SNMP_CODE_FAILED); + + return (code); +} + +/* + * Check whether what we have is the complete PDU by snooping at the + * enclosing structure header. This returns: + * -1 if there are ASN.1 errors + * 0 if we need more data + * > 0 the length of this PDU + */ +int +snmp_pdu_snoop(const struct asn_buf *b0) +{ + u_int length; + asn_len_t len; + struct asn_buf b = *b0; + + /* <0x10|0x20> */ + + if (b.asn_len == 0) + return (0); + if (b.asn_cptr[0] != (ASN_TYPE_SEQUENCE | ASN_TYPE_CONSTRUCTED)) { + asn_error(&b, "bad sequence type %u", b.asn_cptr[0]); + return (-1); + } + b.asn_len--; + b.asn_cptr++; + + if (b.asn_len == 0) + return (0); + + if (*b.asn_cptr & 0x80) { + /* long length */ + length = *b.asn_cptr++ & 0x7f; + b.asn_len--; + if (length == 0) { + asn_error(&b, "indefinite length not supported"); + return (-1); + } + if (length > ASN_MAXLENLEN) { + asn_error(&b, "long length too long (%u)", length); + return (-1); + } + if (length > b.asn_len) + return (0); + len = 0; + while (length--) { + len = (len << 8) | *b.asn_cptr++; + b.asn_len--; + } + } else { + len = *b.asn_cptr++; + b.asn_len--; + } + + if (len > b.asn_len) + return (0); + + return (len + b.asn_cptr - b0->asn_cptr); +} + +/* + * Encode the SNMP PDU without the variable bindings field. + * We do this the rather uneffective way by + * moving things around and assuming that the length field will never + * use more than 2 bytes. + * We need a number of pointers to apply the fixes afterwards. + */ +enum snmp_code +snmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu) +{ + enum asn_err err; + u_char *v3_hdr_ptr; + + if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED), + &pdu->outer_ptr) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + if (pdu->version == SNMP_V1) + err = asn_put_integer(b, 0); + else if (pdu->version == SNMP_V2c) + err = asn_put_integer(b, 1); + else if (pdu->version == SNMP_V3) + err = asn_put_integer(b, 3); + else + return (SNMP_CODE_BADVERS); + if (err != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + if (pdu->version == SNMP_V3) { + if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE | + ASN_TYPE_CONSTRUCTED), &v3_hdr_ptr) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + if (asn_put_integer(b, pdu->identifier) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + if (asn_put_integer(b, pdu->engine.max_msg_size) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + if (pdu->type != SNMP_PDU_RESPONSE && + pdu->type != SNMP_PDU_TRAP && + pdu->type != SNMP_PDU_TRAP2 && + pdu->type != SNMP_PDU_REPORT) + pdu->flags |= SNMP_MSG_REPORT_FLAG; + + if (asn_put_octetstring(b, (u_char *)&pdu->flags, 1) + != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + if (asn_put_integer(b, pdu->security_model) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + if (asn_commit_header(b, v3_hdr_ptr, NULL) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + if (pdu->security_model != SNMP_SECMODEL_USM) + return (SNMP_CODE_FAILED); + + if (pdu_encode_secparams(b, pdu) != SNMP_CODE_OK) + return (SNMP_CODE_FAILED); + + /* View-based Access Conntrol information */ + if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE | + ASN_TYPE_CONSTRUCTED), &pdu->scoped_ptr) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + if (asn_put_octetstring(b, (u_char *)pdu->context_engine, + pdu->context_engine_len) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + if (asn_put_octetstring(b, (u_char *)pdu->context_name, + strlen(pdu->context_name)) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + } else { + if (asn_put_octetstring(b, (u_char *)pdu->community, + strlen(pdu->community)) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + } + + if (asn_put_temp_header(b, (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT | + pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + if (pdu->type == SNMP_PDU_TRAP) { + if (pdu->version != SNMP_V1 || + asn_put_objid(b, &pdu->enterprise) != ASN_ERR_OK || + asn_put_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK || + asn_put_integer(b, pdu->generic_trap) != ASN_ERR_OK || + asn_put_integer(b, pdu->specific_trap) != ASN_ERR_OK || + asn_put_timeticks(b, pdu->time_stamp) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + } else { + if (pdu->version == SNMP_V1 && (pdu->type == SNMP_PDU_GETBULK || + pdu->type == SNMP_PDU_INFORM || + pdu->type == SNMP_PDU_TRAP2 || + pdu->type == SNMP_PDU_REPORT)) + return (SNMP_CODE_FAILED); + + if (asn_put_integer(b, pdu->request_id) != ASN_ERR_OK || + asn_put_integer(b, pdu->error_status) != ASN_ERR_OK || + asn_put_integer(b, pdu->error_index) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + } + + if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED), + &pdu->vars_ptr) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + return (SNMP_CODE_OK); +} + +static enum asn_err +snmp_pdu_fix_padd(struct asn_buf *b, struct snmp_pdu *pdu) +{ + asn_len_t padlen; + + if (pdu->user.priv_proto == SNMP_PRIV_DES && pdu->scoped_len % 8 != 0) { + padlen = 8 - (pdu->scoped_len % 8); + if (asn_pad(b, padlen) != ASN_ERR_OK) + return (ASN_ERR_FAILED); + pdu->scoped_len += padlen; + } + + return (ASN_ERR_OK); +} + +enum snmp_code +snmp_fix_encoding(struct asn_buf *b, struct snmp_pdu *pdu) +{ + size_t moved = 0; + enum snmp_code code; + + if (asn_commit_header(b, pdu->vars_ptr, NULL) != ASN_ERR_OK || + asn_commit_header(b, pdu->pdu_ptr, NULL) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + if (pdu->version == SNMP_V3) { + if (asn_commit_header(b, pdu->scoped_ptr, NULL) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + pdu->scoped_len = b->asn_ptr - pdu->scoped_ptr; + if (snmp_pdu_fix_padd(b, pdu) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + if (pdu->security_model != SNMP_SECMODEL_USM) + return (SNMP_CODE_FAILED); + + if (snmp_pdu_encrypt(pdu) != SNMP_CODE_OK) + return (SNMP_CODE_FAILED); + + if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV && + asn_commit_header(b, pdu->encrypted_ptr, NULL) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + } + + if (asn_commit_header(b, pdu->outer_ptr, &moved) != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + pdu->outer_len = b->asn_ptr - pdu->outer_ptr; + pdu->digest_ptr -= moved; + + if (pdu->version == SNMP_V3) { + if ((code = snmp_pdu_calc_digest(pdu, pdu->msg_digest)) != + SNMP_CODE_OK) + return (SNMP_CODE_FAILED); + + if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) + memcpy(pdu->digest_ptr, pdu->msg_digest, + sizeof(pdu->msg_digest)); + } + + return (SNMP_CODE_OK); +} + +/* + * Encode a binding. Caller must ensure, that the syntax is ok for that version. + * Be sure not to cobber b, when something fails. + */ +enum asn_err +snmp_binding_encode(struct asn_buf *b, const struct snmp_value *binding) +{ + u_char *ptr; + enum asn_err err; + struct asn_buf save = *b; + + if ((err = asn_put_temp_header(b, (ASN_TYPE_SEQUENCE | + ASN_TYPE_CONSTRUCTED), &ptr)) != ASN_ERR_OK) { + *b = save; + return (err); + } + + if ((err = asn_put_objid(b, &binding->var)) != ASN_ERR_OK) { + *b = save; + return (err); + } + + switch (binding->syntax) { + + case SNMP_SYNTAX_NULL: + err = asn_put_null(b); + break; + + case SNMP_SYNTAX_INTEGER: + err = asn_put_integer(b, binding->v.integer); + break; + + case SNMP_SYNTAX_OCTETSTRING: + err = asn_put_octetstring(b, binding->v.octetstring.octets, + binding->v.octetstring.len); + break; + + case SNMP_SYNTAX_OID: + err = asn_put_objid(b, &binding->v.oid); + break; + + case SNMP_SYNTAX_IPADDRESS: + err = asn_put_ipaddress(b, binding->v.ipaddress); + break; + + case SNMP_SYNTAX_TIMETICKS: + err = asn_put_uint32(b, ASN_APP_TIMETICKS, binding->v.uint32); + break; + + case SNMP_SYNTAX_COUNTER: + err = asn_put_uint32(b, ASN_APP_COUNTER, binding->v.uint32); + break; + + case SNMP_SYNTAX_GAUGE: + err = asn_put_uint32(b, ASN_APP_GAUGE, binding->v.uint32); + break; + + case SNMP_SYNTAX_COUNTER64: + err = asn_put_counter64(b, binding->v.counter64); + break; + + case SNMP_SYNTAX_NOSUCHOBJECT: + err = asn_put_exception(b, ASN_EXCEPT_NOSUCHOBJECT); + break; + + case SNMP_SYNTAX_NOSUCHINSTANCE: + err = asn_put_exception(b, ASN_EXCEPT_NOSUCHINSTANCE); + break; + + case SNMP_SYNTAX_ENDOFMIBVIEW: + err = asn_put_exception(b, ASN_EXCEPT_ENDOFMIBVIEW); + break; + } + + if (err != ASN_ERR_OK) { + *b = save; + return (err); + } + + err = asn_commit_header(b, ptr, NULL); + if (err != ASN_ERR_OK) { + *b = save; + return (err); + } + + return (ASN_ERR_OK); +} + +/* + * Encode an PDU. + */ +enum snmp_code +snmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b) +{ + u_int idx; + enum snmp_code err; + + if ((err = snmp_pdu_encode_header(resp_b, pdu)) != SNMP_CODE_OK) + return (err); + for (idx = 0; idx < pdu->nbindings; idx++) + if (snmp_binding_encode(resp_b, &pdu->bindings[idx]) + != ASN_ERR_OK) + return (SNMP_CODE_FAILED); + + return (snmp_fix_encoding(resp_b, pdu)); +} + +static void +dump_binding(const struct snmp_value *b) +{ + u_int i; + char buf[ASN_OIDSTRLEN]; + + snmp_printf("%s=", asn_oid2str_r(&b->var, buf)); + switch (b->syntax) { + + case SNMP_SYNTAX_NULL: + snmp_printf("NULL"); + break; + + case SNMP_SYNTAX_INTEGER: + snmp_printf("INTEGER %d", b->v.integer); + break; + + case SNMP_SYNTAX_OCTETSTRING: + snmp_printf("OCTET STRING %lu:", b->v.octetstring.len); + for (i = 0; i < b->v.octetstring.len; i++) + snmp_printf(" %02x", b->v.octetstring.octets[i]); + break; + + case SNMP_SYNTAX_OID: + snmp_printf("OID %s", asn_oid2str_r(&b->v.oid, buf)); + break; + + case SNMP_SYNTAX_IPADDRESS: + snmp_printf("IPADDRESS %u.%u.%u.%u", b->v.ipaddress[0], + b->v.ipaddress[1], b->v.ipaddress[2], b->v.ipaddress[3]); + break; + + case SNMP_SYNTAX_COUNTER: + snmp_printf("COUNTER %u", b->v.uint32); + break; + + case SNMP_SYNTAX_GAUGE: + snmp_printf("GAUGE %u", b->v.uint32); + break; + + case SNMP_SYNTAX_TIMETICKS: + snmp_printf("TIMETICKS %u", b->v.uint32); + break; + + case SNMP_SYNTAX_COUNTER64: + snmp_printf("COUNTER64 %lld", b->v.counter64); + break; + + case SNMP_SYNTAX_NOSUCHOBJECT: + snmp_printf("NoSuchObject"); + break; + + case SNMP_SYNTAX_NOSUCHINSTANCE: + snmp_printf("NoSuchInstance"); + break; + + case SNMP_SYNTAX_ENDOFMIBVIEW: + snmp_printf("EndOfMibView"); + break; + + default: + snmp_printf("UNKNOWN SYNTAX %u", b->syntax); + break; + } +} + +static __inline void +dump_bindings(const struct snmp_pdu *pdu) +{ + u_int i; + + for (i = 0; i < pdu->nbindings; i++) { + snmp_printf(" [%u]: ", i); + dump_binding(&pdu->bindings[i]); + snmp_printf("\n"); + } +} + +static __inline void +dump_notrap(const struct snmp_pdu *pdu) +{ + snmp_printf(" request_id=%d", pdu->request_id); + snmp_printf(" error_status=%d", pdu->error_status); + snmp_printf(" error_index=%d\n", pdu->error_index); + dump_bindings(pdu); +} + +void +snmp_pdu_dump(const struct snmp_pdu *pdu) +{ + char buf[ASN_OIDSTRLEN]; + const char *vers; + static const char *types[] = { + [SNMP_PDU_GET] = "GET", + [SNMP_PDU_GETNEXT] = "GETNEXT", + [SNMP_PDU_RESPONSE] = "RESPONSE", + [SNMP_PDU_SET] = "SET", + [SNMP_PDU_TRAP] = "TRAPv1", + [SNMP_PDU_GETBULK] = "GETBULK", + [SNMP_PDU_INFORM] = "INFORM", + [SNMP_PDU_TRAP2] = "TRAPv2", + [SNMP_PDU_REPORT] = "REPORT", + }; + + if (pdu->version == SNMP_V1) + vers = "SNMPv1"; + else if (pdu->version == SNMP_V2c) + vers = "SNMPv2c"; + else if (pdu->version == SNMP_V3) + vers = "SNMPv3"; + else + vers = "v?"; + + switch (pdu->type) { + case SNMP_PDU_TRAP: + snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community); + snmp_printf(" enterprise=%s", asn_oid2str_r(&pdu->enterprise, buf)); + snmp_printf(" agent_addr=%u.%u.%u.%u", pdu->agent_addr[0], + pdu->agent_addr[1], pdu->agent_addr[2], pdu->agent_addr[3]); + snmp_printf(" generic_trap=%d", pdu->generic_trap); + snmp_printf(" specific_trap=%d", pdu->specific_trap); + snmp_printf(" time-stamp=%u\n", pdu->time_stamp); + dump_bindings(pdu); + break; + + case SNMP_PDU_GET: + case SNMP_PDU_GETNEXT: + case SNMP_PDU_RESPONSE: + case SNMP_PDU_SET: + case SNMP_PDU_GETBULK: + case SNMP_PDU_INFORM: + case SNMP_PDU_TRAP2: + case SNMP_PDU_REPORT: + snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community); + dump_notrap(pdu); + break; + + default: + snmp_printf("bad pdu type %u\n", pdu->type); + break; + } +} + +void +snmp_value_free(struct snmp_value *value) +{ + + if (value->syntax == SNMP_SYNTAX_OCTETSTRING) { + free(value->v.octetstring.octets); + value->v.octetstring.octets = NULL; + } + value->syntax = SNMP_SYNTAX_NULL; +} + +int +snmp_value_copy(struct snmp_value *to, const struct snmp_value *from) +{ + to->var = from->var; + to->syntax = from->syntax; + + if (from->syntax == SNMP_SYNTAX_OCTETSTRING) { + if ((to->v.octetstring.len = from->v.octetstring.len) == 0) + to->v.octetstring.octets = NULL; + else { + to->v.octetstring.octets = malloc(to->v.octetstring.len); + if (to->v.octetstring.octets == NULL) + return (-1); + (void)memcpy(to->v.octetstring.octets, + from->v.octetstring.octets, to->v.octetstring.len); + } + } else + to->v = from->v; + return (0); +} + +void +snmp_pdu_init_secparams(struct snmp_pdu *pdu) +{ + int32_t rval; + + if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH) + pdu->flags |= SNMP_MSG_AUTH_FLAG; + + switch (pdu->user.priv_proto) { + case SNMP_PRIV_DES: + memcpy(pdu->msg_salt, &pdu->engine.engine_boots, + sizeof(pdu->engine.engine_boots)); + rval = random(); + memcpy(pdu->msg_salt + sizeof(pdu->engine.engine_boots), &rval, + sizeof(int32_t)); + pdu->flags |= SNMP_MSG_PRIV_FLAG; + break; + case SNMP_PRIV_AES: + rval = random(); + memcpy(pdu->msg_salt, &rval, sizeof(int32_t)); + rval = random(); + memcpy(pdu->msg_salt + sizeof(int32_t), &rval, sizeof(int32_t)); + pdu->flags |= SNMP_MSG_PRIV_FLAG; + break; + default: + break; + } +} + +void +snmp_pdu_free(struct snmp_pdu *pdu) +{ + u_int i; + + for (i = 0; i < pdu->nbindings; i++) + snmp_value_free(&pdu->bindings[i]); + pdu->nbindings = 0; +} + +/* + * Parse an ASCII SNMP value into the binary form + */ +int +snmp_value_parse(const char *str, enum snmp_syntax syntax, union snmp_values *v) +{ + char *end; + + switch (syntax) { + + case SNMP_SYNTAX_NULL: + case SNMP_SYNTAX_NOSUCHOBJECT: + case SNMP_SYNTAX_NOSUCHINSTANCE: + case SNMP_SYNTAX_ENDOFMIBVIEW: + if (*str != '\0') + return (-1); + return (0); + + case SNMP_SYNTAX_INTEGER: + v->integer = strtoll(str, &end, 0); + if (*end != '\0') + return (-1); + return (0); + + case SNMP_SYNTAX_OCTETSTRING: + { + u_long len; /* actual length of string */ + u_long alloc; /* allocate length of string */ + u_char *octs; /* actual octets */ + u_long oct; /* actual octet */ + u_char *nocts; /* to avoid memory leak */ + u_char c; /* actual character */ + +# define STUFFC(C) \ + if (alloc == len) { \ + alloc += 100; \ + if ((nocts = realloc(octs, alloc)) == NULL) { \ + free(octs); \ + return (-1); \ + } \ + octs = nocts; \ + } \ + octs[len++] = (C); + + len = alloc = 0; + octs = NULL; + + if (*str == '"') { + str++; + while((c = *str++) != '\0') { + if (c == '"') { + if (*str != '\0') { + free(octs); + return (-1); + } + break; + } + if (c == '\\') { + switch (c = *str++) { + + case '\\': + break; + case 'a': + c = '\a'; + break; + case 'b': + c = '\b'; + break; + case 'f': + c = '\f'; + break; + case 'n': + c = '\n'; + break; + case 'r': + c = '\r'; + break; + case 't': + c = '\t'; + break; + case 'v': + c = '\v'; + break; + case 'x': + c = 0; + if (!isxdigit(*str)) + break; + if (isdigit(*str)) + c = *str++ - '0'; + else if (isupper(*str)) + c = *str++ - 'A' + 10; + else + c = *str++ - 'a' + 10; + if (!isxdigit(*str)) + break; + if (isdigit(*str)) + c += *str++ - '0'; + else if (isupper(*str)) + c += *str++ - 'A' + 10; + else + c += *str++ - 'a' + 10; + break; + case '0': case '1': case '2': + case '3': case '4': case '5': + case '6': case '7': + c = *str++ - '0'; + if (*str < '0' || *str > '7') + break; + c = *str++ - '0'; + if (*str < '0' || *str > '7') + break; + c = *str++ - '0'; + break; + default: + break; + } + } + STUFFC(c); + } + } else { + while (*str != '\0') { + oct = strtoul(str, &end, 16); + str = end; + if (oct > 0xff) { + free(octs); + return (-1); + } + STUFFC(oct); + if (*str == ':') + str++; + else if(*str != '\0') { + free(octs); + return (-1); + } + } + } + v->octetstring.octets = octs; + v->octetstring.len = len; + return (0); +# undef STUFFC + } + + case SNMP_SYNTAX_OID: + { + u_long subid; + + v->oid.len = 0; + + for (;;) { + if (v->oid.len == ASN_MAXOIDLEN) + return (-1); + subid = strtoul(str, &end, 10); + str = end; + if (subid > ASN_MAXID) + return (-1); + v->oid.subs[v->oid.len++] = (asn_subid_t)subid; + if (*str == '\0') + break; + if (*str != '.') + return (-1); + str++; + } + return (0); + } + + case SNMP_SYNTAX_IPADDRESS: + { + struct hostent *he; + + if (inet_pton(AF_INET, str, &v->ipaddress) == 1) + return (0); + if ((he = gethostbyname2(str, AF_INET)) == NULL) + return (-1); + if (he->h_addrtype != AF_INET) + return (-1); + + memcpy(v->ipaddress, he->h_addr, sizeof(v->ipaddress)); + + return (0); + } + + case SNMP_SYNTAX_COUNTER: + case SNMP_SYNTAX_GAUGE: + case SNMP_SYNTAX_TIMETICKS: + { + uint64_t sub; + + sub = strtoull(str, &end, 0); + if (*end != '\0' || sub > 0xffffffff) + return (-1); + v->uint32 = (uint32_t)sub; + return (0); + } + + case SNMP_SYNTAX_COUNTER64: + v->counter64 = strtoull(str, &end, 0); + if (*end != '\0') + return (-1); + return (0); + } + abort(); +} + +static void +snmp_error_func(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "SNMP: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +static void +snmp_printf_func(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); +} Property changes on: vendor/1.14/lib/snmp.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/lib/snmpagent.c =================================================================== --- vendor/1.14/lib/snmpagent.c (nonexistent) +++ vendor/1.14/lib/snmpagent.c (revision 359491) @@ -0,0 +1,1070 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/lib/snmpagent.c,v 1.20 2005/10/04 11:21:33 brandt_h Exp $ + * + * SNMP Agent functions + */ +#include +#include +#include +#include +#include +#include +#ifdef HAVE_STDINT_H +#include +#elif defined(HAVE_INTTYPES_H) +#include +#endif +#include + +#include "asn1.h" +#include "snmp.h" +#include "snmppriv.h" +#include "snmpagent.h" + +static void snmp_debug_func(const char *fmt, ...); + +void (*snmp_debug)(const char *fmt, ...) = snmp_debug_func; + +struct snmp_node *tree; +u_int tree_size; + +/* + * Structure to hold dependencies during SET processing + * The last two members of this structure must be the + * dependency visible by the user and the user data. + */ +struct depend { + TAILQ_ENTRY(depend) link; + size_t len; /* size of data part */ + snmp_depop_t func; + struct snmp_dependency dep; +#if defined(__GNUC__) && __GNUC__ < 3 + u_char data[0]; +#else + u_char data[]; +#endif +}; +TAILQ_HEAD(depend_list, depend); + +/* + * Set context + */ +struct context { + struct snmp_context ctx; + struct depend_list dlist; + const struct snmp_node *node[SNMP_MAX_BINDINGS]; + struct snmp_scratch scratch[SNMP_MAX_BINDINGS]; + struct depend *depend; +}; + +#define TR(W) (snmp_trace & SNMP_TRACE_##W) +u_int snmp_trace = 0; + +static char oidbuf[ASN_OIDSTRLEN]; + +/* + * Allocate a context + */ +struct snmp_context * +snmp_init_context(void) +{ + struct context *context; + + if ((context = malloc(sizeof(*context))) == NULL) + return (NULL); + + memset(context, 0, sizeof(*context)); + TAILQ_INIT(&context->dlist); + + return (&context->ctx); +} + +/* + * Find a variable for SET/GET and the first GETBULK pass. + * Return the node pointer. If the search fails, set the errp to + * the correct SNMPv2 GET exception code. + */ +static struct snmp_node * +find_node(const struct snmp_value *value, enum snmp_syntax *errp) +{ + struct snmp_node *tp; + + if (TR(FIND)) + snmp_debug("find: searching %s", + asn_oid2str_r(&value->var, oidbuf)); + + /* + * If we have an exact match (the entry in the table is a + * sub-oid from the variable) we have found what we are for. + * If the table oid is higher than the variable, there is no match. + */ + for (tp = tree; tp < tree + tree_size; tp++) { + if (asn_is_suboid(&tp->oid, &value->var)) + goto found; + if (asn_compare_oid(&tp->oid, &value->var) >= 0) + break; + } + + if (TR(FIND)) + snmp_debug("find: no match"); + *errp = SNMP_SYNTAX_NOSUCHOBJECT; + return (NULL); + + found: + /* leafs must have a 0 instance identifier */ + if (tp->type == SNMP_NODE_LEAF && + (value->var.len != tp->oid.len + 1 || + value->var.subs[tp->oid.len] != 0)) { + if (TR(FIND)) + snmp_debug("find: bad leaf index"); + *errp = SNMP_SYNTAX_NOSUCHINSTANCE; + return (NULL); + } + if (TR(FIND)) + snmp_debug("find: found %s", + asn_oid2str_r(&value->var, oidbuf)); + return (tp); +} + +static struct snmp_node * +find_subnode(const struct snmp_value *value) +{ + struct snmp_node *tp; + + for (tp = tree; tp < tree + tree_size; tp++) { + if (asn_is_suboid(&value->var, &tp->oid)) + return (tp); + } + return (NULL); +} + +static void +snmp_pdu_create_response(const struct snmp_pdu *pdu, struct snmp_pdu *resp) +{ + memset(resp, 0, sizeof(*resp)); + strcpy(resp->community, pdu->community); + resp->version = pdu->version; + if (pdu->flags & SNMP_MSG_AUTODISCOVER) + resp->type = SNMP_PDU_REPORT; /* RFC 3414.4 */ + else + resp->type = SNMP_PDU_RESPONSE; + resp->request_id = pdu->request_id; + resp->version = pdu->version; + + if (resp->version != SNMP_V3) + return; + + memcpy(&resp->engine, &pdu->engine, sizeof(pdu->engine)); + memcpy(&resp->user, &pdu->user, sizeof(pdu->user)); + snmp_pdu_init_secparams(resp); + resp->identifier = pdu->identifier; + resp->security_model = pdu->security_model; + resp->context_engine_len = pdu->context_engine_len; + memcpy(resp->context_engine, pdu->context_engine, + resp->context_engine_len); + strlcpy(resp->context_name, pdu->context_name, + sizeof(resp->context_name)); +} + +/* + * Execute a GET operation. The tree is rooted at the global 'root'. + * Build the response PDU on the fly. If the return code is SNMP_RET_ERR + * the pdu error status and index will be set. + */ +enum snmp_ret +snmp_get(struct snmp_pdu *pdu, struct asn_buf *resp_b, + struct snmp_pdu *resp, void *data) +{ + int ret; + u_int i; + struct snmp_node *tp; + enum snmp_syntax except; + struct context context; + enum asn_err err; + + memset(&context, 0, sizeof(context)); + context.ctx.data = data; + + snmp_pdu_create_response(pdu, resp); + + if (snmp_pdu_encode_header(resp_b, resp) != SNMP_CODE_OK) + /* cannot even encode header - very bad */ + return (SNMP_RET_IGN); + + for (i = 0; i < pdu->nbindings; i++) { + resp->bindings[i].var = pdu->bindings[i].var; + if ((tp = find_node(&pdu->bindings[i], &except)) == NULL) { + if (pdu->version == SNMP_V1) { + if (TR(GET)) + snmp_debug("get: nosuchname"); + pdu->error_status = SNMP_ERR_NOSUCHNAME; + pdu->error_index = i + 1; + snmp_pdu_free(resp); + return (SNMP_RET_ERR); + } + if (TR(GET)) + snmp_debug("get: exception %u", except); + resp->bindings[i].syntax = except; + + } else { + /* call the action to fetch the value. */ + resp->bindings[i].syntax = tp->syntax; + ret = (*tp->op)(&context.ctx, &resp->bindings[i], + tp->oid.len, tp->index, SNMP_OP_GET); + if (TR(GET)) + snmp_debug("get: action returns %d", ret); + + if (ret == SNMP_ERR_NOSUCHNAME) { + if (pdu->version == SNMP_V1) { + pdu->error_status = SNMP_ERR_NOSUCHNAME; + pdu->error_index = i + 1; + snmp_pdu_free(resp); + return (SNMP_RET_ERR); + } + if (TR(GET)) + snmp_debug("get: exception noSuchInstance"); + resp->bindings[i].syntax = SNMP_SYNTAX_NOSUCHINSTANCE; + + } else if (ret != SNMP_ERR_NOERROR) { + pdu->error_status = SNMP_ERR_GENERR; + pdu->error_index = i + 1; + snmp_pdu_free(resp); + return (SNMP_RET_ERR); + } + } + resp->nbindings++; + + err = snmp_binding_encode(resp_b, &resp->bindings[i]); + + if (err == ASN_ERR_EOBUF) { + pdu->error_status = SNMP_ERR_TOOBIG; + pdu->error_index = 0; + snmp_pdu_free(resp); + return (SNMP_RET_ERR); + } + if (err != ASN_ERR_OK) { + if (TR(GET)) + snmp_debug("get: binding encoding: %u", err); + pdu->error_status = SNMP_ERR_GENERR; + pdu->error_index = i + 1; + snmp_pdu_free(resp); + return (SNMP_RET_ERR); + } + } + + if (snmp_fix_encoding(resp_b, resp) != SNMP_CODE_OK) { + snmp_debug("get: failed to encode PDU"); + return (SNMP_RET_ERR); + } + + return (SNMP_RET_OK); +} + +static struct snmp_node * +next_node(const struct snmp_value *value, int *pnext) +{ + struct snmp_node *tp; + + if (TR(FIND)) + snmp_debug("next: searching %s", + asn_oid2str_r(&value->var, oidbuf)); + + *pnext = 0; + for (tp = tree; tp < tree + tree_size; tp++) { + if (asn_is_suboid(&tp->oid, &value->var)) { + /* the tree OID is a sub-oid of the requested OID. */ + if (tp->type == SNMP_NODE_LEAF) { + if (tp->oid.len == value->var.len) { + /* request for scalar type */ + if (TR(FIND)) + snmp_debug("next: found scalar %s", + asn_oid2str_r(&tp->oid, oidbuf)); + return (tp); + } + /* try next */ + } else { + if (TR(FIND)) + snmp_debug("next: found column %s", + asn_oid2str_r(&tp->oid, oidbuf)); + return (tp); + } + } else if (asn_is_suboid(&value->var, &tp->oid) || + asn_compare_oid(&tp->oid, &value->var) >= 0) { + if (TR(FIND)) + snmp_debug("next: found %s", + asn_oid2str_r(&tp->oid, oidbuf)); + *pnext = 1; + return (tp); + } + } + + if (TR(FIND)) + snmp_debug("next: failed"); + + return (NULL); +} + +static enum snmp_ret +do_getnext(struct context *context, const struct snmp_value *inb, + struct snmp_value *outb, struct snmp_pdu *pdu) +{ + const struct snmp_node *tp; + int ret, next; + + if ((tp = next_node(inb, &next)) == NULL) + goto eofMib; + + /* retain old variable if we are doing a GETNEXT on an exact + * matched leaf only */ + if (tp->type == SNMP_NODE_LEAF || next) + outb->var = tp->oid; + else + outb->var = inb->var; + + for (;;) { + outb->syntax = tp->syntax; + if (tp->type == SNMP_NODE_LEAF) { + /* make a GET operation */ + outb->var.subs[outb->var.len++] = 0; + ret = (*tp->op)(&context->ctx, outb, tp->oid.len, + tp->index, SNMP_OP_GET); + } else { + /* make a GETNEXT */ + ret = (*tp->op)(&context->ctx, outb, tp->oid.len, + tp->index, SNMP_OP_GETNEXT); + } + if (ret != SNMP_ERR_NOSUCHNAME) { + /* got something */ + if (ret != SNMP_ERR_NOERROR && TR(GETNEXT)) + snmp_debug("getnext: %s returns %u", + asn_oid2str(&outb->var), ret); + break; + } + + /* object has no data - try next */ + if (++tp == tree + tree_size) + break; + + if (TR(GETNEXT)) + snmp_debug("getnext: no data - avancing to %s", + asn_oid2str(&tp->oid)); + + outb->var = tp->oid; + } + + if (ret == SNMP_ERR_NOSUCHNAME) { + eofMib: + outb->var = inb->var; + if (pdu->version == SNMP_V1) { + pdu->error_status = SNMP_ERR_NOSUCHNAME; + return (SNMP_RET_ERR); + } + outb->syntax = SNMP_SYNTAX_ENDOFMIBVIEW; + + } else if (ret != SNMP_ERR_NOERROR) { + pdu->error_status = SNMP_ERR_GENERR; + return (SNMP_RET_ERR); + } + return (SNMP_RET_OK); +} + + +/* + * Execute a GETNEXT operation. The tree is rooted at the global 'root'. + * Build the response PDU on the fly. The return is: + */ +enum snmp_ret +snmp_getnext(struct snmp_pdu *pdu, struct asn_buf *resp_b, + struct snmp_pdu *resp, void *data) +{ + struct context context; + u_int i; + enum asn_err err; + enum snmp_ret result; + + memset(&context, 0, sizeof(context)); + context.ctx.data = data; + + snmp_pdu_create_response(pdu, resp); + + if (snmp_pdu_encode_header(resp_b, resp)) + return (SNMP_RET_IGN); + + for (i = 0; i < pdu->nbindings; i++) { + result = do_getnext(&context, &pdu->bindings[i], + &resp->bindings[i], pdu); + + if (result != SNMP_RET_OK) { + pdu->error_index = i + 1; + snmp_pdu_free(resp); + return (result); + } + + resp->nbindings++; + + err = snmp_binding_encode(resp_b, &resp->bindings[i]); + + if (err == ASN_ERR_EOBUF) { + pdu->error_status = SNMP_ERR_TOOBIG; + pdu->error_index = 0; + snmp_pdu_free(resp); + return (SNMP_RET_ERR); + } + if (err != ASN_ERR_OK) { + if (TR(GET)) + snmp_debug("getnext: binding encoding: %u", err); + pdu->error_status = SNMP_ERR_GENERR; + pdu->error_index = i + 1; + snmp_pdu_free(resp); + return (SNMP_RET_ERR); + } + } + + if (snmp_fix_encoding(resp_b, resp) != SNMP_CODE_OK) { + snmp_debug("getnext: failed to encode PDU"); + return (SNMP_RET_ERR); + } + + return (SNMP_RET_OK); +} + +enum snmp_ret +snmp_getbulk(struct snmp_pdu *pdu, struct asn_buf *resp_b, + struct snmp_pdu *resp, void *data) +{ + struct context context; + u_int i; + int cnt; + u_int non_rep; + int eomib; + enum snmp_ret result; + enum asn_err err; + + memset(&context, 0, sizeof(context)); + context.ctx.data = data; + + snmp_pdu_create_response(pdu, resp); + + if (snmp_pdu_encode_header(resp_b, resp) != SNMP_CODE_OK) + /* cannot even encode header - very bad */ + return (SNMP_RET_IGN); + + if ((non_rep = pdu->error_status) > pdu->nbindings) + non_rep = pdu->nbindings; + + /* non-repeaters */ + for (i = 0; i < non_rep; i++) { + result = do_getnext(&context, &pdu->bindings[i], + &resp->bindings[resp->nbindings], pdu); + + if (result != SNMP_RET_OK) { + pdu->error_index = i + 1; + snmp_pdu_free(resp); + return (result); + } + + err = snmp_binding_encode(resp_b, + &resp->bindings[resp->nbindings++]); + + if (err == ASN_ERR_EOBUF) + goto done; + + if (err != ASN_ERR_OK) { + if (TR(GET)) + snmp_debug("getnext: binding encoding: %u", err); + pdu->error_status = SNMP_ERR_GENERR; + pdu->error_index = i + 1; + snmp_pdu_free(resp); + return (SNMP_RET_ERR); + } + } + + if (non_rep == pdu->nbindings) + goto done; + + /* repeates */ + for (cnt = 0; cnt < pdu->error_index; cnt++) { + eomib = 1; + for (i = non_rep; i < pdu->nbindings; i++) { + + if (resp->nbindings == SNMP_MAX_BINDINGS) + /* PDU is full */ + goto done; + + if (cnt == 0) + result = do_getnext(&context, &pdu->bindings[i], + &resp->bindings[resp->nbindings], pdu); + else + result = do_getnext(&context, + &resp->bindings[resp->nbindings - + (pdu->nbindings - non_rep)], + &resp->bindings[resp->nbindings], pdu); + + if (result != SNMP_RET_OK) { + pdu->error_index = i + 1; + snmp_pdu_free(resp); + return (result); + } + if (resp->bindings[resp->nbindings].syntax != + SNMP_SYNTAX_ENDOFMIBVIEW) + eomib = 0; + + err = snmp_binding_encode(resp_b, + &resp->bindings[resp->nbindings++]); + + if (err == ASN_ERR_EOBUF) + goto done; + + if (err != ASN_ERR_OK) { + if (TR(GET)) + snmp_debug("getnext: binding encoding: %u", err); + pdu->error_status = SNMP_ERR_GENERR; + pdu->error_index = i + 1; + snmp_pdu_free(resp); + return (SNMP_RET_ERR); + } + } + if (eomib) + break; + } + + done: + if (snmp_fix_encoding(resp_b, resp) != SNMP_CODE_OK) { + snmp_debug("getnext: failed to encode PDU"); + return (SNMP_RET_ERR); + } + + return (SNMP_RET_OK); +} + +/* + * Rollback a SET operation. Failed index is 'i'. + */ +static void +rollback(struct context *context, struct snmp_pdu *pdu, u_int i) +{ + struct snmp_value *b; + const struct snmp_node *np; + int ret; + + while (i-- > 0) { + b = &pdu->bindings[i]; + np = context->node[i]; + + context->ctx.scratch = &context->scratch[i]; + + ret = (*np->op)(&context->ctx, b, np->oid.len, np->index, + SNMP_OP_ROLLBACK); + + if (ret != SNMP_ERR_NOERROR) { + snmp_error("set: rollback failed (%d) on variable %s " + "index %u", ret, asn_oid2str(&b->var), i); + if (pdu->version != SNMP_V1) { + pdu->error_status = SNMP_ERR_UNDO_FAILED; + pdu->error_index = 0; + } + } + } +} + +/* + * Commit dependencies. + */ +int +snmp_dep_commit(struct snmp_context *ctx) +{ + struct context *context = (struct context *)ctx; + int ret; + + TAILQ_FOREACH(context->depend, &context->dlist, link) { + ctx->dep = &context->depend->dep; + + if (TR(SET)) + snmp_debug("set: dependency commit %s", + asn_oid2str(&ctx->dep->obj)); + + ret = context->depend->func(ctx, ctx->dep, SNMP_DEPOP_COMMIT); + + if (ret != SNMP_ERR_NOERROR) { + if (TR(SET)) + snmp_debug("set: dependency failed %d", ret); + return (ret); + } + } + return (SNMP_ERR_NOERROR); +} + +/* + * Rollback dependencies + */ +int +snmp_dep_rollback(struct snmp_context *ctx) +{ + struct context *context = (struct context *)ctx; + int ret, ret1; + char objbuf[ASN_OIDSTRLEN]; + char idxbuf[ASN_OIDSTRLEN]; + + ret1 = SNMP_ERR_NOERROR; + while ((context->depend = + TAILQ_PREV(context->depend, depend_list, link)) != NULL) { + ctx->dep = &context->depend->dep; + + if (TR(SET)) + snmp_debug("set: dependency rollback %s", + asn_oid2str(&ctx->dep->obj)); + + ret = context->depend->func(ctx, ctx->dep, SNMP_DEPOP_ROLLBACK); + + if (ret != SNMP_ERR_NOERROR) { + snmp_debug("set: dep rollback returns %u: %s %s", ret, + asn_oid2str_r(&ctx->dep->obj, objbuf), + asn_oid2str_r(&ctx->dep->idx, idxbuf)); + if (ret1 == SNMP_ERR_NOERROR) + ret1 = ret; + } + } + return (ret1); +} + +void +snmp_dep_finish(struct snmp_context *ctx) +{ + struct context *context = (struct context *)ctx; + struct depend *d; + + while ((d = TAILQ_FIRST(&context->dlist)) != NULL) { + ctx->dep = &d->dep; + (void)d->func(ctx, ctx->dep, SNMP_DEPOP_FINISH); + TAILQ_REMOVE(&context->dlist, d, link); + free(d); + } +} + +/* + * Do a SET operation. + */ +enum snmp_ret +snmp_set(struct snmp_pdu *pdu, struct asn_buf *resp_b, + struct snmp_pdu *resp, void *data) +{ + int ret; + u_int i; + enum asn_err asnerr; + struct context context; + const struct snmp_node *np; + struct snmp_value *b; + enum snmp_syntax except; + + memset(&context, 0, sizeof(context)); + TAILQ_INIT(&context.dlist); + context.ctx.data = data; + + snmp_pdu_create_response(pdu, resp); + + if (snmp_pdu_encode_header(resp_b, resp)) + return (SNMP_RET_IGN); + + /* + * 1. Find all nodes, check that they are writeable and + * that the syntax is ok, copy over the binding to the response. + */ + for (i = 0; i < pdu->nbindings; i++) { + b = &pdu->bindings[i]; + + if ((np = context.node[i] = find_node(b, &except)) == NULL) { + /* not found altogether or LEAF with wrong index */ + if (TR(SET)) + snmp_debug("set: node not found %s", + asn_oid2str_r(&b->var, oidbuf)); + if (pdu->version == SNMP_V1) { + pdu->error_index = i + 1; + pdu->error_status = SNMP_ERR_NOSUCHNAME; + } else if ((np = find_subnode(b)) != NULL) { + /* 2. intermediate object */ + pdu->error_index = i + 1; + pdu->error_status = SNMP_ERR_NOT_WRITEABLE; + } else if (except == SNMP_SYNTAX_NOSUCHOBJECT) { + pdu->error_index = i + 1; + pdu->error_status = SNMP_ERR_NO_ACCESS; + } else { + pdu->error_index = i + 1; + pdu->error_status = SNMP_ERR_NO_CREATION; + } + snmp_pdu_free(resp); + return (SNMP_RET_ERR); + } + /* + * 2. write/createable? + * Can check this for leafs only, because in v2 we have + * to differentiate between NOT_WRITEABLE and NO_CREATION + * and only the action routine for COLUMNS knows, whether + * a column exists. + */ + if (np->type == SNMP_NODE_LEAF && + !(np->flags & SNMP_NODE_CANSET)) { + if (pdu->version == SNMP_V1) { + pdu->error_index = i + 1; + pdu->error_status = SNMP_ERR_NOSUCHNAME; + } else { + pdu->error_index = i + 1; + pdu->error_status = SNMP_ERR_NOT_WRITEABLE; + } + snmp_pdu_free(resp); + return (SNMP_RET_ERR); + } + /* + * 3. Ensure the right syntax + */ + if (np->syntax != b->syntax) { + if (pdu->version == SNMP_V1) { + pdu->error_index = i + 1; + pdu->error_status = SNMP_ERR_BADVALUE; /* v2: wrongType */ + } else { + pdu->error_index = i + 1; + pdu->error_status = SNMP_ERR_WRONG_TYPE; + } + snmp_pdu_free(resp); + return (SNMP_RET_ERR); + } + /* + * 4. Copy binding + */ + if (snmp_value_copy(&resp->bindings[i], b)) { + pdu->error_index = i + 1; + pdu->error_status = SNMP_ERR_GENERR; + snmp_pdu_free(resp); + return (SNMP_RET_ERR); + } + asnerr = snmp_binding_encode(resp_b, &resp->bindings[i]); + if (asnerr == ASN_ERR_EOBUF) { + pdu->error_index = i + 1; + pdu->error_status = SNMP_ERR_TOOBIG; + snmp_pdu_free(resp); + return (SNMP_RET_ERR); + } else if (asnerr != ASN_ERR_OK) { + pdu->error_index = i + 1; + pdu->error_status = SNMP_ERR_GENERR; + snmp_pdu_free(resp); + return (SNMP_RET_ERR); + } + resp->nbindings++; + } + + context.ctx.code = SNMP_RET_OK; + + /* + * 2. Call the SET method for each node. If a SET fails, rollback + * everything. Map error codes depending on the version. + */ + for (i = 0; i < pdu->nbindings; i++) { + b = &pdu->bindings[i]; + np = context.node[i]; + + context.ctx.var_index = i + 1; + context.ctx.scratch = &context.scratch[i]; + + ret = (*np->op)(&context.ctx, b, np->oid.len, np->index, + SNMP_OP_SET); + + if (TR(SET)) + snmp_debug("set: action %s returns %d", np->name, ret); + + if (pdu->version == SNMP_V1) { + switch (ret) { + case SNMP_ERR_NO_ACCESS: + ret = SNMP_ERR_NOSUCHNAME; + break; + case SNMP_ERR_WRONG_TYPE: + /* should no happen */ + ret = SNMP_ERR_BADVALUE; + break; + case SNMP_ERR_WRONG_LENGTH: + ret = SNMP_ERR_BADVALUE; + break; + case SNMP_ERR_WRONG_ENCODING: + /* should not happen */ + ret = SNMP_ERR_BADVALUE; + break; + case SNMP_ERR_WRONG_VALUE: + ret = SNMP_ERR_BADVALUE; + break; + case SNMP_ERR_NO_CREATION: + ret = SNMP_ERR_NOSUCHNAME; + break; + case SNMP_ERR_INCONS_VALUE: + ret = SNMP_ERR_BADVALUE; + break; + case SNMP_ERR_RES_UNAVAIL: + ret = SNMP_ERR_GENERR; + break; + case SNMP_ERR_COMMIT_FAILED: + ret = SNMP_ERR_GENERR; + break; + case SNMP_ERR_UNDO_FAILED: + ret = SNMP_ERR_GENERR; + break; + case SNMP_ERR_AUTH_ERR: + /* should not happen */ + ret = SNMP_ERR_GENERR; + break; + case SNMP_ERR_NOT_WRITEABLE: + ret = SNMP_ERR_NOSUCHNAME; + break; + case SNMP_ERR_INCONS_NAME: + ret = SNMP_ERR_BADVALUE; + break; + } + } + if (ret != SNMP_ERR_NOERROR) { + pdu->error_index = i + 1; + pdu->error_status = ret; + + rollback(&context, pdu, i); + snmp_pdu_free(resp); + + context.ctx.code = SNMP_RET_ERR; + + goto errout; + } + } + + /* + * 3. Call dependencies + */ + if (TR(SET)) + snmp_debug("set: set operations ok"); + + if ((ret = snmp_dep_commit(&context.ctx)) != SNMP_ERR_NOERROR) { + pdu->error_status = ret; + pdu->error_index = context.ctx.var_index; + + if ((ret = snmp_dep_rollback(&context.ctx)) != SNMP_ERR_NOERROR) { + if (pdu->version != SNMP_V1) { + pdu->error_status = SNMP_ERR_UNDO_FAILED; + pdu->error_index = 0; + } + } + rollback(&context, pdu, i); + snmp_pdu_free(resp); + + context.ctx.code = SNMP_RET_ERR; + + goto errout; + } + + /* + * 4. Commit and copy values from the original packet to the response. + * This is not the commit operation from RFC 1905 but rather an + * 'FREE RESOURCES' operation. It shouldn't fail. + */ + if (TR(SET)) + snmp_debug("set: commiting"); + + for (i = 0; i < pdu->nbindings; i++) { + b = &resp->bindings[i]; + np = context.node[i]; + + context.ctx.var_index = i + 1; + context.ctx.scratch = &context.scratch[i]; + + ret = (*np->op)(&context.ctx, b, np->oid.len, np->index, + SNMP_OP_COMMIT); + + if (ret != SNMP_ERR_NOERROR) + snmp_error("set: commit failed (%d) on" + " variable %s index %u", ret, + asn_oid2str_r(&b->var, oidbuf), i); + } + + if (snmp_fix_encoding(resp_b, resp) != SNMP_CODE_OK) { + snmp_error("set: fix_encoding failed"); + snmp_pdu_free(resp); + context.ctx.code = SNMP_RET_IGN; + } + + /* + * Done + */ + errout: + snmp_dep_finish(&context.ctx); + + if (TR(SET)) + snmp_debug("set: returning %d", context.ctx.code); + + return (context.ctx.code); +} +/* + * Lookup a dependency. If it doesn't exist, create one + */ +struct snmp_dependency * +snmp_dep_lookup(struct snmp_context *ctx, const struct asn_oid *obj, + const struct asn_oid *idx, size_t len, snmp_depop_t func) +{ + struct context *context; + struct depend *d; + + context = (struct context *)(void *) + ((char *)ctx - offsetof(struct context, ctx)); + if (TR(DEPEND)) { + snmp_debug("depend: looking for %s", asn_oid2str(obj)); + if (idx) + snmp_debug("depend: index is %s", asn_oid2str(idx)); + } + TAILQ_FOREACH(d, &context->dlist, link) + if (asn_compare_oid(obj, &d->dep.obj) == 0 && + ((idx == NULL && d->dep.idx.len == 0) || + (idx != NULL && asn_compare_oid(idx, &d->dep.idx) == 0))) { + if(TR(DEPEND)) + snmp_debug("depend: found"); + return (&d->dep); + } + + if(TR(DEPEND)) + snmp_debug("depend: creating"); + + if ((d = malloc(offsetof(struct depend, dep) + len)) == NULL) + return (NULL); + memset(&d->dep, 0, len); + + d->dep.obj = *obj; + if (idx == NULL) + d->dep.idx.len = 0; + else + d->dep.idx = *idx; + d->len = len; + d->func = func; + + TAILQ_INSERT_TAIL(&context->dlist, d, link); + + return (&d->dep); +} + +/* + * Make an error response from a PDU. We do this without decoding the + * variable bindings. This means we can sent the junk back to a caller + * that has sent us junk in the first place. + */ +enum snmp_ret +snmp_make_errresp(const struct snmp_pdu *pdu, struct asn_buf *pdu_b, + struct asn_buf *resp_b) +{ + u_char type; + asn_len_t len; + struct snmp_pdu resp; + enum asn_err err; + enum snmp_code code; + + snmp_pdu_create_response(pdu, &resp); + + if ((code = snmp_pdu_decode_header(pdu_b, &resp)) != SNMP_CODE_OK) + return (SNMP_RET_IGN); + + if (pdu->version == SNMP_V3) { + if (resp.user.priv_proto != SNMP_PRIV_NOPRIV && + (asn_get_header(pdu_b, &type, &resp.scoped_len) != ASN_ERR_OK + || type != ASN_TYPE_OCTETSTRING)) { + snmp_error("cannot decode encrypted pdu"); + return (SNMP_RET_IGN); + } + + if (asn_get_sequence(pdu_b, &len) != ASN_ERR_OK) { + snmp_error("cannot decode scoped pdu header"); + return (SNMP_RET_IGN); + } + + len = SNMP_ENGINE_ID_SIZ; + if (asn_get_octetstring(pdu_b, (u_char *)resp.context_engine, + &len) != ASN_ERR_OK) { + snmp_error("cannot decode msg context engine"); + return (SNMP_RET_IGN); + } + resp.context_engine_len = len; + len = SNMP_CONTEXT_NAME_SIZ; + if (asn_get_octetstring(pdu_b, (u_char *)resp.context_name, + &len) != ASN_ERR_OK) { + snmp_error("cannot decode msg context name"); + return (SNMP_RET_IGN); + } + resp.context_name[len] = '\0'; + } + + + if (asn_get_header(pdu_b, &type, &len) != ASN_ERR_OK) { + snmp_error("cannot get pdu header"); + return (SNMP_RET_IGN); + } + + if ((type & ~ASN_TYPE_MASK) != + (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) { + snmp_error("bad pdu header tag"); + return (SNMP_RET_IGN); + } + + err = snmp_parse_pdus_hdr(pdu_b, &resp, &len); + if (ASN_ERR_STOPPED(err)) + return (SNMP_RET_IGN); + if (pdu_b->asn_len < len) + return (SNMP_RET_IGN); + pdu_b->asn_len = len; + + /* now we have the bindings left - construct new message */ + resp.error_status = pdu->error_status; + resp.error_index = pdu->error_index; + resp.type = SNMP_PDU_RESPONSE; + + code = snmp_pdu_encode_header(resp_b, &resp); + if (code != SNMP_CODE_OK) + return (SNMP_RET_IGN); + + if (pdu_b->asn_len > resp_b->asn_len) + /* too short */ + return (SNMP_RET_IGN); + (void)memcpy(resp_b->asn_ptr, pdu_b->asn_cptr, pdu_b->asn_len); + resp_b->asn_len -= pdu_b->asn_len; + resp_b->asn_ptr += pdu_b->asn_len; + + code = snmp_fix_encoding(resp_b, &resp); + if (code != SNMP_CODE_OK) + return (SNMP_RET_IGN); + + return (SNMP_RET_OK); +} + +static void +snmp_debug_func(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, "\n"); +} Property changes on: vendor/1.14/lib/snmpagent.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/lib/snmpagent.h =================================================================== --- vendor/1.14/lib/snmpagent.h (nonexistent) +++ vendor/1.14/lib/snmpagent.h (revision 359491) @@ -0,0 +1,152 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/lib/snmpagent.h,v 1.13 2004/08/06 08:46:56 brandt Exp $ + * + * Header file for SNMP functions. This requires snmp.h to be included. + */ +#ifndef snmp_agent_h_ +#define snmp_agent_h_ + +struct snmp_dependency; + +enum snmp_ret { + /* OK, generate a response */ + SNMP_RET_OK = 0, + /* Error, ignore packet (no response) */ + SNMP_RET_IGN = 1, + /* Error, generate response from original packet */ + SNMP_RET_ERR = 2 +}; + +/* Semi-Opaque object for SET operations */ +struct snmp_context { + u_int var_index; + struct snmp_scratch *scratch; + struct snmp_dependency *dep; + void *data; /* user data */ + enum snmp_ret code; /* return code */ +}; + +struct snmp_scratch { + void *ptr1; + void *ptr2; + uint32_t int1; + uint32_t int2; +}; + +enum snmp_depop { + SNMP_DEPOP_COMMIT, + SNMP_DEPOP_ROLLBACK, + SNMP_DEPOP_FINISH +}; + +typedef int (*snmp_depop_t)(struct snmp_context *, struct snmp_dependency *, + enum snmp_depop); + +struct snmp_dependency { + struct asn_oid obj; + struct asn_oid idx; +}; + +/* + * The TREE + */ +enum snmp_node_type { + SNMP_NODE_LEAF = 1, + SNMP_NODE_COLUMN +}; + +enum snmp_op { + SNMP_OP_GET = 1, + SNMP_OP_GETNEXT, + SNMP_OP_SET, + SNMP_OP_COMMIT, + SNMP_OP_ROLLBACK, +}; + +typedef int (*snmp_op_t)(struct snmp_context *, struct snmp_value *, + u_int, u_int, enum snmp_op); + +struct snmp_node { + struct asn_oid oid; + const char *name; /* name of the leaf */ + enum snmp_node_type type; /* type of this node */ + enum snmp_syntax syntax; + snmp_op_t op; + u_int flags; + uint32_t index; /* index data */ + void *data; /* application data */ + void *tree_data; /* application data */ +}; +extern struct snmp_node *tree; +extern u_int tree_size; + +#define SNMP_NODE_CANSET 0x0001 /* SET allowed */ + +#define SNMP_INDEXES_MAX 7 +#define SNMP_INDEX_SHIFT 4 +#define SNMP_INDEX_MASK 0xf +#define SNMP_INDEX_COUNT(V) ((V) & SNMP_INDEX_MASK) +#define SNMP_INDEX(V,I) \ + (((V) >> (((I) + 1) * SNMP_INDEX_SHIFT)) & SNMP_INDEX_MASK) + +enum { + SNMP_TRACE_GET = 0x00000001, + SNMP_TRACE_GETNEXT = 0x00000002, + SNMP_TRACE_SET = 0x00000004, + SNMP_TRACE_DEPEND = 0x00000008, + SNMP_TRACE_FIND = 0x00000010, +}; +/* trace flag for the following functions */ +extern u_int snmp_trace; + +/* called to write the trace */ +extern void (*snmp_debug)(const char *fmt, ...); + +enum snmp_ret snmp_get(struct snmp_pdu *pdu, struct asn_buf *resp_b, + struct snmp_pdu *resp, void *); +enum snmp_ret snmp_getnext(struct snmp_pdu *pdu, struct asn_buf *resp_b, + struct snmp_pdu *resp, void *); +enum snmp_ret snmp_getbulk(struct snmp_pdu *pdu, struct asn_buf *resp_b, + struct snmp_pdu *resp, void *); +enum snmp_ret snmp_set(struct snmp_pdu *pdu, struct asn_buf *resp_b, + struct snmp_pdu *resp, void *); + +enum snmp_ret snmp_make_errresp(const struct snmp_pdu *, struct asn_buf *, + struct asn_buf *); + +struct snmp_dependency *snmp_dep_lookup(struct snmp_context *, + const struct asn_oid *, const struct asn_oid *, size_t, snmp_depop_t); + +struct snmp_context *snmp_init_context(void); +int snmp_dep_commit(struct snmp_context *); +int snmp_dep_rollback(struct snmp_context *); +void snmp_dep_finish(struct snmp_context *); + +#endif Property changes on: vendor/1.14/lib/snmpagent.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/lib/snmppriv.h =================================================================== --- vendor/1.14/lib/snmppriv.h (nonexistent) +++ vendor/1.14/lib/snmppriv.h (revision 359491) @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/lib/snmppriv.h,v 1.9 2004/08/06 08:46:58 brandt Exp $ + * + * Private functions. + */ +#include + +enum asn_err snmp_binding_encode(struct asn_buf *, const struct snmp_value *); +enum snmp_code snmp_pdu_encode_header(struct asn_buf *, struct snmp_pdu *); +enum snmp_code snmp_fix_encoding(struct asn_buf *, struct snmp_pdu *); +enum asn_err snmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu, + asn_len_t *lenp); + +enum snmp_code snmp_pdu_calc_digest(const struct snmp_pdu *, uint8_t *); +enum snmp_code snmp_pdu_encrypt(const struct snmp_pdu *); +enum snmp_code snmp_pdu_decrypt(const struct snmp_pdu *); + +#define DEFAULT_HOST "localhost" +#define DEFAULT_PORT "snmp" +#define DEFAULT_LOCAL "/var/run/snmp.sock" Property changes on: vendor/1.14/lib/snmppriv.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/lib/support.c =================================================================== --- vendor/1.14/lib/support.c (nonexistent) +++ vendor/1.14/lib/support.c (revision 359491) @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2004 + * Hartmut Brandt. + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/lib/support.c,v 1.1 2004/08/06 08:47:58 brandt Exp $ + * + * Functions that are missing on certain systems. + */ +#include +#include +#include +#include +#include +#include "support.h" + +#ifndef HAVE_ERR_H + +void +warnx(const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "warning: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); +} + +void +warn(const char *fmt, ...) +{ + va_list ap; + int e = errno; + + va_start(ap, fmt); + fprintf(stderr, "warning: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ": %s\n", strerror(e)); + va_end(ap); +} + +void +errx(int code, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + fprintf(stderr, "error: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, "\n"); + va_end(ap); + exit(code); +} + +void +err(int code, const char *fmt, ...) +{ + va_list ap; + int e = errno; + + va_start(ap, fmt); + fprintf(stderr, "error: "); + vfprintf(stderr, fmt, ap); + fprintf(stderr, ": %s\n", strerror(e)); + va_end(ap); + exit(code); +} + +#endif + +#ifndef HAVE_STRLCPY + +size_t +strlcpy(char *dst, const char *src, size_t len) +{ + size_t ret = strlen(dst); + + while (len > 1) { + *dst++ = *src++; + len--; + } + if (len > 0) + *dst = '\0'; + return (ret); +} + +#endif + +#ifndef HAVE_GETADDRINFO + +#include +#include +#include +#include + +extern int h_nerr; +extern int h_errno; +extern const char *h_errlist[]; + +/* + * VERY poor man's implementation + */ +int +getaddrinfo(const char *host, const char *port, const struct addrinfo *hints, + struct addrinfo **res) +{ + struct hostent *hent; + struct sockaddr_in *s; + struct servent *sent; + + if ((hent = gethostbyname(host)) == NULL) + return (h_errno); + if (hent->h_addrtype != hints->ai_family) + return (HOST_NOT_FOUND); + if (hent->h_addrtype != AF_INET) + return (HOST_NOT_FOUND); + + if ((*res = malloc(sizeof(**res))) == NULL) + return (HOST_NOT_FOUND); + + (*res)->ai_flags = hints->ai_flags; + (*res)->ai_family = hints->ai_family; + (*res)->ai_socktype = hints->ai_socktype; + (*res)->ai_protocol = hints->ai_protocol; + (*res)->ai_next = NULL; + + if (((*res)->ai_addr = malloc(sizeof(struct sockaddr_in))) == NULL) { + freeaddrinfo(*res); + return (HOST_NOT_FOUND); + } + (*res)->ai_addrlen = sizeof(struct sockaddr_in); + s = (struct sockaddr_in *)(*res)->ai_addr; + s->sin_family = hints->ai_family; + s->sin_len = sizeof(*s); + memcpy(&s->sin_addr, hent->h_addr, 4); + + if ((sent = getservbyname(port, NULL)) == NULL) { + freeaddrinfo(*res); + return (HOST_NOT_FOUND); + } + s->sin_port = sent->s_port; + + return (0); +} + +const char * +gai_strerror(int e) +{ + + if (e < 0 || e >= h_nerr) + return ("unknown error"); + return (h_errlist[e]); +} + +void +freeaddrinfo(struct addrinfo *p) +{ + struct addrinfo *next; + + while (p != NULL) { + next = p->ai_next; + if (p->ai_addr != NULL) + free(p->ai_addr); + free(p); + p = next; + } +} + +#endif Property changes on: vendor/1.14/lib/support.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/lib/support.h =================================================================== --- vendor/1.14/lib/support.h (nonexistent) +++ vendor/1.14/lib/support.h (revision 359491) @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2004-2005 + * Hartmut Brandt. + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/lib/support.h,v 1.2 2005/10/06 07:14:59 brandt_h Exp $ + * + * Functions that are missing on certain systems. This header file is not + * to be installed. + */ +#ifndef bsnmp_support_h_ +#define bsnmp_support_h_ + +#include + +#ifndef HAVE_ERR_H +void err(int, const char *, ...) __printflike(2, 3) __dead2; +void errx(int, const char *, ...) __printflike(2, 3) __dead2; + +void warn(const char *, ...) __printflike(1, 2); +void warnx(const char *, ...) __printflike(1, 2); +#endif + +#ifndef HAVE_STRLCPY +size_t strlcpy(char *, const char *, size_t); +#endif + +#ifndef HAVE_GETADDRINFO + +struct addrinfo { + u_int ai_flags; + int ai_family; + int ai_socktype; + int ai_protocol; + struct sockaddr *ai_addr; + int ai_addrlen; + struct addrinfo *ai_next; +}; +#define AI_CANONNAME 0x0001 + +int getaddrinfo(const char *, const char *, const struct addrinfo *, + struct addrinfo **); +const char *gai_strerror(int); +void freeaddrinfo(struct addrinfo *); + +#endif + +/* + * For systems with missing stdint.h or inttypes.h + */ +#if !defined(INT32_MIN) +#define INT32_MIN (-0x7fffffff-1) +#endif +#if !defined(INT32_MAX) +#define INT32_MAX (0x7fffffff) +#endif +#if !defined(UINT32_MAX) +#define UINT32_MAX (0xffffffff) +#endif + +/* + * Systems missing SA_SIZE(). Taken from FreeBSD net/route.h:1.63 + */ +#ifndef SA_SIZE + +#define SA_SIZE(sa) \ + ( (!(sa) || ((struct sockaddr *)(sa))->sa_len == 0) ? \ + sizeof(long) : \ + 1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) ) + +#endif + +#endif Property changes on: vendor/1.14/lib/support.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_mibII/mibII.c =================================================================== --- vendor/1.14/snmp_mibII/mibII.c (nonexistent) +++ vendor/1.14/snmp_mibII/mibII.c (revision 359491) @@ -0,0 +1,1870 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: mibII.c 516 2006-10-27 15:54:02Z brandt_h $ + * + * Implementation of the standard interfaces and ip MIB. + */ +#include "mibII.h" +#include "mibII_oid.h" +#include +#include + + +/*****************************/ + +/* our module */ +static struct lmodule *module; + +/* routing socket */ +static int route; +static void *route_fd; + +/* if-index allocator */ +static uint32_t next_if_index = 1; + +/* currently fetching the arp table */ +static int in_update_arp; + +/* OR registrations */ +static u_int ifmib_reg; +static u_int ipmib_reg; +static u_int tcpmib_reg; +static u_int udpmib_reg; +static u_int ipForward_reg; + +/*****************************/ + +/* list of all IP addresses */ +struct mibifa_list mibifa_list = TAILQ_HEAD_INITIALIZER(mibifa_list); + +/* list of all interfaces */ +struct mibif_list mibif_list = TAILQ_HEAD_INITIALIZER(mibif_list); + +/* list of dynamic interface names */ +struct mibdynif_list mibdynif_list = SLIST_HEAD_INITIALIZER(mibdynif_list); + +/* list of all interface index mappings */ +struct mibindexmap_list mibindexmap_list = STAILQ_HEAD_INITIALIZER(mibindexmap_list); + +/* list of all stacking entries */ +struct mibifstack_list mibifstack_list = TAILQ_HEAD_INITIALIZER(mibifstack_list); + +/* list of all receive addresses */ +struct mibrcvaddr_list mibrcvaddr_list = TAILQ_HEAD_INITIALIZER(mibrcvaddr_list); + +/* list of all NetToMedia entries */ +struct mibarp_list mibarp_list = TAILQ_HEAD_INITIALIZER(mibarp_list); + +/* number of interfaces */ +int32_t mib_if_number; + +/* last change of table */ +uint64_t mib_iftable_last_change; + +/* last change of stack table */ +uint64_t mib_ifstack_last_change; + +/* if this is set, one of our lists may be bad. refresh them when idle */ +int mib_iflist_bad; + +/* network socket */ +int mib_netsock; + +/* last time refreshed */ +uint64_t mibarpticks; + +/* info on system clocks */ +struct clockinfo clockinfo; + +/* list of all New if registrations */ +static struct newifreg_list newifreg_list = TAILQ_HEAD_INITIALIZER(newifreg_list); + +/* baud rate of fastest interface */ +uint64_t mibif_maxspeed; + +/* user-forced update interval */ +u_int mibif_force_hc_update_interval; + +/* current update interval */ +u_int mibif_hc_update_interval; + +/* HC update timer handle */ +static void *hc_update_timer; + +/* Idle poll timer */ +static void *mibII_poll_timer; + +/* interfaces' data poll interval */ +u_int mibII_poll_ticks; + +/* Idle poll hook */ +static void mibII_idle(void *arg __unused); + +/*****************************/ + +static const struct asn_oid oid_ifMIB = OIDX_ifMIB; +static const struct asn_oid oid_ipMIB = OIDX_ipMIB; +static const struct asn_oid oid_tcpMIB = OIDX_tcpMIB; +static const struct asn_oid oid_udpMIB = OIDX_udpMIB; +static const struct asn_oid oid_ipForward = OIDX_ipForward; +static const struct asn_oid oid_linkDown = OIDX_linkDown; +static const struct asn_oid oid_linkUp = OIDX_linkUp; +static const struct asn_oid oid_ifIndex = OIDX_ifIndex; + +/*****************************/ + +/* + * Find an interface + */ +struct mibif * +mib_find_if(u_int idx) +{ + struct mibif *ifp; + + TAILQ_FOREACH(ifp, &mibif_list, link) + if (ifp->index == idx) + return (ifp); + return (NULL); +} + +struct mibif * +mib_find_if_sys(u_int sysindex) +{ + struct mibif *ifp; + + TAILQ_FOREACH(ifp, &mibif_list, link) + if (ifp->sysindex == sysindex) + return (ifp); + return (NULL); +} + +struct mibif * +mib_find_if_name(const char *name) +{ + struct mibif *ifp; + + TAILQ_FOREACH(ifp, &mibif_list, link) + if (strcmp(ifp->name, name) == 0) + return (ifp); + return (NULL); +} + +/* + * Check whether an interface is dynamic. The argument may include the + * unit number. This assumes, that the name part does NOT contain digits. + */ +int +mib_if_is_dyn(const char *name) +{ + size_t len; + struct mibdynif *d; + + for (len = 0; name[len] != '\0' && isalpha(name[len]) ; len++) + ; + SLIST_FOREACH(d, &mibdynif_list, link) + if (strlen(d->name) == len && strncmp(d->name, name, len) == 0) + return (1); + return (0); +} + +/* set an interface name to dynamic mode */ +void +mib_if_set_dyn(const char *name) +{ + struct mibdynif *d; + + SLIST_FOREACH(d, &mibdynif_list, link) + if (strcmp(name, d->name) == 0) + return; + if ((d = malloc(sizeof(*d))) == NULL) + err(1, NULL); + strlcpy(d->name, name, sizeof(d->name)); + SLIST_INSERT_HEAD(&mibdynif_list, d, link); +} + +/* + * register for interface creations + */ +int +mib_register_newif(int (*func)(struct mibif *), const struct lmodule *mod) +{ + struct newifreg *reg; + + TAILQ_FOREACH(reg, &newifreg_list, link) + if (reg->mod == mod) { + reg->func = func; + return (0); + } + if ((reg = malloc(sizeof(*reg))) == NULL) { + syslog(LOG_ERR, "newifreg: %m"); + return (-1); + } + reg->mod = mod; + reg->func = func; + TAILQ_INSERT_TAIL(&newifreg_list, reg, link); + + return (0); +} + +void +mib_unregister_newif(const struct lmodule *mod) +{ + struct newifreg *reg; + + TAILQ_FOREACH(reg, &newifreg_list, link) + if (reg->mod == mod) { + TAILQ_REMOVE(&newifreg_list, reg, link); + free(reg); + return; + } + +} + +struct mibif * +mib_first_if(void) +{ + return (TAILQ_FIRST(&mibif_list)); +} +struct mibif * +mib_next_if(const struct mibif *ifp) +{ + return (TAILQ_NEXT(ifp, link)); +} + +/* + * Change the admin status of an interface + */ +int +mib_if_admin(struct mibif *ifp, int up) +{ + struct ifreq ifr; + + strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); + if (ioctl(mib_netsock, SIOCGIFFLAGS, &ifr) == -1) { + syslog(LOG_ERR, "SIOCGIFFLAGS(%s): %m", ifp->name); + return (-1); + } + if (up) + ifr.ifr_flags |= IFF_UP; + else + ifr.ifr_flags &= ~IFF_UP; + if (ioctl(mib_netsock, SIOCSIFFLAGS, &ifr) == -1) { + syslog(LOG_ERR, "SIOCSIFFLAGS(%s): %m", ifp->name); + return (-1); + } + + (void)mib_fetch_ifmib(ifp); + + return (0); +} + +/* + * Generate a link up/down trap + */ +static void +link_trap(struct mibif *ifp, int up) +{ + struct snmp_value ifindex; + + ifindex.var = oid_ifIndex; + ifindex.var.subs[ifindex.var.len++] = ifp->index; + ifindex.syntax = SNMP_SYNTAX_INTEGER; + ifindex.v.integer = ifp->index; + + snmp_send_trap(up ? &oid_linkUp : &oid_linkDown, &ifindex, + (struct snmp_value *)NULL); +} + +/** + * Fetch the GENERIC IFMIB and update the HC counters + */ +static int +fetch_generic_mib(struct mibif *ifp, const struct ifmibdata *old) +{ + int name[6]; + size_t len; + struct mibif_private *p = ifp->private; + + name[0] = CTL_NET; + name[1] = PF_LINK; + name[2] = NETLINK_GENERIC; + name[3] = IFMIB_IFDATA; + name[4] = ifp->sysindex; + name[5] = IFDATA_GENERAL; + + len = sizeof(ifp->mib); + if (sysctl(name, nitems(name), &ifp->mib, &len, NULL, 0) == -1) { + if (errno != ENOENT) + syslog(LOG_WARNING, "sysctl(ifmib, %s) failed %m", + ifp->name); + return (-1); + } + + /* + * Assume that one of the two following compounds is optimized away + */ + if (ULONG_MAX >= 0xffffffffffffffffULL) { + p->hc_inoctets = ifp->mib.ifmd_data.ifi_ibytes; + p->hc_outoctets = ifp->mib.ifmd_data.ifi_obytes; + p->hc_omcasts = ifp->mib.ifmd_data.ifi_omcasts; + p->hc_opackets = ifp->mib.ifmd_data.ifi_opackets; + p->hc_imcasts = ifp->mib.ifmd_data.ifi_imcasts; + p->hc_ipackets = ifp->mib.ifmd_data.ifi_ipackets; + + } else if (ULONG_MAX >= 0xffffffff) { + +#define UPDATE(HC, MIB) \ + if (old->ifmd_data.MIB > ifp->mib.ifmd_data.MIB) \ + p->HC += (0x100000000ULL + \ + ifp->mib.ifmd_data.MIB) - \ + old->ifmd_data.MIB; \ + else \ + p->HC += ifp->mib.ifmd_data.MIB - \ + old->ifmd_data.MIB; + + UPDATE(hc_inoctets, ifi_ibytes) + UPDATE(hc_outoctets, ifi_obytes) + UPDATE(hc_omcasts, ifi_omcasts) + UPDATE(hc_opackets, ifi_opackets) + UPDATE(hc_imcasts, ifi_imcasts) + UPDATE(hc_ipackets, ifi_ipackets) + +#undef UPDATE + } else + abort(); + return (0); +} + +/** + * Update the 64-bit interface counters + */ +static void +update_hc_counters(void *arg __unused) +{ + struct mibif *ifp; + struct ifmibdata oldmib; + + TAILQ_FOREACH(ifp, &mibif_list, link) { + oldmib = ifp->mib; + (void)fetch_generic_mib(ifp, &oldmib); + } +} + +/** + * Recompute the poll timer for the HC counters + */ +void +mibif_reset_hc_timer(void) +{ + u_int ticks; + + if ((ticks = mibif_force_hc_update_interval) == 0) { + if (mibif_maxspeed <= IF_Mbps(10)) { + /* at 10Mbps overflow needs 3436 seconds */ + ticks = 3000 * 100; /* 50 minutes */ + } else if (mibif_maxspeed <= IF_Mbps(100)) { + /* at 100Mbps overflow needs 343 seconds */ + ticks = 300 * 100; /* 5 minutes */ + } else if (mibif_maxspeed < IF_Mbps(622)) { + /* at 622Mbps overflow needs 53 seconds */ + ticks = 40 * 100; /* 40 seconds */ + } else if (mibif_maxspeed <= IF_Mbps(1000)) { + /* at 1Gbps overflow needs 34 seconds */ + ticks = 20 * 100; /* 20 seconds */ + } else { + /* at 10Gbps overflow needs 3.4 seconds */ + ticks = 100; /* 1 seconds */ + } + } + + if (ticks == mibif_hc_update_interval) + return; + + if (hc_update_timer != NULL) { + timer_stop(hc_update_timer); + hc_update_timer = NULL; + } + update_hc_counters(NULL); + if ((hc_update_timer = timer_start_repeat(ticks, ticks, + update_hc_counters, NULL, module)) == NULL) { + syslog(LOG_ERR, "timer_start(%u): %m", ticks); + return; + } + mibif_hc_update_interval = ticks; +} + +/** + * Restart the idle poll timer. + */ +void +mibif_restart_mibII_poll_timer(void) +{ + if (mibII_poll_timer != NULL) + timer_stop(mibII_poll_timer); + + if ((mibII_poll_timer = timer_start_repeat(mibII_poll_ticks * 10, + mibII_poll_ticks * 10, mibII_idle, NULL, module)) == NULL) + syslog(LOG_ERR, "timer_start(%u): %m", mibII_poll_ticks); +} + +/* + * Fetch new MIB data. + */ +int +mib_fetch_ifmib(struct mibif *ifp) +{ + static int kmib[2] = { -1, 0 }; /* for sysctl net.ifdescr_maxlen */ + + int name[6]; + size_t kmiblen = nitems(kmib); + size_t len; + void *newmib; + struct ifmibdata oldmib = ifp->mib; + struct ifreq irr; + u_int alias_maxlen = MIBIF_ALIAS_SIZE_MAX; + + if (fetch_generic_mib(ifp, &oldmib) == -1) + return (-1); + + /* + * Quoting RFC2863, 3.1.15: "... LinkUp and linkDown traps are + * generated just after ifOperStatus leaves, or just before it + * enters, the down state, respectively;" + */ + if (ifp->trap_enable && ifp->mib.ifmd_data.ifi_link_state != + oldmib.ifmd_data.ifi_link_state && + (ifp->mib.ifmd_data.ifi_link_state == LINK_STATE_DOWN || + oldmib.ifmd_data.ifi_link_state == LINK_STATE_DOWN)) + link_trap(ifp, ifp->mib.ifmd_data.ifi_link_state == + LINK_STATE_UP ? 1 : 0); + + ifp->flags &= ~(MIBIF_HIGHSPEED | MIBIF_VERYHIGHSPEED); + if (ifp->mib.ifmd_data.ifi_baudrate > 20000000) { + ifp->flags |= MIBIF_HIGHSPEED; + if (ifp->mib.ifmd_data.ifi_baudrate > 650000000) + ifp->flags |= MIBIF_VERYHIGHSPEED; + } + if (ifp->mib.ifmd_data.ifi_baudrate > mibif_maxspeed) { + mibif_maxspeed = ifp->mib.ifmd_data.ifi_baudrate; + mibif_reset_hc_timer(); + } + + /* + * linkspecific MIB + */ + name[0] = CTL_NET; + name[1] = PF_LINK; + name[2] = NETLINK_GENERIC; + name[3] = IFMIB_IFDATA; + name[4] = ifp->sysindex; + name[5] = IFDATA_LINKSPECIFIC; + if (sysctl(name, nitems(name), NULL, &len, NULL, 0) == -1) { + syslog(LOG_WARNING, "sysctl linkmib estimate (%s): %m", + ifp->name); + if (ifp->specmib != NULL) { + ifp->specmib = NULL; + ifp->specmiblen = 0; + } + goto out; + } + if (len == 0) { + if (ifp->specmib != NULL) { + ifp->specmib = NULL; + ifp->specmiblen = 0; + } + goto out; + } + + if (ifp->specmiblen != len) { + if ((newmib = realloc(ifp->specmib, len)) == NULL) { + ifp->specmib = NULL; + ifp->specmiblen = 0; + goto out; + } + ifp->specmib = newmib; + ifp->specmiblen = len; + } + if (sysctl(name, nitems(name), ifp->specmib, &len, NULL, 0) == -1) { + syslog(LOG_WARNING, "sysctl linkmib (%s): %m", ifp->name); + if (ifp->specmib != NULL) { + ifp->specmib = NULL; + ifp->specmiblen = 0; + } + } + + out: + /* + * Find sysctl mib for net.ifdescr_maxlen (one time). + * kmib[0] == -1 at first call to mib_fetch_ifmib(). + * Then kmib[0] > 0 if we found sysctl mib for net.ifdescr_maxlen. + * Else, kmib[0] == 0 (unexpected error from a kernel). + */ + if (kmib[0] < 0 && + sysctlnametomib("net.ifdescr_maxlen", kmib, &kmiblen) < 0) { + kmib[0] = 0; + syslog(LOG_WARNING, "sysctlnametomib net.ifdescr_maxlen: %m"); + } + + /* + * Fetch net.ifdescr_maxlen value every time to catch up with changes. + */ + len = sizeof(alias_maxlen); + if (kmib[0] > 0 && sysctl(kmib, 2, &alias_maxlen, &len, NULL, 0) < 0) { + /* unexpected error from the kernel, use default value */ + alias_maxlen = MIBIF_ALIAS_SIZE_MAX; + syslog(LOG_WARNING, "sysctl net.ifdescr_maxlen: %m"); + } + + /* + * Kernel limit might be decreased after interfaces got + * their descriptions assigned. Try to obtain them anyway. + */ + if (alias_maxlen == 0) + alias_maxlen = MIBIF_ALIAS_SIZE_MAX; + + /* + * Allocate maximum memory for a buffer and later reallocate + * to free extra memory. + */ + if ((ifp->alias = malloc(alias_maxlen)) == NULL) { + syslog(LOG_WARNING, "malloc(%d) failed: %m", (int)alias_maxlen); + goto fin; + } + + strlcpy(irr.ifr_name, ifp->name, sizeof(irr.ifr_name)); + irr.ifr_buffer.buffer = ifp->alias; + irr.ifr_buffer.length = alias_maxlen; + if (ioctl(mib_netsock, SIOCGIFDESCR, &irr) == -1) { + free(ifp->alias); + ifp->alias = NULL; + if (errno != ENOMSG) + syslog(LOG_WARNING, "SIOCGIFDESCR (%s): %m", ifp->name); + } else if (irr.ifr_buffer.buffer == NULL) { + free(ifp->alias); + ifp->alias = NULL; + syslog(LOG_WARNING, "SIOCGIFDESCR (%s): too long (%zu)", + ifp->name, irr.ifr_buffer.length); + } else { + ifp->alias_size = strnlen(ifp->alias, alias_maxlen) + 1; + + if (ifp->alias_size > MIBIF_ALIAS_SIZE) + ifp->alias_size = MIBIF_ALIAS_SIZE; + + if (ifp->alias_size < alias_maxlen) + ifp->alias = realloc(ifp->alias, ifp->alias_size); + } + + fin: + ifp->mibtick = get_ticks(); + return (0); +} + +/* find first/next address for a given interface */ +struct mibifa * +mib_first_ififa(const struct mibif *ifp) +{ + struct mibifa *ifa; + + TAILQ_FOREACH(ifa, &mibifa_list, link) + if (ifp->index == ifa->ifindex) + return (ifa); + return (NULL); +} + +struct mibifa * +mib_next_ififa(struct mibifa *ifa0) +{ + struct mibifa *ifa; + + ifa = ifa0; + while ((ifa = TAILQ_NEXT(ifa, link)) != NULL) + if (ifa->ifindex == ifa0->ifindex) + return (ifa); + return (NULL); +} + +/* + * Allocate a new IFA + */ +static struct mibifa * +alloc_ifa(u_int ifindex, struct in_addr addr) +{ + struct mibifa *ifa; + uint32_t ha; + + if ((ifa = malloc(sizeof(struct mibifa))) == NULL) { + syslog(LOG_ERR, "ifa: %m"); + return (NULL); + } + ifa->inaddr = addr; + ifa->ifindex = ifindex; + + ha = ntohl(ifa->inaddr.s_addr); + ifa->index.len = 4; + ifa->index.subs[0] = (ha >> 24) & 0xff; + ifa->index.subs[1] = (ha >> 16) & 0xff; + ifa->index.subs[2] = (ha >> 8) & 0xff; + ifa->index.subs[3] = (ha >> 0) & 0xff; + + ifa->flags = 0; + ifa->inbcast.s_addr = 0; + ifa->inmask.s_addr = 0xffffffff; + + INSERT_OBJECT_OID(ifa, &mibifa_list); + + return (ifa); +} + +/* + * Delete an interface address + */ +static void +destroy_ifa(struct mibifa *ifa) +{ + TAILQ_REMOVE(&mibifa_list, ifa, link); + free(ifa); +} + + +/* + * Helper routine to extract the sockaddr structures from a routing + * socket message. + */ +void +mib_extract_addrs(int addrs, u_char *info, struct sockaddr **out) +{ + u_int i; + + for (i = 0; i < RTAX_MAX; i++) { + if ((addrs & (1 << i)) != 0) { + *out = (struct sockaddr *)(void *)info; + info += roundup((*out)->sa_len, sizeof(long)); + } else + *out = NULL; + out++; + } +} + +/* + * save the phys address of an interface. Handle receive address entries here. + */ +static void +get_physaddr(struct mibif *ifp, struct sockaddr_dl *sdl, u_char *ptr) +{ + u_char *np; + struct mibrcvaddr *rcv; + + if (sdl->sdl_alen == 0) { + /* no address */ + if (ifp->physaddrlen != 0) { + if ((rcv = mib_find_rcvaddr(ifp->index, ifp->physaddr, + ifp->physaddrlen)) != NULL) + mib_rcvaddr_delete(rcv); + free(ifp->physaddr); + ifp->physaddr = NULL; + ifp->physaddrlen = 0; + } + return; + } + + if (ifp->physaddrlen != sdl->sdl_alen) { + /* length changed */ + if (ifp->physaddrlen) { + /* delete olf receive address */ + if ((rcv = mib_find_rcvaddr(ifp->index, ifp->physaddr, + ifp->physaddrlen)) != NULL) + mib_rcvaddr_delete(rcv); + } + if ((np = realloc(ifp->physaddr, sdl->sdl_alen)) == NULL) { + free(ifp->physaddr); + ifp->physaddr = NULL; + ifp->physaddrlen = 0; + return; + } + ifp->physaddr = np; + ifp->physaddrlen = sdl->sdl_alen; + + } else if (memcmp(ifp->physaddr, ptr, ifp->physaddrlen) == 0) { + /* no change */ + return; + + } else { + /* address changed */ + + /* delete olf receive address */ + if ((rcv = mib_find_rcvaddr(ifp->index, ifp->physaddr, + ifp->physaddrlen)) != NULL) + mib_rcvaddr_delete(rcv); + } + + memcpy(ifp->physaddr, ptr, ifp->physaddrlen); + + /* make new receive address */ + if ((rcv = mib_rcvaddr_create(ifp, ifp->physaddr, ifp->physaddrlen)) != NULL) + rcv->flags |= MIBRCVADDR_HW; +} + +/* + * Free an interface + */ +static void +mibif_free(struct mibif *ifp) +{ + struct mibif *ifp1; + struct mibindexmap *map; + struct mibifa *ifa, *ifa1; + struct mibrcvaddr *rcv, *rcv1; + struct mibarp *at, *at1; + + if (ifp->xnotify != NULL) + (*ifp->xnotify)(ifp, MIBIF_NOTIFY_DESTROY, ifp->xnotify_data); + + (void)mib_ifstack_delete(ifp, NULL); + (void)mib_ifstack_delete(NULL, ifp); + + TAILQ_REMOVE(&mibif_list, ifp, link); + + /* if this was the fastest interface - recompute this */ + if (ifp->mib.ifmd_data.ifi_baudrate == mibif_maxspeed) { + mibif_maxspeed = ifp->mib.ifmd_data.ifi_baudrate; + TAILQ_FOREACH(ifp1, &mibif_list, link) + if (ifp1->mib.ifmd_data.ifi_baudrate > mibif_maxspeed) + mibif_maxspeed = + ifp1->mib.ifmd_data.ifi_baudrate; + mibif_reset_hc_timer(); + } + + if (ifp->alias != NULL) { + free(ifp->alias); + ifp->alias = NULL; + } + free(ifp->private); + ifp->private = NULL; + free(ifp->physaddr); + ifp->physaddr = NULL; + free(ifp->specmib); + ifp->specmib = NULL; + + STAILQ_FOREACH(map, &mibindexmap_list, link) + if (map->mibif == ifp) { + map->mibif = NULL; + break; + } + + /* purge interface addresses */ + ifa = TAILQ_FIRST(&mibifa_list); + while (ifa != NULL) { + ifa1 = TAILQ_NEXT(ifa, link); + if (ifa->ifindex == ifp->index) + destroy_ifa(ifa); + ifa = ifa1; + } + + /* purge receive addresses */ + rcv = TAILQ_FIRST(&mibrcvaddr_list); + while (rcv != NULL) { + rcv1 = TAILQ_NEXT(rcv, link); + if (rcv->ifindex == ifp->index) + mib_rcvaddr_delete(rcv); + rcv = rcv1; + } + + /* purge ARP entries */ + at = TAILQ_FIRST(&mibarp_list); + while (at != NULL) { + at1 = TAILQ_NEXT(at, link); + if (at->index.subs[0] == ifp->index) + mib_arp_delete(at); + at = at1; + } + + free(ifp); + ifp = NULL; + mib_if_number--; + mib_iftable_last_change = this_tick; +} + +/* + * Create a new interface + */ +static struct mibif * +mibif_create(u_int sysindex, const char *name) +{ + struct mibif *ifp; + struct mibindexmap *map; + + if ((ifp = malloc(sizeof(*ifp))) == NULL) { + syslog(LOG_WARNING, "%s: %m", __func__); + return (NULL); + } + memset(ifp, 0, sizeof(*ifp)); + if ((ifp->private = malloc(sizeof(struct mibif_private))) == NULL) { + syslog(LOG_WARNING, "%s: %m", __func__); + free(ifp); + return (NULL); + } + memset(ifp->private, 0, sizeof(struct mibif_private)); + + ifp->sysindex = sysindex; + strlcpy(ifp->name, name, sizeof(ifp->name)); + strlcpy(ifp->descr, name, sizeof(ifp->descr)); + ifp->spec_oid = oid_zeroDotZero; + + map = NULL; + if (!mib_if_is_dyn(ifp->name)) { + /* non-dynamic. look whether we know the interface */ + STAILQ_FOREACH(map, &mibindexmap_list, link) + if (strcmp(map->name, ifp->name) == 0) { + ifp->index = map->ifindex; + map->mibif = ifp; + break; + } + /* assume it has a connector if it is not dynamic */ + ifp->has_connector = 1; + ifp->trap_enable = 1; + } + if (map == NULL) { + /* new interface - get new index */ + if (next_if_index > 0x7fffffff) + errx(1, "ifindex wrap"); + + if ((map = malloc(sizeof(*map))) == NULL) { + syslog(LOG_ERR, "ifmap: %m"); + free(ifp); + return (NULL); + } + map->ifindex = next_if_index++; + map->sysindex = ifp->sysindex; + strcpy(map->name, ifp->name); + map->mibif = ifp; + STAILQ_INSERT_TAIL(&mibindexmap_list, map, link); + } else { + /* re-instantiate. Introduce a counter discontinuity */ + ifp->counter_disc = get_ticks(); + } + ifp->index = map->ifindex; + ifp->mib.ifmd_data.ifi_link_state = LINK_STATE_UNKNOWN; + + INSERT_OBJECT_INT(ifp, &mibif_list); + mib_if_number++; + mib_iftable_last_change = this_tick; + + /* instantiate default ifStack entries */ + (void)mib_ifstack_create(ifp, NULL); + (void)mib_ifstack_create(NULL, ifp); + + return (ifp); +} + +/* + * Inform all interested parties about a new interface + */ +static void +notify_newif(struct mibif *ifp) +{ + struct newifreg *reg; + + TAILQ_FOREACH(reg, &newifreg_list, link) + if ((*reg->func)(ifp)) + return; +} + +/* + * This is called for new interfaces after we have fetched the interface + * MIB. If this is a broadcast interface try to guess the broadcast address + * depending on the interface type. + */ +static void +check_llbcast(struct mibif *ifp) +{ + static u_char ether_bcast[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; + struct mibrcvaddr *rcv; + + if (!(ifp->mib.ifmd_flags & IFF_BROADCAST)) + return; + + switch (ifp->mib.ifmd_data.ifi_type) { + + case IFT_ETHER: + case IFT_FDDI: + case IFT_ISO88025: + case IFT_L2VLAN: + if (mib_find_rcvaddr(ifp->index, ether_bcast, 6) == NULL && + (rcv = mib_rcvaddr_create(ifp, ether_bcast, 6)) != NULL) + rcv->flags |= MIBRCVADDR_BCAST; + break; + } +} + + +/* + * Retrieve the current interface list from the system. + */ +void +mib_refresh_iflist(void) +{ + struct mibif *ifp, *ifp1; + size_t len; + u_short idx; + int name[6]; + int count; + struct ifmibdata mib; + + TAILQ_FOREACH(ifp, &mibif_list, link) + ifp->flags &= ~MIBIF_FOUND; + + len = sizeof(count); + if (sysctlbyname("net.link.generic.system.ifcount", &count, &len, + NULL, 0) == -1) { + syslog(LOG_ERR, "ifcount: %m"); + return; + } + name[0] = CTL_NET; + name[1] = PF_LINK; + name[2] = NETLINK_GENERIC; + name[3] = IFMIB_IFDATA; + name[5] = IFDATA_GENERAL; + for (idx = 1; idx <= count; idx++) { + name[4] = idx; + len = sizeof(mib); + if (sysctl(name, nitems(name), &mib, &len, NULL, 0) == -1) { + if (errno == ENOENT) + continue; + syslog(LOG_ERR, "ifmib(%u): %m", idx); + return; + } + if ((ifp = mib_find_if_sys(idx)) != NULL) { + ifp->flags |= MIBIF_FOUND; + continue; + } + /* Unknown interface - create */ + if ((ifp = mibif_create(idx, mib.ifmd_name)) != NULL) { + ifp->flags |= MIBIF_FOUND; + (void)mib_fetch_ifmib(ifp); + check_llbcast(ifp); + notify_newif(ifp); + } + } + + /* + * Purge interfaces that disappeared + */ + ifp = TAILQ_FIRST(&mibif_list); + while (ifp != NULL) { + ifp1 = TAILQ_NEXT(ifp, link); + if (!(ifp->flags & MIBIF_FOUND)) + mibif_free(ifp); + ifp = ifp1; + } +} + +/* + * Find an interface address + */ +struct mibifa * +mib_find_ifa(struct in_addr addr) +{ + struct mibifa *ifa; + + TAILQ_FOREACH(ifa, &mibifa_list, link) + if (ifa->inaddr.s_addr == addr.s_addr) + return (ifa); + return (NULL); +} + +/* + * Process a new ARP entry + */ +static void +process_arp(const struct rt_msghdr *rtm, const struct sockaddr_dl *sdl, + const struct sockaddr_in *sa) +{ + struct mibif *ifp; + struct mibarp *at; + + /* IP arp table entry */ + if (sdl->sdl_alen == 0) + return; + if ((ifp = mib_find_if_sys(sdl->sdl_index)) == NULL) + return; + /* have a valid entry */ + if ((at = mib_find_arp(ifp, sa->sin_addr)) == NULL && + (at = mib_arp_create(ifp, sa->sin_addr, + sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) == NULL) + return; + + if (rtm->rtm_rmx.rmx_expire == 0) + at->flags |= MIBARP_PERM; + else + at->flags &= ~MIBARP_PERM; + at->flags |= MIBARP_FOUND; +} + +/* + * Handle a routing socket message. + */ +static void +handle_rtmsg(struct rt_msghdr *rtm) +{ + struct sockaddr *addrs[RTAX_MAX]; + struct if_msghdr *ifm; + struct ifa_msghdr ifam, *ifamp; + struct ifma_msghdr *ifmam; +#ifdef RTM_IFANNOUNCE + struct if_announcemsghdr *ifan; +#endif + struct mibif *ifp; + struct sockaddr_dl *sdl; + struct sockaddr_in *sa; + struct mibifa *ifa; + struct mibrcvaddr *rcv; + u_char *ptr; + + if (rtm->rtm_version != RTM_VERSION) { + syslog(LOG_ERR, "Bogus RTM version %u", rtm->rtm_version); + return; + } + + switch (rtm->rtm_type) { + + case RTM_NEWADDR: + ifamp = (struct ifa_msghdr *)rtm; + memcpy(&ifam, ifamp, sizeof(ifam)); + mib_extract_addrs(ifam.ifam_addrs, (u_char *)(ifamp + 1), addrs); + if (addrs[RTAX_IFA] == NULL || addrs[RTAX_NETMASK] == NULL) + break; + + sa = (struct sockaddr_in *)(void *)addrs[RTAX_IFA]; + if ((ifa = mib_find_ifa(sa->sin_addr)) == NULL) { + /* unknown address */ + if ((ifp = mib_find_if_sys(ifam.ifam_index)) == NULL) { + syslog(LOG_WARNING, "RTM_NEWADDR for unknown " + "interface %u", ifam.ifam_index); + break; + } + if ((ifa = alloc_ifa(ifp->index, sa->sin_addr)) == NULL) + break; + } + sa = (struct sockaddr_in *)(void *)addrs[RTAX_NETMASK]; + ifa->inmask = sa->sin_addr; + + if (addrs[RTAX_BRD] != NULL) { + sa = (struct sockaddr_in *)(void *)addrs[RTAX_BRD]; + ifa->inbcast = sa->sin_addr; + } + ifa->flags |= MIBIFA_FOUND; + break; + + case RTM_DELADDR: + ifamp = (struct ifa_msghdr *)rtm; + memcpy(&ifam, ifamp, sizeof(ifam)); + mib_extract_addrs(ifam.ifam_addrs, (u_char *)(ifamp + 1), addrs); + if (addrs[RTAX_IFA] == NULL) + break; + + sa = (struct sockaddr_in *)(void *)addrs[RTAX_IFA]; + if ((ifa = mib_find_ifa(sa->sin_addr)) != NULL) { + ifa->flags |= MIBIFA_FOUND; + if (!(ifa->flags & MIBIFA_DESTROYED)) + destroy_ifa(ifa); + } + break; + + case RTM_NEWMADDR: + ifmam = (struct ifma_msghdr *)rtm; + mib_extract_addrs(ifmam->ifmam_addrs, (u_char *)(ifmam + 1), addrs); + if (addrs[RTAX_IFA] == NULL || + addrs[RTAX_IFA]->sa_family != AF_LINK) + break; + sdl = (struct sockaddr_dl *)(void *)addrs[RTAX_IFA]; + if ((rcv = mib_find_rcvaddr(sdl->sdl_index, + sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) == NULL) { + /* unknown address */ + if ((ifp = mib_find_if_sys(sdl->sdl_index)) == NULL) { + syslog(LOG_WARNING, "RTM_NEWMADDR for unknown " + "interface %u", sdl->sdl_index); + break; + } + if ((rcv = mib_rcvaddr_create(ifp, + sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) == NULL) + break; + rcv->flags |= MIBRCVADDR_VOLATILE; + } + rcv->flags |= MIBRCVADDR_FOUND; + break; + + case RTM_DELMADDR: + ifmam = (struct ifma_msghdr *)rtm; + mib_extract_addrs(ifmam->ifmam_addrs, (u_char *)(ifmam + 1), addrs); + if (addrs[RTAX_IFA] == NULL || + addrs[RTAX_IFA]->sa_family != AF_LINK) + break; + sdl = (struct sockaddr_dl *)(void *)addrs[RTAX_IFA]; + if ((rcv = mib_find_rcvaddr(sdl->sdl_index, + sdl->sdl_data + sdl->sdl_nlen, sdl->sdl_alen)) != NULL) + mib_rcvaddr_delete(rcv); + break; + + case RTM_IFINFO: + ifm = (struct if_msghdr *)(void *)rtm; + mib_extract_addrs(ifm->ifm_addrs, (u_char *)(ifm + 1), addrs); + if ((ifp = mib_find_if_sys(ifm->ifm_index)) == NULL) + break; + if (addrs[RTAX_IFP] != NULL && + addrs[RTAX_IFP]->sa_family == AF_LINK) { + sdl = (struct sockaddr_dl *)(void *)addrs[RTAX_IFP]; + ptr = sdl->sdl_data + sdl->sdl_nlen; + get_physaddr(ifp, sdl, ptr); + } + (void)mib_fetch_ifmib(ifp); + break; + +#ifdef RTM_IFANNOUNCE + case RTM_IFANNOUNCE: + ifan = (struct if_announcemsghdr *)rtm; + ifp = mib_find_if_sys(ifan->ifan_index); + + switch (ifan->ifan_what) { + + case IFAN_ARRIVAL: + if (ifp == NULL && (ifp = mibif_create(ifan->ifan_index, + ifan->ifan_name)) != NULL) { + (void)mib_fetch_ifmib(ifp); + check_llbcast(ifp); + notify_newif(ifp); + } + break; + + case IFAN_DEPARTURE: + if (ifp != NULL) + mibif_free(ifp); + break; + } + break; +#endif + case RTM_GET: + case RTM_ADD: + mib_extract_addrs(rtm->rtm_addrs, (u_char *)(rtm + 1), addrs); + if (rtm->rtm_flags & RTF_LLINFO) { + if (addrs[RTAX_DST] == NULL || + addrs[RTAX_GATEWAY] == NULL || + addrs[RTAX_DST]->sa_family != AF_INET || + addrs[RTAX_GATEWAY]->sa_family != AF_LINK) + break; + process_arp(rtm, + (struct sockaddr_dl *)(void *)addrs[RTAX_GATEWAY], + (struct sockaddr_in *)(void *)addrs[RTAX_DST]); + } else { + if (rtm->rtm_errno == 0 && (rtm->rtm_flags & RTF_UP)) + mib_sroute_process(rtm, addrs[RTAX_GATEWAY], + addrs[RTAX_DST], addrs[RTAX_NETMASK]); + } + break; + + case RTM_DELETE: + mib_extract_addrs(rtm->rtm_addrs, (u_char *)(rtm + 1), addrs); + + if (rtm->rtm_errno == 0 && (rtm->rtm_flags & RTF_UP)) + mib_sroute_process(rtm, addrs[RTAX_GATEWAY], + addrs[RTAX_DST], addrs[RTAX_NETMASK]); + break; + } +} + +/* + * send a routing message + */ +void +mib_send_rtmsg(struct rt_msghdr *rtm, struct sockaddr *gw, + struct sockaddr *dst, struct sockaddr *mask) +{ + size_t len; + struct rt_msghdr *msg; + char *cp; + ssize_t sent; + + len = sizeof(*rtm) + SA_SIZE(gw) + SA_SIZE(dst) + SA_SIZE(mask); + if ((msg = malloc(len)) == NULL) { + syslog(LOG_ERR, "%s: %m", __func__); + return; + } + cp = (char *)(msg + 1); + + memset(msg, 0, sizeof(*msg)); + msg->rtm_flags = 0; + msg->rtm_version = RTM_VERSION; + msg->rtm_addrs = RTA_DST | RTA_GATEWAY; + + memcpy(cp, dst, SA_SIZE(dst)); + cp += SA_SIZE(dst); + memcpy(cp, gw, SA_SIZE(gw)); + cp += SA_SIZE(gw); + if (mask != NULL) { + memcpy(cp, mask, SA_SIZE(mask)); + cp += SA_SIZE(mask); + msg->rtm_addrs |= RTA_NETMASK; + } + msg->rtm_msglen = cp - (char *)msg; + msg->rtm_type = RTM_GET; + if ((sent = write(route, msg, msg->rtm_msglen)) == -1) { + syslog(LOG_ERR, "%s: write: %m", __func__); + free(msg); + return; + } + if (sent != msg->rtm_msglen) { + syslog(LOG_ERR, "%s: short write", __func__); + free(msg); + return; + } + free(msg); +} + +/* + * Fetch the routing table via sysctl + */ +u_char * +mib_fetch_rtab(int af, int info, int arg, size_t *lenp) +{ + int name[6]; + u_char *buf, *newbuf; + + name[0] = CTL_NET; + name[1] = PF_ROUTE; + name[2] = 0; + name[3] = af; + name[4] = info; + name[5] = arg; + + *lenp = 0; + + /* initial estimate */ + if (sysctl(name, nitems(name), NULL, lenp, NULL, 0) == -1) { + syslog(LOG_ERR, "sysctl estimate (%d,%d,%d,%d,%d,%d): %m", + name[0], name[1], name[2], name[3], name[4], name[5]); + return (NULL); + } + if (*lenp == 0) + return (NULL); + + buf = NULL; + for (;;) { + if ((newbuf = realloc(buf, *lenp)) == NULL) { + syslog(LOG_ERR, "sysctl buffer: %m"); + free(buf); + return (NULL); + } + buf = newbuf; + + if (sysctl(name, nitems(name), buf, lenp, NULL, 0) == 0) + break; + + if (errno != ENOMEM) { + syslog(LOG_ERR, "sysctl get: %m"); + free(buf); + return (NULL); + } + *lenp += *lenp / 8 + 1; + } + + return (buf); +} + +/* + * Update the following info: interface, interface addresses, interface + * receive addresses, arp-table. + * This does not change the interface list itself. + */ +static void +update_ifa_info(void) +{ + u_char *buf, *next; + struct rt_msghdr *rtm; + struct mibifa *ifa, *ifa1; + struct mibrcvaddr *rcv, *rcv1; + size_t needed; + static const int infos[][3] = { + { 0, NET_RT_IFLIST, 0 }, +#ifdef NET_RT_IFMALIST + { AF_LINK, NET_RT_IFMALIST, 0 }, +#endif + }; + u_int i; + + TAILQ_FOREACH(ifa, &mibifa_list, link) + ifa->flags &= ~MIBIFA_FOUND; + TAILQ_FOREACH(rcv, &mibrcvaddr_list, link) + rcv->flags &= ~MIBRCVADDR_FOUND; + + for (i = 0; i < sizeof(infos) / sizeof(infos[0]); i++) { + if ((buf = mib_fetch_rtab(infos[i][0], infos[i][1], infos[i][2], + &needed)) == NULL) + continue; + + next = buf; + while (next < buf + needed) { + rtm = (struct rt_msghdr *)(void *)next; + next += rtm->rtm_msglen; + handle_rtmsg(rtm); + } + free(buf); + } + + /* + * Purge the address list of unused entries. These may happen for + * interface aliases that are on the same subnet. We don't receive + * routing socket messages for them. + */ + ifa = TAILQ_FIRST(&mibifa_list); + while (ifa != NULL) { + ifa1 = TAILQ_NEXT(ifa, link); + if (!(ifa->flags & MIBIFA_FOUND)) + destroy_ifa(ifa); + ifa = ifa1; + } + + rcv = TAILQ_FIRST(&mibrcvaddr_list); + while (rcv != NULL) { + rcv1 = TAILQ_NEXT(rcv, link); + if (!(rcv->flags & (MIBRCVADDR_FOUND | MIBRCVADDR_BCAST | + MIBRCVADDR_HW))) + mib_rcvaddr_delete(rcv); + rcv = rcv1; + } +} + +/* + * Update arp table + */ +void +mib_arp_update(void) +{ + struct mibarp *at, *at1; + size_t needed; + u_char *buf, *next; + struct rt_msghdr *rtm; + + if (in_update_arp) + return; /* Aaargh */ + in_update_arp = 1; + + TAILQ_FOREACH(at, &mibarp_list, link) + at->flags &= ~MIBARP_FOUND; + + if ((buf = mib_fetch_rtab(AF_INET, NET_RT_FLAGS, 0, &needed)) == NULL) { + in_update_arp = 0; + return; + } + + next = buf; + while (next < buf + needed) { + rtm = (struct rt_msghdr *)(void *)next; + next += rtm->rtm_msglen; + handle_rtmsg(rtm); + } + free(buf); + + at = TAILQ_FIRST(&mibarp_list); + while (at != NULL) { + at1 = TAILQ_NEXT(at, link); + if (!(at->flags & MIBARP_FOUND)) + mib_arp_delete(at); + at = at1; + } + mibarpticks = get_ticks(); + in_update_arp = 0; +} + + +/* + * Input on the routing socket. + */ +static void +route_input(int fd, void *udata __unused) +{ + u_char buf[1024 * 16]; + ssize_t n; + struct rt_msghdr *rtm; + + if ((n = read(fd, buf, sizeof(buf))) == -1) + err(1, "read(rt_socket)"); + + if (n == 0) + errx(1, "EOF on rt_socket"); + + rtm = (struct rt_msghdr *)(void *)buf; + if ((size_t)n != rtm->rtm_msglen) + errx(1, "n=%zu, rtm_msglen=%u", (size_t)n, rtm->rtm_msglen); + + handle_rtmsg(rtm); +} + +/* + * execute and SIOCAIFADDR + */ +static int +siocaifaddr(char *ifname, struct in_addr addr, struct in_addr mask, + struct in_addr bcast) +{ + struct ifaliasreq addreq; + struct sockaddr_in *sa; + + memset(&addreq, 0, sizeof(addreq)); + strlcpy(addreq.ifra_name, ifname, sizeof(addreq.ifra_name)); + + sa = (struct sockaddr_in *)(void *)&addreq.ifra_addr; + sa->sin_family = AF_INET; + sa->sin_len = sizeof(*sa); + sa->sin_addr = addr; + + sa = (struct sockaddr_in *)(void *)&addreq.ifra_mask; + sa->sin_family = AF_INET; + sa->sin_len = sizeof(*sa); + sa->sin_addr = mask; + + sa = (struct sockaddr_in *)(void *)&addreq.ifra_broadaddr; + sa->sin_family = AF_INET; + sa->sin_len = sizeof(*sa); + sa->sin_addr = bcast; + + return (ioctl(mib_netsock, SIOCAIFADDR, &addreq)); +} + +/* + * Exececute a SIOCDIFADDR + */ +static int +siocdifaddr(const char *ifname, struct in_addr addr) +{ + struct ifreq delreq; + struct sockaddr_in *sa; + + memset(&delreq, 0, sizeof(delreq)); + strlcpy(delreq.ifr_name, ifname, sizeof(delreq.ifr_name)); + sa = (struct sockaddr_in *)(void *)&delreq.ifr_addr; + sa->sin_family = AF_INET; + sa->sin_len = sizeof(*sa); + sa->sin_addr = addr; + + return (ioctl(mib_netsock, SIOCDIFADDR, &delreq)); +} + +/* + * Verify an interface address without fetching the entire list + */ +static int +verify_ifa(const char *name, struct mibifa *ifa) +{ + struct ifreq req; + struct sockaddr_in *sa; + + memset(&req, 0, sizeof(req)); + strlcpy(req.ifr_name, name, sizeof(req.ifr_name)); + sa = (struct sockaddr_in *)(void *)&req.ifr_addr; + sa->sin_family = AF_INET; + sa->sin_len = sizeof(*sa); + sa->sin_addr = ifa->inaddr; + + if (ioctl(mib_netsock, SIOCGIFADDR, &req) == -1) + return (-1); + if (ifa->inaddr.s_addr != sa->sin_addr.s_addr) { + syslog(LOG_ERR, "%s: address mismatch", __func__); + return (-1); + } + + if (ioctl(mib_netsock, SIOCGIFNETMASK, &req) == -1) + return (-1); + if (ifa->inmask.s_addr != sa->sin_addr.s_addr) { + syslog(LOG_ERR, "%s: netmask mismatch", __func__); + return (-1); + } + return (0); +} + +/* + * Restore a deleted interface address. Don't wait for the routing socket + * to update us. + */ +void +mib_undestroy_ifa(struct mibifa *ifa) +{ + struct mibif *ifp; + + if ((ifp = mib_find_if(ifa->ifindex)) == NULL) + /* keep it destroyed */ + return; + + if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) + /* keep it destroyed */ + return; + + ifa->flags &= ~MIBIFA_DESTROYED; +} + +/* + * Destroy an interface address + */ +int +mib_destroy_ifa(struct mibifa *ifa) +{ + struct mibif *ifp; + + if ((ifp = mib_find_if(ifa->ifindex)) == NULL) { + /* ups. */ + mib_iflist_bad = 1; + return (-1); + } + if (siocdifaddr(ifp->name, ifa->inaddr)) { + /* ups. */ + syslog(LOG_ERR, "SIOCDIFADDR: %m"); + mib_iflist_bad = 1; + return (-1); + } + ifa->flags |= MIBIFA_DESTROYED; + return (0); +} + +/* + * Rollback the modification of an address. Don't bother to wait for + * the routing socket. + */ +void +mib_unmodify_ifa(struct mibifa *ifa) +{ + struct mibif *ifp; + + if ((ifp = mib_find_if(ifa->ifindex)) == NULL) { + /* ups. */ + mib_iflist_bad = 1; + return; + } + + if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) { + /* ups. */ + mib_iflist_bad = 1; + return; + } +} + +/* + * Modify an IFA. + */ +int +mib_modify_ifa(struct mibifa *ifa) +{ + struct mibif *ifp; + + if ((ifp = mib_find_if(ifa->ifindex)) == NULL) { + /* ups. */ + mib_iflist_bad = 1; + return (-1); + } + + if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) { + /* ups. */ + mib_iflist_bad = 1; + return (-1); + } + + if (verify_ifa(ifp->name, ifa)) { + /* ups. */ + mib_iflist_bad = 1; + return (-1); + } + + return (0); +} + +/* + * Destroy a freshly created interface address. Don't bother to wait for + * the routing socket. + */ +void +mib_uncreate_ifa(struct mibifa *ifa) +{ + struct mibif *ifp; + + if ((ifp = mib_find_if(ifa->ifindex)) == NULL) { + /* ups. */ + mib_iflist_bad = 1; + return; + } + if (siocdifaddr(ifp->name, ifa->inaddr)) { + /* ups. */ + mib_iflist_bad = 1; + return; + } + + destroy_ifa(ifa); +} + +/* + * Create a new ifa and verify it + */ +struct mibifa * +mib_create_ifa(u_int ifindex, struct in_addr addr, struct in_addr mask, + struct in_addr bcast) +{ + struct mibif *ifp; + struct mibifa *ifa; + + if ((ifp = mib_find_if(ifindex)) == NULL) + return (NULL); + if ((ifa = alloc_ifa(ifindex, addr)) == NULL) + return (NULL); + ifa->inmask = mask; + ifa->inbcast = bcast; + + if (siocaifaddr(ifp->name, ifa->inaddr, ifa->inmask, ifa->inbcast)) { + syslog(LOG_ERR, "%s: %m", __func__); + destroy_ifa(ifa); + return (NULL); + } + if (verify_ifa(ifp->name, ifa)) { + destroy_ifa(ifa); + return (NULL); + } + return (ifa); +} + +/* + * Get all cloning interfaces and make them dynamic. + * Hah! Whe should probably do this on a periodic basis (XXX). + */ +static void +get_cloners(void) +{ + struct if_clonereq req; + char *buf, *cp; + int i; + + memset(&req, 0, sizeof(req)); + if (ioctl(mib_netsock, SIOCIFGCLONERS, &req) == -1) { + syslog(LOG_ERR, "get cloners: %m"); + return; + } + if ((buf = malloc(req.ifcr_total * IFNAMSIZ)) == NULL) { + syslog(LOG_ERR, "%m"); + return; + } + req.ifcr_count = req.ifcr_total; + req.ifcr_buffer = buf; + if (ioctl(mib_netsock, SIOCIFGCLONERS, &req) == -1) { + syslog(LOG_ERR, "get cloners: %m"); + free(buf); + return; + } + for (cp = buf, i = 0; i < req.ifcr_total; i++, cp += IFNAMSIZ) + mib_if_set_dyn(cp); + free(buf); +} + +/* + * Idle function + */ +static void +mibII_idle(void *arg __unused) +{ + struct mibifa *ifa; + + if (mib_iflist_bad) { + TAILQ_FOREACH(ifa, &mibifa_list, link) + ifa->flags &= ~MIBIFA_DESTROYED; + + /* assume, that all cloning interfaces are dynamic */ + get_cloners(); + + mib_refresh_iflist(); + update_ifa_info(); + mib_arp_update(); + mib_iflist_bad = 0; + } + + mib_arp_update(); +} + + +/* + * Start the module + */ +static void +mibII_start(void) +{ + if ((route_fd = fd_select(route, route_input, NULL, module)) == NULL) { + syslog(LOG_ERR, "fd_select(route): %m"); + return; + } + mib_refresh_iflist(); + update_ifa_info(); + mib_arp_update(); + (void)mib_fetch_route(); + mib_iftable_last_change = 0; + mib_ifstack_last_change = 0; + + ifmib_reg = or_register(&oid_ifMIB, + "The MIB module to describe generic objects for network interface" + " sub-layers.", module); + + ipmib_reg = or_register(&oid_ipMIB, + "The MIB module for managing IP and ICMP implementations, but " + "excluding their management of IP routes.", module); + + tcpmib_reg = or_register(&oid_tcpMIB, + "The MIB module for managing TCP implementations.", module); + + udpmib_reg = or_register(&oid_udpMIB, + "The MIB module for managing UDP implementations.", module); + + ipForward_reg = or_register(&oid_ipForward, + "The MIB module for the display of CIDR multipath IP Routes.", + module); + + mibII_poll_timer = NULL; + mibII_poll_ticks = MIBII_POLL_TICKS; + mibif_restart_mibII_poll_timer(); +} + +/* + * Initialize the module + */ +static int +mibII_init(struct lmodule *mod, int argc __unused, char *argv[] __unused) +{ + size_t len; + + module = mod; + + len = sizeof(clockinfo); + if (sysctlbyname("kern.clockrate", &clockinfo, &len, NULL, 0) == -1) { + syslog(LOG_ERR, "kern.clockrate: %m"); + return (-1); + } + if (len != sizeof(clockinfo)) { + syslog(LOG_ERR, "kern.clockrate: wrong size"); + return (-1); + } + + if ((route = socket(PF_ROUTE, SOCK_RAW, AF_UNSPEC)) == -1) { + syslog(LOG_ERR, "PF_ROUTE: %m"); + return (-1); + } + + if ((mib_netsock = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { + syslog(LOG_ERR, "PF_INET: %m"); + (void)close(route); + return (-1); + } + (void)shutdown(mib_netsock, SHUT_RDWR); + + /* assume, that all cloning interfaces are dynamic */ + get_cloners(); + + return (0); +} + +static int +mibII_fini(void) +{ + if (mibII_poll_timer != NULL ) { + timer_stop(mibII_poll_timer); + mibII_poll_timer = NULL; + } + + if (route_fd != NULL) + fd_deselect(route_fd); + if (route != -1) + (void)close(route); + if (mib_netsock != -1) + (void)close(mib_netsock); + /* XXX free memory */ + + or_unregister(ipForward_reg); + or_unregister(udpmib_reg); + or_unregister(tcpmib_reg); + or_unregister(ipmib_reg); + or_unregister(ifmib_reg); + + return (0); +} + +static void +mibII_loading(const struct lmodule *mod, int loaded) +{ + struct mibif *ifp; + + if (loaded == 1) + return; + + TAILQ_FOREACH(ifp, &mibif_list, link) + if (ifp->xnotify_mod == mod) { + ifp->xnotify_mod = NULL; + ifp->xnotify_data = NULL; + ifp->xnotify = NULL; + } + + mib_unregister_newif(mod); +} + +extern const struct snmp_module config; +const struct snmp_module config = { + "This module implements the interface and ip groups.", + mibII_init, + mibII_fini, + NULL, /* idle */ + NULL, /* dump */ + NULL, /* config */ + mibII_start, + NULL, + mibII_ctree, + mibII_CTREE_SIZE, + mibII_loading +}; + +/* + * Should have a list of these attached to each interface. + */ +void * +mibif_notify(struct mibif *ifp, const struct lmodule *mod, + mibif_notify_f func, void *data) +{ + ifp->xnotify = func; + ifp->xnotify_data = data; + ifp->xnotify_mod = mod; + + return (ifp); +} + +void +mibif_unnotify(void *arg) +{ + struct mibif *ifp = arg; + + ifp->xnotify = NULL; + ifp->xnotify_data = NULL; + ifp->xnotify_mod = NULL; +} Property changes on: vendor/1.14/snmp_mibII/mibII.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_mibII/mibII.h =================================================================== --- vendor/1.14/snmp_mibII/mibII.h (nonexistent) +++ vendor/1.14/snmp_mibII/mibII.h (revision 359491) @@ -0,0 +1,276 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmp_mibII/mibII.h,v 1.16 2006/02/14 09:04:19 brandt_h Exp $ + * + * Implementation of the interfaces and IP groups of MIB-II. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "asn1.h" +#include "snmp.h" +#include "snmpmod.h" +#include "snmp_mibII.h" +#include "mibII_tree.h" + +/* maximum size of interface alias unless overridden with net.ifdescr_maxlen */ +#define MIBIF_ALIAS_SIZE (64 + 1) +#define MIBIF_ALIAS_SIZE_MAX 1024 + +/* + * Interface list and flags. + */ +TAILQ_HEAD(mibif_list, mibif); +enum { + MIBIF_FOUND = 0x0001, + MIBIF_HIGHSPEED = 0x0002, + MIBIF_VERYHIGHSPEED = 0x0004, +}; + +/* + * Private mibif data - hang off from the mibif. + */ +struct mibif_private { + uint64_t hc_inoctets; + uint64_t hc_outoctets; + uint64_t hc_omcasts; + uint64_t hc_opackets; + uint64_t hc_imcasts; + uint64_t hc_ipackets; +}; +#define MIBIF_PRIV(IFP) ((struct mibif_private *)((IFP)->private)) + +/* + * Interface addresses. + */ +TAILQ_HEAD(mibifa_list, mibifa); +enum { + MIBIFA_FOUND = 0x0001, + MIBIFA_DESTROYED = 0x0002, +}; + +/* + * Receive addresses + */ +TAILQ_HEAD(mibrcvaddr_list, mibrcvaddr); +enum { + MIBRCVADDR_FOUND = 0x00010000, +}; + +/* + * Interface index mapping. The problem here is, that if the same interface + * is reinstantiated (for examble by unloading and loading the hardware driver) + * we must use the same index for this interface. For dynamic interfaces + * (clip, lane) we must use a fresh index, each time a new interface is created. + * To differentiate between these types of interfaces we use the following table + * which contains an entry for each dynamic interface type. All other interface + * types are supposed to be static. The mibindexmap contains an entry for + * all interfaces. The mibif pointer is NULL, if the interface doesn't exist + * anymore. + */ +struct mibdynif { + SLIST_ENTRY(mibdynif) link; + char name[IFNAMSIZ]; +}; +SLIST_HEAD(mibdynif_list, mibdynif); + +struct mibindexmap { + STAILQ_ENTRY(mibindexmap) link; + u_short sysindex; + u_int ifindex; + struct mibif *mibif; /* may be NULL */ + char name[IFNAMSIZ]; +}; +STAILQ_HEAD(mibindexmap_list, mibindexmap); + +/* + * Interface stacking. The generic code cannot know how the interfaces stack. + * For this reason it instantiates only the x.0 and 0.x table elements. All + * others have to be instantiated by the interface specific modules. + * The table is read-only. + */ +struct mibifstack { + TAILQ_ENTRY(mibifstack) link; + struct asn_oid index; +}; +TAILQ_HEAD(mibifstack_list, mibifstack); + +/* + * NetToMediaTable (ArpTable) + */ +struct mibarp { + TAILQ_ENTRY(mibarp) link; + struct asn_oid index; /* contains both the ifindex and addr */ + u_char phys[128]; /* the physical address */ + u_int physlen; /* and its length */ + u_int flags; +}; +TAILQ_HEAD(mibarp_list, mibarp); +enum { + MIBARP_FOUND = 0x00010000, + MIBARP_PERM = 0x00000001, +}; + +/* + * New if registrations + */ +struct newifreg { + TAILQ_ENTRY(newifreg) link; + const struct lmodule *mod; + int (*func)(struct mibif *); +}; +TAILQ_HEAD(newifreg_list, newifreg); + +/* list of all IP addresses */ +extern struct mibifa_list mibifa_list; + +/* list of all interfaces */ +extern struct mibif_list mibif_list; + +/* list of dynamic interface names */ +extern struct mibdynif_list mibdynif_list; + +/* list of all interface index mappings */ +extern struct mibindexmap_list mibindexmap_list; + +/* list of all stacking entries */ +extern struct mibifstack_list mibifstack_list; + +/* list of all receive addresses */ +extern struct mibrcvaddr_list mibrcvaddr_list; + +/* list of all NetToMedia entries */ +extern struct mibarp_list mibarp_list; + +/* number of interfaces */ +extern int32_t mib_if_number; + +/* last change of interface table */ +extern uint64_t mib_iftable_last_change; + +/* last change of stack table */ +extern uint64_t mib_ifstack_last_change; + +/* if this is set, one of our lists may be bad. refresh them when idle */ +extern int mib_iflist_bad; + +/* last time refreshed */ +extern uint64_t mibarpticks; + +/* info on system clocks */ +extern struct clockinfo clockinfo; + +/* baud rate of fastest interface */ +extern uint64_t mibif_maxspeed; + +/* user-forced update interval */ +extern u_int mibif_force_hc_update_interval; + +/* current update interval */ +extern u_int mibif_hc_update_interval; + +/* re-compute update interval */ +void mibif_reset_hc_timer(void); + +/* interfaces' data poll interval */ +extern u_int mibII_poll_ticks; + +/* restart the data poll timer */ +void mibif_restart_mibII_poll_timer(void); + +#define MIBII_POLL_TICKS 100 + +/* get interfaces and interface addresses. */ +void mib_fetch_interfaces(void); + +/* check whether this interface(type) is dynamic */ +int mib_if_is_dyn(const char *name); + +/* destroy an interface address */ +int mib_destroy_ifa(struct mibifa *); + +/* restituate a deleted interface address */ +void mib_undestroy_ifa(struct mibifa *); + +/* change interface address */ +int mib_modify_ifa(struct mibifa *); + +/* undo if address modification */ +void mib_unmodify_ifa(struct mibifa *); + +/* create an interface address */ +struct mibifa * mib_create_ifa(u_int ifindex, struct in_addr addr, struct in_addr mask, struct in_addr bcast); + +/* delete a freshly created address */ +void mib_uncreate_ifa(struct mibifa *); + +/* create/delete arp entries */ +struct mibarp *mib_arp_create(const struct mibif *, struct in_addr, const u_char *, size_t); +void mib_arp_delete(struct mibarp *); + +/* find arp entry */ +struct mibarp *mib_find_arp(const struct mibif *, struct in_addr); + +/* update arp table */ +void mib_arp_update(void); + +/* fetch routing table */ +u_char *mib_fetch_rtab(int af, int info, int arg, size_t *lenp); + +/* process routing message */ +void mib_sroute_process(struct rt_msghdr *, struct sockaddr *, + struct sockaddr *, struct sockaddr *); + +/* send a routing message */ +void mib_send_rtmsg(struct rt_msghdr *, struct sockaddr *, + struct sockaddr *, struct sockaddr *); + +/* extract addresses from routing message */ +void mib_extract_addrs(int, u_char *, struct sockaddr **); + +/* fetch routing table */ +int mib_fetch_route(void); Property changes on: vendor/1.14/snmp_mibII/mibII.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_mibII/mibII_interfaces.c =================================================================== --- vendor/1.14/snmp_mibII/mibII_interfaces.c (nonexistent) +++ vendor/1.14/snmp_mibII/mibII_interfaces.c (revision 359491) @@ -0,0 +1,521 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmp_mibII/mibII_interfaces.c,v 1.17 2006/02/14 09:04:19 brandt_h Exp $ + * + * Interfaces group. + */ +#include "mibII.h" +#include "mibII_oid.h" + +/* + * This structure catches all changes to a interface entry + */ +struct ifchange { + struct snmp_dependency dep; + + u_int ifindex; + + uint32_t set; + int promisc; + int admin; + int traps; + + uint32_t rb; + int rb_flags; + int rb_traps; +}; +#define IFC_PROMISC 0x0001 +#define IFC_ADMIN 0x0002 +#define IFC_TRAPS 0x0004 +#define IFRB_FLAGS 0x0001 +#define IFRB_TRAPS 0x0002 + +static const struct asn_oid + oid_ifTable = OIDX_ifTable; + +/* + * This function handles all changes to the interface table and interface + * extension table. + */ +static int +ifchange_func(struct snmp_context *ctx __unused, struct snmp_dependency *dep, + enum snmp_depop op) +{ + struct ifchange *ifc = (struct ifchange *)dep; + struct mibif *ifp; + struct ifreq ifr, ifr1; + + if ((ifp = mib_find_if(ifc->ifindex)) == NULL) + return (SNMP_ERR_NO_CREATION); + + switch (op) { + + case SNMP_DEPOP_COMMIT: + strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); + if (ioctl(mib_netsock, SIOCGIFFLAGS, &ifr) == -1) { + syslog(LOG_ERR, "GIFFLAGS(%s): %m", ifp->name); + return (SNMP_ERR_GENERR); + } + if (ifc->set & IFC_PROMISC) { + ifr.ifr_flags &= ~IFF_PROMISC; + if (ifc->promisc) + ifr.ifr_flags |= IFF_PROMISC; + ifc->rb |= IFRB_FLAGS; + } + if (ifc->set & IFC_ADMIN) { + ifr.ifr_flags &= ~IFF_UP; + if (ifc->admin) + ifr.ifr_flags |= IFF_UP; + ifc->rb |= IFRB_FLAGS; + } + if (ifc->rb & IFRB_FLAGS) { + strlcpy(ifr1.ifr_name, ifp->name, sizeof(ifr1.ifr_name)); + if (ioctl(mib_netsock, SIOCGIFFLAGS, &ifr1) == -1) { + syslog(LOG_ERR, "GIFFLAGS(%s): %m", ifp->name); + return (SNMP_ERR_GENERR); + } + ifc->rb_flags = ifr1.ifr_flags; + if (ioctl(mib_netsock, SIOCSIFFLAGS, &ifr) == -1) { + syslog(LOG_ERR, "SIFFLAGS(%s): %m", ifp->name); + return (SNMP_ERR_GENERR); + } + (void)mib_fetch_ifmib(ifp); + } + if (ifc->set & IFC_TRAPS) { + ifc->rb |= IFRB_TRAPS; + ifc->rb_traps = ifp->trap_enable; + ifp->trap_enable = ifc->traps; + } + return (SNMP_ERR_NOERROR); + + case SNMP_DEPOP_ROLLBACK: + if (ifc->rb & IFRB_FLAGS) { + strlcpy(ifr.ifr_name, ifp->name, sizeof(ifr.ifr_name)); + ifr.ifr_flags = ifc->rb_flags; + if (ioctl(mib_netsock, SIOCSIFFLAGS, &ifr) == -1) { + syslog(LOG_ERR, "SIFFLAGS(%s): %m", ifp->name); + return (SNMP_ERR_UNDO_FAILED); + } + (void)mib_fetch_ifmib(ifp); + } + if (ifc->rb & IFRB_TRAPS) + ifp->trap_enable = ifc->rb_traps; + return (SNMP_ERR_NOERROR); + + case SNMP_DEPOP_FINISH: + return (SNMP_ERR_NOERROR); + + } + abort(); +} + +/* + * Return difference to daemon start time in ticks truncated to a + * 32-bit value. If the timeval is 0 then return 0. + */ +static uint32_t +ticks_get_timeval(struct timeval *tv) +{ + uint64_t v; + + if (tv->tv_sec != 0 || tv->tv_usec != 0) { + v = 100ULL * tv->tv_sec + tv->tv_usec / 10000ULL; + if (v > start_tick) + return (v - start_tick); + } + return (0); +} + +/* + * Scalars + */ +int +op_interfaces(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int idx __unused, enum snmp_op op) +{ + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + break; + + case SNMP_OP_SET: + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + abort(); + } + + switch (value->var.subs[sub - 1]) { + + case LEAF_ifNumber: + value->v.integer = mib_if_number; + break; + } + return (SNMP_ERR_NOERROR); +} + +/* + * Iftable entry + */ +int +op_ifentry(struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + struct mibif *ifp = NULL; + int ret; + struct ifchange *ifc; + struct asn_oid idx; + + switch (op) { + + case SNMP_OP_GETNEXT: + if ((ifp = NEXT_OBJECT_INT(&mibif_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + value->var.len = sub + 1; + value->var.subs[sub] = ifp->index; + break; + + case SNMP_OP_GET: + if (value->var.len - sub != 1) + return (SNMP_ERR_NOSUCHNAME); + if ((ifp = mib_find_if(value->var.subs[sub])) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + if (value->var.len - sub != 1) + return (SNMP_ERR_NO_CREATION); + if ((ifp = mib_find_if(value->var.subs[sub])) == NULL) + return (SNMP_ERR_NO_CREATION); + if (value->var.subs[sub - 1] != LEAF_ifAdminStatus) + return (SNMP_ERR_NOT_WRITEABLE); + + idx.len = 1; + idx.subs[0] = ifp->index; + + if (value->v.integer != 1 && value->v.integer != 2) + return (SNMP_ERR_WRONG_VALUE); + + if ((ifc = (struct ifchange *)snmp_dep_lookup(ctx, + &oid_ifTable, &idx, sizeof(*ifc), ifchange_func)) == NULL) + return (SNMP_ERR_RES_UNAVAIL); + ifc->ifindex = ifp->index; + + if (ifc->set & IFC_ADMIN) + return (SNMP_ERR_INCONS_VALUE); + ifc->set |= IFC_ADMIN; + ifc->admin = (value->v.integer == 1) ? 1 : 0; + + return (SNMP_ERR_NOERROR); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + return (SNMP_ERR_NOERROR); + } + + if (ifp->mibtick < this_tick) + (void)mib_fetch_ifmib(ifp); + + ret = SNMP_ERR_NOERROR; + switch (value->var.subs[sub - 1]) { + + case LEAF_ifIndex: + value->v.integer = ifp->index; + break; + + case LEAF_ifDescr: + ret = string_get(value, ifp->descr, -1); + break; + + case LEAF_ifType: + value->v.integer = ifp->mib.ifmd_data.ifi_type; + break; + + case LEAF_ifMtu: + value->v.integer = ifp->mib.ifmd_data.ifi_mtu; + break; + + case LEAF_ifSpeed: + value->v.integer = ifp->mib.ifmd_data.ifi_baudrate; + break; + + case LEAF_ifPhysAddress: + ret = string_get(value, ifp->physaddr, + ifp->physaddrlen); + break; + + case LEAF_ifAdminStatus: + value->v.integer = + (ifp->mib.ifmd_flags & IFF_UP) ? 1 : 2; + break; + + case LEAF_ifOperStatus: + /* + * According to RFC 2863 the state should be Up if the + * interface is ready to transmit packets. We takes this to + * mean that the interface should be running and should have + * a carrier. If it is running and has no carrier we interpret + * this as 'waiting for an external event' (plugging in the + * cable) and hence return 'dormant'. + */ + if (ifp->mib.ifmd_flags & IFF_RUNNING) { + if (ifp->mib.ifmd_data.ifi_link_state != LINK_STATE_UP) + value->v.integer = 5; /* state dormant */ + else + value->v.integer = 1; /* state up */ + } else + value->v.integer = 2; /* state down */ + break; + + case LEAF_ifLastChange: + value->v.uint32 = + ticks_get_timeval(&ifp->mib.ifmd_data.ifi_lastchange); + break; + + case LEAF_ifInOctets: + value->v.uint32 = ifp->mib.ifmd_data.ifi_ibytes; + break; + + case LEAF_ifInUcastPkts: + value->v.uint32 = ifp->mib.ifmd_data.ifi_ipackets - + ifp->mib.ifmd_data.ifi_imcasts; + break; + + case LEAF_ifInNUcastPkts: + value->v.uint32 = ifp->mib.ifmd_data.ifi_imcasts; + break; + + case LEAF_ifInDiscards: + value->v.uint32 = ifp->mib.ifmd_data.ifi_iqdrops; + break; + + case LEAF_ifInErrors: + value->v.uint32 = ifp->mib.ifmd_data.ifi_ierrors; + break; + + case LEAF_ifInUnknownProtos: + value->v.uint32 = ifp->mib.ifmd_data.ifi_noproto; + break; + + case LEAF_ifOutOctets: + value->v.uint32 = ifp->mib.ifmd_data.ifi_obytes; + break; + + case LEAF_ifOutUcastPkts: + value->v.uint32 = ifp->mib.ifmd_data.ifi_opackets - + ifp->mib.ifmd_data.ifi_omcasts; + break; + + case LEAF_ifOutNUcastPkts: + value->v.uint32 = ifp->mib.ifmd_data.ifi_omcasts; + break; + + case LEAF_ifOutDiscards: + value->v.uint32 = ifp->mib.ifmd_snd_drops; + break; + + case LEAF_ifOutErrors: + value->v.uint32 = ifp->mib.ifmd_data.ifi_oerrors; + break; + + case LEAF_ifOutQLen: + value->v.uint32 = ifp->mib.ifmd_snd_len; + break; + + case LEAF_ifSpecific: + value->v.oid = ifp->spec_oid; + break; + } + return (ret); +} + +/* + * IfXtable entry + */ +int +op_ifxtable(struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + struct mibif *ifp = NULL; + int ret; + struct ifchange *ifc; + struct asn_oid idx; + + switch (op) { + + case SNMP_OP_GETNEXT: + if ((ifp = NEXT_OBJECT_INT(&mibif_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + value->var.len = sub + 1; + value->var.subs[sub] = ifp->index; + break; + + case SNMP_OP_GET: + if (value->var.len - sub != 1) + return (SNMP_ERR_NOSUCHNAME); + if ((ifp = mib_find_if(value->var.subs[sub])) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + if (value->var.len - sub != 1) + return (SNMP_ERR_NO_CREATION); + if ((ifp = mib_find_if(value->var.subs[sub])) == NULL) + return (SNMP_ERR_NO_CREATION); + + idx.len = 1; + idx.subs[0] = ifp->index; + + if ((ifc = (struct ifchange *)snmp_dep_lookup(ctx, + &oid_ifTable, &idx, sizeof(*ifc), ifchange_func)) == NULL) + return (SNMP_ERR_RES_UNAVAIL); + ifc->ifindex = ifp->index; + + switch (value->var.subs[sub - 1]) { + + case LEAF_ifLinkUpDownTrapEnable: + if (value->v.integer != 1 && value->v.integer != 2) + return (SNMP_ERR_WRONG_VALUE); + if (ifc->set & IFC_TRAPS) + return (SNMP_ERR_INCONS_VALUE); + ifc->set |= IFC_TRAPS; + ifc->traps = (value->v.integer == 1) ? 1 : 0; + return (SNMP_ERR_NOERROR); + + case LEAF_ifPromiscuousMode: + if (value->v.integer != 1 && value->v.integer != 2) + return (SNMP_ERR_WRONG_VALUE); + if (ifc->set & IFC_PROMISC) + return (SNMP_ERR_INCONS_VALUE); + ifc->set |= IFC_PROMISC; + ifc->promisc = (value->v.integer == 1) ? 1 : 0; + return (SNMP_ERR_NOERROR); + } + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + return (SNMP_ERR_NOERROR); + } + + if (ifp->mibtick < this_tick) + (void)mib_fetch_ifmib(ifp); + + ret = SNMP_ERR_NOERROR; + switch (value->var.subs[sub - 1]) { + + case LEAF_ifName: + ret = string_get(value, ifp->name, -1); + break; + + case LEAF_ifInMulticastPkts: + value->v.uint32 = ifp->mib.ifmd_data.ifi_imcasts; + break; + + case LEAF_ifInBroadcastPkts: + value->v.uint32 = 0; + break; + + case LEAF_ifOutMulticastPkts: + value->v.uint32 = ifp->mib.ifmd_data.ifi_omcasts; + break; + + case LEAF_ifOutBroadcastPkts: + value->v.uint32 = 0; + break; + + case LEAF_ifHCInOctets: + value->v.counter64 = MIBIF_PRIV(ifp)->hc_inoctets; + break; + + case LEAF_ifHCInUcastPkts: + value->v.counter64 = MIBIF_PRIV(ifp)->hc_ipackets - + MIBIF_PRIV(ifp)->hc_imcasts; + break; + + case LEAF_ifHCInMulticastPkts: + value->v.counter64 = MIBIF_PRIV(ifp)->hc_imcasts; + break; + + case LEAF_ifHCInBroadcastPkts: + value->v.counter64 = 0; + break; + + case LEAF_ifHCOutOctets: + value->v.counter64 = MIBIF_PRIV(ifp)->hc_outoctets; + break; + + case LEAF_ifHCOutUcastPkts: + value->v.counter64 = MIBIF_PRIV(ifp)->hc_opackets - + MIBIF_PRIV(ifp)->hc_omcasts; + break; + + case LEAF_ifHCOutMulticastPkts: + value->v.counter64 = MIBIF_PRIV(ifp)->hc_omcasts; + break; + + case LEAF_ifHCOutBroadcastPkts: + value->v.counter64 = 0; + break; + + case LEAF_ifLinkUpDownTrapEnable: + value->v.integer = ifp->trap_enable ? 1 : 2; + break; + + case LEAF_ifHighSpeed: + value->v.integer = + (ifp->mib.ifmd_data.ifi_baudrate + 499999) / 1000000; + break; + + case LEAF_ifPromiscuousMode: + value->v.integer = + (ifp->mib.ifmd_flags & IFF_PROMISC) ? 1 : 2; + break; + + case LEAF_ifConnectorPresent: + value->v.integer = ifp->has_connector ? 1 : 2; + break; + + case LEAF_ifAlias: + ret = string_get(value, ifp->alias, ifp->alias_size - 1); + break; + + case LEAF_ifCounterDiscontinuityTime: + if (ifp->counter_disc > start_tick) + value->v.uint32 = ifp->counter_disc - start_tick; + else + value->v.uint32 = 0; + break; + } + return (ret); +} Property changes on: vendor/1.14/snmp_mibII/mibII_interfaces.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_mibII/snmp_mibII.h =================================================================== --- vendor/1.14/snmp_mibII/snmp_mibII.h (nonexistent) +++ vendor/1.14/snmp_mibII/snmp_mibII.h (revision 359491) @@ -0,0 +1,172 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmp_mibII/snmp_mibII.h,v 1.18 2006/02/14 09:04:19 brandt_h Exp $ + * + * Implementation of the interfaces and IP groups of MIB-II. + */ +#ifndef snmp_mibII_h_ +#define snmp_mibII_h_ + +/* forward declaration */ +struct mibif; + +enum mibif_notify { + MIBIF_NOTIFY_DESTROY +}; + +typedef void (*mibif_notify_f)(struct mibif *, enum mibif_notify, void *); + +/* + * Interfaces. This structure describes one interface as seen in the MIB. + * Interfaces are indexed by ifindex. This is not the same as the index + * used by the system because of the rules in RFC-2863 section 3.1.5. This + * RFC requires, that an ifindex is not to be re-used for ANOTHER dynamically + * interfaces once the interface was deleted. The system's ifindex is in + * sysindex. Mapping is via the mapping table below. + */ +struct mibif { + TAILQ_ENTRY(mibif) link; + u_int flags; + u_int index; /* the logical ifindex */ + u_int sysindex; + char name[IFNAMSIZ]; + char descr[256]; + struct ifmibdata mib; + uint64_t mibtick; + void *specmib; + size_t specmiblen; + u_char *physaddr; + u_int physaddrlen; + int has_connector; + int trap_enable; + uint64_t counter_disc; + + /* + * This is needed to handle interface type specific information + * in sub-modules. It contains a function pointer which handles + * notifications and a data pointer to arbitrary data. + * Should be set via the mibif_notify function. + */ + mibif_notify_f xnotify; + void *xnotify_data; + const struct lmodule *xnotify_mod; + + /* to be set by ifType specific modules. This is ifSpecific. */ + struct asn_oid spec_oid; + + char *alias; + size_t alias_size; + + /* private data - don't touch */ + void *private; +}; + +/* + * Interface IP-address table. + */ +struct mibifa { + TAILQ_ENTRY(mibifa) link; + struct in_addr inaddr; + struct in_addr inmask; + struct in_addr inbcast; + struct asn_oid index; /* index for table search */ + u_int ifindex; + u_int flags; +}; + +/* + * Interface receive addresses. Interface link-level multicast, broadcast + * and hardware addresses are handled automatically. + */ +struct mibrcvaddr { + TAILQ_ENTRY(mibrcvaddr) link; + struct asn_oid index; + u_int ifindex; + u_char addr[ASN_MAXOIDLEN]; + size_t addrlen; + u_int flags; +}; +enum { + MIBRCVADDR_VOLATILE = 0x00000001, + MIBRCVADDR_BCAST = 0x00000002, + MIBRCVADDR_HW = 0x00000004, +}; + +/* network socket */ +extern int mib_netsock; + +/* set an interface name to dynamic mode */ +void mib_if_set_dyn(const char *); + +/* re-read the systems interface list */ +void mib_refresh_iflist(void); + +/* find interface by index */ +struct mibif *mib_find_if(u_int); +struct mibif *mib_find_if_sys(u_int); +struct mibif *mib_find_if_name(const char *); + +/* iterate through all interfaces */ +struct mibif *mib_first_if(void); +struct mibif *mib_next_if(const struct mibif *); + +/* register for interface creations */ +int mib_register_newif(int (*)(struct mibif *), const struct lmodule *); +void mib_unregister_newif(const struct lmodule *); + +/* get fresh MIB data */ +int mib_fetch_ifmib(struct mibif *); + +/* change the ADMIN status of an interface and refresh the MIB */ +int mib_if_admin(struct mibif *, int up); + +/* find interface address by address */ +struct mibifa *mib_find_ifa(struct in_addr); + +/* find first/next address for a given interface */ +struct mibifa *mib_first_ififa(const struct mibif *); +struct mibifa *mib_next_ififa(struct mibifa *); + +/* create/delete stacking entries */ +int mib_ifstack_create(const struct mibif *lower, const struct mibif *upper); +void mib_ifstack_delete(const struct mibif *lower, const struct mibif *upper); + +/* find receive address */ +struct mibrcvaddr *mib_find_rcvaddr(u_int, const u_char *, size_t); + +/* create/delete receive addresses */ +struct mibrcvaddr *mib_rcvaddr_create(struct mibif *, const u_char *, size_t); +void mib_rcvaddr_delete(struct mibrcvaddr *); + +/* register for interface notification */ +void *mibif_notify(struct mibif *, const struct lmodule *, mibif_notify_f, + void *); +void mibif_unnotify(void *); + +#endif Property changes on: vendor/1.14/snmp_mibII/snmp_mibII.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_mibII/BEGEMOT-IP-MIB.txt =================================================================== --- vendor/1.14/snmp_mibII/BEGEMOT-IP-MIB.txt (nonexistent) +++ vendor/1.14/snmp_mibII/BEGEMOT-IP-MIB.txt (revision 359491) @@ -0,0 +1,64 @@ +-- +-- Copyright (c) 2006 +-- Hartmut Brandt +-- All rights reserved. +-- +-- Author: Harti Brandt +-- +-- Redistribution and use in source and binary forms, with or without +-- modification, are permitted provided that the following conditions +-- are met: +-- 1. Redistributions of source code must retain the above copyright +-- notice, this list of conditions and the following disclaimer. +-- 2. Redistributions in binary form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +-- ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +-- SUCH DAMAGE. +-- +-- $Begemot: bsnmp/snmp_mibII/BEGEMOT-IP-MIB.txt,v 1.1 2006/02/14 09:04:18 brandt_h Exp $ +-- +-- Private MIB for IP stuff. +-- +BEGEMOT-IP-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY + FROM SNMPv2-SMI + begemot + FROM BEGEMOT-MIB; + +begemotIp MODULE-IDENTITY + LAST-UPDATED "200602130000Z" + ORGANIZATION "German Aerospace Center" + CONTACT-INFO + " Hartmut Brandt + + Postal: German Aerospace Center + Oberpfaffenhofen + 82234 Wessling + Germany + + Fax: +49 8153 28 2843 + + E-mail: harti@freebsd.org" + DESCRIPTION + "The MIB for IP stuff that is not in the official IP MIBs." + REVISION "200602130000Z" + DESCRIPTION + "Initial revision." + ::= { begemot 3 } + +begemotIpObjects OBJECT IDENTIFIER ::= { begemotIp 1 } + +END Property changes on: vendor/1.14/snmp_mibII/BEGEMOT-IP-MIB.txt ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_mibII/BEGEMOT-MIB2-MIB.txt =================================================================== --- vendor/1.14/snmp_mibII/BEGEMOT-MIB2-MIB.txt (nonexistent) +++ vendor/1.14/snmp_mibII/BEGEMOT-MIB2-MIB.txt (revision 359491) @@ -0,0 +1,106 @@ +-- +-- Copyright (c) 2006 +-- Hartmut Brandt +-- All rights reserved. +-- +-- Author: Harti Brandt +-- +-- Redistribution and use in source and binary forms, with or without +-- modification, are permitted provided that the following conditions +-- are met: +-- 1. Redistributions of source code must retain the above copyright +-- notice, this list of conditions and the following disclaimer. +-- 2. Redistributions in binary form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +-- ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +-- SUCH DAMAGE. +-- +-- $Begemot: bsnmp/snmp_mibII/BEGEMOT-MIB2-MIB.txt,v 1.1 2006/02/14 09:04:18 brandt_h Exp $ +-- +-- Private MIB for MIB2. +-- +BEGEMOT-MIB2-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, TimeTicks, Counter64 + FROM SNMPv2-SMI + begemotIp + FROM BEGEMOT-IP-MIB; + +begemotMib2 MODULE-IDENTITY + LAST-UPDATED "200908030000Z" + ORGANIZATION "German Aerospace Center" + CONTACT-INFO + " Hartmut Brandt + + Postal: German Aerospace Center + Oberpfaffenhofen + 82234 Wessling + Germany + + Fax: +49 8153 28 2843 + + E-mail: harti@freebsd.org" + DESCRIPTION + "The MIB for private mib2 stuff." + REVISION "200908030000Z" + DESCRIPTION + "Second edition adds begemotIfDataPoll object." + REVISION "200602130000Z" + DESCRIPTION + "Initial revision." + ::= { begemotIp 1 } + +begemotIfMaxspeed OBJECT-TYPE + SYNTAX Counter64 + UNITS "bps" + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The speed of the fastest interface in ifTable in bps." + ::= { begemotMib2 1 } + +begemotIfPoll OBJECT-TYPE + SYNTAX TimeTicks + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The current polling rate for the HC 64-bit counters." + ::= { begemotMib2 2 } + +begemotIfForcePoll OBJECT-TYPE + SYNTAX TimeTicks + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The polling rate to be enforced for the HC 64-bit counters. + If this value is 0 the mib2 module computes a polling rate + depending on the value of begemotIfMaxspeed. If this value + turns out to be wrong, the polling rate can be force to an + arbitrary value by setting begemotIfForcePoll to a non-0 + value. This may be necessary if an interface announces a wrong + bit rate in its MIB." + ::= { begemotMib2 3 } + +begemotIfDataPoll OBJECT-TYPE + SYNTAX TimeTicks + UNITS "deciseconds" + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The rate at which the mib2 module will poll interface data." + DEFVAL { 100 } + ::= { begemotMib2 4 } + +END Property changes on: vendor/1.14/snmp_mibII/BEGEMOT-MIB2-MIB.txt ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_mibII/mibII_begemot.c =================================================================== --- vendor/1.14/snmp_mibII/mibII_begemot.c (nonexistent) +++ vendor/1.14/snmp_mibII/mibII_begemot.c (revision 359491) @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2006 + * Hartmut Brandt. + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmp_mibII/mibII_begemot.c,v 1.1 2006/02/14 09:04:19 brandt_h Exp $ + * + * Private MIB. + */ +#include "mibII.h" +#include "mibII_oid.h" + +/* + * Scalars + */ +int +op_begemot_mibII(struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int idx __unused, enum snmp_op op) +{ + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + goto get; + + case SNMP_OP_SET: + switch (value->var.subs[sub - 1]) { + + case LEAF_begemotIfMaxspeed: + case LEAF_begemotIfPoll: + return (SNMP_ERR_NOT_WRITEABLE); + + case LEAF_begemotIfForcePoll: + ctx->scratch->int1 = mibif_force_hc_update_interval; + mibif_force_hc_update_interval = value->v.uint32; + return (SNMP_ERR_NOERROR); + + case LEAF_begemotIfDataPoll: + ctx->scratch->int1 = mibII_poll_ticks; + mibII_poll_ticks = value->v.uint32; + return (SNMP_ERR_NOERROR); + } + abort(); + + case SNMP_OP_ROLLBACK: + switch (value->var.subs[sub - 1]) { + + case LEAF_begemotIfForcePoll: + mibif_force_hc_update_interval = ctx->scratch->int1; + return (SNMP_ERR_NOERROR); + + case LEAF_begemotIfDataPoll: + mibII_poll_ticks = ctx->scratch->int1; + return (SNMP_ERR_NOERROR); + } + abort(); + + case SNMP_OP_COMMIT: + switch (value->var.subs[sub - 1]) { + + case LEAF_begemotIfForcePoll: + mibif_force_hc_update_interval = ctx->scratch->int1; + mibif_reset_hc_timer(); + return (SNMP_ERR_NOERROR); + + case LEAF_begemotIfDataPoll: + mibif_restart_mibII_poll_timer(); + return (SNMP_ERR_NOERROR); + } + abort(); + } + abort(); + + get: + + switch (value->var.subs[sub - 1]) { + + case LEAF_begemotIfMaxspeed: + value->v.counter64 = mibif_maxspeed; + return (SNMP_ERR_NOERROR); + + case LEAF_begemotIfPoll: + value->v.uint32 = mibif_hc_update_interval; + return (SNMP_ERR_NOERROR); + + case LEAF_begemotIfForcePoll: + value->v.uint32 = mibif_force_hc_update_interval; + return (SNMP_ERR_NOERROR); + + case LEAF_begemotIfDataPoll: + value->v.uint32 = mibII_poll_ticks; + return (SNMP_ERR_NOERROR); + } + abort(); +} Property changes on: vendor/1.14/snmp_mibII/mibII_begemot.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_mibII/mibII_ifmib.c =================================================================== --- vendor/1.14/snmp_mibII/mibII_ifmib.c (nonexistent) +++ vendor/1.14/snmp_mibII/mibII_ifmib.c (revision 359491) @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmp_mibII/mibII_ifmib.c,v 1.9 2004/08/06 08:47:00 brandt Exp $ + * + * Interfaces group. + */ +#include "mibII.h" +#include "mibII_oid.h" + +/* + * Scalars + */ +int +op_ifmib(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int idx __unused, enum snmp_op op) +{ + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + break; + + case SNMP_OP_SET: + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + abort(); + } + + switch (value->var.subs[sub - 1]) { + + case LEAF_ifTableLastChange: + if (mib_iftable_last_change > start_tick) + value->v.uint32 = mib_iftable_last_change - start_tick; + else + value->v.uint32 = 0; + break; + + case LEAF_ifStackLastChange: + if (mib_ifstack_last_change > start_tick) + value->v.uint32 = mib_ifstack_last_change - start_tick; + else + value->v.uint32 = 0; + break; + } + return (SNMP_ERR_NOERROR); +} Property changes on: vendor/1.14/snmp_mibII/mibII_ifmib.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_mibII/mibII_ifstack.c =================================================================== --- vendor/1.14/snmp_mibII/mibII_ifstack.c (nonexistent) +++ vendor/1.14/snmp_mibII/mibII_ifstack.c (revision 359491) @@ -0,0 +1,105 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmp_mibII/mibII_ifstack.c,v 1.7 2004/08/06 08:47:00 brandt Exp $ + * + * ifStackTable. Read-only. + */ +#include "mibII.h" + +int +mib_ifstack_create(const struct mibif *lower, const struct mibif *upper) +{ + struct mibifstack *stack; + + if ((stack = malloc(sizeof(*stack))) == NULL) + return (-1); + + stack->index.len = 2; + stack->index.subs[0] = upper ? upper->index : 0; + stack->index.subs[1] = lower ? lower->index : 0; + + INSERT_OBJECT_OID(stack, &mibifstack_list); + + mib_ifstack_last_change = get_ticks(); + + return (0); +} + +void +mib_ifstack_delete(const struct mibif *lower, const struct mibif *upper) +{ + struct mibifstack *stack; + + TAILQ_FOREACH(stack, &mibifstack_list, link) + if (stack->index.subs[0] == (upper ? upper->index : 0) && + stack->index.subs[1] == (lower ? lower->index : 0)) { + TAILQ_REMOVE(&mibifstack_list, stack, link); + free(stack); + mib_ifstack_last_change = get_ticks(); + return; + } +} + +int +op_ifstack(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + struct mibifstack *stack; + + switch (op) { + + case SNMP_OP_GETNEXT: + if ((stack = NEXT_OBJECT_OID(&mibifstack_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + index_append(&value->var, sub, &stack->index); + break; + + case SNMP_OP_GET: + if ((stack = FIND_OBJECT_OID(&mibifstack_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + if ((stack = FIND_OBJECT_OID(&mibifstack_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NO_CREATION); + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + abort(); + } + + switch (value->var.subs[sub - 1]) { + + case LEAF_ifStackStatus: + value->v.integer = 1; + break; + } + return (SNMP_ERR_NOERROR); +} Property changes on: vendor/1.14/snmp_mibII/mibII_ifstack.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_mibII/mibII_ip.c =================================================================== --- vendor/1.14/snmp_mibII/mibII_ip.c (nonexistent) +++ vendor/1.14/snmp_mibII/mibII_ip.c (revision 359491) @@ -0,0 +1,493 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmp_mibII/mibII_ip.c,v 1.11 2005/05/23 09:03:40 brandt_h Exp $ + * + * ip group scalars. + */ +#include "mibII.h" +#include "mibII_oid.h" +#include +#include +#include +#include +#include + +static struct ipstat ipstat; +static u_int ip_idrop; +static struct icmpstat icmpstat; + +static int ip_forwarding; +static int ip_defttl; +static uint64_t ip_tick; + +static uint64_t ipstat_tick; + +static int +fetch_ipstat(void) +{ + size_t len; + + len = sizeof(ipstat); + if (sysctlbyname("net.inet.ip.stats", &ipstat, &len, NULL, 0) == -1) { + syslog(LOG_ERR, "net.inet.ip.stats: %m"); + return (-1); + } + if (len != sizeof(ipstat)) { + syslog(LOG_ERR, "net.inet.ip.stats: wrong size"); + return (-1); + } + len = sizeof(ip_idrop); + if (sysctlbyname("net.inet.ip.intr_queue_drops", &ip_idrop, &len, NULL, 0) == -1) + syslog(LOG_WARNING, "net.inet.ip.intr_queue_drops: %m"); + if (len != sizeof(ip_idrop)) { + syslog(LOG_WARNING, "net.inet.ip.intr_queue_drops: wrong size"); + ip_idrop = 0; + } + len = sizeof(icmpstat); + if (sysctlbyname("net.inet.icmp.stats", &icmpstat, &len, NULL, 0) == -1) { + syslog(LOG_ERR, "net.inet.icmp.stats: %m"); + return (-1); + } + if (len != sizeof(icmpstat)) { + syslog(LOG_ERR, "net.inet.icmp.stats: wrong size"); + return (-1); + } + + ipstat_tick = get_ticks(); + return (0); +} + +static int +fetch_ip(void) +{ + size_t len; + + len = sizeof(ip_forwarding); + if (sysctlbyname("net.inet.ip.forwarding", &ip_forwarding, &len, + NULL, 0) == -1) { + syslog(LOG_ERR, "net.inet.ip.forwarding: %m"); + return (-1); + } + if (len != sizeof(ip_forwarding)) { + syslog(LOG_ERR, "net.inet.ip.forwarding: wrong size"); + return (-1); + } + + len = sizeof(ip_defttl); + if (sysctlbyname("net.inet.ip.ttl", &ip_defttl, &len, + NULL, 0) == -1) { + syslog(LOG_ERR, "net.inet.ip.ttl: %m"); + return (-1); + } + if (len != sizeof(ip_defttl)) { + syslog(LOG_ERR, "net.inet.ip.ttl: wrong size"); + return (-1); + } + + ip_tick = get_ticks(); + return (0); +} + +static int +ip_forward(int forw, int *old) +{ + size_t olen; + + olen = sizeof(*old); + if (sysctlbyname("net.inet.ip.forwarding", old, old ? &olen : NULL, + &forw, sizeof(forw)) == -1) { + syslog(LOG_ERR, "set net.inet.ip.forwarding: %m"); + return (-1); + } + ip_forwarding = forw; + return (0); +} + +static int +ip_setttl(int ttl, int *old) +{ + size_t olen; + + olen = sizeof(*old); + if (sysctlbyname("net.inet.ip.ttl", old, old ? &olen : NULL, + &ttl, sizeof(ttl)) == -1) { + syslog(LOG_ERR, "set net.inet.ip.ttl: %m"); + return (-1); + } + ip_defttl = ttl; + return (0); +} + +/* + * READ/WRITE ip group. + */ +int +op_ip(struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int idx __unused, enum snmp_op op) +{ + int old = 0; + + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + break; + + case SNMP_OP_SET: + if (ip_tick < this_tick) + if (fetch_ip() == -1) + return (SNMP_ERR_GENERR); + + switch (value->var.subs[sub - 1]) { + + case LEAF_ipForwarding: + ctx->scratch->int1 = ip_forwarding ? 1 : 2; + ctx->scratch->int2 = value->v.integer; + if (value->v.integer == 1) { + if (!ip_forwarding && ip_forward(1, &old)) + return (SNMP_ERR_GENERR); + ctx->scratch->int1 = old ? 1 : 2; + } else if (value->v.integer == 2) { + if (ip_forwarding && ip_forward(0, &old)) + return (SNMP_ERR_GENERR); + ctx->scratch->int1 = old; + } else + return (SNMP_ERR_WRONG_VALUE); + break; + + case LEAF_ipDefaultTTL: + ctx->scratch->int1 = ip_defttl; + ctx->scratch->int2 = value->v.integer; + if (value->v.integer < 1 || value->v.integer > 255) + return (SNMP_ERR_WRONG_VALUE); + if (ip_defttl != value->v.integer && + ip_setttl(value->v.integer, &old)) + return (SNMP_ERR_GENERR); + ctx->scratch->int1 = old; + break; + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_ROLLBACK: + switch (value->var.subs[sub - 1]) { + + case LEAF_ipForwarding: + if (ctx->scratch->int1 == 1) { + if (ctx->scratch->int2 == 2) + (void)ip_forward(1, NULL); + } else { + if (ctx->scratch->int2 == 1) + (void)ip_forward(0, NULL); + } + break; + + case LEAF_ipDefaultTTL: + if (ctx->scratch->int1 != ctx->scratch->int2) + (void)ip_setttl(ctx->scratch->int1, NULL); + break; + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_COMMIT: + return (SNMP_ERR_NOERROR); + } + + if (ip_tick < this_tick) + if (fetch_ip() == -1) + return (SNMP_ERR_GENERR); + + switch (value->var.subs[sub - 1]) { + + case LEAF_ipForwarding: + value->v.integer = ip_forwarding ? 1 : 2; + break; + + case LEAF_ipDefaultTTL: + value->v.integer = ip_defttl; + break; + } + return (SNMP_ERR_NOERROR); +} + +/* + * READ-ONLY statistics ip group. + */ +int +op_ipstat(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int idx __unused, enum snmp_op op) +{ + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + break; + + case SNMP_OP_SET: + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + abort(); + } + + if (ipstat_tick < this_tick) + fetch_ipstat(); + + switch (value->var.subs[sub - 1]) { + + case LEAF_ipInReceives: + value->v.uint32 = ipstat.ips_total; + break; + + case LEAF_ipInHdrErrors: + value->v.uint32 = ipstat.ips_badsum + ipstat.ips_tooshort + + ipstat.ips_toosmall + ipstat.ips_badhlen + + ipstat.ips_badlen + ipstat.ips_badvers + + + ipstat.ips_toolong; + break; + + case LEAF_ipInAddrErrors: + value->v.uint32 = ipstat.ips_cantforward; + break; + + case LEAF_ipForwDatagrams: + value->v.uint32 = ipstat.ips_forward; + break; + + case LEAF_ipInUnknownProtos: + value->v.uint32 = ipstat.ips_noproto; + break; + + case LEAF_ipInDiscards: + value->v.uint32 = ip_idrop; + break; + + case LEAF_ipInDelivers: + value->v.uint32 = ipstat.ips_delivered; + break; + + case LEAF_ipOutRequests: + value->v.uint32 = ipstat.ips_localout; + break; + + case LEAF_ipOutDiscards: + value->v.uint32 = ipstat.ips_odropped; + break; + + case LEAF_ipOutNoRoutes: + value->v.uint32 = ipstat.ips_noroute; + break; + + case LEAF_ipReasmTimeout: + value->v.integer = IPFRAGTTL; + break; + + case LEAF_ipReasmReqds: + value->v.uint32 = ipstat.ips_fragments; + break; + + case LEAF_ipReasmOKs: + value->v.uint32 = ipstat.ips_reassembled; + break; + + case LEAF_ipReasmFails: + value->v.uint32 = ipstat.ips_fragdropped + + ipstat.ips_fragtimeout; + break; + + case LEAF_ipFragOKs: + value->v.uint32 = ipstat.ips_fragmented; + break; + + case LEAF_ipFragFails: + value->v.uint32 = ipstat.ips_cantfrag; + break; + + case LEAF_ipFragCreates: + value->v.uint32 = ipstat.ips_ofragments; + break; + } + return (SNMP_ERR_NOERROR); +} + +/* + * READ-ONLY statistics icmp group. + */ +int +op_icmpstat(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int idx __unused, enum snmp_op op) +{ + u_int i; + + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + break; + + case SNMP_OP_SET: + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + abort(); + } + + if (ipstat_tick < this_tick) + fetch_ipstat(); + + switch (value->var.subs[sub - 1]) { + + case LEAF_icmpInMsgs: + value->v.integer = 0; + for (i = 0; i <= ICMP_MAXTYPE; i++) + value->v.integer += icmpstat.icps_inhist[i]; + value->v.integer += icmpstat.icps_tooshort + + icmpstat.icps_checksum; + /* missing: bad type and packets on faith */ + break; + + case LEAF_icmpInErrors: + value->v.integer = icmpstat.icps_tooshort + + icmpstat.icps_checksum + + icmpstat.icps_badlen + + icmpstat.icps_badcode + + icmpstat.icps_bmcastecho + + icmpstat.icps_bmcasttstamp; + break; + + case LEAF_icmpInDestUnreachs: + value->v.integer = icmpstat.icps_inhist[ICMP_UNREACH]; + break; + + case LEAF_icmpInTimeExcds: + value->v.integer = icmpstat.icps_inhist[ICMP_TIMXCEED]; + break; + + case LEAF_icmpInParmProbs: + value->v.integer = icmpstat.icps_inhist[ICMP_PARAMPROB]; + break; + + case LEAF_icmpInSrcQuenchs: + value->v.integer = icmpstat.icps_inhist[ICMP_SOURCEQUENCH]; + break; + + case LEAF_icmpInRedirects: + value->v.integer = icmpstat.icps_inhist[ICMP_REDIRECT]; + break; + + case LEAF_icmpInEchos: + value->v.integer = icmpstat.icps_inhist[ICMP_ECHO]; + break; + + case LEAF_icmpInEchoReps: + value->v.integer = icmpstat.icps_inhist[ICMP_ECHOREPLY]; + break; + + case LEAF_icmpInTimestamps: + value->v.integer = icmpstat.icps_inhist[ICMP_TSTAMP]; + break; + + case LEAF_icmpInTimestampReps: + value->v.integer = icmpstat.icps_inhist[ICMP_TSTAMPREPLY]; + break; + + case LEAF_icmpInAddrMasks: + value->v.integer = icmpstat.icps_inhist[ICMP_MASKREQ]; + break; + + case LEAF_icmpInAddrMaskReps: + value->v.integer = icmpstat.icps_inhist[ICMP_MASKREPLY]; + break; + + case LEAF_icmpOutMsgs: + value->v.integer = 0; + for (i = 0; i <= ICMP_MAXTYPE; i++) + value->v.integer += icmpstat.icps_outhist[i]; + value->v.integer += icmpstat.icps_badaddr + + icmpstat.icps_noroute; + break; + + case LEAF_icmpOutErrors: + value->v.integer = icmpstat.icps_badaddr + + icmpstat.icps_noroute; + break; + + case LEAF_icmpOutDestUnreachs: + value->v.integer = icmpstat.icps_outhist[ICMP_UNREACH]; + break; + + case LEAF_icmpOutTimeExcds: + value->v.integer = icmpstat.icps_outhist[ICMP_TIMXCEED]; + break; + + case LEAF_icmpOutParmProbs: + value->v.integer = icmpstat.icps_outhist[ICMP_PARAMPROB]; + break; + + case LEAF_icmpOutSrcQuenchs: + value->v.integer = icmpstat.icps_outhist[ICMP_SOURCEQUENCH]; + break; + + case LEAF_icmpOutRedirects: + value->v.integer = icmpstat.icps_outhist[ICMP_REDIRECT]; + break; + + case LEAF_icmpOutEchos: + value->v.integer = icmpstat.icps_outhist[ICMP_ECHO]; + break; + + case LEAF_icmpOutEchoReps: + value->v.integer = icmpstat.icps_outhist[ICMP_ECHOREPLY]; + break; + + case LEAF_icmpOutTimestamps: + value->v.integer = icmpstat.icps_outhist[ICMP_TSTAMP]; + break; + + case LEAF_icmpOutTimestampReps: + value->v.integer = icmpstat.icps_outhist[ICMP_TSTAMPREPLY]; + break; + + case LEAF_icmpOutAddrMasks: + value->v.integer = icmpstat.icps_outhist[ICMP_MASKREQ]; + break; + + case LEAF_icmpOutAddrMaskReps: + value->v.integer = icmpstat.icps_outhist[ICMP_MASKREPLY]; + break; + } + return (SNMP_ERR_NOERROR); +} Property changes on: vendor/1.14/snmp_mibII/mibII_ip.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_mibII/mibII_ipaddr.c =================================================================== --- vendor/1.14/snmp_mibII/mibII_ipaddr.c (nonexistent) +++ vendor/1.14/snmp_mibII/mibII_ipaddr.c (revision 359491) @@ -0,0 +1,340 @@ +/* + * Copyright (c) 2001-2002 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmp_mibII/mibII_ipaddr.c,v 1.10 2005/10/04 11:21:35 brandt_h Exp $ + * + * IP address table. This table is writeable! + * + * Writing to this table will add a new IP address to the interface. + * An address can be deleted with writing the interface index 0. + */ +#include "mibII.h" +#include "mibII_oid.h" + +static const struct asn_oid + oid_ipAddrTable = OIDX_ipAddrTable; + +/* + * Be careful not to hold any pointers during the SET processing - the + * interface and address lists can be relocated at any time. + */ +struct update { + struct snmp_dependency dep; + + uint32_t set; + struct in_addr addr; + struct in_addr mask; + int bcast; + u_int ifindex; + + uint32_t rb; + struct in_addr rb_mask; + struct in_addr rb_bcast; +}; +#define UPD_IFINDEX 0x0001 +#define UPD_MASK 0x0002 +#define UPD_BCAST 0x0004 +#define RB_CREATE 0x0001 +#define RB_DESTROY 0x0002 +#define RB_MODIFY 0x0004 + +/* + * Create a new interface address + */ +static int +create(struct update *upd) +{ + struct in_addr bcast; + struct mibifa *ifa; + + if (!(upd->set & UPD_MASK)) { + if (IN_CLASSA(ntohl(upd->addr.s_addr))) + upd->mask.s_addr = htonl(IN_CLASSA_NET); + else if (IN_CLASSB(ntohl(upd->addr.s_addr))) + upd->mask.s_addr = htonl(IN_CLASSB_NET); + else if (IN_CLASSC(ntohl(upd->addr.s_addr))) + upd->mask.s_addr = htonl(IN_CLASSC_NET); + else + upd->mask.s_addr = 0xffffffff; + } + + bcast.s_addr = upd->addr.s_addr & upd->mask.s_addr; + if (!(upd->set & UPD_BCAST) || upd->bcast) { + uint32_t tmp = ~ntohl(upd->mask.s_addr); + bcast.s_addr |= htonl(0xffffffff & ~tmp); + } + + if ((ifa = mib_create_ifa(upd->ifindex, upd->addr, upd->mask, bcast)) + == NULL) + return (SNMP_ERR_GENERR); + + upd->rb |= RB_CREATE; + return (SNMP_ERR_NOERROR); +} + +/* + * Modify the netmask or broadcast address. The ifindex cannot be + * changed (obviously). + */ +static int +modify(struct update *upd, struct mibifa *ifa) +{ + struct mibif *ifp; + + if ((ifp = mib_find_if(ifa->ifindex)) == NULL) + return (SNMP_ERR_WRONG_VALUE); + if ((upd->set & UPD_IFINDEX) && upd->ifindex != ifa->ifindex) + return (SNMP_ERR_INCONS_VALUE); + + upd->rb_mask = ifa->inmask; + upd->rb_bcast = ifa->inbcast; + if (((upd->set & UPD_MASK) && upd->mask.s_addr != ifa->inmask.s_addr) || + (upd->set & UPD_BCAST)) { + if (upd->set & UPD_MASK) + ifa->inmask = upd->mask; + if (upd->set & UPD_BCAST) { + ifa->inbcast.s_addr = ifa->inaddr.s_addr + & ifa->inmask.s_addr; + if (upd->bcast) + ifa->inbcast.s_addr |= 0xffffffff + & ~ifa->inmask.s_addr; + } + if (mib_modify_ifa(ifa)) { + syslog(LOG_ERR, "set netmask/bcast: %m"); + ifa->inmask = upd->rb_mask; + ifa->inbcast = upd->rb_bcast; + mib_unmodify_ifa(ifa); + return (SNMP_ERR_GENERR); + } + upd->rb |= RB_MODIFY; + } + return (SNMP_ERR_NOERROR); +} + +/* + * Destroy the given row in the table. We remove the address from the + * system, but keep the structure around for the COMMIT. It's deleted + * only in the FINISH operation. + */ +static int +destroy(struct snmp_context *ctx __unused, struct update *upd, + struct mibifa *ifa) +{ + if (mib_destroy_ifa(ifa)) + return (SNMP_ERR_GENERR); + upd->rb |= RB_DESTROY; + return (SNMP_ERR_NOERROR); +} + +/* + * This function is called to commit/rollback a SET on an IpAddrEntry + */ +static int +update_func(struct snmp_context *ctx, struct snmp_dependency *dep, + enum snmp_depop op) +{ + struct update *upd = (struct update *)dep; + struct mibifa *ifa; + + switch (op) { + + case SNMP_DEPOP_COMMIT: + if ((ifa = mib_find_ifa(upd->addr)) == NULL) { + /* non existing entry - must have ifindex */ + if (!(upd->set & UPD_IFINDEX)) + return (SNMP_ERR_INCONS_NAME); + return (create(upd)); + } + /* existing entry */ + if ((upd->set & UPD_IFINDEX) && upd->ifindex == 0) { + /* delete */ + return (destroy(ctx, upd, ifa)); + } + /* modify entry */ + return (modify(upd, ifa)); + + case SNMP_DEPOP_ROLLBACK: + if ((ifa = mib_find_ifa(upd->addr)) == NULL) { + /* ups */ + mib_iflist_bad = 1; + return (SNMP_ERR_NOERROR); + } + if (upd->rb & RB_CREATE) { + mib_uncreate_ifa(ifa); + return (SNMP_ERR_NOERROR); + } + if (upd->rb & RB_DESTROY) { + mib_undestroy_ifa(ifa); + return (SNMP_ERR_NOERROR); + } + if (upd->rb & RB_MODIFY) { + ifa->inmask = upd->rb_mask; + ifa->inbcast = upd->rb_bcast; + mib_unmodify_ifa(ifa); + return (SNMP_ERR_NOERROR); + } + return (SNMP_ERR_NOERROR); + + case SNMP_DEPOP_FINISH: + if ((upd->rb & RB_DESTROY) && + (ifa = mib_find_ifa(upd->addr)) != NULL && + (ifa->flags & MIBIFA_DESTROYED)) { + TAILQ_REMOVE(&mibifa_list, ifa, link); + free(ifa); + } + return (SNMP_ERR_NOERROR); + } + abort(); +} + +/**********************************************************************/ +/* + * ACTION + */ +int +op_ipaddr(struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int iidx, enum snmp_op op) +{ + asn_subid_t which; + struct mibifa *ifa; + struct update *upd; + struct asn_oid idx; + u_char ipaddr[4]; + + which = value->var.subs[sub - 1]; + + ifa = NULL; + + switch (op) { + + case SNMP_OP_GETNEXT: + if ((ifa = NEXT_OBJECT_OID(&mibifa_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + index_append(&value->var, sub, &ifa->index); + break; + + case SNMP_OP_GET: + if ((ifa = FIND_OBJECT_OID(&mibifa_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + if (index_decode(&value->var, sub, iidx, ipaddr)) + return (SNMP_ERR_NO_CREATION); + ifa = FIND_OBJECT_OID(&mibifa_list, &value->var, sub); + idx.len = 4; + idx.subs[0] = ipaddr[0]; + idx.subs[1] = ipaddr[1]; + idx.subs[2] = ipaddr[2]; + idx.subs[3] = ipaddr[3]; + + if ((upd = (struct update *)snmp_dep_lookup(ctx, + &oid_ipAddrTable, &idx, sizeof(*upd), update_func)) == NULL) + return (SNMP_ERR_RES_UNAVAIL); + + upd->addr.s_addr = htonl((ipaddr[0] << 24) | (ipaddr[1] << 16) | + (ipaddr[2] << 8) | (ipaddr[3] << 0)); + + switch (which) { + + case LEAF_ipAdEntIfIndex: + if (upd->set & UPD_IFINDEX) + return (SNMP_ERR_INCONS_VALUE); + if (value->v.integer < 0 || + value->v.integer > 0x07fffffff) + return (SNMP_ERR_WRONG_VALUE); + if (ifa != NULL) { + if (ifa->ifindex != (u_int)value->v.integer && + value->v.integer != 0) + return (SNMP_ERR_INCONS_VALUE); + } + upd->set |= UPD_IFINDEX; + upd->ifindex = (u_int)value->v.integer; + break; + + case LEAF_ipAdEntNetMask: + if (upd->set & UPD_MASK) + return (SNMP_ERR_INCONS_VALUE); + upd->mask.s_addr = htonl((value->v.ipaddress[0] << 24) + | (value->v.ipaddress[1] << 16) + | (value->v.ipaddress[2] << 8) + | (value->v.ipaddress[3] << 0)); + upd->set |= UPD_MASK; + break; + + case LEAF_ipAdEntBcastAddr: + if (upd->set & UPD_BCAST) + return (SNMP_ERR_INCONS_VALUE); + if (value->v.integer != 0 && value->v.integer != 1) + return (SNMP_ERR_WRONG_VALUE); + upd->bcast = value->v.integer; + upd->set |= UPD_BCAST; + break; + + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + return (SNMP_ERR_NOERROR); + } + + switch (which) { + + case LEAF_ipAdEntAddr: + value->v.ipaddress[0] = ifa->index.subs[0]; + value->v.ipaddress[1] = ifa->index.subs[1]; + value->v.ipaddress[2] = ifa->index.subs[2]; + value->v.ipaddress[3] = ifa->index.subs[3]; + break; + + case LEAF_ipAdEntIfIndex: + if (ifa->flags & MIBIFA_DESTROYED) + value->v.integer = 0; + else + value->v.integer = ifa->ifindex; + break; + + case LEAF_ipAdEntNetMask: + value->v.ipaddress[0] = (ntohl(ifa->inmask.s_addr) >> 24) & 0xff; + value->v.ipaddress[1] = (ntohl(ifa->inmask.s_addr) >> 16) & 0xff; + value->v.ipaddress[2] = (ntohl(ifa->inmask.s_addr) >> 8) & 0xff; + value->v.ipaddress[3] = (ntohl(ifa->inmask.s_addr) >> 0) & 0xff; + break; + + case LEAF_ipAdEntBcastAddr: + value->v.integer = ntohl(ifa->inbcast.s_addr) & 1; + break; + + + case LEAF_ipAdEntReasmMaxSize: + value->v.integer = 65535; + break; + } + return (SNMP_ERR_NOERROR); +} Property changes on: vendor/1.14/snmp_mibII/mibII_ipaddr.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_mibII/mibII_nettomedia.c =================================================================== --- vendor/1.14/snmp_mibII/mibII_nettomedia.c (nonexistent) +++ vendor/1.14/snmp_mibII/mibII_nettomedia.c (revision 359491) @@ -0,0 +1,150 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmp_mibII/mibII_nettomedia.c,v 1.8 2004/08/06 08:47:03 brandt Exp $ + * + * Read-only implementation of the Arp table (ipNetToMediaTable) + * + * The problem with the table is, that we don't receive routing message + * when a) an arp table entry is resolved and b) when an arp table entry is + * deleted automatically. Therefor we need to poll the table from time to + * time. + */ +#include "mibII.h" +#include "mibII_oid.h" + +#define ARPREFRESH 30 + +struct mibarp * +mib_find_arp(const struct mibif *ifp, struct in_addr in) +{ + struct mibarp *at; + uint32_t a = ntohl(in.s_addr); + + if (get_ticks() >= mibarpticks + ARPREFRESH) + mib_arp_update(); + + TAILQ_FOREACH(at, &mibarp_list, link) + if (at->index.subs[0] == ifp->index && + (at->index.subs[1] == ((a >> 24) & 0xff)) && + (at->index.subs[2] == ((a >> 16) & 0xff)) && + (at->index.subs[3] == ((a >> 8) & 0xff)) && + (at->index.subs[4] == ((a >> 0) & 0xff))) + return (at); + return (NULL); +} + +struct mibarp * +mib_arp_create(const struct mibif *ifp, struct in_addr in, const u_char *phys, + size_t physlen) +{ + struct mibarp *at; + uint32_t a = ntohl(in.s_addr); + + if ((at = malloc(sizeof(*at))) == NULL) + return (NULL); + at->flags = 0; + + at->index.len = 5; + at->index.subs[0] = ifp->index; + at->index.subs[1] = (a >> 24) & 0xff; + at->index.subs[2] = (a >> 16) & 0xff; + at->index.subs[3] = (a >> 8) & 0xff; + at->index.subs[4] = (a >> 0) & 0xff; + if ((at->physlen = physlen) > sizeof(at->phys)) + at->physlen = sizeof(at->phys); + memcpy(at->phys, phys, at->physlen); + + INSERT_OBJECT_OID(at, &mibarp_list); + + return (at); +} + +void +mib_arp_delete(struct mibarp *at) +{ + TAILQ_REMOVE(&mibarp_list, at, link); + free(at); +} + +int +op_nettomedia(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + struct mibarp *at; + + at = NULL; /* gcc */ + + if (get_ticks() >= mibarpticks + ARPREFRESH) + mib_arp_update(); + + switch (op) { + + case SNMP_OP_GETNEXT: + if ((at = NEXT_OBJECT_OID(&mibarp_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + index_append(&value->var, sub, &at->index); + break; + + case SNMP_OP_GET: + if ((at = FIND_OBJECT_OID(&mibarp_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + if ((at = FIND_OBJECT_OID(&mibarp_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NO_CREATION); + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + abort(); + } + + switch (value->var.subs[sub - 1]) { + + case LEAF_ipNetToMediaIfIndex: + value->v.integer = at->index.subs[0]; + break; + + case LEAF_ipNetToMediaPhysAddress: + return (string_get(value, at->phys, at->physlen)); + + case LEAF_ipNetToMediaNetAddress: + value->v.ipaddress[0] = at->index.subs[1]; + value->v.ipaddress[1] = at->index.subs[2]; + value->v.ipaddress[2] = at->index.subs[3]; + value->v.ipaddress[3] = at->index.subs[4]; + break; + + case LEAF_ipNetToMediaType: + value->v.integer = (at->flags & MIBARP_PERM) ? 4 : 3; + break; + } + return (SNMP_ERR_NOERROR); +} Property changes on: vendor/1.14/snmp_mibII/mibII_nettomedia.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_mibII/mibII_rcvaddr.c =================================================================== --- vendor/1.14/snmp_mibII/mibII_rcvaddr.c (nonexistent) +++ vendor/1.14/snmp_mibII/mibII_rcvaddr.c (revision 359491) @@ -0,0 +1,134 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmp_mibII/mibII_rcvaddr.c,v 1.9 2004/08/06 08:47:03 brandt Exp $ + * + * Interface receive address table. + */ +#include "mibII.h" +#include "mibII_oid.h" + +/* + * find receive address + */ +struct mibrcvaddr * +mib_find_rcvaddr(u_int ifindex, const u_char *addr, size_t addrlen) +{ + struct mibrcvaddr *rcv; + + TAILQ_FOREACH(rcv, &mibrcvaddr_list, link) + if (rcv->ifindex == ifindex && + rcv->addrlen == addrlen && + memcmp(rcv->addr, addr, addrlen) == 0) + return (rcv); + return (NULL); +} + +/* + * Create receive address + */ +struct mibrcvaddr * +mib_rcvaddr_create(struct mibif *ifp, const u_char *addr, size_t addrlen) +{ + struct mibrcvaddr *rcv; + u_int i; + + if (addrlen + OIDLEN_ifRcvAddressEntry + 1 > ASN_MAXOIDLEN) + return (NULL); + + if ((rcv = malloc(sizeof(*rcv))) == NULL) + return (NULL); + rcv->ifindex = ifp->index; + rcv->addrlen = addrlen; + memcpy(rcv->addr, addr, addrlen); + rcv->flags = 0; + + rcv->index.len = addrlen + 2; + rcv->index.subs[0] = ifp->index; + rcv->index.subs[1] = addrlen; + for (i = 0; i < addrlen; i++) + rcv->index.subs[i + 2] = addr[i]; + + INSERT_OBJECT_OID(rcv, &mibrcvaddr_list); + + return (rcv); +} + +/* + * Delete a receive address + */ +void +mib_rcvaddr_delete(struct mibrcvaddr *rcv) +{ + TAILQ_REMOVE(&mibrcvaddr_list, rcv, link); + free(rcv); +} + +int +op_rcvaddr(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + struct mibrcvaddr *rcv; + + rcv = NULL; /* make compiler happy */ + + switch (op) { + + case SNMP_OP_GETNEXT: + if ((rcv = NEXT_OBJECT_OID(&mibrcvaddr_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + index_append(&value->var, sub, &rcv->index); + break; + + case SNMP_OP_GET: + if ((rcv = FIND_OBJECT_OID(&mibrcvaddr_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + if ((rcv = FIND_OBJECT_OID(&mibrcvaddr_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NO_CREATION); + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + abort(); + } + + switch (value->var.subs[sub - 1]) { + + case LEAF_ifRcvAddressStatus: + value->v.integer = 1; + break; + + case LEAF_ifRcvAddressType: + value->v.integer = (rcv->flags & MIBRCVADDR_VOLATILE) ? 2 : 3; + break; + } + return (SNMP_ERR_NOERROR); +} Property changes on: vendor/1.14/snmp_mibII/mibII_rcvaddr.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_mibII/mibII_route.c =================================================================== --- vendor/1.14/snmp_mibII/mibII_route.c (nonexistent) +++ vendor/1.14/snmp_mibII/mibII_route.c (revision 359491) @@ -0,0 +1,514 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmp_mibII/mibII_route.c,v 1.9 2005/10/06 07:15:00 brandt_h Exp $ + * + * Routing table + */ + +#ifdef HAVE_SYS_TREE_H +#include +#else +#include "tree.h" +#endif + +#include "mibII.h" +#include "mibII_oid.h" + +struct sroute { + RB_ENTRY(sroute) link; + uint32_t ifindex; + uint8_t index[13]; + uint8_t type; + uint8_t proto; +}; +static RB_HEAD(sroutes, sroute) sroutes = RB_INITIALIZER(&sroutes); + +RB_PROTOTYPE(sroutes, sroute, link, sroute_compare); + +#define ROUTE_UPDATE_INTERVAL (100 * 60 * 10) /* 10 min */ +static uint64_t route_tick; +static u_int route_total; + +/* + * Compare two routes + */ +static int +sroute_compare(struct sroute *s1, struct sroute *s2) +{ + + return (memcmp(s1->index, s2->index, 13)); +} + +static void +sroute_index_append(struct asn_oid *oid, u_int sub, const struct sroute *s) +{ + int i; + + oid->len = sub + 13; + for (i = 0; i < 13; i++) + oid->subs[sub + i] = s->index[i]; +} + +#if 0 +static void +sroute_print(const struct sroute *r) +{ + u_int i; + + for (i = 0; i < 13 - 1; i++) + printf("%u.", r->index[i]); + printf("%u proto=%u type=%u", r->index[i], r->proto, r->type); +} +#endif + +/* + * process routing message + */ +void +mib_sroute_process(struct rt_msghdr *rtm, struct sockaddr *gw, + struct sockaddr *dst, struct sockaddr *mask) +{ + struct sockaddr_in *in_dst, *in_gw; + struct in_addr in_mask; + struct mibif *ifp; + struct sroute key; + struct sroute *r, *r1; + in_addr_t ha; + + if (dst == NULL || gw == NULL || dst->sa_family != AF_INET || + gw->sa_family != AF_INET) + return; + + in_dst = (struct sockaddr_in *)(void *)dst; + in_gw = (struct sockaddr_in *)(void *)gw; + + if (rtm->rtm_flags & RTF_HOST) + in_mask.s_addr = 0xffffffff; + else if (mask == NULL || mask->sa_len == 0) + in_mask.s_addr = 0; + else + in_mask = ((struct sockaddr_in *)(void *)mask)->sin_addr; + + /* build the index */ + ha = ntohl(in_dst->sin_addr.s_addr); + key.index[0] = (ha >> 24) & 0xff; + key.index[1] = (ha >> 16) & 0xff; + key.index[2] = (ha >> 8) & 0xff; + key.index[3] = (ha >> 0) & 0xff; + + ha = ntohl(in_mask.s_addr); + key.index[4] = (ha >> 24) & 0xff; + key.index[5] = (ha >> 16) & 0xff; + key.index[6] = (ha >> 8) & 0xff; + key.index[7] = (ha >> 0) & 0xff; + + /* ToS */ + key.index[8] = 0; + + ha = ntohl(in_gw->sin_addr.s_addr); + key.index[9] = (ha >> 24) & 0xff; + key.index[10] = (ha >> 16) & 0xff; + key.index[11] = (ha >> 8) & 0xff; + key.index[12] = (ha >> 0) & 0xff; + + if (rtm->rtm_type == RTM_DELETE) { + r = RB_FIND(sroutes, &sroutes, &key); + if (r == 0) { +#ifdef DEBUG_ROUTE + syslog(LOG_WARNING, "%s: DELETE: %u.%u.%u.%u " + "%u.%u.%u.%u %u %u.%u.%u.%u not found", __func__, + key.index[0], key.index[1], key.index[2], + key.index[3], key.index[4], key.index[5], + key.index[6], key.index[7], key.index[8], + key.index[9], key.index[10], key.index[11], + key.index[12]); +#endif + return; + } + RB_REMOVE(sroutes, &sroutes, r); + free(r); + route_total--; +#ifdef DEBUG_ROUTE + printf("%s: DELETE: %u.%u.%u.%u " + "%u.%u.%u.%u %u %u.%u.%u.%u\n", __func__, + key.index[0], key.index[1], key.index[2], + key.index[3], key.index[4], key.index[5], + key.index[6], key.index[7], key.index[8], + key.index[9], key.index[10], key.index[11], + key.index[12]); +#endif + return; + } + + /* GET or ADD */ + ifp = NULL; + if ((ifp = mib_find_if_sys(rtm->rtm_index)) == NULL) { + if (rtm->rtm_type == RTM_ADD) { + /* make it a get so the kernel fills the index */ + mib_send_rtmsg(rtm, gw, dst, mask); + return; + } + mib_iflist_bad = 1; + } + + if ((r = malloc(sizeof(*r))) == NULL) { + syslog(LOG_ERR, "%m"); + return; + } + + memcpy(r->index, key.index, sizeof(r->index)); + r->ifindex = (ifp == NULL) ? 0 : ifp->index; + + r->type = (rtm->rtm_flags & RTF_REJECT) ? 2 : 4; + + /* cannot really know, what protocol it runs */ + r->proto = (rtm->rtm_flags & RTF_LOCAL) ? 2 : + (rtm->rtm_flags & RTF_STATIC) ? 3 : + (rtm->rtm_flags & RTF_DYNAMIC) ? 4 : 10; + + r1 = RB_INSERT(sroutes, &sroutes, r); + if (r1 != NULL) { +#ifdef DEBUG_ROUTE + syslog(LOG_WARNING, "%s: %u.%u.%u.%u " + "%u.%u.%u.%u %u %u.%u.%u.%u duplicate route", __func__, + key.index[0], key.index[1], key.index[2], + key.index[3], key.index[4], key.index[5], + key.index[6], key.index[7], key.index[8], + key.index[9], key.index[10], key.index[11], + key.index[12]); +#endif + r1->ifindex = r->ifindex; + r1->type = r->type; + r1->proto = r->proto; + free(r); + return; + } + + route_total++; +#ifdef DEBUG_ROUTE + printf("%s: ADD/GET: %u.%u.%u.%u " + "%u.%u.%u.%u %u %u.%u.%u.%u\n", __func__, + key.index[0], key.index[1], key.index[2], + key.index[3], key.index[4], key.index[5], + key.index[6], key.index[7], key.index[8], + key.index[9], key.index[10], key.index[11], + key.index[12]); +#endif +} + +int +mib_fetch_route(void) +{ + u_char *rtab, *next; + size_t len; + struct sroute *r, *r1; + struct rt_msghdr *rtm; + struct sockaddr *addrs[RTAX_MAX]; + + if (route_tick != 0 && route_tick + ROUTE_UPDATE_INTERVAL > this_tick) + return (0); + + /* + * Remove all routes + */ + r = RB_MIN(sroutes, &sroutes); + while (r != NULL) { + r1 = RB_NEXT(sroutes, &sroutes, r); + RB_REMOVE(sroutes, &sroutes, r); + free(r); + r = r1; + } + route_total = 0; + + if ((rtab = mib_fetch_rtab(AF_INET, NET_RT_DUMP, 0, &len)) == NULL) + return (-1); + + next = rtab; + for (next = rtab; next < rtab + len; next += rtm->rtm_msglen) { + rtm = (struct rt_msghdr *)(void *)next; + if (rtm->rtm_type != RTM_GET || + !(rtm->rtm_flags & RTF_UP)) + continue; + mib_extract_addrs(rtm->rtm_addrs, (u_char *)(rtm + 1), addrs); + + + mib_sroute_process(rtm, addrs[RTAX_GATEWAY], addrs[RTAX_DST], + addrs[RTAX_NETMASK]); + } + +#if 0 + u_int n = 0; + r = RB_MIN(sroutes, &sroutes); + while (r != NULL) { + printf("%u: ", n++); + sroute_print(r); + printf("\n"); + r = RB_NEXT(sroutes, &sroutes, r); + } +#endif + free(rtab); + route_tick = get_ticks(); + + return (0); +} + +/** + * Find a route in the table. + */ +static struct sroute * +sroute_get(const struct asn_oid *oid, u_int sub) +{ + struct sroute key; + int i; + + if (oid->len - sub != 13) + return (NULL); + for (i = 0; i < 13; i++) + key.index[i] = oid->subs[sub + i]; + return (RB_FIND(sroutes, &sroutes, &key)); +} + +/** + * Find next route in the table. There is no such RB_ macro, so must + * dig into the innards of the RB stuff. + */ +static struct sroute * +sroute_getnext(struct asn_oid *oid, u_int sub) +{ + u_int i; + int comp; + struct sroute key; + struct sroute *best; + struct sroute *s; + + /* + * We now, that the OID is at least the tableEntry OID. If it is, + * the user wants the first route. + */ + if (oid->len == sub) + return (RB_MIN(sroutes, &sroutes)); + + /* + * This is also true for any index that consists of zeros and is + * shorter than the full index. + */ + if (oid->len < sub + 13) { + for (i = sub; i < oid->len; i++) + if (oid->subs[i] != 0) + break; + if (i == oid->len) + return (RB_MIN(sroutes, &sroutes)); + + /* + * Now if the index is too short, we fill it with zeros and then + * subtract one from the index. We can do this, because we now, + * that there is at least one index element that is not zero. + */ + for (i = oid->len; i < sub + 13; i++) + oid->subs[i] = 0; + + for (i = sub + 13 - 1; i >= sub; i--) { + if (oid->subs[i] != 0) { + oid->subs[i]--; + break; + } + oid->subs[i] = ASN_MAXID; + } + oid->len = sub + 13; + } + + /* build the index */ + for (i = sub; i < sub + 13; i++) + key.index[i - sub] = oid->subs[i]; + + /* now find the element */ + best = NULL; + s = RB_ROOT(&sroutes); + + while (s != NULL) { + comp = sroute_compare(&key, s); + if (comp >= 0) { + /* The current element is smaller than what we search. + * Forget about it and move to the right subtree. */ + s = RB_RIGHT(s, link); + continue; + } + /* the current element is larger than what we search. + * forget about the right subtree (its even larger), but + * the current element may be what we need. */ + if (best == NULL || sroute_compare(s, best) < 0) + /* this one's better */ + best = s; + + s = RB_LEFT(s, link); + } + return (best); +} + +/* + * Table + */ +int +op_route_table(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + struct sroute *r; + + if (mib_fetch_route() == -1) + return (SNMP_ERR_GENERR); + + switch (op) { + + case SNMP_OP_GETNEXT: + if ((r = sroute_getnext(&value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + sroute_index_append(&value->var, sub, r); + break; + + case SNMP_OP_GET: + if ((r = sroute_get(&value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + if ((r = sroute_get(&value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + abort(); + + default: + abort(); + } + + switch (value->var.subs[sub - 1]) { + + case LEAF_ipCidrRouteDest: + value->v.ipaddress[0] = r->index[0]; + value->v.ipaddress[1] = r->index[1]; + value->v.ipaddress[2] = r->index[2]; + value->v.ipaddress[3] = r->index[3]; + break; + + case LEAF_ipCidrRouteMask: + value->v.ipaddress[0] = r->index[4]; + value->v.ipaddress[1] = r->index[5]; + value->v.ipaddress[2] = r->index[6]; + value->v.ipaddress[3] = r->index[7]; + break; + + case LEAF_ipCidrRouteTos: + value->v.integer = r->index[8]; + break; + + case LEAF_ipCidrRouteNextHop: + value->v.ipaddress[0] = r->index[9]; + value->v.ipaddress[1] = r->index[10]; + value->v.ipaddress[2] = r->index[11]; + value->v.ipaddress[3] = r->index[12]; + break; + + case LEAF_ipCidrRouteIfIndex: + value->v.integer = r->ifindex; + break; + + case LEAF_ipCidrRouteType: + value->v.integer = r->type; + break; + + case LEAF_ipCidrRouteProto: + value->v.integer = r->proto; + break; + + case LEAF_ipCidrRouteAge: + value->v.integer = 0; + break; + + case LEAF_ipCidrRouteInfo: + value->v.oid = oid_zeroDotZero; + break; + + case LEAF_ipCidrRouteNextHopAS: + value->v.integer = 0; + break; + + case LEAF_ipCidrRouteMetric1: + case LEAF_ipCidrRouteMetric2: + case LEAF_ipCidrRouteMetric3: + case LEAF_ipCidrRouteMetric4: + case LEAF_ipCidrRouteMetric5: + value->v.integer = -1; + break; + + case LEAF_ipCidrRouteStatus: + value->v.integer = 1; + break; + } + return (SNMP_ERR_NOERROR); +} + +/* + * scalars + */ +int +op_route(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + break; + + case SNMP_OP_SET: + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + abort(); + } + + if (mib_fetch_route() == -1) + return (SNMP_ERR_GENERR); + + switch (value->var.subs[sub - 1]) { + + case LEAF_ipCidrRouteNumber: + value->v.uint32 = route_total; + break; + + } + return (SNMP_ERR_NOERROR); +} + +RB_GENERATE(sroutes, sroute, link, sroute_compare); Property changes on: vendor/1.14/snmp_mibII/mibII_route.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_mibII/mibII_tcp.c =================================================================== --- vendor/1.14/snmp_mibII/mibII_tcp.c (nonexistent) +++ vendor/1.14/snmp_mibII/mibII_tcp.c (revision 359491) @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmp_mibII/mibII_tcp.c,v 1.7 2005/05/23 09:03:42 brandt_h Exp $ + * + * tcp + */ +#include "mibII.h" +#include "mibII_oid.h" +#include +#include +#include +#include +#include +#include + +struct tcp_index { + struct asn_oid index; + struct xtcpcb *tp; +}; + +static uint64_t tcp_tick; +static uint64_t tcp_stats_tick; +static struct tcpstat tcpstat; +static uint64_t tcps_states[TCP_NSTATES]; +static struct xinpgen *xinpgen; +static size_t xinpgen_len; +static u_int tcp_total; + +static u_int oidnum; +static struct tcp_index *tcpoids; + +static int +tcp_compare(const void *p1, const void *p2) +{ + const struct tcp_index *t1 = p1; + const struct tcp_index *t2 = p2; + + return (asn_compare_oid(&t1->index, &t2->index)); +} + +static int +fetch_tcp_stats(void) +{ + size_t len; + + len = sizeof(tcpstat); + if (sysctlbyname("net.inet.tcp.stats", &tcpstat, &len, NULL, 0) == -1) { + syslog(LOG_ERR, "net.inet.tcp.stats: %m"); + return (-1); + } + if (len != sizeof(tcpstat)) { + syslog(LOG_ERR, "net.inet.tcp.stats: wrong size"); + return (-1); + } + + len = sizeof(tcps_states); + if (sysctlbyname("net.inet.tcp.states", &tcps_states, &len, NULL, + 0) == -1) { + syslog(LOG_ERR, "net.inet.tcp.states: %m"); + return (-1); + } + if (len != sizeof(tcps_states)) { + syslog(LOG_ERR, "net.inet.tcp.states: wrong size"); + return (-1); + } + + tcp_stats_tick = get_ticks(); + + return (0); +} + +static int +fetch_tcp(void) +{ + size_t len; + struct xinpgen *ptr; + struct xtcpcb *tp; + struct tcp_index *oid; + in_addr_t inaddr; + + len = 0; + if (sysctlbyname("net.inet.tcp.pcblist", NULL, &len, NULL, 0) == -1) { + syslog(LOG_ERR, "net.inet.tcp.pcblist: %m"); + return (-1); + } + if (len > xinpgen_len) { + if ((ptr = realloc(xinpgen, len)) == NULL) { + syslog(LOG_ERR, "%zu: %m", len); + return (-1); + } + xinpgen = ptr; + xinpgen_len = len; + } + if (sysctlbyname("net.inet.tcp.pcblist", xinpgen, &len, NULL, 0) == -1) { + syslog(LOG_ERR, "net.inet.tcp.pcblist: %m"); + return (-1); + } + + tcp_tick = get_ticks(); + + tcp_total = 0; + for (ptr = (struct xinpgen *)(void *)((char *)xinpgen + xinpgen->xig_len); + ptr->xig_len > sizeof(struct xinpgen); + ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) { + tp = (struct xtcpcb *)ptr; + if (tp->xt_inp.inp_gencnt > xinpgen->xig_gen || + (tp->xt_inp.inp_vflag & (INP_IPV4|INP_IPV6)) == 0) + continue; + + if (tp->xt_inp.inp_vflag & INP_IPV4) + tcp_total++; + } + + if (oidnum < tcp_total) { + oid = realloc(tcpoids, tcp_total * sizeof(tcpoids[0])); + if (oid == NULL) { + free(tcpoids); + oidnum = 0; + return (0); + } + tcpoids = oid; + oidnum = tcp_total; + } + + oid = tcpoids; + for (ptr = (struct xinpgen *)(void *)((char *)xinpgen + xinpgen->xig_len); + ptr->xig_len > sizeof(struct xinpgen); + ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) { + tp = (struct xtcpcb *)ptr; + if (tp->xt_inp.inp_gencnt > xinpgen->xig_gen || + (tp->xt_inp.inp_vflag & INP_IPV4) == 0) + continue; + oid->tp = tp; + oid->index.len = 10; + inaddr = ntohl(tp->xt_inp.inp_laddr.s_addr); + oid->index.subs[0] = (inaddr >> 24) & 0xff; + oid->index.subs[1] = (inaddr >> 16) & 0xff; + oid->index.subs[2] = (inaddr >> 8) & 0xff; + oid->index.subs[3] = (inaddr >> 0) & 0xff; + oid->index.subs[4] = ntohs(tp->xt_inp.inp_lport); + inaddr = ntohl(tp->xt_inp.inp_faddr.s_addr); + oid->index.subs[5] = (inaddr >> 24) & 0xff; + oid->index.subs[6] = (inaddr >> 16) & 0xff; + oid->index.subs[7] = (inaddr >> 8) & 0xff; + oid->index.subs[8] = (inaddr >> 0) & 0xff; + oid->index.subs[9] = ntohs(tp->xt_inp.inp_fport); + oid++; + } + + qsort(tcpoids, tcp_total, sizeof(tcpoids[0]), tcp_compare); + + return (0); +} + +/* + * Scalars + */ +int +op_tcp(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + break; + + case SNMP_OP_SET: + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + abort(); + } + + if (tcp_stats_tick < this_tick) + if (fetch_tcp_stats() == -1) + return (SNMP_ERR_GENERR); + + switch (value->var.subs[sub - 1]) { + + case LEAF_tcpRtoAlgorithm: + value->v.integer = 4; /* Van Jacobson */ + break; + +#define hz clockinfo.hz + + case LEAF_tcpRtoMin: + value->v.integer = 1000 * TCPTV_MIN / hz; + break; + + case LEAF_tcpRtoMax: + value->v.integer = 1000 * TCPTV_REXMTMAX / hz; + break; +#undef hz + + case LEAF_tcpMaxConn: + value->v.integer = -1; + break; + + case LEAF_tcpActiveOpens: + value->v.uint32 = tcpstat.tcps_connattempt; + break; + + case LEAF_tcpPassiveOpens: + value->v.uint32 = tcpstat.tcps_accepts; + break; + + case LEAF_tcpAttemptFails: + value->v.uint32 = tcpstat.tcps_conndrops; + break; + + case LEAF_tcpEstabResets: + value->v.uint32 = tcpstat.tcps_drops; + break; + + case LEAF_tcpCurrEstab: + value->v.uint32 = tcps_states[TCPS_ESTABLISHED] + + tcps_states[TCPS_CLOSE_WAIT]; + break; + + case LEAF_tcpInSegs: + value->v.uint32 = tcpstat.tcps_rcvtotal; + break; + + case LEAF_tcpOutSegs: + value->v.uint32 = tcpstat.tcps_sndtotal - + tcpstat.tcps_sndrexmitpack; + break; + + case LEAF_tcpRetransSegs: + value->v.uint32 = tcpstat.tcps_sndrexmitpack; + break; + + case LEAF_tcpInErrs: + value->v.uint32 = tcpstat.tcps_rcvbadsum + + tcpstat.tcps_rcvbadoff + + tcpstat.tcps_rcvshort; + break; + } + return (SNMP_ERR_NOERROR); +} + +int +op_tcpconn(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + u_int i; + + if (tcp_tick < this_tick) + if (fetch_tcp() == -1) + return (SNMP_ERR_GENERR); + + switch (op) { + + case SNMP_OP_GETNEXT: + for (i = 0; i < tcp_total; i++) + if (index_compare(&value->var, sub, &tcpoids[i].index) < 0) + break; + if (i == tcp_total) + return (SNMP_ERR_NOSUCHNAME); + index_append(&value->var, sub, &tcpoids[i].index); + break; + + case SNMP_OP_GET: + for (i = 0; i < tcp_total; i++) + if (index_compare(&value->var, sub, &tcpoids[i].index) == 0) + break; + if (i == tcp_total) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + default: + abort(); + } + + switch (value->var.subs[sub - 1]) { + + case LEAF_tcpConnState: + switch (tcpoids[i].tp->t_state) { + + case TCPS_CLOSED: + value->v.integer = 1; + break; + case TCPS_LISTEN: + value->v.integer = 2; + break; + case TCPS_SYN_SENT: + value->v.integer = 3; + break; + case TCPS_SYN_RECEIVED: + value->v.integer = 4; + break; + case TCPS_ESTABLISHED: + value->v.integer = 5; + break; + case TCPS_CLOSE_WAIT: + value->v.integer = 8; + break; + case TCPS_FIN_WAIT_1: + value->v.integer = 6; + break; + case TCPS_CLOSING: + value->v.integer = 10; + break; + case TCPS_LAST_ACK: + value->v.integer = 9; + break; + case TCPS_FIN_WAIT_2: + value->v.integer = 7; + break; + case TCPS_TIME_WAIT: + value->v.integer = 11; + break; + default: + value->v.integer = 0; + break; + } + break; + + case LEAF_tcpConnLocalAddress: + value->v.ipaddress[0] = tcpoids[i].index.subs[0]; + value->v.ipaddress[1] = tcpoids[i].index.subs[1]; + value->v.ipaddress[2] = tcpoids[i].index.subs[2]; + value->v.ipaddress[3] = tcpoids[i].index.subs[3]; + break; + + case LEAF_tcpConnLocalPort: + value->v.integer = tcpoids[i].index.subs[4]; + break; + + case LEAF_tcpConnRemAddress: + value->v.ipaddress[0] = tcpoids[i].index.subs[5]; + value->v.ipaddress[1] = tcpoids[i].index.subs[6]; + value->v.ipaddress[2] = tcpoids[i].index.subs[7]; + value->v.ipaddress[3] = tcpoids[i].index.subs[8]; + break; + + case LEAF_tcpConnRemPort: + value->v.integer = tcpoids[i].index.subs[9]; + break; + } + return (SNMP_ERR_NOERROR); +} Property changes on: vendor/1.14/snmp_mibII/mibII_tcp.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_mibII/mibII_tree.def =================================================================== --- vendor/1.14/snmp_mibII/mibII_tree.def (nonexistent) +++ vendor/1.14/snmp_mibII/mibII_tree.def (revision 359491) @@ -0,0 +1,262 @@ +# +# Copyright (c) 2001-2003 +# Fraunhofer Institute for Open Communication Systems (FhG Fokus). +# All rights reserved. +# +# Author: Harti Brandt +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $Begemot: bsnmp/snmp_mibII/mibII_tree.def,v 1.13 2006/02/14 09:04:19 brandt_h Exp $ +# +# Definition of the standard interfaces and ip trees. +# +(1 internet + (2 mgmt + (1 mib2 + (2 interfaces + (1 ifNumber INTEGER op_interfaces GET) + (2 ifTable + (1 ifEntry : INTEGER op_ifentry + (1 ifIndex INTEGER GET) + (2 ifDescr OCTETSTRING GET) + (3 ifType INTEGER GET) + (4 ifMtu INTEGER32 GET) + (5 ifSpeed GAUGE GET) + (6 ifPhysAddress OCTETSTRING GET) + (7 ifAdminStatus INTEGER GET SET) + (8 ifOperStatus INTEGER GET) + (9 ifLastChange TIMETICKS GET) + (10 ifInOctets COUNTER GET) + (11 ifInUcastPkts COUNTER GET) + (12 ifInNUcastPkts COUNTER GET) + (13 ifInDiscards COUNTER GET) + (14 ifInErrors COUNTER GET) + (15 ifInUnknownProtos COUNTER GET) + (16 ifOutOctets COUNTER GET) + (17 ifOutUcastPkts COUNTER GET) + (18 ifOutNUcastPkts COUNTER GET) + (19 ifOutDiscards COUNTER GET) + (20 ifOutErrors COUNTER GET) + (21 ifOutQLen GAUGE GET) + (22 ifSpecific OID GET) + )) + ) + (4 ip + (1 ipForwarding INTEGER op_ip GET SET) + (2 ipDefaultTTL INTEGER op_ip GET SET) + (3 ipInReceives COUNTER op_ipstat GET) + (4 ipInHdrErrors COUNTER op_ipstat GET) + (5 ipInAddrErrors COUNTER op_ipstat GET) + (6 ipForwDatagrams COUNTER op_ipstat GET) + (7 ipInUnknownProtos COUNTER op_ipstat GET) + (8 ipInDiscards COUNTER op_ipstat GET) + (9 ipInDelivers COUNTER op_ipstat GET) + (10 ipOutRequests COUNTER op_ipstat GET) + (11 ipOutDiscards COUNTER op_ipstat GET) + (12 ipOutNoRoutes COUNTER op_ipstat GET) + (13 ipReasmTimeout INTEGER32 op_ipstat GET) + (14 ipReasmReqds COUNTER op_ipstat GET) + (15 ipReasmOKs COUNTER op_ipstat GET) + (16 ipReasmFails COUNTER op_ipstat GET) + (17 ipFragOKs COUNTER op_ipstat GET) + (18 ipFragFails COUNTER op_ipstat GET) + (19 ipFragCreates COUNTER op_ipstat GET) + (20 ipAddrTable + (1 ipAddrEntry : IPADDRESS op_ipaddr + (1 ipAdEntAddr IPADDRESS GET) + (2 ipAdEntIfIndex INTEGER GET SET) + (3 ipAdEntNetMask IPADDRESS GET SET) + (4 ipAdEntBcastAddr INTEGER GET SET) + (5 ipAdEntReasmMaxSize INTEGER GET) + )) + (22 ipNetToMediaTable + (1 ipNetToMediaEntry : INTEGER IPADDRESS op_nettomedia + (1 ipNetToMediaIfIndex INTEGER GET) + (2 ipNetToMediaPhysAddress OCTETSTRING GET) + (3 ipNetToMediaNetAddress IPADDRESS GET) + (4 ipNetToMediaType INTEGER GET) + )) + (23 ipRoutingDiscards INTEGER op_ipstat) # not available + (24 ipForward + (3 ipCidrRouteNumber GAUGE op_route GET) + (4 ipCidrRouteTable + (1 ipCidrRouteEntry : IPADDRESS IPADDRESS INTEGER IPADDRESS op_route_table + (1 ipCidrRouteDest IPADDRESS GET) + (2 ipCidrRouteMask IPADDRESS GET) + (3 ipCidrRouteTos INTEGER GET) + (4 ipCidrRouteNextHop IPADDRESS GET) + (5 ipCidrRouteIfIndex INTEGER GET) # SET + (6 ipCidrRouteType INTEGER GET) # SET + (7 ipCidrRouteProto INTEGER GET) + (8 ipCidrRouteAge INTEGER GET) + (9 ipCidrRouteInfo OID GET) # SET + (10 ipCidrRouteNextHopAS INTEGER GET) # SET + (11 ipCidrRouteMetric1 INTEGER GET) # SET + (12 ipCidrRouteMetric2 INTEGER GET) # SET + (13 ipCidrRouteMetric3 INTEGER GET) # SET + (14 ipCidrRouteMetric4 INTEGER GET) # SET + (15 ipCidrRouteMetric5 INTEGER GET) # SET + (16 ipCidrRouteStatus INTEGER GET) # SET + )) + ) + ) + (5 icmp + (1 icmpInMsgs COUNTER op_icmpstat GET) + (2 icmpInErrors COUNTER op_icmpstat GET) + (3 icmpInDestUnreachs COUNTER op_icmpstat GET) + (4 icmpInTimeExcds COUNTER op_icmpstat GET) + (5 icmpInParmProbs COUNTER op_icmpstat GET) + (6 icmpInSrcQuenchs COUNTER op_icmpstat GET) + (7 icmpInRedirects COUNTER op_icmpstat GET) + (8 icmpInEchos COUNTER op_icmpstat GET) + (9 icmpInEchoReps COUNTER op_icmpstat GET) + (10 icmpInTimestamps COUNTER op_icmpstat GET) + (11 icmpInTimestampReps COUNTER op_icmpstat GET) + (12 icmpInAddrMasks COUNTER op_icmpstat GET) + (13 icmpInAddrMaskReps COUNTER op_icmpstat GET) + (14 icmpOutMsgs COUNTER op_icmpstat GET) + (15 icmpOutErrors COUNTER op_icmpstat GET) + (16 icmpOutDestUnreachs COUNTER op_icmpstat GET) + (17 icmpOutTimeExcds COUNTER op_icmpstat GET) + (18 icmpOutParmProbs COUNTER op_icmpstat GET) + (19 icmpOutSrcQuenchs COUNTER op_icmpstat GET) + (20 icmpOutRedirects COUNTER op_icmpstat GET) + (21 icmpOutEchos COUNTER op_icmpstat GET) + (22 icmpOutEchoReps COUNTER op_icmpstat GET) + (23 icmpOutTimestamps COUNTER op_icmpstat GET) + (24 icmpOutTimestampReps COUNTER op_icmpstat GET) + (25 icmpOutAddrMasks COUNTER op_icmpstat GET) + (26 icmpOutAddrMaskReps COUNTER op_icmpstat GET) + ) + (6 tcp + (1 tcpRtoAlgorithm INTEGER op_tcp GET) + (2 tcpRtoMin INTEGER32 op_tcp GET) + (3 tcpRtoMax INTEGER32 op_tcp GET) + (4 tcpMaxConn INTEGER32 op_tcp GET) + (5 tcpActiveOpens COUNTER op_tcp GET) + (6 tcpPassiveOpens COUNTER op_tcp GET) + (7 tcpAttemptFails COUNTER op_tcp GET) + (8 tcpEstabResets COUNTER op_tcp GET) + (9 tcpCurrEstab GAUGE op_tcp GET) + (10 tcpInSegs COUNTER op_tcp GET) + (11 tcpOutSegs COUNTER op_tcp GET) + (12 tcpRetransSegs COUNTER op_tcp GET) + (13 tcpConnTable + (1 tcpConnEntry : IPADDRESS INTEGER IPADDRESS INTEGER op_tcpconn + (1 tcpConnState INTEGER GET) + (2 tcpConnLocalAddress IPADDRESS GET) + (3 tcpConnLocalPort INTEGER GET) + (4 tcpConnRemAddress IPADDRESS GET) + (5 tcpConnRemPort INTEGER GET) + )) + (14 tcpInErrs COUNTER op_tcp GET) + (15 tcpOutRsts COUNTER op_tcp) # don't know + ) + (7 udp + (1 udpInDatagrams COUNTER op_udp GET) + (2 udpNoPorts COUNTER op_udp GET) + (3 udpInErrors COUNTER op_udp GET) + (4 udpOutDatagrams COUNTER op_udp GET) + (5 udpTable + (1 udpEntry : IPADDRESS INTEGER op_udptable + (1 udpLocalAddress IPADDRESS GET) + (2 udpLocalPort INTEGER GET) + )) + ) + (31 ifMIB + (1 ifMIBObjects + (1 ifXTable + (1 ifXEntry : INTEGER op_ifxtable + (1 ifName OCTETSTRING GET) + (2 ifInMulticastPkts COUNTER GET) + (3 ifInBroadcastPkts COUNTER GET) + (4 ifOutMulticastPkts COUNTER GET) + (5 ifOutBroadcastPkts COUNTER GET) + (6 ifHCInOctets COUNTER64 GET) + (7 ifHCInUcastPkts COUNTER64 GET) + (8 ifHCInMulticastPkts COUNTER64 GET) + (9 ifHCInBroadcastPkts COUNTER64 GET) + (10 ifHCOutOctets COUNTER64 GET) + (11 ifHCOutUcastPkts COUNTER64 GET) + (12 ifHCOutMulticastPkts COUNTER64 GET) + (13 ifHCOutBroadcastPkts COUNTER64 GET) + (14 ifLinkUpDownTrapEnable INTEGER GET SET) + (15 ifHighSpeed GAUGE GET) + (16 ifPromiscuousMode INTEGER GET SET) + (17 ifConnectorPresent INTEGER GET) + (18 ifAlias OCTETSTRING GET) + (19 ifCounterDiscontinuityTime TIMETICKS GET) + )) + (2 ifStackTable + (1 ifStackEntry : INTEGER INTEGER op_ifstack + (1 ifStackHigherLayer INTEGER) + (2 ifStackLowerLayer INTEGER) + (3 ifStackStatus INTEGER GET) + )) + (4 ifRcvAddressTable + (1 ifRcvAddressEntry : INTEGER OCTETSTRING op_rcvaddr + (1 ifRcvAddressAddress OCTETSTRING) + (2 ifRcvAddressStatus INTEGER GET) + (3 ifRcvAddressType INTEGER GET) + )) + (5 ifTableLastChange TIMETICKS op_ifmib GET) + (6 ifStackLastChange TIMETICKS op_ifmib GET) + ) + ) + (48 ipMIB + ) + (49 tcpMIB + ) + (50 udpMIB + ) + )) + (4 private + (1 enterprises + (12325 fokus + (1 begemot + (3 begemotIp + (1 begemotIpObjects + (1 begemotMib2 + (1 begemotIfMaxspeed COUNTER64 op_begemot_mibII GET) + (2 begemotIfPoll TIMETICKS op_begemot_mibII GET) + (3 begemotIfForcePoll TIMETICKS op_begemot_mibII GET SET) + (4 begemotIfDataPoll TIMETICKS op_begemot_mibII GET SET) + ) + ) + ) + ) + ) + ) + ) + (6 snmpV2 + (3 snmpModules + (1 snmpMIB + (1 snmpMIBObjects + (5 snmpTraps + (3 linkDown OID op_snmp_trap) + (4 linkUp OID op_snmp_trap) + ) + ) + ) + )) +) Property changes on: vendor/1.14/snmp_mibII/mibII_tree.def ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_mibII/mibII_udp.c =================================================================== --- vendor/1.14/snmp_mibII/mibII_udp.c (nonexistent) +++ vendor/1.14/snmp_mibII/mibII_udp.c (revision 359491) @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmp_mibII/mibII_udp.c,v 1.7 2005/05/23 09:03:42 brandt_h Exp $ + * + * udp + */ +#include "mibII.h" +#include "mibII_oid.h" +#include +#include +#include +#include +#include + +struct udp_index { + struct asn_oid index; + struct xinpcb *inp; +}; + +static uint64_t udp_tick; +static struct udpstat udpstat; +static struct xinpgen *xinpgen; +static size_t xinpgen_len; +static u_int udp_total; + +static u_int oidnum; +static struct udp_index *udpoids; + +static int +udp_compare(const void *p1, const void *p2) +{ + const struct udp_index *t1 = p1; + const struct udp_index *t2 = p2; + + return (asn_compare_oid(&t1->index, &t2->index)); +} + +static int +fetch_udp(void) +{ + size_t len; + struct xinpgen *ptr; + struct xinpcb *inp; + struct udp_index *oid; + in_addr_t inaddr; + + len = sizeof(udpstat); + if (sysctlbyname("net.inet.udp.stats", &udpstat, &len, NULL, 0) == -1) { + syslog(LOG_ERR, "net.inet.udp.stats: %m"); + return (-1); + } + if (len != sizeof(udpstat)) { + syslog(LOG_ERR, "net.inet.udp.stats: wrong size"); + return (-1); + } + + udp_tick = get_ticks(); + + len = 0; + if (sysctlbyname("net.inet.udp.pcblist", NULL, &len, NULL, 0) == -1) { + syslog(LOG_ERR, "net.inet.udp.pcblist: %m"); + return (-1); + } + if (len > xinpgen_len) { + if ((ptr = realloc(xinpgen, len)) == NULL) { + syslog(LOG_ERR, "%zu: %m", len); + return (-1); + } + xinpgen = ptr; + xinpgen_len = len; + } + if (sysctlbyname("net.inet.udp.pcblist", xinpgen, &len, NULL, 0) == -1) { + syslog(LOG_ERR, "net.inet.udp.pcblist: %m"); + return (-1); + } + + udp_total = 0; + for (ptr = (struct xinpgen *)(void *)((char *)xinpgen + xinpgen->xig_len); + ptr->xig_len > sizeof(struct xinpgen); + ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) { + inp = (struct xinpcb *)ptr; + if (inp->inp_gencnt > xinpgen->xig_gen || + (inp->inp_vflag & INP_IPV4) == 0) + continue; + + udp_total++; + } + + if (oidnum < udp_total) { + oid = realloc(udpoids, udp_total * sizeof(udpoids[0])); + if (oid == NULL) { + free(udpoids); + oidnum = 0; + return (0); + } + udpoids = oid; + oidnum = udp_total; + } + + oid = udpoids; + for (ptr = (struct xinpgen *)(void *)((char *)xinpgen + xinpgen->xig_len); + ptr->xig_len > sizeof(struct xinpgen); + ptr = (struct xinpgen *)(void *)((char *)ptr + ptr->xig_len)) { + inp = (struct xinpcb *)ptr; + if (inp->inp_gencnt > xinpgen->xig_gen || + (inp->inp_vflag & INP_IPV4) == 0) + continue; + oid->inp = inp; + oid->index.len = 5; + inaddr = ntohl(inp->inp_laddr.s_addr); + oid->index.subs[0] = (inaddr >> 24) & 0xff; + oid->index.subs[1] = (inaddr >> 16) & 0xff; + oid->index.subs[2] = (inaddr >> 8) & 0xff; + oid->index.subs[3] = (inaddr >> 0) & 0xff; + oid->index.subs[4] = ntohs(inp->inp_lport); + oid++; + } + + qsort(udpoids, udp_total, sizeof(udpoids[0]), udp_compare); + + return (0); +} + +int +op_udp(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + break; + + case SNMP_OP_SET: + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + abort(); + } + + if (udp_tick < this_tick) + if (fetch_udp() == -1) + return (SNMP_ERR_GENERR); + + switch (value->var.subs[sub - 1]) { + + case LEAF_udpInDatagrams: + value->v.uint32 = udpstat.udps_ipackets; + break; + + case LEAF_udpNoPorts: + value->v.uint32 = udpstat.udps_noport + + udpstat.udps_noportbcast + + udpstat.udps_noportmcast; + break; + + case LEAF_udpInErrors: + value->v.uint32 = udpstat.udps_hdrops + + udpstat.udps_badsum + + udpstat.udps_badlen + + udpstat.udps_fullsock; + break; + + case LEAF_udpOutDatagrams: + value->v.uint32 = udpstat.udps_opackets; + break; + } + return (SNMP_ERR_NOERROR); +} + +int +op_udptable(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + u_int i; + + if (udp_tick < this_tick) + if (fetch_udp() == -1) + return (SNMP_ERR_GENERR); + + switch (op) { + + case SNMP_OP_GETNEXT: + for (i = 0; i < udp_total; i++) + if (index_compare(&value->var, sub, &udpoids[i].index) < 0) + break; + if (i == udp_total) + return (SNMP_ERR_NOSUCHNAME); + index_append(&value->var, sub, &udpoids[i].index); + break; + + case SNMP_OP_GET: + for (i = 0; i < udp_total; i++) + if (index_compare(&value->var, sub, &udpoids[i].index) == 0) + break; + if (i == udp_total) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + default: + abort(); + } + + switch (value->var.subs[sub - 1]) { + + case LEAF_udpLocalAddress: + value->v.ipaddress[0] = udpoids[i].index.subs[0]; + value->v.ipaddress[1] = udpoids[i].index.subs[1]; + value->v.ipaddress[2] = udpoids[i].index.subs[2]; + value->v.ipaddress[3] = udpoids[i].index.subs[3]; + break; + + case LEAF_udpLocalPort: + value->v.integer = udpoids[i].index.subs[4]; + break; + + } + return (SNMP_ERR_NOERROR); +} Property changes on: vendor/1.14/snmp_mibII/mibII_udp.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_mibII/snmp_mibII.3 =================================================================== --- vendor/1.14/snmp_mibII/snmp_mibII.3 (nonexistent) +++ vendor/1.14/snmp_mibII/snmp_mibII.3 (revision 359491) @@ -0,0 +1,368 @@ +.\" +.\" Copyright (c) 2004-2005 +.\" Hartmut Brandt +.\" All rights reserved. +.\" Copyright (c) 2001-2003 +.\" Fraunhofer Institute for Open Communication Systems (FhG Fokus). +.\" All rights reserved. +.\" +.\" Author: Harti Brandt +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Begemot: bsnmp/snmp_mibII/snmp_mibII.3,v 1.10 2005/10/04 08:46:52 brandt_h Exp $ +.\" +.Dd January 4, 2017 +.Dt SNMP_MIBII 3 +.Os +.Sh NAME +.Nm mibII , +.Nm mibif_notify_f , +.Nm mib_netsock , +.Nm mib_if_set_dyn , +.Nm mib_refresh_iflist , +.Nm mib_find_if , +.Nm mib_find_if_sys , +.Nm mib_find_if_name , +.Nm mib_first_if , +.Nm mib_next_if , +.Nm mib_register_newif , +.Nm mib_unregister_newif , +.Nm mib_fetch_ifmib , +.Nm mib_if_admin , +.Nm mib_find_ifa , +.Nm mib_first_ififa , +.Nm mib_next_ififa , +.Nm mib_ifstack_create , +.Nm mib_ifstack_delete , +.Nm mib_find_rcvaddr , +.Nm mib_rcvaddr_create , +.Nm mib_rcvaddr_delete , +.Nm mibif_notify , +.Nm mibif_unnotify +.Nd "mib-2 module for bsnmpd." +.Sh LIBRARY +.Pq begemotSnmpdModulePath."mibII" = "@MODPATH@snmp_mibII.so" +.Sh SYNOPSIS +.In net/if.h +.In net/if_mib.h +.In bsnmp/snmpmod.h +.In bsnmp/snmp_mibII.h +.Ft typedef void +.Fn (*mibif_notify_f) "struct mibif *ifp" "enum mibif_notify event" "void *uarg" +.Vt extern int mib_netsock ; +.Ft void +.Fn mib_if_set_dyn "const char *ifname" +.Ft void +.Fn mib_refresh_iflist "void" +.Ft struct mibif * +.Fn mib_find_if "u_int ifindex" +.Ft struct mibif * +.Fn mib_find_if_sys "u_int sysindex" +.Ft struct mibif * +.Fn mib_find_if_name "const char *ifname" +.Ft struct mibif * +.Fn mib_first_if "void" +.Ft struct mibif * +.Fn mib_next_if "const struct mibif *ifp" +.Ft int +.Fn mib_register_newif "int (*func)(struct mibif *)" "const struct lmodule *mod" +.Ft void +.Fn mib_unregister_newif "const struct lmodule *mod" +.Ft int +.Fn mib_fetch_ifmib "struct mibif *ifp" +.Ft int +.Fn mib_if_admin "struct mibif *ifp" "int up" +.Ft struct mibifa * +.Fn mib_find_ifa "struct in_addr ipa" +.Ft struct mibifa * +.Fn mib_first_ififa "const struct mibif *ifp" +.Ft struct mibifa * +.Fn mib_next_ififa "struct mibifa *ifa" +.Ft int +.Fn mib_ifstack_create "const struct mibif *lower" "const struct mibif *upper" +.Ft void +.Fn mib_ifstack_delete "const struct mibif *lower" "const struct mibif *upper" +.Ft struct mibrcvaddr * +.Fn mib_find_rcvaddr "u_int ifindex" "const u_char *addr" "size_t addrlen" +.Ft struct mibrcvaddr * +.Fn mib_rcvaddr_create "struct mibif *ifp" "const u_char *addr" "size_t addrlen" +.Ft void +.Fn mib_rcvaddr_delete "struct mibrcvaddr *addr" +.Ft void * +.Fn mibif_notify "struct mibif *ifp" "const struct lmodule *mod" "mibif_notify_f func" "void *uarg" +.Ft void +.Fn mibif_unnotify "void *reg" +.Sh DESCRIPTION +The +.Nm snmp_mibII +module implements parts of the internet standard MIB-2. +Most of the relevant MIBs are implemented. +Some of the tables are restricted to be read-only instead of read-write. +The exact current implementation can be found in +.Pa @DEFPATH@mibII_tree.def . +The module also exports a number of functions and global variables for use +by other modules, that need to handle network interfaces. +This man page describes these functions. +.Ss DIRECT NETWORK ACCESS +The +.Nm +module opens a socket that is used to execute all network related +.Xr ioctl 2 +functions. +This socket is globally available under the name +.Va mib_netsock . +.Ss NETWORK INTERFACES +The +.Nm +module handles a list of all currently existing network interfaces. +It allows +other modules to handle their own interface lists with special information +by providing a mechanism to register to events that change the interface list +(see below). +The basic data structure is the interface structure: +.Bd -literal -offset indent +struct mibif { + TAILQ_ENTRY(mibif) link; + u_int flags; + u_int index; /* logical ifindex */ + u_int sysindex; + char name[IFNAMSIZ]; + char descr[256]; + struct ifmibdata mib; + uint64_t mibtick; + void *specmib; + size_t specmiblen; + u_char *physaddr; + u_int physaddrlen; + int has_connector; + int trap_enable; + uint64_t counter_disc; + mibif_notify_f xnotify; + void *xnotify_data; + const struct lmodule *xnotify_mod; + struct asn_oid spec_oid; +}; +.Ed +.Pp +The +.Nm +module tries to implement the semantic if +.Va ifIndex +as described in RFC-2863. +This RFC states, that an interface indexes may not be reused. +That means, for example, if +.Pa tun +is a synthetic interface type and the system creates the interface +.Pa tun0 , +destroys this interfaces and again creates a +.Pa tun 0 , +then these interfaces must have different interface indexes, because in fact +they are different interfaces. +If, on the other hand, there is a hardware interface +.Pa xl0 +and this interface disappears, because its driver is unloaded and appears +again, because the driver is loaded again, the interface index must stay +the same. +.Nm +implements this by differentiating between real and synthetic (dynamic) +interfaces. +An interface type can be declared dynamic by calling the function +.Fn mib_if_set_dyn +with the name if the interface type (for example +.Qq tun ). +For real interfaces, the module keeps the mapping between the interface name +and its +.Va ifIndex +in a special list, if the interface is unloaded. +For dynamic interfaces +a new +.Va ifIndex +is generated each time the interface comes into existence. +This means, that the interface index as seen by SNMP is not the same index +as used by the system. +The SNMP +.Va ifIndex +is held in field +.Va index , +the system's interface index is +.Va sysindex . +.Pp +A call to +.Nm mib_refresh_iflist +causes the entire interface list to be re-created. +.Pp +The interface list can be traversed with the functions +.Fn mib_first_if +and +.Fn mib_next_if . +Be sure not to change the interface list while traversing the list with +these two calls. +.Pp +There are three functions to find an interface by name or index. +.Fn mib_find_if +finds an interface by searching for an SNMP +.Va ifIndex , +.Fn mib_find_if_sys +finds an interface by searching for a system interface index and +.Fn mib_find_if_name +finds an interface by looking for an interface name. +Each of the function returns +.Li NULL +if the interface cannot be found. +.Pp +The function +.Fn mib_fetch_ifmib +causes the interface MIB to be refreshed from the kernel. +.Pp +The function +.Fn mib_if_admin +can be used to change the interface administrative state to up +(argument is 1) or down (argument is 0). +.Ss INTERFACE EVENTS +A module can register itself to receive a notification when a new entry is +created in the interface list. +This is done by calling +.Fn mib_register_newif . +A module can register only one function, a second call to +.Fn mib_register_newif +causes the registration to be overwritten. +The registration can be removed with a call to +.Fn mib_unregister_newif . +It is unregistered automatically, when the registering module is unloaded. +.Pp +A module can also register to events on a specific interface. +This is done by calling +.Fn mibif_notify . +This causes the given callback +.Fa func +to be called with the interface pointer, a notification code and +the user argument +.Fa uarg +when any of the following events occur: +.Bl -tag -width "XXXXX" +.It Li MIBIF_NOTIFY_DESTROY +The interface is destroyed. +.El +.Pp +This mechanism can be used to implement interface type specific MIB parts +in other modules. +The registration can be removed with +.Fn mib_unnotify +which the return value from +.Fa mib_notify . +Any notification registration is removed automatically when the interface +is destroyed or the registering module is unloaded. +.Em Note that only one module can register to any given interface . +.Ss INTERFACE ADDRESSES +The +.Nm +module handles a table of interface IP-addresses. +These addresses are held in a +.Bd -literal -offset indent +struct mibifa { + TAILQ_ENTRY(mibifa) link; + struct in_addr inaddr; + struct in_addr inmask; + struct in_addr inbcast; + struct asn_oid index; + u_int ifindex; + u_int flags; +}; +.Ed +.Pp +The (ordered) list of IP-addresses on a given interface can be traversed by +calling +.Fn mib_first_ififa +and +.Fn mib_next_ififa . +The list should not be considered read-only. +.Ss INTERFACE RECEIVE ADDRESSES +The internet MIB-2 contains a table of interface receive addresses. +These addresses are handled in: +.Bd -literal -offset indent +struct mibrcvaddr { + TAILQ_ENTRY(mibrcvaddr) link; + struct asn_oid index; + u_int ifindex; + u_char addr[ASN_MAXOIDLEN]; + size_t addrlen; + u_int flags; +}; +enum { + MIBRCVADDR_VOLATILE = 0x00000001, + MIBRCVADDR_BCAST = 0x00000002, + MIBRCVADDR_HW = 0x00000004, +}; +.Ed +.Pp +Note, that the assignment of +.Li MIBRCVADDR_BCAST +is based on a list of known interface types. +The flags should be handled +by modules implementing interface type specific MIBs. +.Pp +A receive address can be created with +.Fn mib_rcvaddr_create +and deleted with +.Fn mib_rcvaddr_delete . +This needs to be done only for addresses that are not automatically handled +by the system. +.Pp +A receive address can be found with +.Fn mib_find_rcvaddr . +.Ss INTERFACE STACK TABLE +The +.Nm +module maintains also the interface stack table. +Because for complex stacks, +there is no system supported generic way of getting this information, interface +type specific modules need to help setting up stack entries. +The +.Nm +module handles only the top and bottom entries. +.Pp +A table entry is created with +.Fn mib_ifstack_create +and deleted with +.Fn mib_ifstack_delete . +Both functions need the pointers to the interfaces. +Entries are automatically +deleted if any of the interfaces of the entry is destroyed. +The functions handle +both the stack table and the reverse stack table. +.Sh FILES +.Bl -tag -width ".It Pa @DEFPATH@mibII_tree.def" -compact +.It Pa @DEFPATH@mibII_tree.def +The description of the MIB tree implemented by +.Nm . +.It Pa /usr/local/share/snmp/mibs +.It Pa @MIBSPATH@ +The various internet MIBs. +.El +.Sh SEE ALSO +.Xr gensnmptree 1 , +.Xr snmpmod 3 +.Sh STANDARDS +This implementation conforms to the applicable IETF RFCs. +.Sh AUTHORS +.An Hartmut Brandt Aq harti@FreeBSD.org Property changes on: vendor/1.14/snmp_mibII/snmp_mibII.3 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_ntp/snmp_ntp.c =================================================================== --- vendor/1.14/snmp_ntp/snmp_ntp.c (nonexistent) +++ vendor/1.14/snmp_ntp/snmp_ntp.c (revision 359491) @@ -0,0 +1,1600 @@ +/* + * Copyright (c) 2005,2018 + * Hartmut Brandt. + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution of this software and documentation and use in source and + * binary forms, with or without modification, are permitted provided that + * the following conditions are met: + * + * 1. Redistributions of source code or documentation must retain the above + * copyright notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS + * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, + * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, + * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * $Begemot: bsnmp/snmp_ntp/snmp_ntp.c,v 1.9 2005/10/06 07:15:01 brandt_h Exp $ + * + * NTP interface for SNMPd. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_STDINT_H +#include +#elif defined(HAVE_INTTYPES_H) +#include +#endif +#include +#include +#include +#include +#include + +#include "support.h" +#include "snmpmod.h" + +#define SNMPTREE_TYPES +#include "ntp_tree.h" +#include "ntp_oid.h" + +#define NTPC_MAX 576 +#define NTPC_VERSION 3 +#define NTPC_MODE 6 +#define NTPC_DMAX 468 + +#define NTPC_BIT_RESP 0x80 +#define NTPC_BIT_ERROR 0x40 +#define NTPC_BIT_MORE 0x20 + +#define NTPC_OPMASK 0x1f +#define NTPC_OP_READSTAT 1 +#define NTPC_OP_READVAR 2 + +/* our module handle */ +static struct lmodule *module; + +/* debug flag */ +static uint32_t ntp_debug; +#define DBG_DUMP_PKTS 0x01 +#define DBG_DUMP_VARS 0x02 + +/* OIDs */ +static const struct asn_oid oid_ntpMIB = OIDX_ntpMIB; + +/* the Object Resource registration index */ +static u_int reg_index; + +/* last time we've fetch the system variables */ +static uint64_t sysinfo_tick; + +/* cached system variables */ +static int32_t sys_leap; +static int sysb_leap; +static int32_t sys_stratum; +static int sysb_stratum; +static int32_t sys_precision; +static int sysb_precision; +static char *sys_rootdelay; +static char *sys_rootdispersion; +static char *sys_refid; +static char sys_reftime[8]; +static int sysb_reftime; +static int32_t sys_poll; +static int sysb_poll; +static uint32_t sys_peer; +static int sysb_peer; +static u_char sys_clock[8]; +static int sysb_clock; +static char *sys_system; +static char *sys_processor; +static int sysb_jitter; +static double sys_jitter; +static int sysb_stability; +static double sys_stability; + +/* last time we've fetch the peer list */ +static uint64_t peers_tick; + +/* request sequence number generator */ +static uint16_t seqno; + +/* NTPD socket */ +static int ntpd_sock; +static void *ntpd_fd; + +struct peer { + /* required entries for macros */ + uint32_t index; + TAILQ_ENTRY(peer) link; + + int32_t config; /* config bit */ + u_char srcadr[4]; /* PeerAddress */ + uint32_t srcport; /* PeerPort */ + u_char dstadr[4]; /* HostAddress */ + uint32_t dstport; /* HostPort */ + int32_t leap; /* Leap */ + int32_t hmode; /* Mode */ + int32_t stratum; /* Stratum */ + int32_t ppoll; /* PeerPoll */ + int32_t hpoll; /* HostPoll */ + int32_t precision; /* Precision */ + char *rootdelay; /* RootDelay */ + char *rootdispersion;/* RootDispersion */ + char *refid; /* RefId */ + u_char reftime[8]; /* RefTime */ + u_char orgtime[8]; /* OrgTime */ + u_char rcvtime[8]; /* ReceiveTime */ + u_char xmttime[8]; /* TransmitTime */ + u_int32_t reach; /* Reach */ + int32_t timer; /* Timer */ + char *offset; /* Offset */ + char *delay; /* Delay */ + char *dispersion; /* Dispersion */ + int32_t filt_entries; +}; +TAILQ_HEAD(peer_list, peer); + +/* list of peers */ +static struct peer_list peers = TAILQ_HEAD_INITIALIZER(peers); + +struct filt { + /* required fields */ + struct asn_oid index; + TAILQ_ENTRY(filt) link; + + char *offset; + char *delay; + char *dispersion; +}; +TAILQ_HEAD(filt_list, filt); + +/* list of filters */ +static struct filt_list filts = TAILQ_HEAD_INITIALIZER(filts); + +/* configuration */ +static u_char *ntp_host; +static u_char *ntp_port; +static uint32_t ntp_timeout; + +static void ntpd_input(int, void *); +static int open_socket(void); + +/* the initialization function */ +static int +ntp_init(struct lmodule *mod, int argc, char *argv[] __unused) +{ + + module = mod; + + if (argc != 0) { + syslog(LOG_ERR, "bad number of arguments for %s", __func__); + return (EINVAL); + } + + ntp_host = strdup("localhost"); + ntp_port = strdup("ntp"); + ntp_timeout = 50; /* 0.5sec */ + + return (0); +} + +/* + * Module is started + */ +static void +ntp_start(void) +{ + + if (open_socket() != -1) { + ntpd_fd = fd_select(ntpd_sock, ntpd_input, NULL, module); + if (ntpd_fd == NULL) { + syslog(LOG_ERR, "fd_select failed on ntpd socket: %m"); + return; + } + } + reg_index = or_register(&oid_ntpMIB, "The MIB for NTP.", module); +} + +/* + * Called, when the module is to be unloaded after it was successfully loaded + */ +static int +ntp_fini(void) +{ + + or_unregister(reg_index); + fd_deselect(ntpd_fd); + + return (0); +} + +const struct snmp_module config = { + .comment = "This module implements the NTP MIB", + .init = ntp_init, + .start = ntp_start, + .fini = ntp_fini, + .tree = ntp_ctree, + .tree_size = ntp_CTREE_SIZE, +}; + +/* + * Open the NTPD socket + */ +static int +open_socket(void) +{ + struct addrinfo hints, *res, *res0; + int error; + const char *cause; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + + error = getaddrinfo(ntp_host, ntp_port, &hints, &res0); + if (error) { + syslog(LOG_ERR, "%s(%s): %s", ntp_host, ntp_port, + gai_strerror(error)); + return (-1); + } + + ntpd_sock = -1; + cause = "no address"; + errno = EADDRNOTAVAIL; + for (res = res0; res != NULL; res = res->ai_next) { + ntpd_sock = socket(res->ai_family, res->ai_socktype, + res->ai_protocol); + if (ntpd_sock == -1) { + cause = "socket"; + continue; + } + if (connect(ntpd_sock, res->ai_addr, res->ai_addrlen) == -1) { + cause = "connect"; + (void)close(ntpd_sock); + ntpd_sock = -1; + continue; + } + break; + } + if (ntpd_sock == -1) { + syslog(LOG_ERR, "%s: %m", cause); + return (-1); + } + freeaddrinfo(res0); + return (0); +} + +/* + * Dump a packet + */ +static void +dump_packet(const u_char *pkt, size_t ret) +{ + char buf[8 * 3 + 1]; + size_t i, j; + + for (i = 0; i < ret; i += 8) { + buf[0] = '\0'; + for (j = 0; i + j < (size_t)ret && j < 8; j++) + sprintf(buf + strlen(buf), " %02x", pkt[i + j]); + syslog(LOG_INFO, "%04zu:%s", i, buf); + } +} + +/* + * Execute an NTP request. + */ +static int +ntpd_request(u_int op, u_int associd, const char *vars) +{ + u_char *rpkt; + u_char *ptr; + size_t vlen; + ssize_t ret; + + if ((rpkt = malloc(NTPC_MAX)) == NULL) { + syslog(LOG_ERR, "%m"); + return (-1); + } + memset(rpkt, 0, NTPC_MAX); + + ptr = rpkt; + *ptr++ = (NTPC_VERSION << 3) | NTPC_MODE; + *ptr++ = op; + + if (++seqno == 0) + seqno++; + *ptr++ = seqno >> 8; + *ptr++ = seqno; + + /* skip status */ + ptr += 2; + + *ptr++ = associd >> 8; + *ptr++ = associd; + + /* skip offset */ + ptr += 2; + + if (vars != NULL) { + vlen = strlen(vars); + if (vlen > NTPC_DMAX) { + syslog(LOG_ERR, "NTP request too long (%zu)", vlen); + free(rpkt); + return (-1); + } + *ptr++ = vlen >> 8; + *ptr++ = vlen; + + memcpy(ptr, vars, vlen); + ptr += vlen; + } else + /* skip data length (is already zero) */ + ptr += 2; + + while ((ptr - rpkt) % 4 != 0) + *ptr++ = 0; + + if (ntp_debug & DBG_DUMP_PKTS) { + syslog(LOG_INFO, "sending %zd bytes", ptr - rpkt); + dump_packet(rpkt, ptr - rpkt); + } + + ret = send(ntpd_sock, rpkt, ptr - rpkt, 0); + if (ret == -1) { + syslog(LOG_ERR, "cannot send to ntpd: %m"); + free(rpkt); + return (-1); + } + return (0); +} + +/* + * Callback if packet arrived from NTPD + */ +static int +ntpd_read(uint16_t *op, uint16_t *associd, u_char **data, size_t *datalen) +{ + u_char pkt[NTPC_MAX + 1]; + u_char *ptr, *nptr; + u_int n; + ssize_t ret; + size_t z; + u_int offset; /* current offset */ + int more; /* more flag */ + int sel; + struct timeval inc, end, rem; + fd_set iset; + + *datalen = 0; + *data = NULL; + offset = 0; + + inc.tv_sec = ntp_timeout / 100; + inc.tv_usec = (ntp_timeout % 100) * 1000; + + (void)gettimeofday(&end, NULL); + timeradd(&end, &inc, &end); + + next: + /* compute remaining time */ + (void)gettimeofday(&rem, NULL); + if (timercmp(&rem, &end, >=)) { + /* do a poll */ + rem.tv_sec = 0; + rem.tv_usec = 0; + } else { + timersub(&end, &rem, &rem); + } + + /* select */ + FD_ZERO(&iset); + FD_SET(ntpd_sock, &iset); + sel = select(ntpd_sock + 1, &iset, NULL, NULL, &rem); + if (sel == -1) { + if (errno == EINTR) + goto next; + syslog(LOG_ERR, "select ntpd_sock: %m"); + free(*data); + return (-1); + } + if (sel == 0) { + syslog(LOG_ERR, "timeout on NTP connection"); + free(*data); + return (-1); + } + + /* now read it */ + ret = recv(ntpd_sock, pkt, sizeof(pkt), 0); + if (ret == -1) { + syslog(LOG_ERR, "error reading from ntpd: %m"); + free(*data); + return (-1); + } + + if (ntp_debug & DBG_DUMP_PKTS) { + syslog(LOG_INFO, "got %zd bytes", ret); + dump_packet(pkt, (size_t)ret); + } + + ptr = pkt; + if ((*ptr & 0x3f) != ((NTPC_VERSION << 3) | NTPC_MODE)) { + syslog(LOG_ERR, "unexpected packet version 0x%x", *ptr); + free(*data); + return (-1); + } + ptr++; + + if (!(*ptr & NTPC_BIT_RESP)) { + syslog(LOG_ERR, "not a response packet"); + return (-1); + } + if (*ptr & NTPC_BIT_ERROR) { + z = *datalen - 12; + if (z > NTPC_DMAX) + z = NTPC_DMAX; + syslog(LOG_ERR, "error response: %.*s", (int)z, pkt + 12); + free(*data); + return (-1); + } + more = (*ptr & NTPC_BIT_MORE); + + *op = *ptr++ & NTPC_OPMASK; + + /* seqno */ + n = *ptr++ << 8; + n |= *ptr++; + + if (n != seqno) { + syslog(LOG_ERR, "expecting seqno %u, got %u", seqno, n); + free(*data); + return (-1); + } + + /* status */ + n = *ptr++ << 8; + n |= *ptr++; + + /* associd */ + *associd = *ptr++ << 8; + *associd |= *ptr++; + + /* offset */ + n = *ptr++ << 8; + n |= *ptr++; + + if (n != offset) { + syslog(LOG_ERR, "offset: expecting %u, got %u", offset, n); + free(*data); + return (-1); + } + + /* count */ + n = *ptr++ << 8; + n |= *ptr++; + + if ((size_t)ret < 12 + n) { + syslog(LOG_ERR, "packet too short"); + return (-1); + } + + nptr = realloc(*data, *datalen + n); + if (nptr == NULL) { + syslog(LOG_ERR, "cannot allocate memory: %m"); + free(*data); + return (-1); + } + *data = nptr; + + memcpy(*data + offset, ptr, n); + *datalen += n; + + if (!more) + return (0); + + offset += n; + goto next; +} + +/* + * Send a request and wait for the response + */ +static int +ntpd_dialog(u_int op, u_int associd, const char *vars, u_char **data, + size_t *datalen) +{ + uint16_t rassocid; + uint16_t rop; + + if (ntpd_request(op, associd, vars) == -1) + return (-1); + if (ntpd_read(&rop, &rassocid, data, datalen) == -1) + return (-1); + + if (rop != op) { + syslog(LOG_ERR, "bad response op 0x%x", rop); + free(data); + return (-1); + } + + if (associd != rassocid) { + syslog(LOG_ERR, "response for wrong associd"); + free(data); + return (-1); + } + return (0); +} + +/* + * Callback if packet arrived from NTPD + */ +static void +ntpd_input(int fd __unused, void *arg __unused) +{ + uint16_t associd; + uint16_t op; + u_char *data; + size_t datalen; + + if (ntpd_read(&op, &associd, &data, &datalen) == -1) + return; + + free(data); +} + +/* + * Find the value of a variable + */ +static int +ntpd_parse(u_char **data, size_t *datalen, char **namep, char **valp) +{ + u_char *ptr = *data; + u_char *end = ptr + *datalen; + char *ptr1; + char endc; + + /* skip leading spaces */ + while (ptr < end && isspace((int)*ptr)) + ptr++; + + if (ptr == end) + return (0); + + *namep = ptr; + + /* skip to space or '=' or ','*/ + while (ptr < end && !isspace((int)*ptr) && *ptr != '=' && *ptr != ',') + ptr++; + endc = *ptr; + *ptr++ = '\0'; + + /* skip space */ + while (ptr < end && isspace((int)*ptr)) + ptr++; + + if (ptr == end || endc == ',') { + /* no value */ + *valp = NULL; + *datalen -= ptr - *data; + *data = ptr; + return (1); + } + + if (*ptr == '"') { + /* quoted */ + ptr++; + *valp = ptr; + while (ptr < end && *ptr != '"') + ptr++; + if (ptr == end) + return (0); + + *ptr++ = '\0'; + + /* find comma */ + while (ptr < end && isspace((int)*ptr) && *ptr == ',') + ptr++; + } else { + *valp = ptr; + + /* skip to end of value */ + while (ptr < end && *ptr != ',') + ptr++; + + /* remove trailing blanks */ + for (ptr1 = ptr; ptr1 > *valp; ptr1--) + if (!isspace((int)ptr1[-1])) + break; + *ptr1 = '\0'; + + if (ptr < end) + ptr++; + } + + *datalen -= ptr - *data; + *data = ptr; + + return (1); +} + +/* + * Parse an int32 value + */ +static int +val_parse_int32(const char *val, int32_t *p, int32_t min, int32_t max, int base) +{ + long n; + char *end; + + errno = 0; + n = strtol(val, &end, base); + if (errno != 0 || *end != '\0') + return (0); + if (n < min || n > max) + return (0); + *p = (int32_t)n; + return (1); +} + +/* + * Parse an uint32 value + */ +static int +val_parse_uint32(const char *val, uint32_t *p, uint32_t min, uint32_t max, + int base) +{ + u_long n; + char *end; + + errno = 0; + n = strtoul(val, &end, base); + if (errno != 0 || *end != '\0') + return (0); + if (n < min || n > max) + return (0); + *p = (uint32_t)n; + return (1); +} + +/* + * Parse a double + */ +static int +val_parse_double(const char *val, double *p) +{ + char *end; + + errno = 0; + *p = strtod(val, &end); + if (errno != 0 || *end != '\0') + return (0); + return (1); +} + +static int +val_parse_ts(const char *val, char *buf) +{ + int r, n; + u_int i, f; + + if (strlen(val) > 2 && val[0] == '0' && val[1] == 'x') { + /* hex format */ + r = sscanf(val + 2, "%x.%x%n", &i, &f, &n); + if (r != 2 || (size_t)n != strlen(val + 2)) + return (0); + } else { + /* probably decimal */ + r = sscanf(val, "%d.%d%n", &i, &f, &n); + if (r != 2 || (size_t)n != strlen(val)) + return (0); + } + buf[0] = i >> 24; + buf[1] = i >> 16; + buf[2] = i >> 8; + buf[3] = i >> 0; + buf[4] = f >> 24; + buf[5] = f >> 16; + buf[6] = f >> 8; + buf[7] = f >> 0; + return (1); +} + +/* + * Parse an IP address. This resolves non-numeric names. + */ +static int +val_parse_ip(const char *val, u_char ip[4]) +{ + int r, n, error; + struct addrinfo hints, *res0; + struct sockaddr_in *sin_local; + + r = sscanf(val, "%hhd.%hhd.%hhd.%hhd%n", + &ip[0], &ip[1], &ip[2], &ip[3], &n); + if (n == 4 && (size_t)n == strlen(val)) + return (0); + + memset(ip, 0, 4); + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + + error = getaddrinfo(val, NULL, &hints, &res0); + if (error) { + syslog(LOG_ERR, "%s: %s", val, gai_strerror(error)); + return (-1); + } + if (res0 == NULL) { + syslog(LOG_ERR, "%s: no address", val); + return (-1); + } + + sin_local = (struct sockaddr_in *)(void *)res0->ai_addr; + ip[3] = sin_local->sin_addr.s_addr >> 24; + ip[2] = sin_local->sin_addr.s_addr >> 16; + ip[1] = sin_local->sin_addr.s_addr >> 8; + ip[0] = sin_local->sin_addr.s_addr >> 0; + + freeaddrinfo(res0); + return (0); +} + +/* + * Fetch system info + */ +static int +fetch_sysinfo(void) +{ + u_char *data; + u_char *ptr; + size_t datalen; + char *name; + char *val; + + if (ntpd_dialog(NTPC_OP_READVAR, 0, + "leap,stratum,precision,rootdelay,rootdispersion,refid,reftime," + "poll,peer,clock,system,processor,jitter,stability", + &data, &datalen)) + return (-1); + + /* clear info */ + sysb_leap = 0; + sysb_stratum = 0; + sysb_precision = 0; + free(sys_rootdelay); + sys_rootdelay = NULL; + free(sys_rootdispersion); + sys_rootdispersion = NULL; + free(sys_refid); + sys_refid = NULL; + sysb_reftime = 0; + sysb_poll = 0; + sysb_peer = 0; + sysb_clock = 0; + free(sys_system); + sys_system = NULL; + free(sys_processor); + sys_processor = NULL; + sysb_jitter = 0; + sysb_stability = 0; + + ptr = data; + while (ntpd_parse(&ptr, &datalen, &name, &val)) { + if (ntp_debug & DBG_DUMP_VARS) + syslog(LOG_DEBUG, "%s: '%s'='%s'", __func__, name, val); + if (strcmp(name, "leap") == 0 || + strcmp(name, "sys.leap") == 0) { + sysb_leap = val_parse_int32(val, &sys_leap, + 0, 3, 2); + + } else if (strcmp(name, "stratum") == 0 || + strcmp(name, "sys.stratum") == 0) { + sysb_stratum = val_parse_int32(val, &sys_stratum, + 0, 255, 0); + + } else if (strcmp(name, "precision") == 0 || + strcmp(name, "sys.precision") == 0) { + sysb_precision = val_parse_int32(val, &sys_precision, + INT32_MIN, INT32_MAX, 0); + + } else if (strcmp(name, "rootdelay") == 0 || + strcmp(name, "sys.rootdelay") == 0) { + sys_rootdelay = strdup(val); + + } else if (strcmp(name, "rootdispersion") == 0 || + strcmp(name, "sys.rootdispersion") == 0) { + sys_rootdispersion = strdup(val); + + } else if (strcmp(name, "refid") == 0 || + strcmp(name, "sys.refid") == 0) { + sys_refid = strdup(val); + + } else if (strcmp(name, "reftime") == 0 || + strcmp(name, "sys.reftime") == 0) { + sysb_reftime = val_parse_ts(val, sys_reftime); + + } else if (strcmp(name, "poll") == 0 || + strcmp(name, "sys.poll") == 0) { + sysb_poll = val_parse_int32(val, &sys_poll, + INT32_MIN, INT32_MAX, 0); + + } else if (strcmp(name, "peer") == 0 || + strcmp(name, "sys.peer") == 0) { + sysb_peer = val_parse_uint32(val, &sys_peer, + 0, UINT32_MAX, 0); + + } else if (strcmp(name, "clock") == 0 || + strcmp(name, "sys.clock") == 0) { + sysb_clock = val_parse_ts(val, sys_clock); + + } else if (strcmp(name, "system") == 0 || + strcmp(name, "sys.system") == 0) { + sys_system = strdup(val); + + } else if (strcmp(name, "processor") == 0 || + strcmp(name, "sys.processor") == 0) { + sys_processor = strdup(val); + + } else if (strcmp(name, "jitter") == 0 || + strcmp(name, "sys.jitter") == 0) { + sysb_jitter = val_parse_double(val, &sys_jitter); + + } else if (strcmp(name, "stability") == 0 || + strcmp(name, "sys.stability") == 0) { + sysb_stability = val_parse_double(val, &sys_stability); + } + } + + free(data); + return (0); +} + +static int +parse_filt(char *val, uint16_t associd, int which) +{ + char *w; + int cnt; + struct filt *f; + + cnt = 0; + for (w = strtok(val, " \t"); w != NULL; w = strtok(NULL, " \t")) { + TAILQ_FOREACH(f, &filts, link) + if (f->index.subs[0] == associd && + f->index.subs[1] == (asn_subid_t)(cnt + 1)) + break; + if (f == NULL) { + f = malloc(sizeof(*f)); + memset(f, 0, sizeof(*f)); + f->index.len = 2; + f->index.subs[0] = associd; + f->index.subs[1] = cnt + 1; + + INSERT_OBJECT_OID(f, &filts); + } + + switch (which) { + + case 0: + f->offset = strdup(w); + break; + + case 1: + f->delay = strdup(w); + break; + + case 2: + f->dispersion = strdup(w); + break; + + default: + abort(); + } + cnt++; + } + return (cnt); +} + +/* + * Fetch the complete peer list + */ +static int +fetch_peers(void) +{ + u_char *data, *pdata, *ptr; + size_t datalen, pdatalen; + int i; + struct peer *p; + struct filt *f; + uint16_t associd; + char *name, *val; + + /* free the old list */ + while ((p = TAILQ_FIRST(&peers)) != NULL) { + TAILQ_REMOVE(&peers, p, link); + free(p->rootdelay); + free(p->rootdispersion); + free(p->refid); + free(p->offset); + free(p->delay); + free(p->dispersion); + free(p); + } + while ((f = TAILQ_FIRST(&filts)) != NULL) { + TAILQ_REMOVE(&filts, f, link); + free(f->offset); + free(f->delay); + free(f->dispersion); + free(f); + } + + /* fetch the list of associations */ + if (ntpd_dialog(NTPC_OP_READSTAT, 0, NULL, &data, &datalen)) + return (-1); + + for (i = 0; i < (int)(datalen / 4); i++) { + associd = data[4 * i + 0] << 8; + associd |= data[4 * i + 1] << 0; + + /* ask for the association variables */ + if (ntpd_dialog(NTPC_OP_READVAR, associd, + "config,srcadr,srcport,dstadr,dstport,leap,hmode,stratum," + "hpoll,ppoll,precision,rootdelay,rootdispersion,refid," + "reftime,org,rec,xmt,reach,timer,offset,delay,dispersion," + "filtdelay,filtoffset,filtdisp", + &pdata, &pdatalen)) { + free(data); + return (-1); + } + + /* now save and parse the data */ + p = malloc(sizeof(*p)); + if (p == NULL) { + free(data); + syslog(LOG_ERR, "%m"); + return (-1); + } + memset(p, 0, sizeof(*p)); + p->index = associd; + INSERT_OBJECT_INT(p, &peers); + + ptr = pdata; + while (ntpd_parse(&ptr, &pdatalen, &name, &val)) { + if (ntp_debug & DBG_DUMP_VARS) + syslog(LOG_DEBUG, "%s: '%s'='%s'", + __func__, name, val); + if (strcmp(name, "config") == 0 || + strcmp(name, "peer.config") == 0) { + val_parse_int32(val, &p->config, 0, 1, 0); + + } else if (strcmp(name, "srcadr") == 0 || + strcmp(name, "peer.srcadr") == 0) { + val_parse_ip(val, p->srcadr); + + } else if (strcmp(name, "srcport") == 0 || + strcmp(name, "peer.srcport") == 0) { + val_parse_uint32(val, &p->srcport, + 1, 65535, 0); + + } else if (strcmp(name, "dstadr") == 0 || + strcmp(name, "peer.dstadr") == 0) { + val_parse_ip(val, p->dstadr); + + } else if (strcmp(name, "dstport") == 0 || + strcmp(name, "peer.dstport") == 0) { + val_parse_uint32(val, &p->dstport, + 1, 65535, 0); + + } else if (strcmp(name, "leap") == 0 || + strcmp(name, "peer.leap") == 0) { + val_parse_int32(val, &p->leap, 0, 3, 2); + + } else if (strcmp(name, "hmode") == 0 || + strcmp(name, "peer.hmode") == 0) { + val_parse_int32(val, &p->hmode, 0, 7, 0); + + } else if (strcmp(name, "stratum") == 0 || + strcmp(name, "peer.stratum") == 0) { + val_parse_int32(val, &p->stratum, 0, 255, 0); + + } else if (strcmp(name, "ppoll") == 0 || + strcmp(name, "peer.ppoll") == 0) { + val_parse_int32(val, &p->ppoll, + INT32_MIN, INT32_MAX, 0); + + } else if (strcmp(name, "hpoll") == 0 || + strcmp(name, "peer.hpoll") == 0) { + val_parse_int32(val, &p->hpoll, + INT32_MIN, INT32_MAX, 0); + + } else if (strcmp(name, "precision") == 0 || + strcmp(name, "peer.precision") == 0) { + val_parse_int32(val, &p->hpoll, + INT32_MIN, INT32_MAX, 0); + + } else if (strcmp(name, "rootdelay") == 0 || + strcmp(name, "peer.rootdelay") == 0) { + p->rootdelay = strdup(val); + + } else if (strcmp(name, "rootdispersion") == 0 || + strcmp(name, "peer.rootdispersion") == 0) { + p->rootdispersion = strdup(val); + + } else if (strcmp(name, "refid") == 0 || + strcmp(name, "peer.refid") == 0) { + p->refid = strdup(val); + + } else if (strcmp(name, "reftime") == 0 || + strcmp(name, "sys.reftime") == 0) { + val_parse_ts(val, p->reftime); + + } else if (strcmp(name, "org") == 0 || + strcmp(name, "sys.org") == 0) { + val_parse_ts(val, p->orgtime); + + } else if (strcmp(name, "rec") == 0 || + strcmp(name, "sys.rec") == 0) { + val_parse_ts(val, p->rcvtime); + + } else if (strcmp(name, "xmt") == 0 || + strcmp(name, "sys.xmt") == 0) { + val_parse_ts(val, p->xmttime); + + } else if (strcmp(name, "reach") == 0 || + strcmp(name, "peer.reach") == 0) { + val_parse_uint32(val, &p->reach, + 0, 65535, 0); + + } else if (strcmp(name, "timer") == 0 || + strcmp(name, "peer.timer") == 0) { + val_parse_int32(val, &p->timer, + INT32_MIN, INT32_MAX, 0); + + } else if (strcmp(name, "offset") == 0 || + strcmp(name, "peer.offset") == 0) { + p->offset = strdup(val); + + } else if (strcmp(name, "delay") == 0 || + strcmp(name, "peer.delay") == 0) { + p->delay = strdup(val); + + } else if (strcmp(name, "dispersion") == 0 || + strcmp(name, "peer.dispersion") == 0) { + p->dispersion = strdup(val); + + } else if (strcmp(name, "filtdelay") == 0 || + strcmp(name, "peer.filtdelay") == 0) { + p->filt_entries = parse_filt(val, associd, 0); + + } else if (strcmp(name, "filtoffset") == 0 || + strcmp(name, "peer.filtoffset") == 0) { + p->filt_entries = parse_filt(val, associd, 1); + + } else if (strcmp(name, "filtdisp") == 0 || + strcmp(name, "peer.filtdisp") == 0) { + p->filt_entries = parse_filt(val, associd, 2); + } + } + free(pdata); + } + + free(data); + return (0); +} + +/* + * System variables - read-only scalars only. + */ +int +op_ntpSystem(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + asn_subid_t which = value->var.subs[sub - 1]; + + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + if (this_tick > sysinfo_tick) { + if (fetch_sysinfo() == -1) + return (SNMP_ERR_GENERR); + sysinfo_tick = this_tick; + } + + switch (which) { + + case LEAF_ntpSysLeap: + if (!sysb_leap) + return (SNMP_ERR_NOSUCHNAME); + value->v.integer = sys_leap; + break; + + case LEAF_ntpSysStratum: + if (!sysb_stratum) + return (SNMP_ERR_NOSUCHNAME); + value->v.integer = sys_stratum; + break; + + case LEAF_ntpSysPrecision: + if (!sysb_precision) + return (SNMP_ERR_NOSUCHNAME); + value->v.integer = sys_precision; + break; + + case LEAF_ntpSysRootDelay: + if (sys_rootdelay == NULL) + return (SNMP_ERR_NOSUCHNAME); + return (string_get(value, sys_rootdelay, -1)); + + case LEAF_ntpSysRootDispersion: + if (sys_rootdispersion == NULL) + return (SNMP_ERR_NOSUCHNAME); + return (string_get(value, sys_rootdispersion, -1)); + + case LEAF_ntpSysRefId: + if (sys_refid == NULL) + return (SNMP_ERR_NOSUCHNAME); + return (string_get(value, sys_refid, -1)); + + case LEAF_ntpSysRefTime: + if (sysb_reftime == 0) + return (SNMP_ERR_NOSUCHNAME); + return (string_get(value, sys_reftime, 8)); + + case LEAF_ntpSysPoll: + if (sysb_poll == 0) + return (SNMP_ERR_NOSUCHNAME); + value->v.integer = sys_poll; + break; + + case LEAF_ntpSysPeer: + if (sysb_peer == 0) + return (SNMP_ERR_NOSUCHNAME); + value->v.uint32 = sys_peer; + break; + + case LEAF_ntpSysClock: + if (sysb_clock == 0) + return (SNMP_ERR_NOSUCHNAME); + return (string_get(value, sys_clock, 8)); + + case LEAF_ntpSysSystem: + if (sys_system == NULL) + return (SNMP_ERR_NOSUCHNAME); + return (string_get(value, sys_system, -1)); + + case LEAF_ntpSysProcessor: + if (sys_processor == NULL) + return (SNMP_ERR_NOSUCHNAME); + return (string_get(value, sys_processor, -1)); + + default: + abort(); + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_SET: + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_COMMIT: + case SNMP_OP_ROLLBACK: + abort(); + } + abort(); +} + +int +op_ntpPeersVarTable(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx, enum snmp_op op) +{ + asn_subid_t which = value->var.subs[sub - 1]; + uint32_t peer; + struct peer *t; + + if (this_tick > peers_tick) { + if (fetch_peers() == -1) + return (SNMP_ERR_GENERR); + peers_tick = this_tick; + } + + switch (op) { + + case SNMP_OP_GETNEXT: + t = NEXT_OBJECT_INT(&peers, &value->var, sub); + if (t == NULL) + return (SNMP_ERR_NOSUCHNAME); + value->var.len = sub + 1; + value->var.subs[sub] = t->index; + break; + + case SNMP_OP_GET: + t = FIND_OBJECT_INT(&peers, &value->var, sub); + if (t == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + if (index_decode(&value->var, sub, iidx, &peer)) + return (SNMP_ERR_NO_CREATION); + t = FIND_OBJECT_INT(&peers, &value->var, sub); + if (t != NULL) + return (SNMP_ERR_NOT_WRITEABLE); + return (SNMP_ERR_NO_CREATION); + + case SNMP_OP_COMMIT: + case SNMP_OP_ROLLBACK: + default: + abort(); + } + + /* + * Come here for GET and COMMIT + */ + switch (which) { + + case LEAF_ntpPeersConfigured: + value->v.integer = t->config; + break; + + case LEAF_ntpPeersPeerAddress: + return (ip_get(value, t->srcadr)); + + case LEAF_ntpPeersPeerPort: + value->v.uint32 = t->srcport; + break; + + case LEAF_ntpPeersHostAddress: + return (ip_get(value, t->dstadr)); + + case LEAF_ntpPeersHostPort: + value->v.uint32 = t->dstport; + break; + + case LEAF_ntpPeersLeap: + value->v.integer = t->leap; + break; + + case LEAF_ntpPeersMode: + value->v.integer = t->hmode; + break; + + case LEAF_ntpPeersStratum: + value->v.integer = t->stratum; + break; + + case LEAF_ntpPeersPeerPoll: + value->v.integer = t->ppoll; + break; + + case LEAF_ntpPeersHostPoll: + value->v.integer = t->hpoll; + break; + + case LEAF_ntpPeersPrecision: + value->v.integer = t->precision; + break; + + case LEAF_ntpPeersRootDelay: + return (string_get(value, t->rootdelay, -1)); + + case LEAF_ntpPeersRootDispersion: + return (string_get(value, t->rootdispersion, -1)); + + case LEAF_ntpPeersRefId: + return (string_get(value, t->refid, -1)); + + case LEAF_ntpPeersRefTime: + return (string_get(value, t->reftime, 8)); + + case LEAF_ntpPeersOrgTime: + return (string_get(value, t->orgtime, 8)); + + case LEAF_ntpPeersReceiveTime: + return (string_get(value, t->rcvtime, 8)); + + case LEAF_ntpPeersTransmitTime: + return (string_get(value, t->xmttime, 8)); + + case LEAF_ntpPeersReach: + value->v.uint32 = t->reach; + break; + + case LEAF_ntpPeersTimer: + value->v.uint32 = t->timer; + break; + + case LEAF_ntpPeersOffset: + return (string_get(value, t->offset, -1)); + + case LEAF_ntpPeersDelay: + return (string_get(value, t->delay, -1)); + + case LEAF_ntpPeersDispersion: + return (string_get(value, t->dispersion, -1)); + + default: + abort(); + } + return (SNMP_ERR_NOERROR); +} + + +int +op_ntpFilterPeersVarTable(struct snmp_context *ctx __unused, + struct snmp_value *value, u_int sub, u_int iidx, enum snmp_op op) +{ + asn_subid_t which = value->var.subs[sub - 1]; + uint32_t peer; + struct peer *t; + + if (this_tick > peers_tick) { + if (fetch_peers() == -1) + return (SNMP_ERR_GENERR); + peers_tick = this_tick; + } + + switch (op) { + + case SNMP_OP_GETNEXT: + t = NEXT_OBJECT_INT(&peers, &value->var, sub); + if (t == NULL) + return (SNMP_ERR_NOSUCHNAME); + value->var.len = sub + 1; + value->var.subs[sub] = t->index; + break; + + case SNMP_OP_GET: + t = FIND_OBJECT_INT(&peers, &value->var, sub); + if (t == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + if (index_decode(&value->var, sub, iidx, &peer)) + return (SNMP_ERR_NO_CREATION); + t = FIND_OBJECT_INT(&peers, &value->var, sub); + if (t != NULL) + return (SNMP_ERR_NOT_WRITEABLE); + return (SNMP_ERR_NO_CREATION); + + case SNMP_OP_COMMIT: + case SNMP_OP_ROLLBACK: + default: + abort(); + } + + /* + * Come here for GET and COMMIT + */ + switch (which) { + + case LEAF_ntpFilterValidEntries: + value->v.integer = t->filt_entries; + break; + + default: + abort(); + } + return (SNMP_ERR_NOERROR); +} + +int +op_ntpFilterRegisterTable(struct snmp_context *ctx __unused, struct snmp_value *value __unused, + u_int sub __unused, u_int iidx __unused, enum snmp_op op __unused) +{ + asn_subid_t which = value->var.subs[sub - 1]; + uint32_t peer; + uint32_t filt; + struct filt *t; + + if (this_tick > peers_tick) { + if (fetch_peers() == -1) + return (SNMP_ERR_GENERR); + peers_tick = this_tick; + } + + switch (op) { + + case SNMP_OP_GETNEXT: + t = NEXT_OBJECT_OID(&filts, &value->var, sub); + if (t == NULL) + return (SNMP_ERR_NOSUCHNAME); + index_append(&value->var, sub, &t->index); + break; + + case SNMP_OP_GET: + t = FIND_OBJECT_OID(&filts, &value->var, sub); + if (t == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + if (index_decode(&value->var, sub, iidx, &peer, &filt)) + return (SNMP_ERR_NO_CREATION); + t = FIND_OBJECT_OID(&filts, &value->var, sub); + if (t != NULL) + return (SNMP_ERR_NOT_WRITEABLE); + return (SNMP_ERR_NO_CREATION); + + case SNMP_OP_COMMIT: + case SNMP_OP_ROLLBACK: + default: + abort(); + } + + /* + * Come here for GET and COMMIT + */ + switch (which) { + + case LEAF_ntpFilterPeersOffset: + return (string_get(value, t->offset, -1)); + + case LEAF_ntpFilterPeersDelay: + return (string_get(value, t->delay, -1)); + + case LEAF_ntpFilterPeersDispersion: + return (string_get(value, t->dispersion, -1)); + + default: + abort(); + } + return (SNMP_ERR_NOERROR); +} + +/* + * System variables - read-only scalars only. + */ +int +op_begemot_ntp(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + asn_subid_t which = value->var.subs[sub - 1]; + int ret; + + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + switch (which) { + + case LEAF_begemotNtpHost: + return (string_get(value, ntp_host, -1)); + + case LEAF_begemotNtpPort: + return (string_get(value, ntp_port, -1)); + + case LEAF_begemotNtpTimeout: + value->v.uint32 = ntp_timeout; + return (SNMP_ERR_NOERROR); + + case LEAF_begemotNtpDebug: + value->v.uint32 = ntp_debug; + return (SNMP_ERR_NOERROR); + + case LEAF_begemotNtpJitter: + if (this_tick > sysinfo_tick) { + if (fetch_sysinfo() == -1) + return (SNMP_ERR_GENERR); + sysinfo_tick = this_tick; + } + if (!sysb_jitter) + return (SNMP_ERR_NOSUCHNAME); + value->v.counter64 = sys_jitter / 1000 * (1ULL << 32); + return (SNMP_ERR_NOERROR); + + case LEAF_begemotNtpStability: + if (this_tick > sysinfo_tick) { + if (fetch_sysinfo() == -1) + return (SNMP_ERR_GENERR); + sysinfo_tick = this_tick; + } + if (!sysb_stability) + return (SNMP_ERR_NOSUCHNAME); + value->v.counter64 = sys_stability * (1ULL << 32); + return (SNMP_ERR_NOERROR); + } + abort(); + + case SNMP_OP_SET: + switch (which) { + + case LEAF_begemotNtpHost: + /* only at initialization */ + if (community != COMM_INITIALIZE) + return (SNMP_ERR_NOT_WRITEABLE); + + if ((ret = string_save(value, ctx, -1, &ntp_host)) + != SNMP_ERR_NOERROR) + return (ret); + return (SNMP_ERR_NOERROR); + + case LEAF_begemotNtpPort: + /* only at initialization */ + if (community != COMM_INITIALIZE) + return (SNMP_ERR_NOT_WRITEABLE); + + if ((ret = string_save(value, ctx, -1, &ntp_port)) + != SNMP_ERR_NOERROR) + return (ret); + return (SNMP_ERR_NOERROR); + + case LEAF_begemotNtpTimeout: + ctx->scratch->int1 = ntp_timeout; + if (value->v.uint32 < 1) + return (SNMP_ERR_WRONG_VALUE); + ntp_timeout = value->v.integer; + return (SNMP_ERR_NOERROR); + + case LEAF_begemotNtpDebug: + ctx->scratch->int1 = ntp_debug; + ntp_debug = value->v.integer; + return (SNMP_ERR_NOERROR); + } + abort(); + + case SNMP_OP_ROLLBACK: + switch (which) { + + case LEAF_begemotNtpHost: + string_rollback(ctx, &ntp_host); + return (SNMP_ERR_NOERROR); + + case LEAF_begemotNtpPort: + string_rollback(ctx, &ntp_port); + return (SNMP_ERR_NOERROR); + + case LEAF_begemotNtpTimeout: + ntp_timeout = ctx->scratch->int1; + return (SNMP_ERR_NOERROR); + + case LEAF_begemotNtpDebug: + ntp_debug = ctx->scratch->int1; + return (SNMP_ERR_NOERROR); + } + abort(); + + case SNMP_OP_COMMIT: + switch (which) { + + case LEAF_begemotNtpHost: + string_commit(ctx); + return (SNMP_ERR_NOERROR); + + case LEAF_begemotNtpPort: + string_commit(ctx); + return (SNMP_ERR_NOERROR); + + case LEAF_begemotNtpTimeout: + case LEAF_begemotNtpDebug: + return (SNMP_ERR_NOERROR); + } + abort(); + } + abort(); +} Property changes on: vendor/1.14/snmp_ntp/snmp_ntp.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_ntp/BEGEMOT-NTP-MIB.txt =================================================================== --- vendor/1.14/snmp_ntp/BEGEMOT-NTP-MIB.txt (nonexistent) +++ vendor/1.14/snmp_ntp/BEGEMOT-NTP-MIB.txt (revision 359491) @@ -0,0 +1,144 @@ +-- +-- Copyright (c) 2005 +-- Hartmut Brandt +-- All rights reserved. +-- +-- Author: Harti Brandt +-- +-- Redistribution and use in source and binary forms, with or without +-- modification, are permitted provided that the following conditions +-- are met: +-- 1. Redistributions of source code must retain the above copyright +-- notice, this list of conditions and the following disclaimer. +-- 2. Redistributions in binary form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +-- ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +-- SUCH DAMAGE. +-- +-- $Begemot: bsnmp/snmp_ntp/BEGEMOT-NTP-MIB.txt,v 1.3 2005/10/04 08:13:41 brandt_h Exp $ +-- +-- Private MIB for NTP module. +-- +BEGEMOT-NTP-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, TimeTicks, Unsigned32, Counter64 + FROM SNMPv2-SMI + TruthValue + FROM SNMPv2-TC + begemot + FROM BEGEMOT-MIB; + +begemotNtp MODULE-IDENTITY + LAST-UPDATED "200509300000Z" + ORGANIZATION "German Aerospace Center" + CONTACT-INFO + " Hartmut Brandt + + Postal: German Aerospace Center + Oberpfaffenhofen + 82234 Wessling + Germany + + Fax: +49 8153 28 2843 + + E-mail: harti@freebsd.org" + DESCRIPTION + "The MIB for the NTP control module for SNMP." + ::= { begemot 201 } + +begemotNtpObjects OBJECT IDENTIFIER ::= { begemotNtp 1 } + +begemotNtpHost OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of the host where the NTP daemon is running that + is to be connected." + ::= { begemotNtpObjects 1 } + +begemotNtpPort OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The port of the host where the NTP daemon is running that + is to be connected." + ::= { begemotNtpObjects 2 } + +begemotNtpTimeout OBJECT-TYPE + SYNTAX TimeTicks + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The number of ticks to wait for the response from the NTP + daemon to complete." + ::= { begemotNtpObjects 3 } + +begemotNtpDebug OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Debug flags. The following flags are currently used: + + 0x01 - produce a dump of all received/sent NTP packets. + 0x02 - print the variable names and values return by the daemon + + Other bits are ignored." + ::= { begemotNtpObjects 4 } + +begemotNtpJitter OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current jitter in seconds multiplied by 2^32." + ::= { begemotNtpObjects 5 } + +begemotNtpStability OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Current stability in ppm multiplied by 2^32." + ::= { begemotNtpObjects 6 } + +begemotNtpJitterThresh OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Jitter trap threshold in seconds multiplied by 2^32." + ::= { begemotNtpObjects 7 } + +begemotNtpStabilityThresh OBJECT-TYPE + SYNTAX Counter64 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Stability trap threshold in ppm multiplied by 2^32." + ::= { begemotNtpObjects 8 } + +begemotNtpTrapEnable OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Enables the sending of traps when either the peer is lost/ + found or one of the above thresholds is crossed." + ::= { begemotNtpObjects 9 } + +END Property changes on: vendor/1.14/snmp_ntp/BEGEMOT-NTP-MIB.txt ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_ntp/NTP-MIB.txt =================================================================== --- vendor/1.14/snmp_ntp/NTP-MIB.txt (nonexistent) +++ vendor/1.14/snmp_ntp/NTP-MIB.txt (revision 359491) @@ -0,0 +1,627 @@ +-- +-- NTP MIB, Revision 0.2, 7/25/97 +-- + +NTP-MIB DEFINITIONS ::= BEGIN + +IMPORTS + Integer32, IpAddress, MODULE-IDENTITY, OBJECT-TYPE, Unsigned32, + enterprises + FROM SNMPv2-SMI + + TEXTUAL-CONVENTION, TruthValue + FROM SNMPv2-TC; + +ntpMIB MODULE-IDENTITY + LAST-UPDATED "199707251530Z" + ORGANIZATION + "University of Delaware" + CONTACT-INFO + "Adarsh Sethi + Department of Computer & Information Sciences + University of Delaware + Newark, DE 19716 + Tel: +1 302 831 1945 + E-mail: sethi@cis.udel.edu + + David Mills + Department of Electrical Engineering + University of Delaware + Newark, DE 19716 + Tel: +1 302 831 ???? + E-mail: mills@ee.udel.edu" + DESCRIPTION + "This MIB module defines a MIB which provides mechanisms to + monitor and control an NTP server." + ::= { udel 3 } + +-- +-- Position within the OID hierarchy of this MIB: +-- +udel OBJECT IDENTIFIER + ::= { enterprises 1277 } + +-- +-- The various groups defined within this MIB definition: +-- +ntpSystem OBJECT IDENTIFIER + ::= { ntpMIB 1 } + +ntpPeers OBJECT IDENTIFIER + ::= { ntpMIB 2 } + +ntpFilter OBJECT IDENTIFIER + ::= { ntpMIB 3 } + +-- +-- Textual conventions: +-- + +NTPTimeStamp ::= TEXTUAL-CONVENTION + DISPLAY-HINT "4x.4x" + STATUS current + DESCRIPTION + "" + SYNTAX OCTET STRING (SIZE(8)) + +NTPLeapIndicator ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "" + SYNTAX INTEGER { + noWarning(0), + addSecond(1), + subtractSecond(2), + alarm(3) } + +-- +-- System Group +-- + +ntpSysLeap OBJECT-TYPE + SYNTAX NTPLeapIndicator + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " two-bit code warning of an impending leap + second to be inserted in the NTP timescale." + ::= { ntpSystem 1 } + +ntpSysStratum OBJECT-TYPE + SYNTAX Integer32 (0..255) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " indicating the stratum of the local clock. + 0, unspecified + 1, primary reference (e.g.,, calibrated atomic clock, + radio clock) + 2-255, secondary reference (via NTP)" + ::= { ntpSystem 2 } + +ntpSysPrecision OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "signed integer indicating the precision + of the various clocks, in seconds to the nearest power + of two." + ::= { ntpSystem 3 } + +ntpSysRootDelay OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "the total roundtrip delay to the primary + reference source at the root of the synchronization + subnet, in seconds" + ::= { ntpSystem 4 } + +ntpSysRootDispersion OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "the maximum error relative to the primary + reference source at the root of the synchronization + subnet, in seconds. Only positive values greater + than zero are possible" + ::= { ntpSystem 5 } + +ntpSysRefId OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " the particular reference clock. In the case of + stratum 0 (unspecified) or stratum 1 (primary reference + source), this is a four-octet, left-justified,zero-padded + ASCII string.In the case of stratum 2 and greater (secondary + reference) this is the four-octet Internet address of the + peer selected for synchronization." + ::= { ntpSystem 6 } + +ntpSysRefTime OBJECT-TYPE + SYNTAX NTPTimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " the local time when the local clock was last + updated. If the local clock has neverbeen synchronized, + the value is zero." + ::= { ntpSystem 7 } + +ntpSysPoll OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " the minimum interval between transmitted + messages, in seconds as a power of two. For instance, + a value of six indicates a minimum interval of 64 seconds." + ::= { ntpSystem 8 } + +ntpSysPeer OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " the current synchronization source. Usually + this will be a pointer to a structure containing the peer + variables. The special value NULL indicates there is no + currently valid synchronization source." + ::= { ntpSystem 9 } + +ntpSysPhase OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpSystem 10 } + +ntpSysFreq OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpSystem 11 } + +ntpSysError OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpSystem 12 } + +ntpSysClock OBJECT-TYPE + SYNTAX NTPTimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "the current local time. Local time is derived + from the hardware clock of the particular machine and + increments at intervals depending on the design used." + ::= { ntpSystem 13 } + +ntpSysSystem OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " the type of the local Operating System" + ::= { ntpSystem 14 } + +ntpSysProcessor OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " the type of the local Processor" + ::= { ntpSystem 15 } + +-- +-- Peers Group +-- + +-- +-- Peer Variables Table +-- + +ntpPeersVarTable OBJECT-TYPE + SYNTAX SEQUENCE OF NtpPeersVarEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "" + ::= { ntpPeers 1 } + +ntpPeersVarEntry OBJECT-TYPE + SYNTAX NtpPeersVarEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "" + INDEX { ntpPeersAssocId } + ::= { ntpPeersVarTable 1 } + +NtpPeersVarEntry ::= SEQUENCE { + ntpPeersAssocId Unsigned32, + ntpPeersConfigured TruthValue, + ntpPeersPeerAddress IpAddress, + ntpPeersPeerPort Unsigned32, + ntpPeersHostAddress IpAddress, + ntpPeersHostPort Unsigned32, + ntpPeersLeap NTPLeapIndicator, + ntpPeersMode INTEGER, + ntpPeersStratum Integer32, + ntpPeersPeerPoll Integer32, + ntpPeersHostPoll Integer32, + ntpPeersPrecision Integer32, + ntpPeersRootDelay OCTET STRING, + ntpPeersRootDispersion OCTET STRING, + ntpPeersRefId OCTET STRING, + ntpPeersRefTime NTPTimeStamp, + ntpPeersOrgTime NTPTimeStamp, + ntpPeersReceiveTime NTPTimeStamp, + ntpPeersTransmitTime NTPTimeStamp, + ntpPeersUpdateTime NTPTimeStamp, + ntpPeersReach Unsigned32, + ntpPeersTimer Integer32, + ntpPeersOffset OCTET STRING, + ntpPeersDelay OCTET STRING, + ntpPeersDispersion OCTET STRING +} + +ntpPeersAssocId OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "" + ::= { ntpPeersVarEntry 1 } + +ntpPeersConfigured OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " This is a bit indicating that the association + was created from configuration information and should not + be demobilized if the peer becomes unreachable." + ::= { ntpPeersVarEntry 2 } + +ntpPeersPeerAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " the Internet address of the peer" + ::= { ntpPeersVarEntry 3 } + +ntpPeersPeerPort OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " 16-bit port number of the peer." + ::= { ntpPeersVarEntry 4 } + +ntpPeersHostAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " the Internet address of the host" + ::= { ntpPeersVarEntry 5 } + +ntpPeersHostPort OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " 16-bit port number of the host" + ::= { ntpPeersVarEntry 6 } + +ntpPeersLeap OBJECT-TYPE + SYNTAX NTPLeapIndicator + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " two-bit code warning of an impending leap + second to be inserted in the NTP timescale." + ::= { ntpPeersVarEntry 7 } + +ntpPeersMode OBJECT-TYPE + SYNTAX INTEGER { + unspecified(0), + symmetricActive(1), + symmetricPassive(2), + client(3), + server(4), + broadcast(5), + reservedControl(6), + reservedPrivate(7) + } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " the association mode,with values coded as + follows: + 0, unspecified + 1, symmetric active + 2, symmetric passive + 3, client + 4, server + 5, broadcast + 6, reserved for NTP control messages + 7, reserved for private use + " + ::= { ntpPeersVarEntry 8 } + +ntpPeersStratum OBJECT-TYPE + SYNTAX Integer32 (0..255) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " indicating the stratum of the peer clock. + 0, unspecified + 1, primary reference (e.g.,, calibrated atomic clock, + radio clock) + 2-255, secondary reference (via NTP)" + ::= { ntpPeersVarEntry 9 } + +ntpPeersPeerPoll OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "poll interval of the peer" + ::= { ntpPeersVarEntry 10 } + +ntpPeersHostPoll OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "poll interval of the host" + ::= { ntpPeersVarEntry 11 } + +ntpPeersPrecision OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "the same as the systemPrecision except this is + for the peer" + ::= { ntpPeersVarEntry 12 } + +ntpPeersRootDelay OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "the same as the systemRootDealy except this is for + the peer" + ::= { ntpPeersVarEntry 13 } + +ntpPeersRootDispersion OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "the same as the systemDispersion except this is for + the peer" + ::= { ntpPeersVarEntry 14 } + +ntpPeersRefId OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "the same as the systemRefid except this is for + the peer" + ::= { ntpPeersVarEntry 15 } + +ntpPeersRefTime OBJECT-TYPE + SYNTAX NTPTimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "the same as the systemRefTime except this is for + the peer" + ::= { ntpPeersVarEntry 16 } + +ntpPeersOrgTime OBJECT-TYPE + SYNTAX NTPTimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " the local time at the peer when its latest + NTP message was sent. If the peer becomes unreachable the + value is set to zero." + ::= { ntpPeersVarEntry 17 } + +ntpPeersReceiveTime OBJECT-TYPE + SYNTAX NTPTimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "the local time when the latest NTP message + from the peer arrived. If the peer becomes unreachable the + value is set to zero." + ::= { ntpPeersVarEntry 18 } + +ntpPeersTransmitTime OBJECT-TYPE + SYNTAX NTPTimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "the local time at which the NTP message + departed the sender." + ::= { ntpPeersVarEntry 19 } + +ntpPeersUpdateTime OBJECT-TYPE + SYNTAX NTPTimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + " " + ::= { ntpPeersVarEntry 20 } + +ntpPeersReach OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "a shift register of NTP.WINDOW bits used to determine + the reachability status of the peer, with bits entering + from the least significant (rightmost) end. A peer is + considered reachable if at least one bit in this register is + set to one." + ::= { ntpPeersVarEntry 21 } + +ntpPeersTimer OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpPeersVarEntry 22 } + +ntpPeersOffset OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpPeersVarEntry 23 } + +ntpPeersDelay OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpPeersVarEntry 24 } + +ntpPeersDispersion OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpPeersVarEntry 25 } + +-- +-- Filter Group +-- +-- Implementation of this group is optional. It must be implemented +-- when the filter and selection algorithms described in Section 4 +-- of RFC 1305 are used. +-- + +-- +-- Filter Group Peer Variables Table +-- +ntpFilterPeersVarTable OBJECT-TYPE + SYNTAX SEQUENCE OF NtpFilterPeersVarEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "This table is an extension of the Peer Variables Table + in the Peer Group." + ::= { ntpFilter 1 } + +ntpFilterPeersVarEntry OBJECT-TYPE + SYNTAX NtpFilterPeersVarEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "" + AUGMENTS { ntpPeersVarEntry } + ::= { ntpFilterPeersVarTable 1 } + +NtpFilterPeersVarEntry ::= SEQUENCE { + ntpFilterValidEntries Integer32 +} + +ntpFilterValidEntries OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of valid entries for a peer in the Filter Register Table." + ::= { ntpFilterPeersVarEntry 1 } + +-- +-- Filter Register Table +-- + +ntpFilterRegisterTable OBJECT-TYPE + SYNTAX SEQUENCE OF NtpFilterRegisterEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "" + ::= { ntpFilter 2 } + +ntpFilterRegisterEntry OBJECT-TYPE + SYNTAX NtpFilterRegisterEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "" + INDEX { ntpPeersAssocId, ntpFilterIndex } + ::= { ntpFilterRegisterTable 1 } + +NtpFilterRegisterEntry ::= SEQUENCE { + ntpFilterIndex Unsigned32, + ntpFilterPeersOffset OCTET STRING, + ntpFilterPeersDelay OCTET STRING, + ntpFilterPeersDispersion OCTET STRING +} + +ntpFilterIndex OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "" + ::= { ntpFilterRegisterEntry 1 } + +ntpFilterPeersOffset OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "the offset of the peer clock relative to the + local clock in seconds" + ::= { ntpFilterRegisterEntry 2 } + +ntpFilterPeersDelay OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "roundtrip delay of the peer clock relative to the + local clock over the network path between them, in seconds. + this variable can take on both positive and negative values, + depending on clock precision and skew-error accumulation." + ::= { ntpFilterRegisterEntry 3 } + +ntpFilterPeersDispersion OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "the maximum error of the peer clock relative to the + local clock over the network path between them, in seconds. + Only positive values greater than zero are possible." + ::= { ntpFilterRegisterEntry 4 } + +END Property changes on: vendor/1.14/snmp_ntp/NTP-MIB.txt ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_ntp/NTP-PROXY-MIB.txt =================================================================== --- vendor/1.14/snmp_ntp/NTP-PROXY-MIB.txt (nonexistent) +++ vendor/1.14/snmp_ntp/NTP-PROXY-MIB.txt (revision 359491) @@ -0,0 +1,616 @@ +-- +-- NTP Proxy MIB, Revision 0.2, 7/25/97 +-- + +NTP-PROXY-MIB DEFINITIONS ::= BEGIN + +IMPORTS + NTPLeapIndicator, NTPTimeStamp + FROM NTP-MIB + + Integer32, IpAddress, MODULE-IDENTITY, OBJECT-TYPE, Unsigned32, + enterprises + FROM SNMPv2-SMI + + TEXTUAL-CONVENTION, TruthValue + FROM SNMPv2-TC; + +ntpProxyMIB MODULE-IDENTITY + LAST-UPDATED "199707251540Z" + ORGANIZATION + "University of Delaware" + CONTACT-INFO + "Adarsh Sethi + Department of Computer & Information Sciences + University of Delaware + Newark, DE 19716 + Tel: +1 302 831 1945 + E-mail: sethi@cis.udel.edu + + David Mills + Department of Electrical Engineering + University of Delaware + Newark, DE 19716 + Tel: +1 302 831 ???? + E-mail: mills@ee.udel.edu" + DESCRIPTION + "This MIB module defines a MIB which provides mechanisms to + monitor and control many NTP servers via a Proxy Agent." + ::= { enterprises 1277 4 } + +-- +-- The position within the OID hierarchy of this MIB: +-- + +udel OBJECT IDENTIFIER + ::= { enterprises 1277 } + +-- +-- The various groups defined within this MIB definition: +-- + +ntpProxyControl OBJECT IDENTIFIER + ::= { ntpProxyMIB 1 } + +-- +-- Textual conventions: +-- + +NTPRowStatus ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "The NTPRowStatus textual convention is modeled after the + RowStatus textual convention of RFC 1903, but is simpler + because it only allows one create operation (the create- + and-go of RowStatus) and does not allow row deletion. If + the state of the status column is `notInService' and the + management station tries to set it to `create', the + corresponding row is created and the operation is successful. + If the set to `create' is attempted when the status column + is in state `active', the operation fails and inconsistentValue + is returned. A management station is not permitted to delete + the conceptual row; deletion is carried out by the agent + in an autonomous manner." + SYNTAX INTEGER { + -- the following values are states: + -- these values may be read, but not written + active(1), + notInService(2), + -- the following value is an action: + -- this value may be written, but is never read + create(3) + } + +-- +-- Control group +-- + +-- +-- ProxyControl Table +-- + +ntpProxyControlTable OBJECT-TYPE + SYNTAX SEQUENCE OF NtpProxyControlEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "" + ::= { ntpProxyControl 1 } + +ntpProxyControlEntry OBJECT-TYPE + SYNTAX NtpProxyControlEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "" + INDEX { ntpProxyServerIPAddr } + ::= { ntpProxyControlTable 1 } + +NtpProxyControlEntry ::= SEQUENCE { + ntpProxyServerIPAddr IpAddress, + ntpProxyControlStatus NTPRowStatus +} + +ntpProxyServerIPAddr OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "" + ::= { ntpProxyControlEntry 1 } + +ntpProxyControlStatus OBJECT-TYPE + SYNTAX NTPRowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "" + ::= { ntpProxyControlEntry 2 } + +-- +-- Proxy Server System Table +-- + +ntpProxyServerSystemTable OBJECT-TYPE + SYNTAX SEQUENCE OF NtpProxyServerSystemEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "" + ::= { ntpProxyControl 2 } + +ntpProxyServerSystemEntry OBJECT-TYPE + SYNTAX NtpProxyServerSystemEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "" + INDEX { ntpProxyServerIPAddr } + ::= { ntpProxyServerSystemTable 1 } + +NtpProxyServerSystemEntry ::= SEQUENCE { + ntpProxyServerSysLeap NTPLeapIndicator, + ntpProxyServerSysStratum Integer32, + ntpProxyServerSysPrecision Integer32, + ntpProxyServerSysRootDelay OCTET STRING, + ntpProxyServerSysRootDispersion OCTET STRING, + ntpProxyServerSysRefId OCTET STRING, + ntpProxyServerSysRefTime NTPTimeStamp, + ntpProxyServerSysPoll Integer32, + ntpProxyServerSysPeer Unsigned32, + ntpProxyServerSysPhase OCTET STRING, + ntpProxyServerSysFreq OCTET STRING, + ntpProxyServerSysError OCTET STRING, + ntpProxyServerSysClock NTPTimeStamp, + ntpProxyServerSysSystem OCTET STRING, + ntpProxyServerSysProcessor OCTET STRING +} + +ntpProxyServerSysLeap OBJECT-TYPE + SYNTAX NTPLeapIndicator + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyServerSystemEntry 1 } + +ntpProxyServerSysStratum OBJECT-TYPE + SYNTAX Integer32 (0..255) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyServerSystemEntry 2 } + +ntpProxyServerSysPrecision OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyServerSystemEntry 3 } + +ntpProxyServerSysRootDelay OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyServerSystemEntry 4 } + +ntpProxyServerSysRootDispersion OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyServerSystemEntry 5 } + +ntpProxyServerSysRefId OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyServerSystemEntry 6 } + +ntpProxyServerSysRefTime OBJECT-TYPE + SYNTAX NTPTimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyServerSystemEntry 7 } + +ntpProxyServerSysPoll OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyServerSystemEntry 8 } + +ntpProxyServerSysPeer OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyServerSystemEntry 9 } + +ntpProxyServerSysPhase OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyServerSystemEntry 10 } + +ntpProxyServerSysFreq OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyServerSystemEntry 11 } + +ntpProxyServerSysError OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyServerSystemEntry 12 } + +ntpProxyServerSysClock OBJECT-TYPE + SYNTAX NTPTimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyServerSystemEntry 13 } + +ntpProxyServerSysSystem OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyServerSystemEntry 14 } + +ntpProxyServerSysProcessor OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyServerSystemEntry 15 } + +-- +-- Proxy Peer Variables Table +-- +ntpProxyPeersVarTable OBJECT-TYPE + SYNTAX SEQUENCE OF NtpProxyPeersVarEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "" + ::= { ntpProxyControl 3 } + +ntpProxyPeersVarEntry OBJECT-TYPE + SYNTAX NtpProxyPeersVarEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "" + INDEX { ntpProxyServerIPAddr, ntpProxyPeersAssocId } + ::= { ntpProxyPeersVarTable 1 } + +NtpProxyPeersVarEntry ::= SEQUENCE { + ntpProxyPeersAssocId Unsigned32, + ntpProxyPeersConfigured TruthValue, + ntpProxyPeersPeerAddress IpAddress, + ntpProxyPeersPeerPort Unsigned32, + ntpProxyPeersHostAddress IpAddress, + ntpProxyPeersHostPort Unsigned32, + ntpProxyPeersLeap NTPLeapIndicator, + ntpProxyPeersMode INTEGER, + ntpProxyPeersStratum Integer32, + ntpProxyPeersPeerPoll Integer32, + ntpProxyPeersHostPoll Integer32, + ntpProxyPeersPrecision Integer32, + ntpProxyPeersRootDelay OCTET STRING, + ntpProxyPeersRootDispersion OCTET STRING, + ntpProxyPeersRefId OCTET STRING, + ntpProxyPeersRefTime NTPTimeStamp, + ntpProxyPeersOrgTime NTPTimeStamp, + ntpProxyPeersReceiveTime NTPTimeStamp, + ntpProxyPeersTransmitTime NTPTimeStamp, + ntpProxyPeersUpdateTime NTPTimeStamp, + ntpProxyPeersReach Unsigned32, + ntpProxyPeersTimer Integer32, + ntpProxyPeersOffset OCTET STRING, + ntpProxyPeersDelay OCTET STRING, + ntpProxyPeersDispersion OCTET STRING, + ntpProxyPeersFilterValidEntries Integer32 +} + +ntpProxyPeersAssocId OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 1 } + +ntpProxyPeersConfigured OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 2 } + +ntpProxyPeersPeerAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 3 } + +ntpProxyPeersPeerPort OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 4 } + +ntpProxyPeersHostAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 5 } + +ntpProxyPeersHostPort OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 6 } + +ntpProxyPeersLeap OBJECT-TYPE + SYNTAX NTPLeapIndicator + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 7 } + +ntpProxyPeersMode OBJECT-TYPE + SYNTAX INTEGER { + unspecified(0), + symmetricActive(1), + symmetricPassive(2), + client(3), + server(4), + broadcast(5), + reservedControl(6), + reservedPrivate(7) } + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 8 } + +ntpProxyPeersStratum OBJECT-TYPE + SYNTAX Integer32 (0..255) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 9 } + +ntpProxyPeersPeerPoll OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 10 } + +ntpProxyPeersHostPoll OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 11 } + +ntpProxyPeersPrecision OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 12 } + +ntpProxyPeersRootDelay OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 13 } + +ntpProxyPeersRootDispersion OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 14 } + +ntpProxyPeersRefId OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 15 } + +ntpProxyPeersRefTime OBJECT-TYPE + SYNTAX NTPTimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 16 } + +ntpProxyPeersOrgTime OBJECT-TYPE + SYNTAX NTPTimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 17 } + +ntpProxyPeersReceiveTime OBJECT-TYPE + SYNTAX NTPTimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 18 } + +ntpProxyPeersTransmitTime OBJECT-TYPE + SYNTAX NTPTimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 19 } + +ntpProxyPeersUpdateTime OBJECT-TYPE + SYNTAX NTPTimeStamp + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 20 } + +ntpProxyPeersReach OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 21 } + +ntpProxyPeersTimer OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 22 } + +ntpProxyPeersOffset OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 23 } + +ntpProxyPeersDelay OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 24 } + +ntpProxyPeersDispersion OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyPeersVarEntry 25 } + +ntpProxyPeersFilterValidEntries OBJECT-TYPE + SYNTAX Integer32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The number of valid entries for a peer in the Proxy Filter + Register Table. This number can be zero." + ::= { ntpProxyPeersVarEntry 26 } + +-- +-- Proxy Filter Register Table +-- + +ntpProxyFilterRegisterTable OBJECT-TYPE + SYNTAX SEQUENCE OF NtpProxyFilterRegisterEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "" + ::= { ntpProxyControl 4 } + +ntpProxyFilterRegisterEntry OBJECT-TYPE + SYNTAX NtpProxyFilterRegisterEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "" + INDEX { ntpProxyServerIPAddr, ntpProxyPeersAssocId, + ntpProxyFilterIndex } + ::= { ntpProxyFilterRegisterTable 1 } + +NtpProxyFilterRegisterEntry ::= SEQUENCE { + ntpProxyFilterIndex Unsigned32, + ntpProxyFilterPeersOffset OCTET STRING, + ntpProxyFilterPeersDelay OCTET STRING, + ntpProxyFilterPeersDispersion OCTET STRING +} + +ntpProxyFilterIndex OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "" + ::= { ntpProxyFilterRegisterEntry 1 } + +ntpProxyFilterPeersOffset OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyFilterRegisterEntry 2 } + +ntpProxyFilterPeersDelay OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyFilterRegisterEntry 3 } + +ntpProxyFilterPeersDispersion OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "" + ::= { ntpProxyFilterRegisterEntry 4 } + +END Property changes on: vendor/1.14/snmp_ntp/NTP-PROXY-MIB.txt ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_ntp/ntp_tree.def =================================================================== --- vendor/1.14/snmp_ntp/ntp_tree.def (nonexistent) +++ vendor/1.14/snmp_ntp/ntp_tree.def (revision 359491) @@ -0,0 +1,122 @@ +# +# Copyright (c) 2005 +# Hartmut Brandt. +# All rights reserved. +# +# Author: Harti Brandt +# +# Redistribution of this software and documentation and use in source and +# binary forms, with or without modification, are permitted provided that +# the following conditions are met: +# +# 1. Redistributions of source code or documentation must retain the above +# copyright notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS +# AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, +# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +# FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL +# FRAUNHOFER FOKUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, +# OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +# EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# $Begemot: bsnmp/snmp_ntp/ntp_tree.def,v 1.2 2005/04/26 13:38:01 brandt_h Exp $ +# +# Definition of the tree implemented by snmp_ntp. +# +(1 internet + (4 private + (1 enterprises + (1277 udel + (3 ntpMIB + (1 ntpSystem + (1 ntpSysLeap INTEGER op_ntpSystem GET) + (2 ntpSysStratum INTEGER op_ntpSystem GET) + (3 ntpSysPrecision INTEGER32 op_ntpSystem GET) + (4 ntpSysRootDelay OCTETSTRING op_ntpSystem GET) + (5 ntpSysRootDispersion OCTETSTRING op_ntpSystem GET) + (6 ntpSysRefId OCTETSTRING op_ntpSystem GET) + (7 ntpSysRefTime OCTETSTRING op_ntpSystem GET) + (8 ntpSysPoll INTEGER32 op_ntpSystem GET) + (9 ntpSysPeer UNSIGNED32 op_ntpSystem GET) +# No idea what these should be +# (10 ntpSysPhase OCTETSTRING op_ntpSystem GET) +# (11 ntpSysFreq OCTETSTRING op_ntpSystem GET) +# (12 ntpSysError OCTETSTRING op_ntpSystem GET) + (13 ntpSysClock OCTETSTRING op_ntpSystem GET) + (14 ntpSysSystem OCTETSTRING op_ntpSystem GET) + (15 ntpSysProcessor OCTETSTRING op_ntpSystem GET) + ) + (2 ntpPeers + (1 ntpPeersVarTable + (1 ntpPeersVarEntry : UNSIGNED32 op_ntpPeersVarTable + (1 ntpPeersAssocId UNSIGNED32) + (2 ntpPeersConfigured INTEGER GET) + (3 ntpPeersPeerAddress IPADDRESS GET) + (4 ntpPeersPeerPort UNSIGNED32 GET) + (5 ntpPeersHostAddress IPADDRESS GET) + (6 ntpPeersHostPort UNSIGNED32 GET) + (7 ntpPeersLeap INTEGER GET) + (8 ntpPeersMode INTEGER GET) + (9 ntpPeersStratum INTEGER GET) + (10 ntpPeersPeerPoll INTEGER32 GET) + (11 ntpPeersHostPoll INTEGER32 GET) + (12 ntpPeersPrecision INTEGER32 GET) + (13 ntpPeersRootDelay OCTETSTRING GET) + (14 ntpPeersRootDispersion OCTETSTRING GET) + (15 ntpPeersRefId OCTETSTRING GET) + (16 ntpPeersRefTime OCTETSTRING GET) + (17 ntpPeersOrgTime OCTETSTRING GET) + (18 ntpPeersReceiveTime OCTETSTRING GET) + (19 ntpPeersTransmitTime OCTETSTRING GET) +# No idea what these should be +# (20 ntpPeersUpdateTime OCTETSTRING GET) + (21 ntpPeersReach UNSIGNED32 GET) + (22 ntpPeersTimer INTEGER32 GET) + (23 ntpPeersOffset OCTETSTRING GET) + (24 ntpPeersDelay OCTETSTRING GET) + (25 ntpPeersDispersion OCTETSTRING GET) + ) + ) + ) + (3 ntpFilter + (1 ntpFilterPeersVarTable + (1 ntpFilterPeersVarEntry : UNSIGNED32 op_ntpFilterPeersVarTable + (1 ntpFilterValidEntries INTEGER32 GET) + ) + ) + (2 ntpFilterRegisterTable + (1 ntpFilterRegisterEntry : UNSIGNED32 UNSIGNED32 op_ntpFilterRegisterTable + (1 ntpFilterIndex UNSIGNED32) + (2 ntpFilterPeersOffset OCTETSTRING GET) + (3 ntpFilterPeersDelay OCTETSTRING GET) + (4 ntpFilterPeersDispersion OCTETSTRING GET) + ) + ) + ) + ) + ) + (12325 fokus + (1 begemot + (201 begemotNtp + (1 begemotNtpObjects + (1 begemotNtpHost OCTETSTRING op_begemot_ntp GET) + (2 begemotNtpPort OCTETSTRING op_begemot_ntp GET) + (3 begemotNtpTimeout TIMETICKS op_begemot_ntp GET SET) + (4 begemotNtpDebug UNSIGNED32 op_begemot_ntp GET SET) + (5 begemotNtpJitter COUNTER64 op_begemot_ntp GET) + (6 begemotNtpStability COUNTER64 op_begemot_ntp GET) + ) + ) + ) + ) + ) + ) +) Property changes on: vendor/1.14/snmp_ntp/ntp_tree.def ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_target/target_snmp.c =================================================================== --- vendor/1.14/snmp_target/target_snmp.c (nonexistent) +++ vendor/1.14/snmp_target/target_snmp.c (revision 359491) @@ -0,0 +1,842 @@ +/*- + * Copyright (c) 2010,2018 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Shteryana Sotirova Shopova under + * sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: head/contrib/bsnmp/snmp_target/target_snmp.c 272878 2014-10-10 00:26:28Z syrinx $ + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "asn1.h" +#include "snmp.h" +#include "snmpmod.h" + +#define SNMPTREE_TYPES +#include "target_tree.h" +#include "target_oid.h" + +static struct lmodule *target_module; +/* For the registration. */ +static const struct asn_oid oid_target = OIDX_snmpTargetMIB; +static const struct asn_oid oid_notification = OIDX_snmpNotificationMIB; + +static uint reg_target; +static uint reg_notification; + +static int32_t target_lock; + +static const struct asn_oid oid_udp_domain = OIDX_snmpUDPDomain; + +/* + * Internal datastructures and forward declarations. + */ +static void target_append_index(struct asn_oid *, uint, + const char *); +static int target_decode_index(const struct asn_oid *, uint, + char *); +static struct target_address *target_get_address(const struct asn_oid *, + uint); +static struct target_address *target_get_next_address(const struct asn_oid *, + uint); +static struct target_param *target_get_param(const struct asn_oid *, + uint); +static struct target_param *target_get_next_param(const struct asn_oid *, + uint); +static struct target_notify *target_get_notify(const struct asn_oid *, + uint); +static struct target_notify *target_get_next_notify(const struct asn_oid *, + uint); + +int +op_snmp_target(struct snmp_context *ctx __unused, struct snmp_value *val, + uint32_t sub, uint32_t iidx __unused, enum snmp_op op) +{ + struct snmpd_target_stats *ctx_stats; + + if (val->var.subs[sub - 1] == LEAF_snmpTargetSpinLock) { + switch (op) { + case SNMP_OP_GET: + if (++target_lock == INT32_MAX) + target_lock = 0; + val->v.integer = target_lock; + break; + case SNMP_OP_GETNEXT: + abort(); + case SNMP_OP_SET: + if (val->v.integer != target_lock) + return (SNMP_ERR_INCONS_VALUE); + break; + case SNMP_OP_ROLLBACK: + /* FALLTHROUGH */ + case SNMP_OP_COMMIT: + break; + } + return (SNMP_ERR_NOERROR); + } else if (op == SNMP_OP_SET) + return (SNMP_ERR_NOT_WRITEABLE); + + if ((ctx_stats = bsnmpd_get_target_stats()) == NULL) + return (SNMP_ERR_GENERR); + + if (op == SNMP_OP_GET) { + switch (val->var.subs[sub - 1]) { + case LEAF_snmpUnavailableContexts: + val->v.uint32 = ctx_stats->unavail_contexts; + break; + case LEAF_snmpUnknownContexts: + val->v.uint32 = ctx_stats->unknown_contexts; + break; + default: + return (SNMP_ERR_NOSUCHNAME); + } + return (SNMP_ERR_NOERROR); + } + abort(); +} + +int +op_snmp_target_addrs(struct snmp_context *ctx __unused, struct snmp_value *val, + uint32_t sub, uint32_t iidx __unused, enum snmp_op op) +{ + char aname[SNMP_ADM_STR32_SIZ]; + struct target_address *addrs; + + switch (op) { + case SNMP_OP_GET: + if ((addrs = target_get_address(&val->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_GETNEXT: + if ((addrs = target_get_next_address(&val->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + target_append_index(&val->var, sub, addrs->name); + break; + + case SNMP_OP_SET: + if ((addrs = target_get_address(&val->var, sub)) == NULL && + (val->var.subs[sub - 1] != LEAF_snmpTargetAddrRowStatus || + val->v.integer != RowStatus_createAndWait)) + return (SNMP_ERR_NOSUCHNAME); + + if (addrs != NULL) { + if (community != COMM_INITIALIZE && + addrs->type == StorageType_readOnly) + return (SNMP_ERR_NOT_WRITEABLE); + if (addrs->status == RowStatus_active && + val->v.integer != RowStatus_destroy) + return (SNMP_ERR_INCONS_VALUE); + } + + switch (val->var.subs[sub - 1]) { + case LEAF_snmpTargetAddrTDomain: + return (SNMP_ERR_INCONS_VALUE); + case LEAF_snmpTargetAddrTAddress: + if (val->v.octetstring.len != SNMP_UDP_ADDR_SIZ) + return (SNMP_ERR_INCONS_VALUE); + ctx->scratch->ptr1 = malloc(SNMP_UDP_ADDR_SIZ); + if (ctx->scratch->ptr1 == NULL) + return (SNMP_ERR_GENERR); + memcpy(ctx->scratch->ptr1, addrs->address, + SNMP_UDP_ADDR_SIZ); + memcpy(addrs->address, val->v.octetstring.octets, + SNMP_UDP_ADDR_SIZ); + break; + + case LEAF_snmpTargetAddrTagList: + if (val->v.octetstring.len >= SNMP_TAG_SIZ) + return (SNMP_ERR_INCONS_VALUE); + ctx->scratch->int1 = strlen(addrs->taglist) + 1; + ctx->scratch->ptr1 = malloc(ctx->scratch->int1); + if (ctx->scratch->ptr1 == NULL) + return (SNMP_ERR_GENERR); + strlcpy(ctx->scratch->ptr1, addrs->taglist, + ctx->scratch->int1); + memcpy(addrs->taglist, val->v.octetstring.octets, + val->v.octetstring.len); + addrs->taglist[val->v.octetstring.len] = '\0'; + break; + + case LEAF_snmpTargetAddrParams: + if (val->v.octetstring.len >= SNMP_ADM_STR32_SIZ) + return (SNMP_ERR_INCONS_VALUE); + ctx->scratch->int1 = strlen(addrs->paramname) + 1; + ctx->scratch->ptr1 = malloc(ctx->scratch->int1); + if (ctx->scratch->ptr1 == NULL) + return (SNMP_ERR_GENERR); + strlcpy(ctx->scratch->ptr1, addrs->paramname, + ctx->scratch->int1); + memcpy(addrs->paramname, val->v.octetstring.octets, + val->v.octetstring.len); + addrs->paramname[val->v.octetstring.len] = '\0'; + break; + + case LEAF_snmpTargetAddrRetryCount: + ctx->scratch->int1 = addrs->retry; + addrs->retry = val->v.integer; + break; + + case LEAF_snmpTargetAddrTimeout: + ctx->scratch->int1 = addrs->timeout; + addrs->timeout = val->v.integer / 10; + break; + + case LEAF_snmpTargetAddrStorageType: + return (SNMP_ERR_INCONS_VALUE); + + case LEAF_snmpTargetAddrRowStatus: + if (addrs != NULL) { + if (val->v.integer != RowStatus_active && + val->v.integer != RowStatus_destroy) + return (SNMP_ERR_INCONS_VALUE); + if (val->v.integer == RowStatus_active && + (addrs->address[0] == 0 || + strlen(addrs->taglist) == 0 || + strlen(addrs->paramname) == 0)) + return (SNMP_ERR_INCONS_VALUE); + ctx->scratch->int1 = addrs->status; + addrs->status = val->v.integer; + return (SNMP_ERR_NOERROR); + } + if (val->v.integer != RowStatus_createAndWait || + target_decode_index(&val->var, sub, aname) < 0) + return (SNMP_ERR_INCONS_VALUE); + if ((addrs = target_new_address(aname)) == NULL) + return (SNMP_ERR_GENERR); + addrs->status = RowStatus_destroy; + if (community != COMM_INITIALIZE) + addrs->type = StorageType_volatile; + else + addrs->type = StorageType_readOnly; + break; + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_COMMIT: + switch (val->var.subs[sub - 1]) { + case LEAF_snmpTargetAddrTAddress: + case LEAF_snmpTargetAddrTagList: + case LEAF_snmpTargetAddrParams: + free(ctx->scratch->ptr1); + break; + case LEAF_snmpTargetAddrRowStatus: + if ((addrs = target_get_address(&val->var, sub)) == NULL) + return (SNMP_ERR_GENERR); + if (val->v.integer == RowStatus_destroy) + return (target_delete_address(addrs)); + else if (val->v.integer == RowStatus_active) + return (target_activate_address(addrs)); + break; + default: + break; + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_ROLLBACK: + if ((addrs = target_get_address(&val->var, sub)) == NULL) + return (SNMP_ERR_GENERR); + + switch (val->var.subs[sub - 1]) { + case LEAF_snmpTargetAddrTAddress: + memcpy(addrs->address, ctx->scratch->ptr1, + SNMP_UDP_ADDR_SIZ); + free(ctx->scratch->ptr1); + break; + + case LEAF_snmpTargetAddrTagList: + strlcpy(addrs->taglist, ctx->scratch->ptr1, + ctx->scratch->int1); + free(ctx->scratch->ptr1); + break; + + case LEAF_snmpTargetAddrParams: + strlcpy(addrs->paramname, ctx->scratch->ptr1, + ctx->scratch->int1); + free(ctx->scratch->ptr1); + break; + + case LEAF_snmpTargetAddrRetryCount: + addrs->retry = ctx->scratch->int1; + break; + + case LEAF_snmpTargetAddrTimeout: + addrs->timeout = ctx->scratch->int1; + break; + + case LEAF_snmpTargetAddrRowStatus: + if (ctx->scratch->int1 == RowStatus_destroy) + return (target_delete_address(addrs)); + break; + default: + break; + } + return (SNMP_ERR_NOERROR); + + default: + abort(); + } + + switch (val->var.subs[sub - 1]) { + case LEAF_snmpTargetAddrTDomain: + return (oid_get(val, &oid_udp_domain)); + case LEAF_snmpTargetAddrTAddress: + return (string_get(val, addrs->address, SNMP_UDP_ADDR_SIZ)); + case LEAF_snmpTargetAddrTimeout: + val->v.integer = addrs->timeout; + break; + case LEAF_snmpTargetAddrRetryCount: + val->v.integer = addrs->retry; + break; + case LEAF_snmpTargetAddrTagList: + return (string_get(val, addrs->taglist, -1)); + case LEAF_snmpTargetAddrParams: + return (string_get(val, addrs->paramname, -1)); + case LEAF_snmpTargetAddrStorageType: + val->v.integer = addrs->type; + break; + case LEAF_snmpTargetAddrRowStatus: + val->v.integer = addrs->status; + break; + default: + abort(); + } + + return (SNMP_ERR_NOERROR); +} + +int +op_snmp_target_params(struct snmp_context *ctx __unused, struct snmp_value *val, + uint32_t sub, uint32_t iidx __unused, enum snmp_op op) +{ + char pname[SNMP_ADM_STR32_SIZ]; + struct target_param *param; + + switch (op) { + case SNMP_OP_GET: + if ((param = target_get_param(&val->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_GETNEXT: + if ((param = target_get_next_param(&val->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + target_append_index(&val->var, sub, param->name); + break; + + case SNMP_OP_SET: + if ((param = target_get_param(&val->var, sub)) == NULL && + (val->var.subs[sub - 1] != LEAF_snmpTargetParamsRowStatus || + val->v.integer != RowStatus_createAndWait)) + return (SNMP_ERR_NOSUCHNAME); + + if (param != NULL) { + if (community != COMM_INITIALIZE && + param->type == StorageType_readOnly) + return (SNMP_ERR_NOT_WRITEABLE); + if (param->status == RowStatus_active && + val->v.integer != RowStatus_destroy) + return (SNMP_ERR_INCONS_VALUE); + } + + switch (val->var.subs[sub - 1]) { + case LEAF_snmpTargetParamsMPModel: + if (val->v.integer != SNMP_MPM_SNMP_V1 && + val->v.integer != SNMP_MPM_SNMP_V2c && + val->v.integer != SNMP_MPM_SNMP_V3) + return (SNMP_ERR_INCONS_VALUE); + ctx->scratch->int1 = param->mpmodel; + param->mpmodel = val->v.integer; + break; + + case LEAF_snmpTargetParamsSecurityModel: + if (val->v.integer != SNMP_SECMODEL_SNMPv1 && + val->v.integer != SNMP_SECMODEL_SNMPv2c && + val->v.integer != SNMP_SECMODEL_USM) + return (SNMP_ERR_INCONS_VALUE); + ctx->scratch->int1 = param->sec_model; + param->sec_model = val->v.integer; + break; + + case LEAF_snmpTargetParamsSecurityName: + if (val->v.octetstring.len >= SNMP_ADM_STR32_SIZ) + return (SNMP_ERR_INCONS_VALUE); + ctx->scratch->int1 = strlen(param->secname) + 1; + ctx->scratch->ptr1 = malloc(ctx->scratch->int1); + if (ctx->scratch->ptr1 == NULL) + return (SNMP_ERR_GENERR); + strlcpy(ctx->scratch->ptr1, param->secname, + ctx->scratch->int1); + memcpy(param->secname, val->v.octetstring.octets, + val->v.octetstring.len); + param->secname[val->v.octetstring.len] = '\0'; + break; + + case LEAF_snmpTargetParamsSecurityLevel: + if (val->v.integer != SNMP_noAuthNoPriv && + val->v.integer != SNMP_authNoPriv && + val->v.integer != SNMP_authPriv) + return (SNMP_ERR_INCONS_VALUE); + ctx->scratch->int1 = param->sec_level; + param->sec_level = val->v.integer; + break; + + case LEAF_snmpTargetParamsStorageType: + return (SNMP_ERR_INCONS_VALUE); + + case LEAF_snmpTargetParamsRowStatus: + if (param != NULL) { + if (val->v.integer != RowStatus_active && + val->v.integer != RowStatus_destroy) + return (SNMP_ERR_INCONS_VALUE); + if (val->v.integer == RowStatus_active && + (param->sec_model == 0 || + param->sec_level == 0 || + strlen(param->secname) == 0)) + return (SNMP_ERR_INCONS_VALUE); + ctx->scratch->int1 = param->status; + param->status = val->v.integer; + return (SNMP_ERR_NOERROR); + } + if (val->v.integer != RowStatus_createAndWait || + target_decode_index(&val->var, sub, pname) < 0) + return (SNMP_ERR_INCONS_VALUE); + if ((param = target_new_param(pname)) == NULL) + return (SNMP_ERR_GENERR); + param->status = RowStatus_destroy; + if (community != COMM_INITIALIZE) + param->type = StorageType_volatile; + else + param->type = StorageType_readOnly; + break; + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_COMMIT: + switch (val->var.subs[sub - 1]) { + case LEAF_snmpTargetParamsSecurityName: + free(ctx->scratch->ptr1); + break; + case LEAF_snmpTargetParamsRowStatus: + if ((param = target_get_param(&val->var, sub)) == NULL) + return (SNMP_ERR_GENERR); + if (val->v.integer == RowStatus_destroy) + return (target_delete_param(param)); + break; + default: + break; + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_ROLLBACK: + if ((param = target_get_param(&val->var, sub)) == NULL && + (val->var.subs[sub - 1] != LEAF_snmpTargetParamsRowStatus || + val->v.integer != RowStatus_createAndWait)) + return (SNMP_ERR_GENERR); + switch (val->var.subs[sub - 1]) { + case LEAF_snmpTargetParamsMPModel: + param->mpmodel = ctx->scratch->int1; + break; + case LEAF_snmpTargetParamsSecurityModel: + param->sec_model = ctx->scratch->int1; + break; + case LEAF_snmpTargetParamsSecurityName: + strlcpy(param->secname, ctx->scratch->ptr1, + sizeof(param->secname)); + free(ctx->scratch->ptr1); + break; + case LEAF_snmpTargetParamsSecurityLevel: + param->sec_level = ctx->scratch->int1; + break; + case LEAF_snmpTargetParamsRowStatus: + if (ctx->scratch->int1 == RowStatus_destroy) + return (target_delete_param(param)); + break; + default: + break; + } + + return (SNMP_ERR_NOERROR); + + default: + abort(); + } + + switch (val->var.subs[sub - 1]) { + case LEAF_snmpTargetParamsMPModel: + val->v.integer = param->mpmodel; + break; + case LEAF_snmpTargetParamsSecurityModel: + val->v.integer = param->sec_model; + break; + case LEAF_snmpTargetParamsSecurityName: + return (string_get(val, param->secname, -1)); + case LEAF_snmpTargetParamsSecurityLevel: + val->v.integer = param->sec_level; + break; + case LEAF_snmpTargetParamsStorageType: + val->v.integer = param->type; + break; + case LEAF_snmpTargetParamsRowStatus: + val->v.integer = param->status; + break; + default: + abort(); + } + + return (SNMP_ERR_NOERROR); +} + +int +op_snmp_notify(struct snmp_context *ctx __unused, struct snmp_value *val, + uint32_t sub, uint32_t iidx __unused, enum snmp_op op) +{ + char nname[SNMP_ADM_STR32_SIZ]; + struct target_notify *notify; + + switch (op) { + case SNMP_OP_GET: + if ((notify = target_get_notify(&val->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_GETNEXT: + if ((notify = target_get_next_notify(&val->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + target_append_index(&val->var, sub, notify->name); + break; + + case SNMP_OP_SET: + if ((notify = target_get_notify(&val->var, sub)) == NULL && + (val->var.subs[sub - 1] != LEAF_snmpNotifyRowStatus || + val->v.integer != RowStatus_createAndGo)) + return (SNMP_ERR_NOSUCHNAME); + + if (notify != NULL) { + if (community != COMM_INITIALIZE && + notify->type == StorageType_readOnly) + return (SNMP_ERR_NOT_WRITEABLE); + } + + switch (val->var.subs[sub - 1]) { + case LEAF_snmpNotifyTag: + if (val->v.octetstring.len >= SNMP_TAG_SIZ) + return (SNMP_ERR_INCONS_VALUE); + ctx->scratch->int1 = strlen(notify->taglist) + 1; + ctx->scratch->ptr1 = malloc(ctx->scratch->int1); + if (ctx->scratch->ptr1 == NULL) + return (SNMP_ERR_GENERR); + strlcpy(ctx->scratch->ptr1, notify->taglist, + ctx->scratch->int1); + memcpy(notify->taglist, val->v.octetstring.octets, + val->v.octetstring.len); + notify->taglist[val->v.octetstring.len] = '\0'; + break; + + case LEAF_snmpNotifyType: + /* FALLTHROUGH */ + case LEAF_snmpNotifyStorageType: + return (SNMP_ERR_INCONS_VALUE); + case LEAF_snmpNotifyRowStatus: + if (notify != NULL) { + if (val->v.integer != RowStatus_active && + val->v.integer != RowStatus_destroy) + return (SNMP_ERR_INCONS_VALUE); + ctx->scratch->int1 = notify->status; + notify->status = val->v.integer; + return (SNMP_ERR_NOERROR); + } + if (val->v.integer != RowStatus_createAndGo || + target_decode_index(&val->var, sub, nname) < 0) + return (SNMP_ERR_INCONS_VALUE); + if ((notify = target_new_notify(nname)) == NULL) + return (SNMP_ERR_GENERR); + notify->status = RowStatus_destroy; + if (community != COMM_INITIALIZE) + notify->type = StorageType_volatile; + else + notify->type = StorageType_readOnly; + break; + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_COMMIT: + switch (val->var.subs[sub - 1]) { + case LEAF_snmpNotifyTag: + free(ctx->scratch->ptr1); + break; + case LEAF_snmpNotifyRowStatus: + notify = target_get_notify(&val->var, sub); + if (notify == NULL) + return (SNMP_ERR_GENERR); + if (val->v.integer == RowStatus_destroy) + return (target_delete_notify(notify)); + else + notify->status = RowStatus_active; + break; + default: + break; + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_ROLLBACK: + if ((notify = target_get_notify(&val->var, sub)) == NULL) + return (SNMP_ERR_GENERR); + + switch (val->var.subs[sub - 1]) { + case LEAF_snmpNotifyTag: + strlcpy(notify->taglist, ctx->scratch->ptr1, + ctx->scratch->int1); + free(ctx->scratch->ptr1); + break; + case LEAF_snmpNotifyRowStatus: + if (ctx->scratch->int1 == RowStatus_destroy) + return (target_delete_notify(notify)); + break; + default: + break; + } + return (SNMP_ERR_NOERROR); + + default: + abort(); + } + + + switch (val->var.subs[sub - 1]) { + case LEAF_snmpNotifyTag: + return (string_get(val, notify->taglist, -1)); + case LEAF_snmpNotifyType: + val->v.integer = snmpNotifyType_trap; + break; + case LEAF_snmpNotifyStorageType: + val->v.integer = notify->type; + break; + case LEAF_snmpNotifyRowStatus: + val->v.integer = notify->status; + break; + default: + abort(); + } + + return (SNMP_ERR_NOERROR); +} + +static void +target_append_index(struct asn_oid *oid, uint sub, const char *name) +{ + uint32_t i; + + oid->len = sub + strlen(name); + for (i = 0; i < strlen(name); i++) + oid->subs[sub + i] = name[i]; +} + +static int +target_decode_index(const struct asn_oid *oid, uint sub, char *name) +{ + uint32_t i; + + if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= + SNMP_ADM_STR32_SIZ) + return (-1); + + for (i = 0; i < oid->subs[sub]; i++) + name[i] = oid->subs[sub + i + 1]; + name[i] = '\0'; + + return (0); +} + +static struct target_address * +target_get_address(const struct asn_oid *oid, uint sub) +{ + char aname[SNMP_ADM_STR32_SIZ]; + struct target_address *addrs; + + if (target_decode_index(oid, sub, aname) < 0) + return (NULL); + + for (addrs = target_first_address(); addrs != NULL; + addrs = target_next_address(addrs)) + if (strcmp(aname, addrs->name) == 0) + return (addrs); + + return (NULL); +} + +static struct target_address * +target_get_next_address(const struct asn_oid * oid, uint sub) +{ + char aname[SNMP_ADM_STR32_SIZ]; + struct target_address *addrs; + + if (oid->len - sub == 0) + return (target_first_address()); + + if (target_decode_index(oid, sub, aname) < 0) + return (NULL); + + for (addrs = target_first_address(); addrs != NULL; + addrs = target_next_address(addrs)) + if (strcmp(aname, addrs->name) == 0) + return (target_next_address(addrs)); + + return (NULL); +} + +static struct target_param * +target_get_param(const struct asn_oid *oid, uint sub) +{ + char pname[SNMP_ADM_STR32_SIZ]; + struct target_param *param; + + if (target_decode_index(oid, sub, pname) < 0) + return (NULL); + + for (param = target_first_param(); param != NULL; + param = target_next_param(param)) + if (strcmp(pname, param->name) == 0) + return (param); + + return (NULL); +} + +static struct target_param * +target_get_next_param(const struct asn_oid *oid, uint sub) +{ + char pname[SNMP_ADM_STR32_SIZ]; + struct target_param *param; + + if (oid->len - sub == 0) + return (target_first_param()); + + if (target_decode_index(oid, sub, pname) < 0) + return (NULL); + + for (param = target_first_param(); param != NULL; + param = target_next_param(param)) + if (strcmp(pname, param->name) == 0) + return (target_next_param(param)); + + return (NULL); +} + +static struct target_notify * +target_get_notify(const struct asn_oid *oid, uint sub) +{ + char nname[SNMP_ADM_STR32_SIZ]; + struct target_notify *notify; + + if (target_decode_index(oid, sub, nname) < 0) + return (NULL); + + for (notify = target_first_notify(); notify != NULL; + notify = target_next_notify(notify)) + if (strcmp(nname, notify->name) == 0) + return (notify); + + return (NULL); +} + +static struct target_notify * +target_get_next_notify(const struct asn_oid *oid, uint sub) +{ + char nname[SNMP_ADM_STR32_SIZ]; + struct target_notify *notify; + + if (oid->len - sub == 0) + return (target_first_notify()); + + if (target_decode_index(oid, sub, nname) < 0) + return (NULL); + + for (notify = target_first_notify(); notify != NULL; + notify = target_next_notify(notify)) + if (strcmp(nname, notify->name) == 0) + return (target_next_notify(notify)); + + return (NULL); +} + +static int +target_init(struct lmodule *mod, int argc __unused, char *argv[] __unused) +{ + target_module = mod; + target_lock = random(); + + return (0); +} + + +static int +target_fini(void) +{ + target_flush_all(); + or_unregister(reg_target); + or_unregister(reg_notification); + + return (0); +} + +static void +target_start(void) +{ + reg_target = or_register(&oid_target, + "The MIB module for managing SNMP Management Targets.", + target_module); + reg_notification = or_register(&oid_notification, + "The MIB module for configuring generation of SNMP notifications.", + target_module); +} + +static void +target_dump(void) +{ + /* XXX: dump the module stats & list of mgmt targets */ +} + +static const char target_comment[] = \ +"This module implements SNMP Management Target MIB Module defined in RFC 3413."; + +extern const struct snmp_module config; +const struct snmp_module config = { + .comment = target_comment, + .init = target_init, + .fini = target_fini, + .start = target_start, + .tree = target_ctree, + .dump = target_dump, + .tree_size = target_CTREE_SIZE, +}; Property changes on: vendor/1.14/snmp_target/target_snmp.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_target/snmp_target.3 =================================================================== --- vendor/1.14/snmp_target/snmp_target.3 (nonexistent) +++ vendor/1.14/snmp_target/snmp_target.3 (revision 359491) @@ -0,0 +1,204 @@ +.\"- +.\" Copyright (C) 2010 The FreeBSD Foundation +.\" All rights reserved. +.\" +.\" This documentation was written by Shteryana Sotirova Shopova under +.\" sponsorship from the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD: head/contrib/bsnmp/snmp_target/snmp_target.3 310648 2016-12-27 23:32:54Z ngie $ +.\" +.Dd December 16, 2010 +.Dt SNMP_TARGET 3 +.Os +.Sh NAME +.Nm snmp_target +.Nd "Target addresses and notifications module for" +.Xr bsnmpd 1 +.Sh LIBRARY +.Pq begemotSnmpdModulePath."target" = "/usr/lib/snmp_target.so" +.Sh DESCRIPTION +The +.Nm snmp_target +module implements SNMPv3 Management Target MIB and basic functionality from +Notification MIB as defined in RFC 3413. The module is used to manage the +internal list of SNMPv3 notification target addresses in +.Nm bsnmpd +and their associated transport and encapsulation parameters. +The module must be loaded for +.Nm bsnmpd +to send SNMPv3 Trap-PDUs to the configured notification target addresses. +.Sh IMPLEMENTATION NOTES +A short description of the objects implemented in the module follows. +.Bl -tag -width "XXXXXXXXX" +.It Va snmpTargetSpinLock +An advisory lock used to coordinate several Command Generator Applications when +altering the SNMP Target addresses and their associated parameters. +.It Va snmpTargetAddrTable +The table contains the transport addresses to be used in generation of SNMP +messages. +The table contains the following objects +.Bl -tag -width ".It Va snmpTargetAddrName" +.It Va snmpTargetAddrName +A unique local identifier used as entry key. Not accessible for GET or SET +operations. +.It Va snmpTargetAddrTDomain +The transport domain of the target address. Currently only UDP over IPv4 is +supported and any attempt to SET the value of this object will return an +"inconsistentValue" error. Additional transport domains will be supported +in future via the object definitions in TRANSPORT-ADDRESS-MIB (RFC 3419). +.It Va snmpTargetAddrTAddress +The transport address of this entry interpreted within the context of the value +of +.Va snmpTargetAddrTDomain . +For UDP over IPv4, this is a 6-byte long octetstring, with the first 4 bytes +representing the IPv4 address and the last 2 bytes the UDP port number in +network-byte order. +.It Va snmpTargetAddrTimeout +The value of this object is only relevant when the receiver of the SNMP +message is to send an acknowledgment that the message was received, i.e +for SNMP notifications it is relevant if the notification is SNMP Inform +rather than SNMP Trap. Currently +.Nm bsnmpd +supports only SNMP Trap notifications, so the value of this object is +meaningless. +.It Va snmpTargetAddrRetryCount +As with +.Va snmpTargetAddrTimeout +the value of this object currently is meaningless. +.It Va snmpTargetAddrTagList +A list of human-readable tag values used to select target addresses for a +particular operation. Recognized ASCII delimiting characters between tags are +space (0x20), tab (0x20), carriage return (0xOD) and line feed (0x0A). +.It Va snmpTargetAddrParams +The value of this object contains the value of a key in snmpTargetParamsTable +containing SNMP parameters used when generating messages to this transport +address. +.It Va snmpTargetAddrStorageType +This column always has either of two values. Entries created via +.Nm bsnmpd's +configuration file always have this column set to readOnly (5) and +it is not possible to modify those entries. Entries created by Command Generator +Applications always have this column set to volatile(2) and such entries are +lost when the module is restarted. A SET operation on this column is not +allowed. +.It Va snmpTargetAddrRowStatus +This column is used to create new target address entries or delete existing ones +from the table. +.El +.It Va snmpTargetParamsTable +The table contains the target information to be used in generation of SNMP +messages. +The table contains the following objects +.Bl -tag -width ".It Va snmpTargetParamsName" +.It Va snmpTargetParamsName +A unique local identifier used as entry key. Not accessible for GET or SET +operations. +.It Va snmpTargetParamsMPModel +The Message Processing Model to be used when generating SNMP PDUs using this +entry. Supported values are 0 for SNMPv1, 1 for SNMPv2c and 3 for SNMPv3. +.It Va snmpTargetParamsSecurityModel +The Security Model to be used when generating SNMP PDUs using this entry. +Supported values are 1 for SNMPv1, 2 for SNMPv2c and 3 for SNMPv3 User-Based +Security Model. +.It Va snmpTargetParamsSecurityName +The securityName which identifies the Principal on whose behalf SNMP PDUs +will be generated using this entry. For SNMPv1 and SNMPv2c this is the +name of a community configured in +.Nm bsnmpd , +and for SNMPv3 USM, this is the name of an existing user configured via the +.Nm snmp_usm +module. +.It Va snmpTargetParamsSecurityLevel +The Security Level to be used when generating SNMP PDUs using this entry. +Supported values are noAuthNoPriv(1) for plain-text PDUs with no authentication, +authNoPriv(2) for authenticated plain-text PDUs and authPriv(3) for encrypted +PDUs. +.It Va snmpTargetParamsStorageType +As with +.Va snmpTargetAddrStorageType +this column always has either of two values. Entries created via +.Nm bsnmpd's +configuration file always have this column set to readOnly (5), while entries +created by Command Generator Applications always have this column set to +volatile(2). A SET operation on this column is not allowed. +.It Va snmpTargetParamsRowStatus +This column is used to create new target address parameters entries or delete +existing ones from the table. +.El +.It Va snmpNotifyTable +The table is used to select the management targets which should receive SNMP +notifications. +The table contains the following objects +.Bl -tag -width ".It Va snmpNotifyName" +.It Va snmpNotifyName +A unique local identifier used as entry key. Not accessible for GET or SET +operations. +.It Va snmpNotifyTag +This object contains a single tag value used to select target addresses from +the +.Va snmpTargetAddrTable +to which the notifications will be send. +.It Va snmpNotifyType +The type of SNMP notifications that will be send to the target addresses +matching the corresponding +.Va snmpNotifyTag . +Possible values are Trap (1) or Inform (2). Currently only SNMP Traps are +supported and any attempt to SET the value of this object will return an +"inconsistentValue" error. +.It Va snmpNotifyStorageType +Again this column always has either of two values. Entries created via +.Nm bsnmpd's +configuration file always have this column set to readOnly (5), while entries +created by Command Generator Applications always have this column set to +volatile(2). A SET operation on this column is not allowed. +.It Va snmpNotifyRowStatus +This column is used to create new notification target entries or delete existing +ones from the table. +.El +.El +.Pp +The +.Va snmpNotifyFilterProfileTable +and +.Va snmpNotifyFilterTable +tables from the SNMP-NOTIFICATION-MIB are not supported by the module. +Notification filtering is supported via the +.Xr snmp_vacm 3 +module instead. +.Sh FILES +.Bl -tag -width "XXXXXXXXX" +.It Pa /usr/share/snmp/defs/target_tree.def +The description of the MIB tree implemented by +.Nm . +.El +.Sh SEE ALSO +.Xr bsnmpd 1 , +.Xr gensnmptree 1 , +.Xr snmpmod 3 , +.Xr snmp_usm 3 , +.Xr snmp_vacm 3 +.Sh STANDARDS +IETF RFC 3413 +.Sh AUTHORS +.An Shteryana Shopova Aq syrinx@FreeBSD.org Property changes on: vendor/1.14/snmp_target/snmp_target.3 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_target/target_tree.def =================================================================== --- vendor/1.14/snmp_target/target_tree.def (nonexistent) +++ vendor/1.14/snmp_target/target_tree.def (revision 359491) @@ -0,0 +1,87 @@ +#- +# Copyright (C) 2010 The FreeBSD Foundation +# All rights reserved. +# +# This software was developed by Shteryana Sotirova Shopova under +# sponsorship from the FreeBSD Foundation. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +include "tc.def" + +(1 internet + (6 snmpV2 + (1 snmpDomains + (1 snmpUDPDomain + ) + ) + (3 snmpModules + (12 snmpTargetMIB + (1 snmpTargetObjects + (1 snmpTargetSpinLock INTEGER op_snmp_target GET SET) + (2 snmpTargetAddrTable + (1 snmpTargetAddrEntry : OCTETSTRING op_snmp_target_addrs + (1 snmpTargetAddrName OCTETSTRING) + (2 snmpTargetAddrTDomain OID GET SET) + (3 snmpTargetAddrTAddress OCTETSTRING | TAddress GET SET) + (4 snmpTargetAddrTimeout INTEGER GET SET) + (5 snmpTargetAddrRetryCount INTEGER GET SET) + (6 snmpTargetAddrTagList OCTETSTRING | SnmpTagList GET SET) + (7 snmpTargetAddrParams OCTETSTRING GET SET) + (8 snmpTargetAddrStorageType StorageType GET SET) + (9 snmpTargetAddrRowStatus RowStatus GET SET) + ) + ) + (3 snmpTargetParamsTable + (1 snmpTargetParamsEntry : OCTETSTRING op_snmp_target_params + (1 snmpTargetParamsName OCTETSTRING) + (2 snmpTargetParamsMPModel INTEGER GET SET) + (3 snmpTargetParamsSecurityModel INTEGER GET SET) + (4 snmpTargetParamsSecurityName OCTETSTRING | SnmpAdminString GET SET) + (5 snmpTargetParamsSecurityLevel ENUM ( 1 noAuthNoPriv 2 authNoPriv 3 authPriv ) GET SET) + (6 snmpTargetParamsStorageType StorageType GET SET) + (7 snmpTargetParamsRowStatus RowStatus GET SET) + ) + ) + (4 snmpUnavailableContexts COUNTER op_snmp_target GET) + (5 snmpUnknownContexts COUNTER op_snmp_target GET) + ) + ) + (13 snmpNotificationMIB + (1 snmpNotifyObjects + (1 snmpNotifyTable + (1 snmpNotifyEntry : OCTETSTRING op_snmp_notify + (1 snmpNotifyName OCTETSTRING) + (2 snmpNotifyTag OCTETSTRING | SnmpTagValue GET SET) + (3 snmpNotifyType ENUM ( 1 trap 2 inform ) GET SET) + (4 snmpNotifyStorageType StorageType GET SET) + (5 snmpNotifyRowStatus RowStatus GET SET) + ) + ) + ) + ) + ) + ) +) Property changes on: vendor/1.14/snmp_target/target_tree.def ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_usm/usm_snmp.c =================================================================== --- vendor/1.14/snmp_usm/usm_snmp.c (nonexistent) +++ vendor/1.14/snmp_usm/usm_snmp.c (revision 359491) @@ -0,0 +1,620 @@ +/*- + * Copyright (c) 2010,2018 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Shteryana Sotirova Shopova under + * sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: head/contrib/bsnmp/snmp_usm/usm_snmp.c 311394 2017-01-05 09:46:36Z ngie $ + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "asn1.h" +#include "snmp.h" +#include "snmpmod.h" + +#define SNMPTREE_TYPES +#include "usm_tree.h" +#include "usm_oid.h" + +static struct lmodule *usm_module; +/* For the registration. */ +static const struct asn_oid oid_usm = OIDX_snmpUsmMIB; + +static const struct asn_oid oid_usmNoAuthProtocol = OIDX_usmNoAuthProtocol; +static const struct asn_oid oid_usmHMACMD5AuthProtocol = \ + OIDX_usmHMACMD5AuthProtocol; +static const struct asn_oid oid_usmHMACSHAAuthProtocol = \ + OIDX_usmHMACSHAAuthProtocol; + +static const struct asn_oid oid_usmNoPrivProtocol = OIDX_usmNoPrivProtocol; +static const struct asn_oid oid_usmDESPrivProtocol = OIDX_usmDESPrivProtocol; +static const struct asn_oid oid_usmAesCfb128Protocol = OIDX_usmAesCfb128Protocol; + +static const struct asn_oid oid_usmUserSecurityName = OIDX_usmUserSecurityName; + +/* The registration. */ +static uint reg_usm; + +static int32_t usm_lock; + +static struct usm_user * usm_get_user(const struct asn_oid *, uint); +static struct usm_user * usm_get_next_user(const struct asn_oid *, uint); +static void usm_append_userindex(struct asn_oid *, uint, + const struct usm_user *); +static int usm_user_index_decode(const struct asn_oid *, uint, uint8_t *, + uint32_t *, char *); + +int +op_usm_stats(struct snmp_context *ctx __unused, struct snmp_value *val, + uint32_t sub __unused, uint32_t iidx __unused, enum snmp_op op) +{ + struct snmpd_usmstat *usmstats; + + if (op == SNMP_OP_SET) + return (SNMP_ERR_NOT_WRITEABLE); + + if ((usmstats = bsnmpd_get_usm_stats()) == NULL) + return (SNMP_ERR_GENERR); + + if (op == SNMP_OP_GET) { + switch (val->var.subs[sub - 1]) { + case LEAF_usmStatsUnsupportedSecLevels: + val->v.uint32 = usmstats->unsupported_seclevels; + break; + case LEAF_usmStatsNotInTimeWindows: + val->v.uint32 = usmstats->not_in_time_windows; + break; + case LEAF_usmStatsUnknownUserNames: + val->v.uint32 = usmstats->unknown_users; + break; + case LEAF_usmStatsUnknownEngineIDs: + val->v.uint32 = usmstats->unknown_engine_ids; + break; + case LEAF_usmStatsWrongDigests: + val->v.uint32 = usmstats->wrong_digests; + break; + case LEAF_usmStatsDecryptionErrors: + val->v.uint32 = usmstats->decrypt_errors; + break; + default: + return (SNMP_ERR_NOSUCHNAME); + } + return (SNMP_ERR_NOERROR); + } + abort(); +} + +int +op_usm_lock(struct snmp_context *ctx __unused, struct snmp_value *val, + uint32_t sub, uint32_t iidx __unused, enum snmp_op op) +{ + if (val->var.subs[sub - 1] != LEAF_usmUserSpinLock) + return (SNMP_ERR_NOSUCHNAME); + + switch (op) { + case SNMP_OP_GET: + if (++usm_lock == INT32_MAX) + usm_lock = 0; + val->v.integer = usm_lock; + break; + case SNMP_OP_GETNEXT: + abort(); + case SNMP_OP_SET: + if (val->v.integer != usm_lock) + return (SNMP_ERR_INCONS_VALUE); + break; + case SNMP_OP_ROLLBACK: + /* FALLTHROUGH */ + case SNMP_OP_COMMIT: + break; + } + + return (SNMP_ERR_NOERROR); +} + +int +op_usm_users(struct snmp_context *ctx, struct snmp_value *val, + uint32_t sub, uint32_t iidx __unused, enum snmp_op op) +{ + uint32_t elen; + struct usm_user *uuser, *clone; + char uname[SNMP_ADM_STR32_SIZ]; + uint8_t eid[SNMP_ENGINE_ID_SIZ]; + + switch (op) { + case SNMP_OP_GET: + if ((uuser = usm_get_user(&val->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_GETNEXT: + if ((uuser = usm_get_next_user(&val->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + usm_append_userindex(&val->var, sub, uuser); + break; + + case SNMP_OP_SET: + if ((uuser = usm_get_user(&val->var, sub)) == NULL && + val->var.subs[sub - 1] != LEAF_usmUserStatus && + val->var.subs[sub - 1] != LEAF_usmUserCloneFrom) + return (SNMP_ERR_NOSUCHNAME); + + /* + * XXX (ngie): need to investigate the MIB to determine how + * this is possible given some of the transitions below. + */ + if (community != COMM_INITIALIZE && + uuser != NULL && uuser->type == StorageType_readOnly) + return (SNMP_ERR_NOT_WRITEABLE); + + switch (val->var.subs[sub - 1]) { + case LEAF_usmUserSecurityName: + return (SNMP_ERR_NOT_WRITEABLE); + + case LEAF_usmUserCloneFrom: + if (uuser != NULL || usm_user_index_decode(&val->var, + sub, eid, &elen, uname) < 0 || + !(asn_is_suboid(&oid_usmUserSecurityName, &val->v.oid))) + return (SNMP_ERR_WRONG_VALUE); + if ((clone = usm_get_user(&val->v.oid, sub)) == NULL) + return (SNMP_ERR_INCONS_VALUE); + if ((uuser = usm_new_user(eid, elen, uname)) == NULL) + return (SNMP_ERR_GENERR); + uuser->status = RowStatus_notReady; + if (community != COMM_INITIALIZE) + uuser->type = StorageType_volatile; + else + uuser->type = StorageType_readOnly; + + uuser->suser.auth_proto = clone->suser.auth_proto; + uuser->suser.priv_proto = clone->suser.priv_proto; + memcpy(uuser->suser.auth_key, clone->suser.auth_key, + sizeof(uuser->suser.auth_key)); + memcpy(uuser->suser.priv_key, clone->suser.priv_key, + sizeof(uuser->suser.priv_key)); + ctx->scratch->int1 = RowStatus_createAndWait; + break; + + case LEAF_usmUserAuthProtocol: + ctx->scratch->int1 = uuser->suser.auth_proto; + if (asn_compare_oid(&oid_usmNoAuthProtocol, + &val->v.oid) == 0) + uuser->suser.auth_proto = SNMP_AUTH_NOAUTH; + else if (asn_compare_oid(&oid_usmHMACMD5AuthProtocol, + &val->v.oid) == 0) + uuser->suser.auth_proto = SNMP_AUTH_HMAC_MD5; + else if (asn_compare_oid(&oid_usmHMACSHAAuthProtocol, + &val->v.oid) == 0) + uuser->suser.auth_proto = SNMP_AUTH_HMAC_SHA; + else + return (SNMP_ERR_WRONG_VALUE); + break; + + case LEAF_usmUserAuthKeyChange: + case LEAF_usmUserOwnAuthKeyChange: + if (val->var.subs[sub - 1] == + LEAF_usmUserOwnAuthKeyChange && + (usm_user == NULL || strcmp(uuser->suser.sec_name, + usm_user->suser.sec_name) != 0)) + return (SNMP_ERR_NO_ACCESS); + if (val->v.octetstring.len > SNMP_AUTH_KEY_SIZ) + return (SNMP_ERR_INCONS_VALUE); + ctx->scratch->ptr1 = malloc(SNMP_AUTH_KEY_SIZ); + if (ctx->scratch->ptr1 == NULL) + return (SNMP_ERR_GENERR); + memcpy(ctx->scratch->ptr1, uuser->suser.auth_key, + SNMP_AUTH_KEY_SIZ); + memcpy(uuser->suser.auth_key, val->v.octetstring.octets, + val->v.octetstring.len); + break; + + case LEAF_usmUserPrivProtocol: + ctx->scratch->int1 = uuser->suser.priv_proto; + if (asn_compare_oid(&oid_usmNoPrivProtocol, + &val->v.oid) == 0) + uuser->suser.priv_proto = SNMP_PRIV_NOPRIV; + else if (asn_compare_oid(&oid_usmDESPrivProtocol, + &val->v.oid) == 0) + uuser->suser.priv_proto = SNMP_PRIV_DES; + else if (asn_compare_oid(&oid_usmAesCfb128Protocol, + &val->v.oid) == 0) + uuser->suser.priv_proto = SNMP_PRIV_AES; + else + return (SNMP_ERR_WRONG_VALUE); + break; + + case LEAF_usmUserPrivKeyChange: + case LEAF_usmUserOwnPrivKeyChange: + if (val->var.subs[sub - 1] == + LEAF_usmUserOwnPrivKeyChange && + (usm_user == NULL || strcmp(uuser->suser.sec_name, + usm_user->suser.sec_name) != 0)) + return (SNMP_ERR_NO_ACCESS); + if (val->v.octetstring.len > SNMP_PRIV_KEY_SIZ) + return (SNMP_ERR_INCONS_VALUE); + ctx->scratch->ptr1 = malloc(SNMP_PRIV_KEY_SIZ); + if (ctx->scratch->ptr1 == NULL) + return (SNMP_ERR_GENERR); + memcpy(ctx->scratch->ptr1, uuser->suser.priv_key, + sizeof(uuser->suser.priv_key)); + memcpy(uuser->suser.priv_key, val->v.octetstring.octets, + val->v.octetstring.len); + break; + + case LEAF_usmUserPublic: + if (val->v.octetstring.len > SNMP_ADM_STR32_SIZ) + return (SNMP_ERR_INCONS_VALUE); + if (uuser->user_public_len > 0) { + ctx->scratch->ptr2 = + malloc(uuser->user_public_len); + if (ctx->scratch->ptr2 == NULL) + return (SNMP_ERR_GENERR); + memcpy(ctx->scratch->ptr2, uuser->user_public, + uuser->user_public_len); + ctx->scratch->int2 = uuser->user_public_len; + } + if (val->v.octetstring.len > 0) { + memcpy(uuser->user_public, + val->v.octetstring.octets, + val->v.octetstring.len); + uuser->user_public_len = val->v.octetstring.len; + } else { + memset(uuser->user_public, 0, + sizeof(uuser->user_public)); + uuser->user_public_len = 0; + } + break; + + case LEAF_usmUserStorageType: + return (SNMP_ERR_INCONS_VALUE); + + case LEAF_usmUserStatus: + if (uuser == NULL) { + if (val->v.integer != RowStatus_createAndWait || + usm_user_index_decode(&val->var, sub, eid, + &elen, uname) < 0) + return (SNMP_ERR_INCONS_VALUE); + uuser = usm_new_user(eid, elen, uname); + if (uuser == NULL) + return (SNMP_ERR_GENERR); + uuser->status = RowStatus_notReady; + if (community != COMM_INITIALIZE) + uuser->type = StorageType_volatile; + else + uuser->type = StorageType_readOnly; + } else if (val->v.integer != RowStatus_active && + val->v.integer != RowStatus_destroy) + return (SNMP_ERR_INCONS_VALUE); + + uuser->status = val->v.integer; + break; + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_COMMIT: + switch (val->var.subs[sub - 1]) { + case LEAF_usmUserAuthKeyChange: + case LEAF_usmUserOwnAuthKeyChange: + case LEAF_usmUserPrivKeyChange: + case LEAF_usmUserOwnPrivKeyChange: + free(ctx->scratch->ptr1); + break; + case LEAF_usmUserPublic: + if (ctx->scratch->ptr2 != NULL) + free(ctx->scratch->ptr2); + break; + case LEAF_usmUserStatus: + if (val->v.integer != RowStatus_destroy) + break; + if ((uuser = usm_get_user(&val->var, sub)) == NULL) + return (SNMP_ERR_GENERR); + usm_delete_user(uuser); + break; + default: + break; + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_ROLLBACK: + if ((uuser = usm_get_user(&val->var, sub)) == NULL) + return (SNMP_ERR_GENERR); + switch (val->var.subs[sub - 1]) { + case LEAF_usmUserAuthProtocol: + uuser->suser.auth_proto = ctx->scratch->int1; + break; + case LEAF_usmUserAuthKeyChange: + case LEAF_usmUserOwnAuthKeyChange: + memcpy(uuser->suser.auth_key, ctx->scratch->ptr1, + sizeof(uuser->suser.auth_key)); + free(ctx->scratch->ptr1); + break; + case LEAF_usmUserPrivProtocol: + uuser->suser.priv_proto = ctx->scratch->int1; + break; + case LEAF_usmUserPrivKeyChange: + case LEAF_usmUserOwnPrivKeyChange: + memcpy(uuser->suser.priv_key, ctx->scratch->ptr1, + sizeof(uuser->suser.priv_key)); + free(ctx->scratch->ptr1); + break; + case LEAF_usmUserPublic: + if (ctx->scratch->ptr2 != NULL) { + memcpy(uuser->user_public, ctx->scratch->ptr2, + ctx->scratch->int2); + uuser->user_public_len = ctx->scratch->int2; + free(ctx->scratch->ptr2); + } else { + memset(uuser->user_public, 0, + sizeof(uuser->user_public)); + uuser->user_public_len = 0; + } + break; + case LEAF_usmUserCloneFrom: + case LEAF_usmUserStatus: + if (ctx->scratch->int1 == RowStatus_createAndWait) + usm_delete_user(uuser); + break; + default: + break; + } + return (SNMP_ERR_NOERROR); + + default: + abort(); + } + + switch (val->var.subs[sub - 1]) { + case LEAF_usmUserSecurityName: + return (string_get(val, uuser->suser.sec_name, -1)); + case LEAF_usmUserCloneFrom: + memcpy(&val->v.oid, &oid_zeroDotZero, sizeof(oid_zeroDotZero)); + break; + case LEAF_usmUserAuthProtocol: + switch (uuser->suser.auth_proto) { + case SNMP_AUTH_HMAC_MD5: + memcpy(&val->v.oid, &oid_usmHMACMD5AuthProtocol, + sizeof(oid_usmHMACMD5AuthProtocol)); + break; + case SNMP_AUTH_HMAC_SHA: + memcpy(&val->v.oid, &oid_usmHMACSHAAuthProtocol, + sizeof(oid_usmHMACSHAAuthProtocol)); + break; + default: + memcpy(&val->v.oid, &oid_usmNoAuthProtocol, + sizeof(oid_usmNoAuthProtocol)); + break; + } + break; + case LEAF_usmUserAuthKeyChange: + case LEAF_usmUserOwnAuthKeyChange: + return (string_get(val, (char *)uuser->suser.auth_key, 0)); + case LEAF_usmUserPrivProtocol: + switch (uuser->suser.priv_proto) { + case SNMP_PRIV_DES: + memcpy(&val->v.oid, &oid_usmDESPrivProtocol, + sizeof(oid_usmDESPrivProtocol)); + break; + case SNMP_PRIV_AES: + memcpy(&val->v.oid, &oid_usmAesCfb128Protocol, + sizeof(oid_usmAesCfb128Protocol)); + break; + default: + memcpy(&val->v.oid, &oid_usmNoPrivProtocol, + sizeof(oid_usmNoPrivProtocol)); + break; + } + break; + case LEAF_usmUserPrivKeyChange: + case LEAF_usmUserOwnPrivKeyChange: + return (string_get(val, (char *)uuser->suser.priv_key, 0)); + case LEAF_usmUserPublic: + return (string_get(val, uuser->user_public, + uuser->user_public_len)); + case LEAF_usmUserStorageType: + val->v.integer = uuser->type; + break; + case LEAF_usmUserStatus: + val->v.integer = uuser->status; + break; + } + + return (SNMP_ERR_NOERROR); +} + +static int +usm_user_index_decode(const struct asn_oid *oid, uint sub, uint8_t *engine, + uint32_t *elen, char *uname) +{ + uint32_t i, nlen; + int uname_off; + + if (oid->subs[sub] > SNMP_ENGINE_ID_SIZ) + return (-1); + + for (i = 0; i < oid->subs[sub]; i++) + engine[i] = oid->subs[sub + i + 1]; + *elen = i; + + uname_off = sub + oid->subs[sub] + 1; + if ((nlen = oid->subs[uname_off]) >= SNMP_ADM_STR32_SIZ) + return (-1); + + for (i = 0; i < nlen; i++) + uname[i] = oid->subs[uname_off + i + 1]; + uname[nlen] = '\0'; + + return (0); +} + +static void +usm_append_userindex(struct asn_oid *oid, uint sub, + const struct usm_user *uuser) +{ + uint32_t i; + + oid->len = sub + uuser->user_engine_len + strlen(uuser->suser.sec_name); + oid->len += 2; + oid->subs[sub] = uuser->user_engine_len; + for (i = 1; i < uuser->user_engine_len + 1; i++) + oid->subs[sub + i] = uuser->user_engine_id[i - 1]; + + sub += uuser->user_engine_len + 1; + oid->subs[sub] = strlen(uuser->suser.sec_name); + for (i = 1; i <= oid->subs[sub]; i++) + oid->subs[sub + i] = uuser->suser.sec_name[i - 1]; +} + +static struct usm_user * +usm_get_user(const struct asn_oid *oid, uint sub) +{ + uint32_t enginelen; + char username[SNMP_ADM_STR32_SIZ]; + uint8_t engineid[SNMP_ENGINE_ID_SIZ]; + + if (usm_user_index_decode(oid, sub, engineid, &enginelen, username) < 0) + return (NULL); + + return (usm_find_user(engineid, enginelen, username)); +} + +static struct usm_user * +usm_get_next_user(const struct asn_oid *oid, uint sub) +{ + uint32_t enginelen; + char username[SNMP_ADM_STR32_SIZ]; + uint8_t engineid[SNMP_ENGINE_ID_SIZ]; + struct usm_user *uuser; + + if (oid->len - sub == 0) + return (usm_first_user()); + + if (usm_user_index_decode(oid, sub, engineid, &enginelen, username) < 0) + return (NULL); + + if ((uuser = usm_find_user(engineid, enginelen, username)) != NULL) + return (usm_next_user(uuser)); + + return (NULL); +} + +/* + * USM snmp module initialization hook. + * Returns 0 on success, < 0 on error. + */ +static int +usm_init(struct lmodule * mod, int argc __unused, char *argv[] __unused) +{ + usm_module = mod; + usm_lock = random(); + bsnmpd_reset_usm_stats(); + return (0); +} + +/* + * USM snmp module finalization hook. + */ +static int +usm_fini(void) +{ + usm_flush_users(); + or_unregister(reg_usm); + + return (0); +} + +/* + * USM snmp module start operation. + */ +static void +usm_start(void) +{ + reg_usm = or_register(&oid_usm, + "The MIB module for managing SNMP User-Based Security Model.", + usm_module); +} + +static void +usm_dump(void) +{ + struct usm_user *uuser; + struct snmpd_usmstat *usmstats; + const char *const authstr[] = { + "noauth", + "md5", + "sha", + NULL + }; + const char *const privstr[] = { + "nopriv", + "des", + "aes", + NULL + }; + + if ((usmstats = bsnmpd_get_usm_stats()) != NULL) { + syslog(LOG_ERR, "UnsupportedSecLevels\t\t%u", + usmstats->unsupported_seclevels); + syslog(LOG_ERR, "NotInTimeWindows\t\t%u", + usmstats->not_in_time_windows); + syslog(LOG_ERR, "UnknownUserNames\t\t%u", + usmstats->unknown_users); + syslog(LOG_ERR, "UnknownEngineIDs\t\t%u", + usmstats->unknown_engine_ids); + syslog(LOG_ERR, "WrongDigests\t\t%u", + usmstats->wrong_digests); + syslog(LOG_ERR, "DecryptionErrors\t\t%u", + usmstats->decrypt_errors); + } + + syslog(LOG_ERR, "USM users"); + for (uuser = usm_first_user(); uuser != NULL; + (uuser = usm_next_user(uuser))) + syslog(LOG_ERR, "user %s\t\t%s, %s", uuser->suser.sec_name, + authstr[uuser->suser.auth_proto], + privstr[uuser->suser.priv_proto]); +} + +static const char usm_comment[] = +"This module implements SNMP User-based Security Model defined in RFC 3414."; + +extern const struct snmp_module config; +const struct snmp_module config = { + .comment = usm_comment, + .init = usm_init, + .fini = usm_fini, + .start = usm_start, + .tree = usm_ctree, + .dump = usm_dump, + .tree_size = usm_CTREE_SIZE, +}; Property changes on: vendor/1.14/snmp_usm/usm_snmp.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_usm/snmp_usm.3 =================================================================== --- vendor/1.14/snmp_usm/snmp_usm.3 (nonexistent) +++ vendor/1.14/snmp_usm/snmp_usm.3 (revision 359491) @@ -0,0 +1,132 @@ +.\"- +.\" Copyright (C) 2010 The FreeBSD Foundation +.\" All rights reserved. +.\" +.\" This documentation was written by Shteryana Sotirova Shopova under +.\" sponsorship from the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD: head/contrib/bsnmp/snmp_usm/snmp_usm.3 310648 2016-12-27 23:32:54Z ngie $ +.\" +.Dd September 9, 2010 +.Dt SNMP_USM 3 +.Os +.Sh NAME +.Nm snmp_usm +.Nd "user-based security module for" +.Xr bsnmpd 1 +.Sh LIBRARY +.Pq begemotSnmpdModulePath."usm" = "/usr/lib/snmp_usm.so" +.Sh DESCRIPTION +The +.Nm snmp_usm +module implements SNMPv3 User-Based Security Model MIB as defined in RFC 3414. +The module is used to manage the internal list of SNMPv3 USM active users in +.Nm bsnmpd . +The module must be loaded for +.Nm bsnmpd +to receive and process SNMPv3 USM PDUs correctly. +.Sh IMPLEMENTATION NOTES +A short description of the objects in the MIB follows. +.Bl -tag -width "XXXXXXXXX" +.It Va usmStats +The subtree contains statistics for the User-based Security Model PDU processing. +The statistics are reset each time the module is loaded. +.It Va usmUserSpinLock +An advisory lock used to coordinate several Command Generator Applications when +altering the SNMP USM users. +.It Va usmUserTable +The table contains all SNMP USM users configured in +.Nm bsnmpd . +The table contains the following objects +.Bl -tag -width ".It Va usmUserEngineID" +.It Va usmUserEngineID +An SNMP engine's administratively-unique identifier. Must be set to the same +Engine ID as +.Nm bsnmpd +so that the user will actually be allowed to communicate with the daemon. +The column is used as entry key and is not accessible for GET or SET operations. +.It Va usmUserName +The USM user name. The second entry key, again not accessible for GET or SET +operations. +.It Va usmUserSecurityName +The column has the exact same value as the +.Va usmUserName +column, however is accessible for GET operations. +.It Va usmUserCloneFrom +A GET on this column will return an empty OID. SET operations are currently not +supported. +.It Va usmUserAuthProtocol +The value of this column contains the OID corresponding to the authentication +protocol used by the USM user. The following protocols and their OIDs are known to +.Nm +module +.Bl -tag -width ".It Va NoAuthProtocol" +.It NoAuthProtocol 1.3.6.1.6.3.10.1.1.1 +.It HMACMD5AuthProtocol 1.3.6.1.6.3.10.1.1.2 +.It HMACSHAAuthProtocol 1.3.6.1.6.3.10.1.1.3 +.El +.It Va usmUserAuthKeyChange , Va usmUserOwnAuthKeyChange +These columns may be used to change the user's authentication key. +.It Va usmUserPrivProtocol +The value of this column contains the OID corresponding to the privacy +protocol used by the USM user. The following protocols and their OIDs are known to +.Nm +module +.Bl -tag -width ".It Va NoPrivProtocol" +.It NoPrivProtocol 1.3.6.1.6.3.10.1.2.1 +.It DESPrivProtoco 1.3.6.1.6.3.10.1.2.2 +.It AesCfb128Protocol 1.3.6.1.6.3.10.1.2.4 +.El +.It Va usmUserPrivKeyChange , Va usmUserOwnPrivKeyChange +These columns may be used to change the user's privacy key. +.It Va usmUserPublic +An arbitrary octet string that may be modified to confirm a SET operation on any +of the columns was successful. +.It Va usmUserStorageType +This column always has either of two values. Entries created via +.Nm bsnmpd's +configuration file always have this column set to readOnly (5) and +it is not possible to modify those entries. Entries created by Command Generator +Applications always have this column set to volatile(2) and such entries are +lost when the module is restarted. A SET operation on this column is not +allowed. +.It Va usmUserStatus +This column is used to create new USM user entries or delete existing ones from +the table. +.El +.El +.Sh FILES +.Bl -tag -width "XXXXXXXXX" +.It Pa /usr/share/snmp/defs/usm_tree.def +The description of the MIB tree implemented by +.Nm . +.El +.Sh SEE ALSO +.Xr bsnmpd 1 , +.Xr gensnmptree 1 , +.Xr snmpmod 3 +.Sh STANDARDS +IETF RFC 3414 +.Sh AUTHORS +.An Shteryana Shopova Aq syrinx@FreeBSD.org Property changes on: vendor/1.14/snmp_usm/snmp_usm.3 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_usm/usm_tree.def =================================================================== --- vendor/1.14/snmp_usm/usm_tree.def (nonexistent) +++ vendor/1.14/snmp_usm/usm_tree.def (revision 359491) @@ -0,0 +1,94 @@ +#- +# Copyright (C) 2010 The FreeBSD Foundation +# All rights reserved. +# +# This software was developed by Shteryana Sotirova Shopova under +# sponsorship from the FreeBSD Foundation. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +include "tc.def" + +(1 internet + (6 snmpV2 + (3 snmpModules + (10 snmpFrameworkMIB + (1 snmpFrameworkAdmin + (1 snmpAuthProtocols + (1 usmNoAuthProtocol + ) + (2 usmHMACMD5AuthProtocol + ) + (3 usmHMACSHAAuthProtocol + ) + ) + (2 snmpPrivProtocols + (1 usmNoPrivProtocol + ) + (2 usmDESPrivProtocol + ) + (4 usmAesCfb128Protocol + ) + ) + ) + ) + (15 snmpUsmMIB + (1 usmMIBObjects + (1 usmStats + (1 usmStatsUnsupportedSecLevels COUNTER op_usm_stats GET) + (2 usmStatsNotInTimeWindows COUNTER op_usm_stats GET) + (3 usmStatsUnknownUserNames COUNTER op_usm_stats GET) + (4 usmStatsUnknownEngineIDs COUNTER op_usm_stats GET) + (5 usmStatsWrongDigests COUNTER op_usm_stats GET) + (6 usmStatsDecryptionErrors COUNTER op_usm_stats GET) + ) + (2 usmUser + (1 usmUserSpinLock INTEGER op_usm_lock GET SET) + (2 usmUserTable + (1 usmUserEntry : OCTETSTRING | SnmpEngineID OCTETSTRING op_usm_users + (1 usmUserEngineID OCTETSTRING | SnmpEngineID) + (2 usmUserName OCTETSTRING) + (3 usmUserSecurityName OCTETSTRING | SnmpAdminString GET) + (4 usmUserCloneFrom OID GET SET) + (5 usmUserAuthProtocol OID GET SET) + (6 usmUserAuthKeyChange OCTETSTRING | KeyChange GET SET) + (7 usmUserOwnAuthKeyChange OCTETSTRING | KeyChange GET SET) + (8 usmUserPrivProtocol OID GET SET) + (9 usmUserPrivKeyChange OCTETSTRING | KeyChange GET SET) + (10 usmUserOwnPrivKeyChange OCTETSTRING | KeyChange GET SET) + (11 usmUserPublic OCTETSTRING GET SET) + (12 usmUserStorageType StorageType GET SET) + (13 usmUserStatus RowStatus GET SET) + ) + ) + ) + ) + ) + (20 snmpUsmAesMIB + ) + ) + ) +) + Property changes on: vendor/1.14/snmp_usm/usm_tree.def ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_vacm/vacm_snmp.c =================================================================== --- vendor/1.14/snmp_vacm/vacm_snmp.c (nonexistent) +++ vendor/1.14/snmp_vacm/vacm_snmp.c (revision 359491) @@ -0,0 +1,1028 @@ +/*- + * Copyright (c) 2010,2018 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Shteryana Sotirova Shopova under + * sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD: head/contrib/bsnmp/snmp_vacm/vacm_snmp.c 310648 2016-12-27 23:32:54Z ngie $ + */ +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "asn1.h" +#include "snmp.h" +#include "snmpmod.h" + +#define SNMPTREE_TYPES +#include "vacm_tree.h" +#include "vacm_oid.h" + +static struct lmodule *vacm_module; +/* For the registration. */ +static const struct asn_oid oid_vacm = OIDX_snmpVacmMIB; + +static uint reg_vacm; + +static int32_t vacm_lock; + +/* + * Internal datastructures and forward declarations. + */ +static void vacm_append_userindex(struct asn_oid *, + uint, const struct vacm_user *); +static int vacm_user_index_decode(const struct asn_oid *, + uint, int32_t *, char *); +static struct vacm_user *vacm_get_user(const struct asn_oid *, + uint); +static struct vacm_user *vacm_get_next_user(const struct asn_oid *, + uint); +static void vacm_append_access_rule_index(struct asn_oid *, + uint, const struct vacm_access *); +static int vacm_access_rule_index_decode(const struct asn_oid *, + uint, char *, char *, int32_t *, int32_t *); +static struct vacm_access * vacm_get_access_rule(const struct asn_oid *, + uint); +static struct vacm_access * vacm_get_next_access_rule(const struct asn_oid *, + uint); +static int vacm_view_index_decode(const struct asn_oid *, uint, + char *, struct asn_oid *); +static void vacm_append_viewindex(struct asn_oid *, uint, + const struct vacm_view *); +static struct vacm_view *vacm_get_view(const struct asn_oid *, uint); +static struct vacm_view *vacm_get_next_view(const struct asn_oid *, uint); +static struct vacm_view *vacm_get_view_by_name(u_char *, u_int); +static struct vacm_context *vacm_get_context(const struct asn_oid *, uint); +static struct vacm_context *vacm_get_next_context(const struct asn_oid *, + uint); +static void vacm_append_ctxindex(struct asn_oid *, uint, + const struct vacm_context *); + +int +op_vacm_context(struct snmp_context *ctx __unused, struct snmp_value *val, + uint32_t sub, uint32_t iidx __unused, enum snmp_op op) +{ + char cname[SNMP_ADM_STR32_SIZ]; + size_t cnamelen; + struct vacm_context *vacm_ctx; + + if (val->var.subs[sub - 1] != LEAF_vacmContextName) + abort(); + + switch (op) { + case SNMP_OP_GET: + if ((vacm_ctx = vacm_get_context(&val->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_GETNEXT: + if ((vacm_ctx = vacm_get_next_context(&val->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + vacm_append_ctxindex(&val->var, sub, vacm_ctx); + break; + + case SNMP_OP_SET: + if ((vacm_ctx = vacm_get_context(&val->var, sub)) != NULL) + return (SNMP_ERR_WRONG_VALUE); + if (community != COMM_INITIALIZE) + return (SNMP_ERR_NOT_WRITEABLE); + if (val->var.subs[sub] >= SNMP_ADM_STR32_SIZ) + return (SNMP_ERR_WRONG_VALUE); + if (index_decode(&val->var, sub, iidx, &cname, &cnamelen)) + return (SNMP_ERR_GENERR); + cname[cnamelen] = '\0'; + if ((vacm_ctx = vacm_add_context(cname, reg_vacm)) == NULL) + return (SNMP_ERR_GENERR); + return (SNMP_ERR_NOERROR); + + case SNMP_OP_COMMIT: + /* FALLTHROUGH*/ + case SNMP_OP_ROLLBACK: + return (SNMP_ERR_NOERROR); + default: + abort(); + } + + return (string_get(val, vacm_ctx->ctxname, -1)); +} + +int +op_vacm_security_to_group(struct snmp_context *ctx, struct snmp_value *val, + uint32_t sub, uint32_t iidx __unused, enum snmp_op op) +{ + int32_t smodel; + char uname[SNMP_ADM_STR32_SIZ]; + struct vacm_user *user; + + switch (op) { + case SNMP_OP_GET: + if ((user = vacm_get_user(&val->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_GETNEXT: + if ((user = vacm_get_next_user(&val->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + vacm_append_userindex(&val->var, sub, user); + break; + + case SNMP_OP_SET: + if ((user = vacm_get_user(&val->var, sub)) == NULL && + val->var.subs[sub - 1] != LEAF_vacmSecurityToGroupStatus) + return (SNMP_ERR_NOSUCHNAME); + + if (user != NULL) { + if (community != COMM_INITIALIZE && + user->type == StorageType_readOnly) + return (SNMP_ERR_NOT_WRITEABLE); + if (user->status == RowStatus_active && + val->v.integer != RowStatus_destroy) + return (SNMP_ERR_INCONS_VALUE); + } + + switch (val->var.subs[sub - 1]) { + case LEAF_vacmGroupName: + ctx->scratch->ptr1 = user->group->groupname; + ctx->scratch->int1 = strlen(user->group->groupname); + return (vacm_user_set_group(user, + val->v.octetstring.octets,val->v.octetstring.len)); + + case LEAF_vacmSecurityToGroupStorageType: + return (SNMP_ERR_INCONS_VALUE); + + case LEAF_vacmSecurityToGroupStatus: + if (user == NULL) { + if (val->v.integer != RowStatus_createAndGo || + vacm_user_index_decode(&val->var, sub, + &smodel, uname) < 0) + return (SNMP_ERR_INCONS_VALUE); + user = vacm_new_user(smodel, uname); + if (user == NULL) + return (SNMP_ERR_GENERR); + user->status = RowStatus_destroy; + if (community != COMM_INITIALIZE) + user->type = StorageType_volatile; + else + user->type = StorageType_readOnly; + } else if (val->v.integer != RowStatus_active && + val->v.integer != RowStatus_destroy) + return (SNMP_ERR_INCONS_VALUE); + ctx->scratch->int1 = user->status; + user->status = val->v.integer; + break; + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_COMMIT: + if (val->var.subs[sub - 1] != LEAF_vacmSecurityToGroupStatus) + return (SNMP_ERR_NOERROR); + if ((user = vacm_get_user(&val->var, sub)) == NULL) + return (SNMP_ERR_GENERR); + switch (val->v.integer) { + case RowStatus_destroy: + return (vacm_delete_user(user)); + + case RowStatus_createAndGo: + user->status = RowStatus_active; + break; + + default: + break; + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_ROLLBACK: + if ((user = vacm_get_user(&val->var, sub)) == NULL) + return (SNMP_ERR_GENERR); + switch (val->var.subs[sub - 1]) { + case LEAF_vacmGroupName: + return (vacm_user_set_group(user, ctx->scratch->ptr1, + ctx->scratch->int1)); + + case LEAF_vacmSecurityToGroupStatus: + if (ctx->scratch->int1 == RowStatus_destroy) + return (vacm_delete_user(user)); + user->status = ctx->scratch->int1; + break; + + default: + break; + } + return (SNMP_ERR_NOERROR); + + default: + abort(); + } + + switch (val->var.subs[sub - 1]) { + case LEAF_vacmGroupName: + return (string_get(val, user->group->groupname, -1)); + case LEAF_vacmSecurityToGroupStorageType: + val->v.integer = user->type; + break; + case LEAF_vacmSecurityToGroupStatus: + val->v.integer = user->status; + break; + default: + abort(); + } + + return (SNMP_ERR_NOERROR); +} + +int +op_vacm_access(struct snmp_context *ctx, struct snmp_value *val, uint32_t sub, + uint32_t iidx __unused, enum snmp_op op) +{ + int32_t smodel, slevel; + char gname[SNMP_ADM_STR32_SIZ], cprefix[SNMP_ADM_STR32_SIZ]; + struct vacm_access *acl; + + switch (op) { + case SNMP_OP_GET: + if ((acl = vacm_get_access_rule(&val->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_GETNEXT: + if ((acl = vacm_get_next_access_rule(&val->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + vacm_append_access_rule_index(&val->var, sub, acl); + break; + + case SNMP_OP_SET: + if ((acl = vacm_get_access_rule(&val->var, sub)) == NULL && + val->var.subs[sub - 1] != LEAF_vacmAccessStatus) + return (SNMP_ERR_NOSUCHNAME); + if (acl != NULL && community != COMM_INITIALIZE && + acl->type == StorageType_readOnly) + return (SNMP_ERR_NOT_WRITEABLE); + + switch (val->var.subs[sub - 1]) { + case LEAF_vacmAccessContextMatch: + ctx->scratch->int1 = acl->ctx_match; + if (val->v.integer == vacmAccessContextMatch_exact) + acl->ctx_match = 1; + else if (val->v.integer == vacmAccessContextMatch_prefix) + acl->ctx_match = 0; + else + return (SNMP_ERR_WRONG_VALUE); + break; + + case LEAF_vacmAccessReadViewName: + ctx->scratch->ptr1 = acl->read_view; + acl->read_view = vacm_get_view_by_name(val->v.octetstring.octets, val->v.octetstring.len); + if (acl->read_view == NULL) { + acl->read_view = ctx->scratch->ptr1; + return (SNMP_ERR_INCONS_VALUE); + } + return (SNMP_ERR_NOERROR); + + case LEAF_vacmAccessWriteViewName: + ctx->scratch->ptr1 = acl->write_view; + if ((acl->write_view = + vacm_get_view_by_name(val->v.octetstring.octets, + val->v.octetstring.len)) == NULL) { + acl->write_view = ctx->scratch->ptr1; + return (SNMP_ERR_INCONS_VALUE); + } + break; + + case LEAF_vacmAccessNotifyViewName: + ctx->scratch->ptr1 = acl->notify_view; + if ((acl->notify_view = + vacm_get_view_by_name(val->v.octetstring.octets, + val->v.octetstring.len)) == NULL) { + acl->notify_view = ctx->scratch->ptr1; + return (SNMP_ERR_INCONS_VALUE); + } + break; + + case LEAF_vacmAccessStorageType: + return (SNMP_ERR_INCONS_VALUE); + + case LEAF_vacmAccessStatus: + if (acl == NULL) { + if (val->v.integer != RowStatus_createAndGo || + vacm_access_rule_index_decode(&val->var, + sub, gname, cprefix, &smodel, &slevel) < 0) + return (SNMP_ERR_INCONS_VALUE); + if ((acl = vacm_new_access_rule(gname, cprefix, + smodel, slevel)) == NULL) + return (SNMP_ERR_GENERR); + acl->status = RowStatus_destroy; + if (community != COMM_INITIALIZE) + acl->type = StorageType_volatile; + else + acl->type = StorageType_readOnly; + } else if (val->v.integer != RowStatus_active && + val->v.integer != RowStatus_destroy) + return (SNMP_ERR_INCONS_VALUE); + ctx->scratch->int1 = acl->status; + acl->status = val->v.integer; + break; + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_COMMIT: + if (val->var.subs[sub - 1] != LEAF_vacmAccessStatus) + return (SNMP_ERR_NOERROR); + if ((acl = vacm_get_access_rule(&val->var, sub)) == NULL) + return (SNMP_ERR_GENERR); + if (val->v.integer == RowStatus_destroy) + return (vacm_delete_access_rule(acl)); + else + acl->status = RowStatus_active; + return (SNMP_ERR_NOERROR); + + case SNMP_OP_ROLLBACK: + if ((acl = vacm_get_access_rule(&val->var, sub)) == NULL) + return (SNMP_ERR_GENERR); + switch (val->var.subs[sub - 1]) { + case LEAF_vacmAccessContextMatch: + acl->ctx_match = ctx->scratch->int1; + break; + case LEAF_vacmAccessReadViewName: + acl->read_view = ctx->scratch->ptr1; + break; + case LEAF_vacmAccessWriteViewName: + acl->write_view = ctx->scratch->ptr1; + break; + case LEAF_vacmAccessNotifyViewName: + acl->notify_view = ctx->scratch->ptr1; + break; + case LEAF_vacmAccessStatus: + if (ctx->scratch->int1 == RowStatus_destroy) + return (vacm_delete_access_rule(acl)); + default: + break; + } + return (SNMP_ERR_NOERROR); + + default: + abort(); + } + + switch (val->var.subs[sub - 1]) { + case LEAF_vacmAccessContextMatch: + return (string_get(val, acl->ctx_prefix, -1)); + case LEAF_vacmAccessReadViewName: + if (acl->read_view != NULL) + return (string_get(val, acl->read_view->viewname, -1)); + else + return (string_get(val, NULL, 0)); + case LEAF_vacmAccessWriteViewName: + if (acl->write_view != NULL) + return (string_get(val, acl->write_view->viewname, -1)); + else + return (string_get(val, NULL, 0)); + case LEAF_vacmAccessNotifyViewName: + if (acl->notify_view != NULL) + return (string_get(val, acl->notify_view->viewname, -1)); + else + return (string_get(val, NULL, 0)); + case LEAF_vacmAccessStorageType: + val->v.integer = acl->type; + break; + case LEAF_vacmAccessStatus: + val->v.integer = acl->status; + break; + default: + abort(); + } + + return (SNMP_ERR_NOERROR); +} + +int +op_vacm_view_lock(struct snmp_context *ctx __unused, struct snmp_value *val, + uint32_t sub, uint32_t iidx __unused, enum snmp_op op) +{ + if (val->var.subs[sub - 1] != LEAF_vacmViewSpinLock) + return (SNMP_ERR_NOSUCHNAME); + + switch (op) { + case SNMP_OP_GET: + if (++vacm_lock == INT32_MAX) + vacm_lock = 0; + val->v.integer = vacm_lock; + break; + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_SET: + if (val->v.integer != vacm_lock) + return (SNMP_ERR_INCONS_VALUE); + break; + + case SNMP_OP_ROLLBACK: + /* FALLTHROUGH */ + case SNMP_OP_COMMIT: + break; + } + + return (SNMP_ERR_NOERROR); +} + +int +op_vacm_view(struct snmp_context *ctx, struct snmp_value *val, uint32_t sub, + uint32_t iidx __unused, enum snmp_op op) +{ + char vname[SNMP_ADM_STR32_SIZ]; + struct asn_oid oid; + struct vacm_view *view; + + switch (op) { + case SNMP_OP_GET: + if ((view = vacm_get_view(&val->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_GETNEXT: + if ((view = vacm_get_next_view(&val->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + vacm_append_viewindex(&val->var, sub, view); + break; + + case SNMP_OP_SET: + if ((view = vacm_get_view(&val->var, sub)) == NULL && + val->var.subs[sub - 1] != LEAF_vacmViewTreeFamilyStatus) + return (SNMP_ERR_NOSUCHNAME); + + if (view != NULL) { + if (community != COMM_INITIALIZE && + view->type == StorageType_readOnly) + return (SNMP_ERR_NOT_WRITEABLE); + if (view->status == RowStatus_active && + val->v.integer != RowStatus_destroy) + return (SNMP_ERR_INCONS_VALUE); + } + + switch (val->var.subs[sub - 1]) { + case LEAF_vacmViewTreeFamilyMask: + if (val->v.octetstring.len > sizeof(view->mask)) + ctx->scratch->ptr1 = malloc(sizeof(view->mask)); + if (ctx->scratch->ptr1 == NULL) + return (SNMP_ERR_GENERR); + memset(ctx->scratch->ptr1, 0, sizeof(view->mask)); + memcpy(ctx->scratch->ptr1, view->mask, + sizeof(view->mask)); + memset(view->mask, 0, sizeof(view->mask)); + memcpy(view->mask, val->v.octetstring.octets, + val->v.octetstring.len); + break; + + case LEAF_vacmViewTreeFamilyType: + ctx->scratch->int1 = view->exclude; + if (val->v.integer == vacmViewTreeFamilyType_included) + view->exclude = 0; + else if (val->v.integer == vacmViewTreeFamilyType_excluded) + view->exclude = 1; + else + return (SNMP_ERR_WRONG_VALUE); + break; + + case LEAF_vacmViewTreeFamilyStorageType: + return (SNMP_ERR_INCONS_VALUE); + + case LEAF_vacmViewTreeFamilyStatus: + if (view == NULL) { + if (val->v.integer != RowStatus_createAndGo || + vacm_view_index_decode(&val->var, sub, vname, + &oid) < 0) + return (SNMP_ERR_INCONS_VALUE); + if ((view = vacm_new_view(vname, &oid)) == NULL) + return (SNMP_ERR_GENERR); + view->status = RowStatus_destroy; + if (community != COMM_INITIALIZE) + view->type = StorageType_volatile; + else + view->type = StorageType_readOnly; + } else if (val->v.integer != RowStatus_active && + val->v.integer != RowStatus_destroy) + return (SNMP_ERR_INCONS_VALUE); + ctx->scratch->int1 = view->status; + view->status = val->v.integer; + break; + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_COMMIT: + switch (val->var.subs[sub - 1]) { + case LEAF_vacmViewTreeFamilyMask: + free(ctx->scratch->ptr1); + break; + case LEAF_vacmViewTreeFamilyStatus: + if ((view = vacm_get_view(&val->var, sub)) == NULL) + return (SNMP_ERR_GENERR); + switch (val->v.integer) { + case RowStatus_destroy: + return (vacm_delete_view(view)); + + case RowStatus_createAndGo: + view->status = RowStatus_active; + break; + + default: + /* NOTREACHED*/ + return (SNMP_ERR_GENERR); + } + default: + break; + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_ROLLBACK: + if ((view = vacm_get_view(&val->var, sub)) == NULL) + return (SNMP_ERR_GENERR); + switch (val->var.subs[sub - 1]) { + case LEAF_vacmViewTreeFamilyMask: + memcpy(view->mask, ctx->scratch->ptr1, + sizeof(view->mask)); + free(ctx->scratch->ptr1); + break; + case LEAF_vacmViewTreeFamilyType: + view->exclude = ctx->scratch->int1; + break; + case LEAF_vacmViewTreeFamilyStatus: + if (ctx->scratch->int1 == RowStatus_destroy) + return (vacm_delete_view(view)); + break; + default: + break; + } + return (SNMP_ERR_NOERROR); + + default: + abort(); + } + + switch (val->var.subs[sub - 1]) { + case LEAF_vacmViewTreeFamilyMask: + return (string_get(val, view->mask, sizeof(view->mask))); + case LEAF_vacmViewTreeFamilyType: + if (view->exclude) + val->v.integer = vacmViewTreeFamilyType_excluded; + else + val->v.integer = vacmViewTreeFamilyType_included; + break; + case LEAF_vacmViewTreeFamilyStorageType: + val->v.integer = view->type; + break; + case LEAF_vacmViewTreeFamilyStatus: + val->v.integer = view->status; + break; + default: + abort(); + } + + return (SNMP_ERR_NOERROR); +} + +static void +vacm_append_userindex(struct asn_oid *oid, uint sub, + const struct vacm_user *user) +{ + uint32_t i; + + oid->len = sub + strlen(user->secname) + 2; + oid->subs[sub++] = user->sec_model; + oid->subs[sub] = strlen(user->secname); + for (i = 1; i <= strlen(user->secname); i++) + oid->subs[sub + i] = user->secname[i - 1]; +} + +static int +vacm_user_index_decode(const struct asn_oid *oid, uint sub, + int32_t *smodel, char *uname) +{ + uint32_t i; + + *smodel = oid->subs[sub++]; + + if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ) + return (-1); + + for (i = 0; i < oid->subs[sub]; i++) + uname[i] = oid->subs[sub + i + 1]; + uname[i] = '\0'; + + return (0); +} + +static struct vacm_user * +vacm_get_user(const struct asn_oid *oid, uint sub) +{ + int32_t smodel; + char uname[SNMP_ADM_STR32_SIZ]; + struct vacm_user *user; + + if (vacm_user_index_decode(oid, sub, &smodel, uname) < 0) + return (NULL); + + for (user = vacm_first_user(); user != NULL; user = vacm_next_user(user)) + if (strcmp(uname, user->secname) == 0 && + user->sec_model == smodel) + return (user); + + return (NULL); +} + +static struct vacm_user * +vacm_get_next_user(const struct asn_oid *oid, uint sub) +{ + int32_t smodel; + char uname[SNMP_ADM_STR32_SIZ]; + struct vacm_user *user; + + if (oid->len - sub == 0) + return (vacm_first_user()); + + if (vacm_user_index_decode(oid, sub, &smodel, uname) < 0) + return (NULL); + + for (user = vacm_first_user(); user != NULL; user = vacm_next_user(user)) + if (strcmp(uname, user->secname) == 0 && + user->sec_model == smodel) + return (vacm_next_user(user)); + + return (NULL); +} + +static void +vacm_append_access_rule_index(struct asn_oid *oid, uint sub, + const struct vacm_access *acl) +{ + uint32_t i; + + oid->len = sub + strlen(acl->group->groupname) + + strlen(acl->ctx_prefix) + 4; + + oid->subs[sub] = strlen(acl->group->groupname); + for (i = 1; i <= strlen(acl->group->groupname); i++) + oid->subs[sub + i] = acl->group->groupname[i - 1]; + sub += strlen(acl->group->groupname) + 1; + + oid->subs[sub] = strlen(acl->ctx_prefix); + for (i = 1; i <= strlen(acl->ctx_prefix); i++) + oid->subs[sub + i] = acl->ctx_prefix[i - 1]; + sub += strlen(acl->ctx_prefix) + 1; + oid->subs[sub++] = acl->sec_model; + oid->subs[sub] = acl->sec_level; +} + +static int +vacm_access_rule_index_decode(const struct asn_oid *oid, uint sub, char *gname, + char *cprefix, int32_t *smodel, int32_t *slevel) +{ + uint32_t i; + + if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ) + return (-1); + + for (i = 0; i < oid->subs[sub]; i++) + gname[i] = oid->subs[sub + i + 1]; + gname[i] = '\0'; + sub += strlen(gname) + 1; + + if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ) + return (-1); + + for (i = 0; i < oid->subs[sub]; i++) + cprefix[i] = oid->subs[sub + i + 1]; + cprefix[i] = '\0'; + sub += strlen(cprefix) + 1; + + *smodel = oid->subs[sub++]; + *slevel = oid->subs[sub]; + + return (0); +} + +struct vacm_access * +vacm_get_access_rule(const struct asn_oid *oid, uint sub) +{ + int32_t smodel, slevel; + char gname[SNMP_ADM_STR32_SIZ], prefix[SNMP_ADM_STR32_SIZ]; + struct vacm_access *acl; + + if (vacm_access_rule_index_decode(oid, sub, gname, prefix, &smodel, + &slevel) < 0) + return (NULL); + + for (acl = vacm_first_access_rule(); acl != NULL; + acl = vacm_next_access_rule(acl)) + if (strcmp(gname, acl->group->groupname) == 0 && + strcmp(prefix, acl->ctx_prefix) == 0 && + smodel == acl->sec_model && slevel == acl->sec_level) + return (acl); + + return (NULL); +} + +struct vacm_access * +vacm_get_next_access_rule(const struct asn_oid *oid __unused, uint sub __unused) +{ + int32_t smodel, slevel; + char gname[SNMP_ADM_STR32_SIZ], prefix[SNMP_ADM_STR32_SIZ]; + struct vacm_access *acl; + + if (oid->len - sub == 0) + return (vacm_first_access_rule()); + + if (vacm_access_rule_index_decode(oid, sub, gname, prefix, &smodel, + &slevel) < 0) + return (NULL); + + for (acl = vacm_first_access_rule(); acl != NULL; + acl = vacm_next_access_rule(acl)) + if (strcmp(gname, acl->group->groupname) == 0 && + strcmp(prefix, acl->ctx_prefix) == 0 && + smodel == acl->sec_model && slevel == acl->sec_model) + return (vacm_next_access_rule(acl)); + + return (NULL); +} + +static int +vacm_view_index_decode(const struct asn_oid *oid, uint sub, char *vname, + struct asn_oid *view_oid) +{ + uint32_t i; + int viod_off; + + if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ) + return (-1); + + for (i = 0; i < oid->subs[sub]; i++) + vname[i] = oid->subs[sub + i + 1]; + vname[i] = '\0'; + + viod_off = sub + oid->subs[sub] + 1; + if ((view_oid->len = oid->subs[viod_off]) > ASN_MAXOIDLEN) + return (-1); + + memcpy(&view_oid->subs[0], &oid->subs[viod_off + 1], + view_oid->len * sizeof(view_oid->subs[0])); + + return (0); +} + +static void +vacm_append_viewindex(struct asn_oid *oid, uint sub, const struct vacm_view *view) +{ + uint32_t i; + + oid->len = sub + strlen(view->viewname) + 1; + oid->subs[sub] = strlen(view->viewname); + for (i = 1; i <= strlen(view->viewname); i++) + oid->subs[sub + i] = view->viewname[i - 1]; + + sub += strlen(view->viewname) + 1; + oid->subs[sub] = view->subtree.len; + oid->len++; + asn_append_oid(oid, &view->subtree); +} + +struct vacm_view * +vacm_get_view(const struct asn_oid *oid, uint sub) +{ + char vname[SNMP_ADM_STR32_SIZ]; + struct asn_oid subtree; + struct vacm_view *view; + + if (vacm_view_index_decode(oid, sub, vname, &subtree) < 0) + return (NULL); + + for (view = vacm_first_view(); view != NULL; view = vacm_next_view(view)) + if (strcmp(vname, view->viewname) == 0 && + asn_compare_oid(&subtree, &view->subtree)== 0) + return (view); + + return (NULL); +} + +struct vacm_view * +vacm_get_next_view(const struct asn_oid *oid, uint sub) +{ + char vname[SNMP_ADM_STR32_SIZ]; + struct asn_oid subtree; + struct vacm_view *view; + + if (oid->len - sub == 0) + return (vacm_first_view()); + + if (vacm_view_index_decode(oid, sub, vname, &subtree) < 0) + return (NULL); + + for (view = vacm_first_view(); view != NULL; view = vacm_next_view(view)) + if (strcmp(vname, view->viewname) == 0 && + asn_compare_oid(&subtree, &view->subtree)== 0) + return (vacm_next_view(view)); + + return (NULL); +} + +static struct vacm_view * +vacm_get_view_by_name(u_char *octets, u_int len) +{ + struct vacm_view *view; + + for (view = vacm_first_view(); view != NULL; view = vacm_next_view(view)) + if (strlen(view->viewname) == len && + memcmp(octets, view->viewname, len) == 0) + return (view); + + return (NULL); +} + +static struct vacm_context * +vacm_get_context(const struct asn_oid *oid, uint sub) +{ + char cname[SNMP_ADM_STR32_SIZ]; + size_t cnamelen; + u_int index_count; + struct vacm_context *vacm_ctx; + + if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ) + return (NULL); + + index_count = 0; + index_count = SNMP_INDEX(index_count, 1); + if (index_decode(oid, sub, index_count, &cname, &cnamelen)) + return (NULL); + + for (vacm_ctx = vacm_first_context(); vacm_ctx != NULL; + vacm_ctx = vacm_next_context(vacm_ctx)) + if (strcmp(cname, vacm_ctx->ctxname) == 0) + return (vacm_ctx); + + return (NULL); +} + +static struct vacm_context * +vacm_get_next_context(const struct asn_oid *oid, uint sub) +{ + char cname[SNMP_ADM_STR32_SIZ]; + size_t cnamelen; + u_int index_count; + struct vacm_context *vacm_ctx; + + if (oid->len - sub == 0) + return (vacm_first_context()); + + if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ) + return (NULL); + + index_count = 0; + index_count = SNMP_INDEX(index_count, 1); + if (index_decode(oid, sub, index_count, &cname, &cnamelen)) + return (NULL); + + for (vacm_ctx = vacm_first_context(); vacm_ctx != NULL; + vacm_ctx = vacm_next_context(vacm_ctx)) + if (strcmp(cname, vacm_ctx->ctxname) == 0) + return (vacm_next_context(vacm_ctx)); + + return (NULL); +} + +static void +vacm_append_ctxindex(struct asn_oid *oid, uint sub, + const struct vacm_context *ctx) +{ + uint32_t i; + + oid->len = sub + strlen(ctx->ctxname) + 1; + oid->subs[sub] = strlen(ctx->ctxname); + for (i = 1; i <= strlen(ctx->ctxname); i++) + oid->subs[sub + i] = ctx->ctxname[i - 1]; +} + +/* + * VACM snmp module initialization hook. + * Returns 0 on success, < 0 on error. + */ +static int +vacm_init(struct lmodule *mod, int argc __unused, char *argv[] __unused) +{ + vacm_module = mod; + vacm_lock = random(); + vacm_groups_init(); + + /* XXX: TODO - initialize structures */ + return (0); +} + +/* + * VACM snmp module finalization hook. + */ +static int +vacm_fini(void) +{ + /* XXX: TODO - cleanup */ + vacm_flush_contexts(reg_vacm); + or_unregister(reg_vacm); + + return (0); +} + +/* + * VACM snmp module start operation. + */ +static void +vacm_start(void) +{ + static char dflt_ctx[] = ""; + + reg_vacm = or_register(&oid_vacm, + "The MIB module for managing SNMP View-based Access Control Model.", + vacm_module); + + (void)vacm_add_context(dflt_ctx, reg_vacm); +} + +static void +vacm_dump(void) +{ + struct vacm_context *vacmctx; + struct vacm_user *vuser; + struct vacm_access *vacl; + struct vacm_view *view; + static char oidbuf[ASN_OIDSTRLEN]; + + syslog(LOG_ERR, "\n"); + syslog(LOG_ERR, "Context list:"); + for (vacmctx = vacm_first_context(); vacmctx != NULL; + vacmctx = vacm_next_context(vacmctx)) + syslog(LOG_ERR, "Context \"%s\", module id %d", + vacmctx->ctxname, vacmctx->regid); + + syslog(LOG_ERR, "VACM users:"); + for (vuser = vacm_first_user(); vuser != NULL; + vuser = vacm_next_user(vuser)) + syslog(LOG_ERR, "Uname %s, Group %s, model %d", vuser->secname, + vuser->group!= NULL?vuser->group->groupname:"Unknown", + vuser->sec_model); + + syslog(LOG_ERR, "VACM Access rules:"); + for (vacl = vacm_first_access_rule(); vacl != NULL; + vacl = vacm_next_access_rule(vacl)) + syslog(LOG_ERR, "Group %s, CtxPrefix %s, Model %d, Level %d, " + "RV %s, WR %s, NV %s", vacl->group!=NULL? + vacl->group->groupname:"Unknown", vacl->ctx_prefix, + vacl->sec_model, vacl->sec_level, vacl->read_view!=NULL? + vacl->read_view->viewname:"None", vacl->write_view!=NULL? + vacl->write_view->viewname:"None", vacl->notify_view!=NULL? + vacl->notify_view->viewname:"None"); + + syslog(LOG_ERR, "VACM Views:"); + for (view = vacm_first_view(); view != NULL; view = vacm_next_view(view)) + syslog(LOG_ERR, "View %s, Tree %s - %s", view->viewname, + asn_oid2str_r(&view->subtree, oidbuf), view->exclude? + "excluded":"included"); +} + +static const char vacm_comment[] = +"This module implements SNMP View-based Access Control Model defined in RFC 3415."; + +extern const struct snmp_module config; +const struct snmp_module config = { + .comment = vacm_comment, + .init = vacm_init, + .fini = vacm_fini, + .start = vacm_start, + .tree = vacm_ctree, + .dump = vacm_dump, + .tree_size = vacm_CTREE_SIZE, +}; Property changes on: vendor/1.14/snmp_vacm/vacm_snmp.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_vacm/snmp_vacm.3 =================================================================== --- vendor/1.14/snmp_vacm/snmp_vacm.3 (nonexistent) +++ vendor/1.14/snmp_vacm/snmp_vacm.3 (revision 359491) @@ -0,0 +1,94 @@ +.\"- +.\" Copyright (C) 2010 The FreeBSD Foundation +.\" All rights reserved. +.\" +.\" This documentation was written by Shteryana Sotirova Shopova under +.\" sponsorship from the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD: head/contrib/bsnmp/snmp_vacm/snmp_vacm.3 310648 2016-12-27 23:32:54Z ngie $ +.\" +.Dd October 7, 2010 +.Dt SNMP_VACM 3 +.Os +.Sh NAME +.Nm snmp_vacm +.Nd "View-based Access Control module for" +.Xr bsnmpd 1 +.Sh LIBRARY +.Pq begemotSnmpdModulePath."vacm" = "/usr/lib/snmp_vacm.so" +.Sh DESCRIPTION +The +.Nm snmp_vacm +module implements SNMPv3 View-based Access Control Model MIB as defined in +RFC 3415. The module is used to manage the internal lists of SNMPv1, v2c and +v3 user names and groups and their access rights to fetch or modify the values +of the MIB objects maintained by +.Nm bsnmpd +and the modules loaded in the daemon. +The module must be loaded for +.Nm bsnmpd +to implement proper view-based access control. If the module is not loaded, +access is granted to all configured SNMPv1 & SNMPv2c communities and SNMPv3 +USM users. +.Sh IMPLEMENTATION NOTES +An entry in any table implemented by this MIB may be created by setting the +relevant RowStatus column to createAndGo (4) - in fact, any other value for +those columns in a SET operation will cause an error. When an entry is created, +any of its columns that is not used as index, is set to the default value as +specified in the SNMP-VIEW-BASED-ACM-MIB. All entries maintained by the module +are persistent after reboot if created via +.Nm bsnmpd 's +config file, otherwise entries created via SNMP are lost after reboot. +A short description of the objects in the MIB follows. +.Bl -tag -width "XXXXXXXXX" +.It Va vacmContextTable +A read-only table that consists of a list of SNMP contexts available in +.Nm bsnmpd . +.It Va vacmSecurityToGroupTable +The table contains a list of SNMPv1, v2c and v3 user names and the groups +they belong to. +.It Va vacmAccessTable +The table contains a list of SNMP contexts to groups mappings and respectively +the names of the SNMP views under those contexts, to which users in the group +are granted read-only, read-write access or receive notifications for the +objects under the subtree in the relevant view. +.It Va vacmViewTreeFamilyTable +The table contains a list of SNMP views, i.e. entries specifying the OID of a +MIB subtree and whether access to the objects under this subtree is to be +allowed or forbidden. +.El +.Sh FILES +.Bl -tag -width "XXXXXXXXX" +.It Pa /usr/share/snmp/defs/vacm_tree.def +The description of the MIB tree implemented by +.Nm . +.El +.Sh SEE ALSO +.Xr bsnmpd 1 , +.Xr gensnmptree 1 , +.Xr snmpmod 3 +.Sh STANDARDS +IETF RFC 3415 +.Sh AUTHORS +.An Shteryana Shopova Aq syrinx@FreeBSD.org Property changes on: vendor/1.14/snmp_vacm/snmp_vacm.3 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmp_vacm/vacm_tree.def =================================================================== --- vendor/1.14/snmp_vacm/vacm_tree.def (nonexistent) +++ vendor/1.14/snmp_vacm/vacm_tree.def (revision 359491) @@ -0,0 +1,89 @@ +#- +# Copyright (C) 2010 The FreeBSD Foundation +# All rights reserved. +# +# This software was developed by Shteryana Sotirova Shopova under +# sponsorship from the FreeBSD Foundation. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +include "tc.def" + +(1 internet + (6 snmpV2 + (3 snmpModules + (16 snmpVacmMIB + (1 vacmMIBObjects + (1 vacmContextTable + (1 vacmContextEntry : OCTETSTRING op_vacm_context + (1 vacmContextName OCTETSTRING GET) + ) + ) + (2 vacmSecurityToGroupTable + (1 vacmSecurityToGroupEntry : INTEGER OCTETSTRING op_vacm_security_to_group + (1 vacmSecurityModel INTEGER) + (2 vacmSecurityName OCTETSTRING) + (3 vacmGroupName OCTETSTRING GET SET) + (4 vacmSecurityToGroupStorageType StorageType GET SET) + (5 vacmSecurityToGroupStatus RowStatus GET SET) + ) + ) + (4 vacmAccessTable + (1 vacmAccessEntry : OCTETSTRING OCTETSTRING INTEGER ENUM ( 1 noAuthNoPriv 2 authNoPriv 3 authPriv ) op_vacm_access + (1 vacmAccessContextPrefix OCTETSTRING) + (2 vacmAccessSecurityModel INTEGER) + (3 vacmAccessSecurityLevel ENUM ( 1 noAuthNoPriv 2 authNoPriv 3 authPriv )) + (4 vacmAccessContextMatch ENUM ( 1 exact 2 prefix ) GET SET) + (5 vacmAccessReadViewName OCTETSTRING GET SET) + (6 vacmAccessWriteViewName OCTETSTRING GET SET) + (7 vacmAccessNotifyViewName OCTETSTRING GET SET) + (8 vacmAccessStorageType StorageType GET SET) + (9 vacmAccessStatus RowStatus GET SET) + ) + ) + (5 vacmMIBViews + (1 vacmViewSpinLock INTEGER op_vacm_view_lock GET SET) + (2 vacmViewTreeFamilyTable + (1 vacmViewTreeFamilyEntry : OCTETSTRING OID op_vacm_view + (1 vacmViewTreeFamilyViewName OCTETSTRING) + (2 vacmViewTreeFamilySubtree OID) + (3 vacmViewTreeFamilyMask OCTETSTRING GET SET) + (4 vacmViewTreeFamilyType ENUM ( 1 included 2 excluded ) GET SET) + (5 vacmViewTreeFamilyStorageType StorageType GET SET) + (6 vacmViewTreeFamilyStatus RowStatus GET SET) + ) + ) + ) + ) + (2 vacmMIBConformance + (1 vacmMIBCompliances + ) + (2 vacmMIBGroups + ) + ) + ) + ) + ) +) Property changes on: vendor/1.14/snmp_vacm/vacm_tree.def ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmpd/BEGEMOT-SNMPD.txt =================================================================== --- vendor/1.14/snmpd/BEGEMOT-SNMPD.txt (nonexistent) +++ vendor/1.14/snmpd/BEGEMOT-SNMPD.txt (revision 359491) @@ -0,0 +1,691 @@ +-- +-- Copyright (c) 2001-2003 +-- Fraunhofer Institute for Open Communication Systems (FhG Fokus). +-- All rights reserved. +-- +-- Copyright (c) 2018 +-- Hartmut Brandt. +-- All rights reserved. +-- +-- Author: Harti Brandt +-- +-- Redistribution and use in source and binary forms, with or without +-- modification, are permitted provided that the following conditions +-- are met: +-- 1. Redistributions of source code must retain the above copyright +-- notice, this list of conditions and the following disclaimer. +-- 2. Redistributions in binary form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +-- ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +-- SUCH DAMAGE. +-- +-- $Begemot: bsnmp/snmpd/BEGEMOT-SNMPD.txt,v 1.23 2004/08/06 08:47:08 brandt Exp $ +-- +-- Begemot Private SNMPd MIB. +-- +BEGEMOT-SNMPD-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, OBJECT-IDENTITY, Counter32, + Integer32, Unsigned32, IpAddress + FROM SNMPv2-SMI + TEXTUAL-CONVENTION, TruthValue, RowStatus + FROM SNMPv2-TC + InetAddressType, InetAddress, InetPortNumber + FROM INET-ADDRESS-MIB + begemot + FROM BEGEMOT-MIB; + +begemotSnmpd MODULE-IDENTITY + LAST-UPDATED "201808080000Z" + ORGANIZATION "Fraunhofer FOKUS, CATS" + CONTACT-INFO + " Hartmut Brandt + + Postal: Fraunhofer Institute for Open Communication Systems + Kaiserin-Augusta-Allee 31 + 10589 Berlin + Germany + + Fax: +49 30 3463 7352 + + E-mail: harti@freebsd.org" + DESCRIPTION + "The MIB module for the Begemot SNMP daemon." + REVISION "201808080000Z" + DESCRIPTION + "Add the begemotSnmpdTransInetTable." + ::= { begemot 1 } + +begemotSnmpdObjects OBJECT IDENTIFIER ::= { begemotSnmpd 1 } +begemotSnmpdDefs OBJECT IDENTIFIER ::= { begemotSnmpd 2 } + +-- -------------------------------------------------------------------------- + +SectionName ::= TEXTUAL-CONVENTION + DISPLAY-HINT "14a" + STATUS current + DESCRIPTION + "Name of a loadable module. Should consist of alphanumeric characers + only, the first character must be a letter." + SYNTAX OCTET STRING (SIZE(1..14)) + +-- -------------------------------------------------------------------------- +-- +-- Agent types +-- +begemotSnmpdAgent OBJECT IDENTIFIER ::= { begemotSnmpdDefs 1 } + +begemotSnmpdAgentFreeBSD OBJECT-IDENTITY + STATUS current + DESCRIPTION + "Identifies the agent as running on FreeBSD." + ::= { begemotSnmpdAgent 1 } + +-- -------------------------------------------------------------------------- +-- +-- The Config Group +-- +begemotSnmpdConfig OBJECT IDENTIFIER ::= { begemotSnmpdObjects 1 } + +begemotSnmpdTransmitBuffer OBJECT-TYPE + SYNTAX Integer32 (484..65535) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The size of the receive buffer in bytes. Larger messages + are dropped by SNMPd." + DEFVAL { 2048 } + ::= { begemotSnmpdConfig 1 } + +begemotSnmpdReceiveBuffer OBJECT-TYPE + SYNTAX Integer32 (484..65535) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The size of the transmit buffer in bytes. Larger messages + cannot be sent by the SNMPd." + DEFVAL { 2048 } + ::= { begemotSnmpdConfig 2 } + +begemotSnmpdCommunityDisable OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Disables all access to the CommunityTable from SNMP. Once + set it cannot be cleared." + DEFVAL { false } + ::= { begemotSnmpdConfig 3 } + +begemotSnmpdTrap1Addr OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The trap sink for v1 traps." + ::= { begemotSnmpdConfig 4 } + +begemotSnmpdVersionEnable OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The SNMP versions that the agent processes. The following + bits are defined: + + 0x00000001 - SNMPv1 + 0x00000002 - SNMPv2c + 0x00000004 - SNMPv3" + DEFVAL { 3 } + ::= { begemotSnmpdConfig 5 } + +-- +-- Trap destinations +-- +begemotTrapSinkTable OBJECT-TYPE + SYNTAX SEQUENCE OF BegemotTrapSinkEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table with destinations for standard traps." + INDEX { begemotTrapSinkAddr, begemotTrapSinkPort } + ::= { begemotSnmpdObjects 2 } + +begemotTrapSinkEntry OBJECT-TYPE + SYNTAX BegemotTrapSinkEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Entry describes one trap destination." + INDEX { begemotTrapSinkAddr, begemotTrapSinkPort } + ::= { begemotTrapSinkTable 1 } + +BegemotTrapSinkEntry ::= SEQUENCE { + begemotTrapSinkAddr IpAddress, + begemotTrapSinkPort INTEGER, + begemotTrapSinkStatus RowStatus +} + +begemotTrapSinkAddr OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Destination IP address of the manager station where to send + traps." + ::= { begemotTrapSinkEntry 1 } + +begemotTrapSinkPort OBJECT-TYPE + SYNTAX Integer32 (1..65535) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Destination UDP port of the manager station where to send + traps." + ::= { begemotTrapSinkEntry 2 } + +begemotTrapSinkStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Used to create/activate/destroy the entry." + ::= { begemotTrapSinkEntry 3 } + +-- +-- SNMP port table +-- +begemotSnmpdPortTable OBJECT-TYPE + SYNTAX SEQUENCE OF BegemotSnmpdPortEntry + MAX-ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "A table with descriptions of UDP ports to listen on + for SNMP messages." + ::= { begemotSnmpdObjects 4 } + +begemotSnmpdPortEntry OBJECT-TYPE + SYNTAX BegemotSnmpdPortEntry + MAX-ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "An entry in the table with descriptions of UDP ports to + listen on for SNMP messages." + INDEX { begemotSnmpdPortAddress, begemotSnmpdPortPort } + ::= { begemotSnmpdPortTable 1 } + +BegemotSnmpdPortEntry ::= SEQUENCE { + begemotSnmpdPortAddress IpAddress, + begemotSnmpdPortPort INTEGER, + begemotSnmpdPortStatus INTEGER +} + +begemotSnmpdPortAddress OBJECT-TYPE + SYNTAX IpAddress + MAX-ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "The IP address to bind to." + ::= { begemotSnmpdPortEntry 1 } + +begemotSnmpdPortPort OBJECT-TYPE + SYNTAX Integer32 (1..65535) + MAX-ACCESS not-accessible + STATUS deprecated + DESCRIPTION + "The UDP port to listen on for SNMP messages." + ::= { begemotSnmpdPortEntry 2 } + +begemotSnmpdPortStatus OBJECT-TYPE + SYNTAX INTEGER { valid(1), invalid(2) } + MAX-ACCESS read-create + STATUS deprecated + DESCRIPTION + "Set status to 1 to create entry, set it to 2 to delete it." + ::= { begemotSnmpdPortEntry 3 } + +--- +--- Community table +--- +begemotSnmpdCommunityTable OBJECT-TYPE + SYNTAX SEQUENCE OF BegemotSnmpdCommunityEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table with the community strings for access control." + ::= { begemotSnmpdObjects 5 } + +begemotSnmpdCommunityEntry OBJECT-TYPE + SYNTAX BegemotSnmpdCommunityEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table with the community strings for access control. + When begemotSnmpdCommDisable is true, this table disappears." + INDEX { begemotSnmpdCommunityModule, begemotSnmpdCommunityIndex } + ::= { begemotSnmpdCommunityTable 1 } + +BegemotSnmpdCommunityEntry ::= SEQUENCE { + begemotSnmpdCommunityModule SectionName, + begemotSnmpdCommunityIndex Unsigned32, + begemotSnmpdCommunityString OCTET STRING, + begemotSnmpdCommunityDescr OCTET STRING, + begemotSnmpdCommunityPermission Unsigned32 +} + +begemotSnmpdCommunityModule OBJECT-TYPE + SYNTAX SectionName + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Index of the module that has registered this community. + For global communities this is the empty string." + ::= { begemotSnmpdCommunityEntry 1 } + +begemotSnmpdCommunityIndex OBJECT-TYPE + SYNTAX Unsigned32 (1..4294967295) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The numerical index of the community (private to the module)." + ::= { begemotSnmpdCommunityEntry 2 } + +begemotSnmpdCommunityString OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "The string for access to SNMPd." + ::= { begemotSnmpdCommunityEntry 3 } + +begemotSnmpdCommunityDescr OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A description what this community is good for." + ::= { begemotSnmpdCommunityEntry 4 } + +begemotSnmpdCommunityPermission OBJECT-TYPE + SYNTAX Unsigned32 (1..4294967295) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The numerical value of access rights granted to the community." + ::= { begemotSnmpdCommunityEntry 5 } + +-- +-- Module table +-- +begemotSnmpdModuleTable OBJECT-TYPE + SYNTAX SEQUENCE OF BegemotSnmpdModuleEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table describing all the currently loaded dynamic modules. + Writing to this table loads and unloads modules." + ::= { begemotSnmpdObjects 6 } + +begemotSnmpdModuleEntry OBJECT-TYPE + SYNTAX BegemotSnmpdModuleEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table entry describing a loadable module." + INDEX { begemotSnmpdModuleSection } + ::= { begemotSnmpdModuleTable 1 } + +BegemotSnmpdModuleEntry ::= SEQUENCE { + begemotSnmpdModuleSection SectionName, + begemotSnmpdModulePath OCTET STRING, + begemotSnmpdModuleComment OCTET STRING +} + +begemotSnmpdModuleSection OBJECT-TYPE + SYNTAX SectionName + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The string used for matching configuration file sections + and indexes the module table." + ::= { begemotSnmpdModuleEntry 1 } + + +begemotSnmpdModulePath OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The path name of the module. Set to empty string + to unload a module. The path of an existing module + may not be changed." + ::= { begemotSnmpdModuleEntry 2 } + +begemotSnmpdModuleComment OBJECT-TYPE + SYNTAX OCTET STRING + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A comment describing this module." + ::= { begemotSnmpdModuleEntry 3 } + + +-- -------------------------------------------------------------------------- +-- +-- The STATISTICS Group +-- +begemotSnmpdStats OBJECT IDENTIFIER ::= { begemotSnmpdObjects 7 } + +begemotSnmpdStatsNoRxBufs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of times a receive buffer could not be allocated + for a packet." + ::= { begemotSnmpdStats 1 } + +begemotSnmpdStatsNoTxBufs OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of times a transmit buffer could not be allocated + for a packet." + ::= { begemotSnmpdStats 2 } + +begemotSnmpdStatsInTooLongPkts OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of packets received that were longer than the + receive buffer. These packets are dropped." + ::= { begemotSnmpdStats 3 } + +begemotSnmpdStatsInBadPduTypes OBJECT-TYPE + SYNTAX Counter32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Number of packets received with a bad type field." + ::= { begemotSnmpdStats 4 } + +-- +-- The Debug Group +-- +begemotSnmpdDebug OBJECT IDENTIFIER ::= { begemotSnmpdObjects 8 } + +begemotSnmpdDebugDumpPdus OBJECT-TYPE + SYNTAX TruthValue + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Dump PDUs to log file if true." + DEFVAL { false } + ::= { begemotSnmpdDebug 1 } + +begemotSnmpdDebugSnmpTrace OBJECT-TYPE + SYNTAX Unsigned32 + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Tracing flags for the SNMP library. These flags have the + following meaning: + 0x00000001 trace GET operator + 0x00000002 trace GETNEXT operator + 0x00000004 trace SET operator + 0x00000008 trace dependency processing + 0x00000010 trace node finding + 0x10000000 log ASN1 errors + 0x20000000 log SNMP errors + Individual values can be or-ed together." + DEFVAL { 0 } + ::= { begemotSnmpdDebug 2 } + +begemotSnmpdDebugSyslogPri OBJECT-TYPE + SYNTAX Integer32 (0..8) + MAX-ACCESS read-write + STATUS current + DESCRIPTION + "Events with this or higher priority should not be logged." + DEFVAL { 7 } -- don't log debug messages + ::= { begemotSnmpdDebug 3 } + +-- +-- Local port table +-- +begemotSnmpdLocalPortTable OBJECT-TYPE + SYNTAX SEQUENCE OF BegemotSnmpdLocalPortEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table with descriptions of local (unix domain) ports to listen + on for SNMP messages." + ::= { begemotSnmpdObjects 9 } + +begemotSnmpdLocalPortEntry OBJECT-TYPE + SYNTAX BegemotSnmpdLocalPortEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An entry in the table with descriptions of local ports to + listen on for SNMP messages." + INDEX { begemotSnmpdLocalPortPath } + ::= { begemotSnmpdLocalPortTable 1 } + +BegemotSnmpdLocalPortEntry ::= SEQUENCE { + begemotSnmpdLocalPortPath OCTET STRING, + begemotSnmpdLocalPortStatus INTEGER, + begemotSnmpdLocalPortType INTEGER +} + +begemotSnmpdLocalPortPath OBJECT-TYPE + SYNTAX OCTET STRING (SIZE(1..104)) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The path name to create and listen on." + ::= { begemotSnmpdLocalPortEntry 1 } + +begemotSnmpdLocalPortStatus OBJECT-TYPE + SYNTAX INTEGER { valid(1), invalid(2) } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Set status to 1 to create entry, set it to 2 to delete it." + ::= { begemotSnmpdLocalPortEntry 2 } + +begemotSnmpdLocalPortType OBJECT-TYPE + SYNTAX INTEGER { + dgram-unpriv(1), + dgram-priv(2), + stream-unpriv(3), + stream-priv(4) + } + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "Type of the port. If the type is unpriv SET operations + are allowed from all clients if the community matches. For + priv SET operations are allowed only from peers with uid + zero. If the daemon cannot determine the peer uid it disallows + the SET operation for -priv ports." + ::= { begemotSnmpdLocalPortEntry 3 } + +-- +-- Transport mapping table +-- +begemotSnmpdTransportMappings OBJECT IDENTIFIER ::= { begemotSnmpdObjects 10 } + +begemotSnmpdTransportTable OBJECT-TYPE + SYNTAX SEQUENCE OF BegemotSnmpdTransportEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A table containing all the currently loaded transport mappings." + ::= { begemotSnmpdTransportMappings 1 } + +begemotSnmpdTransportEntry OBJECT-TYPE + SYNTAX BegemotSnmpdTransportEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An entry in the table with the transport mappings." + INDEX { begemotSnmpdTransportName } + ::= { begemotSnmpdTransportTable 1 } + +BegemotSnmpdTransportEntry ::= SEQUENCE { + begemotSnmpdTransportName OCTET STRING, + begemotSnmpdTransportStatus INTEGER, + begemotSnmpdTransportOid OBJECT IDENTIFIER +} + +begemotSnmpdTransportName OBJECT-TYPE + SYNTAX OCTET STRING (SIZE(1..256)) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The name of the mapping." + ::= { begemotSnmpdTransportEntry 1 } + +begemotSnmpdTransportStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Used to create/activate/destroy the entry." + ::= { begemotSnmpdTransportEntry 2 } + +begemotSnmpdTransportOid OBJECT-TYPE + SYNTAX OBJECT IDENTIFIER + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "A pointer to the group with the transport-dependend stuff." + ::= { begemotSnmpdTransportEntry 3 } + +-- ---------------------------------------------------------------------- +-- +-- Internet port table. +-- +BegemotSnmpdTransportProto ::= TEXTUAL-CONVENTION + STATUS current + DESCRIPTION + "A value that represents the type of protocol to be used for + listening on a socket. The following protocols are currently + used: + + udp(1) Use UDP for IPv4 and IPv6 sockets." + SYNTAX INTEGER { + udp(1) + } + +begemotSnmpdTransInetTable OBJECT-TYPE + SYNTAX SEQUENCE OF BegemotSnmpdTransInetEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "This table contains all the ports the daemon should listen on. + Entries can be created at initialization time via the config + file or at run time via a SET. One row can map to several open + sockets in the case of InetAddressType::dns rows. These rows + open one socket for each address returned by getaddrinfo(3). + for SNMP messages." + ::= { begemotSnmpdObjects 11 } + +begemotSnmpdTransInetEntry OBJECT-TYPE + SYNTAX BegemotSnmpdTransInetEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "A row of the internet port table. Each row may map to one or + more listening sockets." + INDEX { + begemotSnmpdTransInetAddressType, + begemotSnmpdTransInetAddress, + begemotSnmpdTransInetPort, + begemotSnmpdTransInetProto + } + ::= { begemotSnmpdTransInetTable 1 } + +BegemotSnmpdTransInetEntry ::= SEQUENCE { + begemotSnmpdTransInetAddressType InetAddressType, + begemotSnmpdTransInetAddress InetAddress, + begemotSnmpdTransInetPort InetPortNumber, + begemotSnmpdTransInetProto BegemotSnmpdTransportProto, + begemotSnmpdTransInetStatus RowStatus +} + +begemotSnmpdTransInetAddressType OBJECT-TYPE + SYNTAX InetAddressType + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The type of the address. Only ipv4, ipv6, ipv6z and dns are + supported." + ::= { begemotSnmpdTransInetEntry 1 } + +begemotSnmpdTransInetAddress OBJECT-TYPE + SYNTAX InetAddress (SIZE (0..64)) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The address. For ipv4 addresses the length must be 4, ipv6 + addresses have a length of 16 and ipv6z addresses a length of + 20 where the last four bytes are the interface index in big + endian format. dns addresses may be of zero-length in which case + getaddrinfo() generates INADDR_ANY and its IPv6 equivalent. dns + addresses will open a socket for all addresses returned by + getaddrinfo()." + ::= { begemotSnmpdTransInetEntry 2 } + +begemotSnmpdTransInetPort OBJECT-TYPE + SYNTAX InetPortNumber (1..65535) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The port to listen on for SNMP messages." + ::= { begemotSnmpdTransInetEntry 3 } + +begemotSnmpdTransInetProto OBJECT-TYPE + SYNTAX BegemotSnmpdTransportProto + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The protocol to use. Currently only the value udp(1) is supported." + ::= { begemotSnmpdTransInetEntry 4 } + +begemotSnmpdTransInetStatus OBJECT-TYPE + SYNTAX RowStatus + MAX-ACCESS read-create + STATUS current + DESCRIPTION + "The status of the conceptual row. A row may be created using + createAndGo(4) or createAndWait(5). An inactive row can be + activated writing active(1) and an active row can be inactivated + by writing notInService(2). Finally active or inactive rows can be + deleted by writing the value destroy(6). The value of this field + will never read as notReady(3)." + ::= { begemotSnmpdTransInetEntry 5 } + +-- +-- XXX These should go into their own MIB +-- +begemotSnmpdTransUdp OBJECT IDENTIFIER ::= { begemotSnmpdTransportMappings 2 } +begemotSnmpdTransLsock OBJECT IDENTIFIER ::= { begemotSnmpdTransportMappings 3 } +begemotSnmpdTransInet OBJECT IDENTIFIER ::= { begemotSnmpdTransportMappings 4 } + +END Property changes on: vendor/1.14/snmpd/BEGEMOT-SNMPD.txt ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmpd/main.c =================================================================== --- vendor/1.14/snmpd/main.c (nonexistent) +++ vendor/1.14/snmpd/main.c (revision 359491) @@ -0,0 +1,3142 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Copyright (c) 2010 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Shteryana Sotirova Shopova + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmpd/main.c,v 1.100 2006/02/14 09:04:20 brandt_h Exp $ + * + * SNMPd main stuff. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef USE_TCPWRAPPERS +#include +#include +#endif + +#include "support.h" +#include "snmpmod.h" +#include "snmpd.h" +#include "tree.h" +#include "oid.h" + +#include "trans_inet.h" + +#define PATH_PID "/var/run/%s.pid" +#define PATH_CONFIG "/etc/%s.config" +#define PATH_ENGINE "/var/%s.engine" + +uint64_t this_tick; /* start of processing of current packet (absolute) */ +uint64_t start_tick; /* start of processing */ + +struct systemg systemg = { + NULL, + { 8, { 1, 3, 6, 1, 4, 1, 1115, 7352 }}, + NULL, NULL, NULL, + 64 + 8 + 4, + 0 +}; +struct debug debug = { + 0, /* dump_pdus */ + LOG_DEBUG, /* log_pri */ + 0, /* evdebug */ +}; + +struct snmpd snmpd = { + 2048, /* txbuf */ + 2048, /* rxbuf */ + 0, /* comm_dis */ + 0, /* auth_traps */ + {0, 0, 0, 0}, /* trap1addr */ + VERS_ENABLE_ALL,/* version_enable */ +}; +struct snmpd_stats snmpd_stats; + +struct snmpd_usmstat snmpd_usmstats; + +/* snmpEngine */ +struct snmp_engine snmpd_engine; + +/* snmpSerialNo */ +int32_t snmp_serial_no; + +struct snmpd_target_stats snmpd_target_stats; + +/* search path for config files */ +const char *syspath = PATH_SYSCONFIG; + +/* list of all loaded modules */ +struct lmodules lmodules = TAILQ_HEAD_INITIALIZER(lmodules); + +/* list of loaded modules during start-up in the order they were loaded */ +static struct lmodules modules_start = TAILQ_HEAD_INITIALIZER(modules_start); + +/* list of all known communities */ +struct community_list community_list = TAILQ_HEAD_INITIALIZER(community_list); + +/* list of all known USM users */ +static struct usm_userlist usm_userlist = SLIST_HEAD_INITIALIZER(usm_userlist); + +/* A list of all VACM users configured, including v1, v2c and v3 */ +static struct vacm_userlist vacm_userlist = + SLIST_HEAD_INITIALIZER(vacm_userlist); + +/* A list of all VACM groups */ +static struct vacm_grouplist vacm_grouplist = + SLIST_HEAD_INITIALIZER(vacm_grouplist); + +static struct vacm_group vacm_default_group = { + .groupname = "", +}; + +/* The list of configured access entries */ +static struct vacm_accesslist vacm_accesslist = + TAILQ_HEAD_INITIALIZER(vacm_accesslist); + +/* The list of configured views */ +static struct vacm_viewlist vacm_viewlist = + SLIST_HEAD_INITIALIZER(vacm_viewlist); + +/* The list of configured contexts */ +static struct vacm_contextlist vacm_contextlist = + SLIST_HEAD_INITIALIZER(vacm_contextlist); + +/* list of all installed object resources */ +struct objres_list objres_list = TAILQ_HEAD_INITIALIZER(objres_list); + +/* community value generator */ +static u_int next_community_index = 1; + +/* list of all known ranges */ +struct idrange_list idrange_list = TAILQ_HEAD_INITIALIZER(idrange_list); + +/* identifier generator */ +u_int next_idrange = 1; + +/* list of all current timers */ +struct timer_list timer_list = LIST_HEAD_INITIALIZER(timer_list); + +/* list of file descriptors */ +struct fdesc_list fdesc_list = LIST_HEAD_INITIALIZER(fdesc_list); + +/* program arguments */ +static char **progargs; +static int nprogargs; + +/* current community */ +u_int community; +static struct community *comm; + +/* current USM user */ +struct usm_user *usm_user; + +/* file names */ +static char config_file[MAXPATHLEN + 1]; +static char pid_file[MAXPATHLEN + 1]; +char engine_file[MAXPATHLEN + 1]; + +#ifndef USE_LIBBEGEMOT +/* event context */ +static evContext evctx; +#endif + +/* signal mask */ +static sigset_t blocked_sigs; + +/* signal handling */ +static int work; +#define WORK_DOINFO 0x0001 +#define WORK_RECONFIG 0x0002 + +/* oids */ +static const struct asn_oid + oid_snmpMIB = OIDX_snmpMIB, + oid_begemotSnmpd = OIDX_begemotSnmpd, + oid_coldStart = OIDX_coldStart, + oid_authenticationFailure = OIDX_authenticationFailure; + +const struct asn_oid oid_zeroDotZero = { 2, { 0, 0 }}; + +const struct asn_oid oid_usmUnknownEngineIDs = + { 11, { 1, 3, 6, 1, 6, 3, 15, 1, 1, 4, 0}}; + +const struct asn_oid oid_usmNotInTimeWindows = + { 11, { 1, 3, 6, 1, 6, 3, 15, 1, 1, 2, 0}}; + +/* request id generator for traps */ +u_int trap_reqid; + +/* help text */ +static const char usgtxt[] = "\ +Begemot simple SNMP daemon. Copyright (c) 2001-2002 Fraunhofer Institute for\n\ +Open Communication Systems (FhG Fokus). All rights reserved.\n\ +Copyright (c) 2010 The FreeBSD Foundation. All rights reserved.\n\ +usage: snmpd [-dh] [-c file] [-D options] [-e file] [-I path]\n\ + [-l prefix] [-m variable=value] [-p file]\n\ +options:\n\ + -d don't daemonize\n\ + -h print this info\n\ + -c file specify configuration file\n\ + -D options debugging options\n\ + -e file specify engine id file\n\ + -I path system include path\n\ + -l prefix default basename for pid and config file\n\ + -m var=val define variable\n\ + -p file specify pid file\n\ +"; + +/* hosts_access(3) request */ +#ifdef USE_TCPWRAPPERS +static struct request_info req; +#endif + +/* transports */ +extern const struct transport_def udp_trans; +extern const struct transport_def lsock_trans; + +struct transport_list transport_list = TAILQ_HEAD_INITIALIZER(transport_list); + +/* forward declarations */ +static void snmp_printf_func(const char *fmt, ...); +static void snmp_error_func(const char *err, ...); +static void snmp_debug_func(const char *err, ...); +static void asn_error_func(const struct asn_buf *b, const char *err, ...); + +/* + * Allocate rx/tx buffer. We allocate one byte more for rx. + */ +void * +buf_alloc(int tx) +{ + void *buf; + + if ((buf = malloc(tx ? snmpd.txbuf : snmpd.rxbuf)) == NULL) { + syslog(LOG_CRIT, "cannot allocate buffer"); + if (tx) + snmpd_stats.noTxbuf++; + else + snmpd_stats.noRxbuf++; + return (NULL); + } + return (buf); +} + +/* + * Return the buffer size. + */ +size_t +buf_size(int tx) +{ + return (tx ? snmpd.txbuf : snmpd.rxbuf); +} + +/* + * Prepare a PDU for output + */ +void +snmp_output(struct snmp_pdu *pdu, u_char *sndbuf, size_t *sndlen, + const char *dest) +{ + struct asn_buf resp_b; + enum snmp_code code; + + resp_b.asn_ptr = sndbuf; + resp_b.asn_len = snmpd.txbuf; + + if ((code = snmp_pdu_encode(pdu, &resp_b)) != SNMP_CODE_OK) { + syslog(LOG_ERR, "cannot encode message (code=%d)", code); + abort(); + } + if (debug.dump_pdus) { + snmp_printf("%s <- ", dest); + snmp_pdu_dump(pdu); + } + *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); +} + +/* + * Check USM PDU header credentials against local SNMP Engine & users. + */ +static enum snmp_code +snmp_pdu_auth_user(struct snmp_pdu *pdu) +{ + usm_user = NULL; + + /* un-authenticated snmpEngineId discovery */ + if (pdu->engine.engine_len == 0 && strlen(pdu->user.sec_name) == 0) { + pdu->engine.engine_len = snmpd_engine.engine_len; + memcpy(pdu->engine.engine_id, snmpd_engine.engine_id, + snmpd_engine.engine_len); + update_snmpd_engine_time(); + pdu->engine.engine_boots = snmpd_engine.engine_boots; + pdu->engine.engine_time = snmpd_engine.engine_time; + pdu->flags |= SNMP_MSG_AUTODISCOVER; + return (SNMP_CODE_OK); + } + + if ((usm_user = usm_find_user(pdu->engine.engine_id, + pdu->engine.engine_len, pdu->user.sec_name)) == NULL || + usm_user->status != 1 /* active */) + return (SNMP_CODE_BADUSER); + + if (usm_user->user_engine_len != snmpd_engine.engine_len || + memcmp(usm_user->user_engine_id, snmpd_engine.engine_id, + snmpd_engine.engine_len) != 0) + return (SNMP_CODE_BADENGINE); + + pdu->user.priv_proto = usm_user->suser.priv_proto; + memcpy(pdu->user.priv_key, usm_user->suser.priv_key, + sizeof(pdu->user.priv_key)); + + /* authenticated snmpEngineId discovery */ + if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) { + update_snmpd_engine_time(); + pdu->user.auth_proto = usm_user->suser.auth_proto; + memcpy(pdu->user.auth_key, usm_user->suser.auth_key, + sizeof(pdu->user.auth_key)); + + if (pdu->engine.engine_boots == 0 && + pdu->engine.engine_time == 0) { + update_snmpd_engine_time(); + pdu->flags |= SNMP_MSG_AUTODISCOVER; + return (SNMP_CODE_OK); + } + + if (pdu->engine.engine_boots != snmpd_engine.engine_boots || + abs(pdu->engine.engine_time - snmpd_engine.engine_time) > + SNMP_TIME_WINDOW) + return (SNMP_CODE_NOTINTIME); + } + + if (((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && + (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0) || + ((pdu->flags & SNMP_MSG_AUTH_FLAG) == 0 && + usm_user->suser.auth_proto != SNMP_AUTH_NOAUTH) || + ((pdu->flags & SNMP_MSG_PRIV_FLAG) == 0 && + usm_user->suser.priv_proto != SNMP_PRIV_NOPRIV)) + return (SNMP_CODE_BADSECLEVEL); + + return (SNMP_CODE_OK); +} + +/* + * Check whether access to each of var bindings in the PDU is allowed based + * on the user credentials against the configured User groups & VACM views. + */ +enum snmp_code +snmp_pdu_auth_access(struct snmp_pdu *pdu, int32_t *ip) +{ + const char *uname; + int32_t suboid, smodel; + uint32_t i; + struct vacm_user *vuser; + struct vacm_access *acl; + struct vacm_context *vacmctx; + struct vacm_view *view; + + /* + * At least a default context exists if the snmpd_vacm(3) module is + * running. + */ + if (SLIST_EMPTY(&vacm_contextlist) || + (pdu->flags & SNMP_MSG_AUTODISCOVER) != 0) + return (SNMP_CODE_OK); + + switch (pdu->version) { + case SNMP_V1: + if ((uname = comm_string(community)) == NULL) + return (SNMP_CODE_FAILED); + smodel = SNMP_SECMODEL_SNMPv1; + break; + + case SNMP_V2c: + if ((uname = comm_string(community)) == NULL) + return (SNMP_CODE_FAILED); + smodel = SNMP_SECMODEL_SNMPv2c; + break; + + case SNMP_V3: + uname = pdu->user.sec_name; + if ((smodel = pdu->security_model) != SNMP_SECMODEL_USM) + return (SNMP_CODE_FAILED); + /* Compare the PDU context engine id against the agent's */ + if (pdu->context_engine_len != snmpd_engine.engine_len || + memcmp(pdu->context_engine, snmpd_engine.engine_id, + snmpd_engine.engine_len) != 0) + return (SNMP_CODE_FAILED); + break; + + default: + abort(); + } + + SLIST_FOREACH(vuser, &vacm_userlist, vvu) + if (strcmp(uname, vuser->secname) == 0 && + vuser->sec_model == smodel) + break; + + if (vuser == NULL || vuser->group == NULL) + return (SNMP_CODE_FAILED); + + /* XXX: shteryana - recheck */ + TAILQ_FOREACH_REVERSE(acl, &vacm_accesslist, vacm_accesslist, vva) { + if (acl->group != vuser->group) + continue; + SLIST_FOREACH(vacmctx, &vacm_contextlist, vcl) + if (memcmp(vacmctx->ctxname, acl->ctx_prefix, + acl->ctx_match) == 0) + goto match; + } + + return (SNMP_CODE_FAILED); + +match: + + switch (pdu->type) { + case SNMP_PDU_GET: + case SNMP_PDU_GETNEXT: + case SNMP_PDU_GETBULK: + if ((view = acl->read_view) == NULL) + return (SNMP_CODE_FAILED); + break; + + case SNMP_PDU_SET: + if ((view = acl->write_view) == NULL) + return (SNMP_CODE_FAILED); + break; + + case SNMP_PDU_TRAP: + case SNMP_PDU_INFORM: + case SNMP_PDU_TRAP2: + case SNMP_PDU_REPORT: + if ((view = acl->notify_view) == NULL) + return (SNMP_CODE_FAILED); + break; + case SNMP_PDU_RESPONSE: + /* NOTREACHED */ + return (SNMP_CODE_FAILED); + default: + abort(); + } + + for (i = 0; i < pdu->nbindings; i++) { + /* XXX - view->mask*/ + suboid = asn_is_suboid(&view->subtree, &pdu->bindings[i].var); + if ((!suboid && !view->exclude) || (suboid && view->exclude)) { + *ip = i + 1; + return (SNMP_CODE_FAILED); + } + } + + return (SNMP_CODE_OK); +} + +/* + * SNMP input. Start: decode the PDU, find the user or community. + */ +enum snmpd_input_err +snmp_input_start(const u_char *buf, size_t len, const char *source, + struct snmp_pdu *pdu, int32_t *ip, size_t *pdulen) +{ + struct asn_buf b; + enum snmp_code code; + enum snmpd_input_err ret; + int sret; + + /* update uptime */ + this_tick = get_ticks(); + + b.asn_cptr = buf; + b.asn_len = len; + + ret = SNMPD_INPUT_OK; + + /* look whether we have enough bytes for the entire PDU. */ + switch (sret = snmp_pdu_snoop(&b)) { + + case 0: + return (SNMPD_INPUT_TRUNC); + + case -1: + snmpd_stats.inASNParseErrs++; + return (SNMPD_INPUT_FAILED); + } + b.asn_len = *pdulen = (size_t)sret; + + memset(pdu, 0, sizeof(*pdu)); + if ((code = snmp_pdu_decode_header(&b, pdu)) != SNMP_CODE_OK) + goto decoded; + + if (pdu->version == SNMP_V3) { + if (pdu->security_model != SNMP_SECMODEL_USM) { + code = SNMP_CODE_FAILED; + goto decoded; + } + if ((code = snmp_pdu_auth_user(pdu)) != SNMP_CODE_OK) + goto decoded; + if ((code = snmp_pdu_decode_secmode(&b, pdu)) != SNMP_CODE_OK) + goto decoded; + } + code = snmp_pdu_decode_scoped(&b, pdu, ip); + +decoded: + snmpd_stats.inPkts++; + + switch (code) { + + case SNMP_CODE_FAILED: + snmpd_stats.inASNParseErrs++; + return (SNMPD_INPUT_FAILED); + + case SNMP_CODE_BADVERS: + bad_vers: + snmpd_stats.inBadVersions++; + return (SNMPD_INPUT_FAILED); + + case SNMP_CODE_BADLEN: + if (pdu->type == SNMP_OP_SET) + ret = SNMPD_INPUT_VALBADLEN; + break; + + case SNMP_CODE_OORANGE: + if (pdu->type == SNMP_OP_SET) + ret = SNMPD_INPUT_VALRANGE; + break; + + case SNMP_CODE_BADENC: + if (pdu->type == SNMP_OP_SET) + ret = SNMPD_INPUT_VALBADENC; + break; + + case SNMP_CODE_BADSECLEVEL: + snmpd_usmstats.unsupported_seclevels++; + return (SNMPD_INPUT_FAILED); + + case SNMP_CODE_NOTINTIME: + snmpd_usmstats.not_in_time_windows++; + return (SNMPD_INPUT_FAILED); + + case SNMP_CODE_BADUSER: + snmpd_usmstats.unknown_users++; + return (SNMPD_INPUT_FAILED); + + case SNMP_CODE_BADENGINE: + snmpd_usmstats.unknown_engine_ids++; + return (SNMPD_INPUT_FAILED); + + case SNMP_CODE_BADDIGEST: + snmpd_usmstats.wrong_digests++; + return (SNMPD_INPUT_FAILED); + + case SNMP_CODE_EDECRYPT: + snmpd_usmstats.decrypt_errors++; + return (SNMPD_INPUT_FAILED); + + case SNMP_CODE_OK: + switch (pdu->version) { + + case SNMP_V1: + if (!(snmpd.version_enable & VERS_ENABLE_V1)) + goto bad_vers; + break; + + case SNMP_V2c: + if (!(snmpd.version_enable & VERS_ENABLE_V2C)) + goto bad_vers; + break; + + case SNMP_V3: + if (!(snmpd.version_enable & VERS_ENABLE_V3)) + goto bad_vers; + break; + + case SNMP_Verr: + goto bad_vers; + } + break; + } + + if (debug.dump_pdus) { + snmp_printf("%s -> ", source); + snmp_pdu_dump(pdu); + } + + /* + * Look, whether we know the community or user + */ + + if (pdu->version != SNMP_V3) { + TAILQ_FOREACH(comm, &community_list, link) + if (comm->string != NULL && + strcmp(comm->string, pdu->community) == 0) + break; + + if (comm == NULL) { + snmpd_stats.inBadCommunityNames++; + snmp_pdu_free(pdu); + if (snmpd.auth_traps) + snmp_send_trap(&oid_authenticationFailure, + (struct snmp_value *)NULL); + ret = SNMPD_INPUT_BAD_COMM; + } else + community = comm->value; + } else if (pdu->nbindings == 0) { + /* RFC 3414 - snmpEngineID Discovery */ + if (strlen(pdu->user.sec_name) == 0) { + asn_append_oid(&(pdu->bindings[pdu->nbindings++].var), + &oid_usmUnknownEngineIDs); + pdu->context_engine_len = snmpd_engine.engine_len; + memcpy(pdu->context_engine, snmpd_engine.engine_id, + snmpd_engine.engine_len); + } else if (pdu->engine.engine_boots == 0 && + pdu->engine.engine_time == 0) { + asn_append_oid(&(pdu->bindings[pdu->nbindings++].var), + &oid_usmNotInTimeWindows); + update_snmpd_engine_time(); + pdu->engine.engine_boots = snmpd_engine.engine_boots; + pdu->engine.engine_time = snmpd_engine.engine_time; + } + } else if (usm_user->suser.auth_proto != SNMP_AUTH_NOAUTH && + (pdu->engine.engine_boots == 0 || pdu->engine.engine_time == 0)) { + snmpd_usmstats.not_in_time_windows++; + ret = SNMPD_INPUT_FAILED; + } + + if ((code = snmp_pdu_auth_access(pdu, ip)) != SNMP_CODE_OK) + ret = SNMPD_INPUT_FAILED; + + return (ret); +} + +/* + * Will return only _OK or _FAILED + */ +enum snmpd_input_err +snmp_input_finish(struct snmp_pdu *pdu, const u_char *rcvbuf, size_t rcvlen, + u_char *sndbuf, size_t *sndlen, const char *source, + enum snmpd_input_err ierr, int32_t ivar, void *data) +{ + struct snmp_pdu resp; + struct asn_buf resp_b, pdu_b; + enum snmp_ret ret; + + resp_b.asn_ptr = sndbuf; + resp_b.asn_len = snmpd.txbuf; + + pdu_b.asn_cptr = rcvbuf; + pdu_b.asn_len = rcvlen; + + if (ierr != SNMPD_INPUT_OK) { + /* error decoding the input of a SET */ + if (pdu->version == SNMP_V1) + pdu->error_status = SNMP_ERR_BADVALUE; + else if (ierr == SNMPD_INPUT_VALBADLEN) + pdu->error_status = SNMP_ERR_WRONG_LENGTH; + else if (ierr == SNMPD_INPUT_VALRANGE) + pdu->error_status = SNMP_ERR_WRONG_VALUE; + else + pdu->error_status = SNMP_ERR_WRONG_ENCODING; + + pdu->error_index = ivar; + + if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { + syslog(LOG_WARNING, "could not encode error response"); + snmpd_stats.silentDrops++; + return (SNMPD_INPUT_FAILED); + } + + if (debug.dump_pdus) { + snmp_printf("%s <- ", source); + snmp_pdu_dump(pdu); + } + *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); + return (SNMPD_INPUT_OK); + } + + switch (pdu->type) { + + case SNMP_PDU_GET: + ret = snmp_get(pdu, &resp_b, &resp, data); + break; + + case SNMP_PDU_GETNEXT: + ret = snmp_getnext(pdu, &resp_b, &resp, data); + break; + + case SNMP_PDU_SET: + ret = snmp_set(pdu, &resp_b, &resp, data); + break; + + case SNMP_PDU_GETBULK: + ret = snmp_getbulk(pdu, &resp_b, &resp, data); + break; + + default: + ret = SNMP_RET_IGN; + break; + } + + switch (ret) { + + case SNMP_RET_OK: + /* normal return - send a response */ + if (debug.dump_pdus) { + snmp_printf("%s <- ", source); + snmp_pdu_dump(&resp); + } + *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); + snmp_pdu_free(&resp); + return (SNMPD_INPUT_OK); + + case SNMP_RET_IGN: + /* error - send nothing */ + snmpd_stats.silentDrops++; + return (SNMPD_INPUT_FAILED); + + case SNMP_RET_ERR: + /* error - send error response. The snmp routine has + * changed the error fields in the original message. */ + resp_b.asn_ptr = sndbuf; + resp_b.asn_len = snmpd.txbuf; + if (snmp_make_errresp(pdu, &pdu_b, &resp_b) == SNMP_RET_IGN) { + syslog(LOG_WARNING, "could not encode error response"); + snmpd_stats.silentDrops++; + return (SNMPD_INPUT_FAILED); + } else { + if (debug.dump_pdus) { + snmp_printf("%s <- ", source); + snmp_pdu_dump(pdu); + } + *sndlen = (size_t)(resp_b.asn_ptr - sndbuf); + return (SNMPD_INPUT_OK); + } + } + abort(); +} + +/* + * Insert a port into the right place in the transport's table of ports + */ +void +trans_insert_port(struct transport *t, struct tport *port) +{ + struct tport *p; + + port->transport = t; + TAILQ_FOREACH(p, &t->table, link) { + if (asn_compare_oid(&p->index, &port->index) > 0) { + TAILQ_INSERT_BEFORE(p, port, link); + return; + } + } + TAILQ_INSERT_TAIL(&t->table, port, link); +} + +/* + * Remove a port from a transport's list + */ +void +trans_remove_port(struct tport *port) +{ + + TAILQ_REMOVE(&port->transport->table, port, link); +} + +/* + * Find a port on a transport's list + */ +struct tport * +trans_find_port(struct transport *t, const struct asn_oid *idx, u_int sub) +{ + + return (FIND_OBJECT_OID(&t->table, idx, sub)); +} + +/* + * Find next port on a transport's list + */ +struct tport * +trans_next_port(struct transport *t, const struct asn_oid *idx, u_int sub) +{ + + return (NEXT_OBJECT_OID(&t->table, idx, sub)); +} + +/* + * Return first port + */ +struct tport * +trans_first_port(struct transport *t) +{ + + return (TAILQ_FIRST(&t->table)); +} + +/* + * Iterate through all ports until a function returns a 0. + */ +struct tport * +trans_iter_port(struct transport *t, int (*func)(struct tport *, intptr_t), + intptr_t arg) +{ + struct tport *p; + + TAILQ_FOREACH(p, &t->table, link) + if (func(p, arg) == 0) + return (p); + return (NULL); +} + +/* + * Register a transport + */ +int +trans_register(const struct transport_def *def, struct transport **pp) +{ + u_int i; + char or_descr[256]; + + if ((*pp = malloc(sizeof(**pp))) == NULL) + return (SNMP_ERR_GENERR); + + /* construct index */ + (*pp)->index.len = strlen(def->name) + 1; + (*pp)->index.subs[0] = strlen(def->name); + for (i = 0; i < (*pp)->index.subs[0]; i++) + (*pp)->index.subs[i + 1] = def->name[i]; + + (*pp)->vtab = def; + + if (FIND_OBJECT_OID(&transport_list, &(*pp)->index, 0) != NULL) { + free(*pp); + return (SNMP_ERR_INCONS_VALUE); + } + + /* register module */ + snprintf(or_descr, sizeof(or_descr), "%s transport mapping", def->name); + if (((*pp)->or_index = or_register(&def->id, or_descr, NULL)) == 0) { + free(*pp); + return (SNMP_ERR_GENERR); + } + + INSERT_OBJECT_OID((*pp), &transport_list); + + TAILQ_INIT(&(*pp)->table); + + return (SNMP_ERR_NOERROR); +} + +/* + * Unregister transport + */ +int +trans_unregister(struct transport *t) +{ + if (!TAILQ_EMPTY(&t->table)) + return (SNMP_ERR_INCONS_VALUE); + + or_unregister(t->or_index); + TAILQ_REMOVE(&transport_list, t, link); + + return (SNMP_ERR_NOERROR); +} + +/* + * File descriptor support + */ +#ifdef USE_LIBBEGEMOT +static void +input(int fd, int mask __unused, void *uap) +#else +static void +input(evContext ctx __unused, void *uap, int fd, int mask __unused) +#endif +{ + struct fdesc *f = uap; + + (*f->func)(fd, f->udata); +} + +void +fd_suspend(void *p) +{ + struct fdesc *f = p; + +#ifdef USE_LIBBEGEMOT + if (f->id >= 0) { + poll_unregister(f->id); + f->id = -1; + } +#else + if (evTestID(f->id)) { + (void)evDeselectFD(evctx, f->id); + evInitID(&f->id); + } +#endif +} + +int +fd_resume(void *p) +{ + struct fdesc *f = p; + int err; + +#ifdef USE_LIBBEGEMOT + if (f->id >= 0) + return (0); + if ((f->id = poll_register(f->fd, input, f, RPOLL_IN)) < 0) { + err = errno; + syslog(LOG_ERR, "select fd %d: %m", f->fd); + errno = err; + return (-1); + } +#else + if (evTestID(f->id)) + return (0); + if (evSelectFD(evctx, f->fd, EV_READ, input, f, &f->id)) { + err = errno; + syslog(LOG_ERR, "select fd %d: %m", f->fd); + errno = err; + return (-1); + } +#endif + return (0); +} + +void * +fd_select(int fd, void (*func)(int, void *), void *udata, struct lmodule *mod) +{ + struct fdesc *f; + int err; + + if ((f = malloc(sizeof(struct fdesc))) == NULL) { + err = errno; + syslog(LOG_ERR, "fd_select: %m"); + errno = err; + return (NULL); + } + f->fd = fd; + f->func = func; + f->udata = udata; + f->owner = mod; +#ifdef USE_LIBBEGEMOT + f->id = -1; +#else + evInitID(&f->id); +#endif + + if (fd_resume(f)) { + err = errno; + free(f); + errno = err; + return (NULL); + } + + LIST_INSERT_HEAD(&fdesc_list, f, link); + + return (f); +} + +void +fd_deselect(void *p) +{ + struct fdesc *f = p; + + LIST_REMOVE(f, link); + fd_suspend(f); + free(f); +} + +static void +fd_flush(struct lmodule *mod) +{ + struct fdesc *t, *t1; + + t = LIST_FIRST(&fdesc_list); + while (t != NULL) { + t1 = LIST_NEXT(t, link); + if (t->owner == mod) + fd_deselect(t); + t = t1; + } +} + +/* + * Consume a message from the input buffer + */ +static void +snmp_input_consume(struct port_input *pi) +{ + if (!pi->stream) { + /* always consume everything */ + pi->length = 0; + return; + } + if (pi->consumed >= pi->length) { + /* all bytes consumed */ + pi->length = 0; + return; + } + memmove(pi->buf, pi->buf + pi->consumed, pi->length - pi->consumed); + pi->length -= pi->consumed; +} + +/* + * Input from a socket + */ +int +snmpd_input(struct port_input *pi, struct tport *tport) +{ + u_char *sndbuf; + size_t sndlen; + struct snmp_pdu pdu; + enum snmpd_input_err ierr, ferr; + enum snmpd_proxy_err perr; + ssize_t ret, slen; + int32_t vi; +#ifdef USE_TCPWRAPPERS + char client[INET6_ADDRSTRLEN]; +#endif + + ret = tport->transport->vtab->recv(tport, pi); + if (ret == -1) + return (-1); + +#ifdef USE_TCPWRAPPERS + /* + * In case of AF_INET{6} peer, do hosts_access(5) check. + */ + if (pi->peer->sa_family != AF_LOCAL && + inet_ntop(pi->peer->sa_family, + &((const struct sockaddr_in *)(const void *)pi->peer)->sin_addr, + client, sizeof(client)) != NULL) { + request_set(&req, RQ_CLIENT_ADDR, client, 0); + if (hosts_access(&req) == 0) { + syslog(LOG_ERR, "refused connection from %.500s", + eval_client(&req)); + return (-1); + } + } else if (pi->peer->sa_family != AF_LOCAL) + syslog(LOG_ERR, "inet_ntop(): %m"); +#endif + + /* + * Handle input + */ + ierr = snmp_input_start(pi->buf, pi->length, "SNMP", &pdu, &vi, + &pi->consumed); + if (ierr == SNMPD_INPUT_TRUNC) { + /* need more bytes. This is ok only for streaming transports. + * but only if we have not reached bufsiz yet. */ + if (pi->stream) { + if (pi->length == buf_size(0)) { + snmpd_stats.silentDrops++; + return (-1); + } + return (0); + } + snmpd_stats.silentDrops++; + return (-1); + } + + /* can't check for bad SET pdus here, because a proxy may have to + * check the access first. We don't want to return an error response + * to a proxy PDU with a wrong community */ + if (ierr == SNMPD_INPUT_FAILED) { + /* for streaming transports this is fatal */ + if (pi->stream) + return (-1); + snmp_input_consume(pi); + return (0); + } + if (ierr == SNMPD_INPUT_BAD_COMM) { + snmp_input_consume(pi); + return (0); + } + + /* + * If that is a module community and the module has a proxy function, + * the hand it over to the module. + */ + if (comm != NULL && comm->owner != NULL && + comm->owner->config->proxy != NULL) { + perr = (*comm->owner->config->proxy)(&pdu, tport->transport, + &tport->index, pi->peer, pi->peerlen, ierr, vi, + !pi->cred || pi->priv); + + switch (perr) { + + case SNMPD_PROXY_OK: + snmp_input_consume(pi); + return (0); + + case SNMPD_PROXY_REJ: + break; + + case SNMPD_PROXY_DROP: + snmp_input_consume(pi); + snmp_pdu_free(&pdu); + snmpd_stats.proxyDrops++; + return (0); + + case SNMPD_PROXY_BADCOMM: + snmp_input_consume(pi); + snmp_pdu_free(&pdu); + snmpd_stats.inBadCommunityNames++; + if (snmpd.auth_traps) + snmp_send_trap(&oid_authenticationFailure, + (struct snmp_value *)NULL); + return (0); + + case SNMPD_PROXY_BADCOMMUSE: + snmp_input_consume(pi); + snmp_pdu_free(&pdu); + snmpd_stats.inBadCommunityUses++; + if (snmpd.auth_traps) + snmp_send_trap(&oid_authenticationFailure, + (struct snmp_value *)NULL); + return (0); + } + } + + /* + * Check type + */ + if (pdu.type == SNMP_PDU_RESPONSE || + pdu.type == SNMP_PDU_TRAP || + pdu.type == SNMP_PDU_TRAP2) { + snmpd_stats.silentDrops++; + snmpd_stats.inBadPduTypes++; + snmp_pdu_free(&pdu); + snmp_input_consume(pi); + return (0); + } + + /* + * Check community + */ + if (pdu.version < SNMP_V3 && + ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) || + (comm != NULL && comm->private != COMM_WRITE && + (pdu.type == SNMP_PDU_SET || comm->private != COMM_READ)))) { + snmpd_stats.inBadCommunityUses++; + snmp_pdu_free(&pdu); + snmp_input_consume(pi); + if (snmpd.auth_traps) + snmp_send_trap(&oid_authenticationFailure, + (struct snmp_value *)NULL); + return (0); + } + + /* + * Execute it. + */ + if ((sndbuf = buf_alloc(1)) == NULL) { + snmpd_stats.silentDrops++; + snmp_pdu_free(&pdu); + snmp_input_consume(pi); + return (0); + } + ferr = snmp_input_finish(&pdu, pi->buf, pi->length, + sndbuf, &sndlen, "SNMP", ierr, vi, NULL); + + if (ferr == SNMPD_INPUT_OK) { + if (tport->transport->vtab->send != NULL) + slen = tport->transport->vtab->send(tport, sndbuf, + sndlen, pi->peer, pi->peerlen); + else + slen = tport->transport->vtab->send2(tport, sndbuf, + sndlen, pi); + if (slen == -1) + syslog(LOG_ERR, "send*: %m"); + else if ((size_t)slen != sndlen) + syslog(LOG_ERR, "send*: short write %zu/%zu", sndlen, + (size_t)slen); + } + + snmp_pdu_free(&pdu); + free(sndbuf); + snmp_input_consume(pi); + + return (0); +} + +/* + * Send a PDU to a given port. If this is a multi-socket port, use the + * first socket. + */ +void +snmp_send_port(void *targ, const struct asn_oid *port, struct snmp_pdu *pdu, + const struct sockaddr *addr, socklen_t addrlen) +{ + struct transport *trans = targ; + struct tport *tp; + u_char *sndbuf; + size_t sndlen; + ssize_t len; + + TAILQ_FOREACH(tp, &trans->table, link) + if (asn_compare_oid(port, &tp->index) == 0) + break; + if (tp == 0) + return; + + if ((sndbuf = buf_alloc(1)) == NULL) + return; + + snmp_output(pdu, sndbuf, &sndlen, "SNMP PROXY"); + + if (trans->vtab->send != NULL) + len = trans->vtab->send(tp, sndbuf, sndlen, addr, addrlen); + else + len = trans->vtab->send2(tp, sndbuf, sndlen, NULL); + + if (len == -1) + syslog(LOG_ERR, "sendto: %m"); + else if ((size_t)len != sndlen) + syslog(LOG_ERR, "sendto: short write %zu/%zu", + sndlen, (size_t)len); + + free(sndbuf); +} + + +/* + * Close an input source + * + * \param pi input instance + */ +void +snmpd_input_close(struct port_input *pi) +{ + if (pi->id != NULL) { + fd_deselect(pi->id); + pi->id = NULL; + } + if (pi->fd >= 0) { + (void)close(pi->fd); + pi->fd = -1; + } + if (pi->buf != NULL) { + free(pi->buf); + pi->buf = NULL; + } +} + +/* + * Initialize an input source. + * + * \param pi input instance + */ +void +snmpd_input_init(struct port_input *pi) +{ + pi->id = NULL; + pi->fd = -1; + pi->buf = NULL; +} + +/* + * Dump internal state. + */ +#ifdef USE_LIBBEGEMOT +static void +info_func(void) +#else +static void +info_func(evContext ctx __unused, void *uap __unused, const void *tag __unused) +#endif +{ + struct lmodule *m; + u_int i; + char buf[10000]; + + syslog(LOG_DEBUG, "Dump of SNMPd %lu\n", (u_long)getpid()); + for (i = 0; i < tree_size; i++) { + switch (tree[i].type) { + + case SNMP_NODE_LEAF: + sprintf(buf, "LEAF: %s %s", tree[i].name, + asn_oid2str(&tree[i].oid)); + break; + + case SNMP_NODE_COLUMN: + sprintf(buf, "COL: %s %s", tree[i].name, + asn_oid2str(&tree[i].oid)); + break; + } + syslog(LOG_DEBUG, "%s", buf); + } + + TAILQ_FOREACH(m, &lmodules, link) + if (m->config->dump) + (*m->config->dump)(); +} + +/* + * Re-read configuration + */ +#ifdef USE_LIBBEGEMOT +static void +config_func(void) +#else +static void +config_func(evContext ctx __unused, void *uap __unused, + const void *tag __unused) +#endif +{ + struct lmodule *m; + + if (read_config(config_file, NULL)) { + syslog(LOG_ERR, "error reading config file '%s'", config_file); + return; + } + TAILQ_FOREACH(m, &lmodules, link) + if (m->config->config) + (*m->config->config)(); +} + +/* + * On USR1 dump actual configuration. + */ +static void +onusr1(int s __unused) +{ + + work |= WORK_DOINFO; +} +static void +onhup(int s __unused) +{ + + work |= WORK_RECONFIG; +} + +static void +onterm(int s __unused) +{ + + /* allow clean-up */ + exit(0); +} + +static void +init_sigs(void) +{ + struct sigaction sa; + + sa.sa_handler = onusr1; + sa.sa_flags = SA_RESTART; + sigemptyset(&sa.sa_mask); + if (sigaction(SIGUSR1, &sa, NULL)) { + syslog(LOG_ERR, "sigaction: %m"); + exit(1); + } + + sa.sa_handler = onhup; + if (sigaction(SIGHUP, &sa, NULL)) { + syslog(LOG_ERR, "sigaction: %m"); + exit(1); + } + + sa.sa_handler = onterm; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + if (sigaction(SIGTERM, &sa, NULL)) { + syslog(LOG_ERR, "sigaction: %m"); + exit(1); + } + if (sigaction(SIGINT, &sa, NULL)) { + syslog(LOG_ERR, "sigaction: %m"); + exit(1); + } +} + +static void +block_sigs(void) +{ + sigset_t set; + + sigfillset(&set); + if (sigprocmask(SIG_BLOCK, &set, &blocked_sigs) == -1) { + syslog(LOG_ERR, "SIG_BLOCK: %m"); + exit(1); + } +} +static void +unblock_sigs(void) +{ + if (sigprocmask(SIG_SETMASK, &blocked_sigs, NULL) == -1) { + syslog(LOG_ERR, "SIG_SETMASK: %m"); + exit(1); + } +} + +/* + * Shut down + */ +static void +term(void) +{ + (void)unlink(pid_file); +} + +static void +trans_stop(void) +{ + struct transport *t; + + TAILQ_FOREACH(t, &transport_list, link) + (void)t->vtab->stop(1); +} + +/* + * Define a macro from the command line + */ +static void +do_macro(char *arg) +{ + char *eq; + int err; + + if ((eq = strchr(arg, '=')) == NULL) + err = define_macro(arg, ""); + else { + *eq++ = '\0'; + err = define_macro(arg, eq); + } + if (err == -1) { + syslog(LOG_ERR, "cannot save macro: %m"); + exit(1); + } +} + +/* + * Re-implement getsubopt from scratch, because the second argument is broken + * and will not compile with WARNS=5. + */ +static int +getsubopt1(char **arg, const char *const *options, char **valp, char **optp) +{ + static const char *const delim = ",\t "; + u_int i; + char *ptr; + + *optp = NULL; + + /* skip leading junk */ + for (ptr = *arg; *ptr != '\0'; ptr++) + if (strchr(delim, *ptr) == NULL) + break; + if (*ptr == '\0') { + *arg = ptr; + return (-1); + } + *optp = ptr; + + /* find the end of the option */ + while (*++ptr != '\0') + if (strchr(delim, *ptr) != NULL || *ptr == '=') + break; + + if (*ptr != '\0') { + if (*ptr == '=') { + *ptr++ = '\0'; + *valp = ptr; + while (*ptr != '\0' && strchr(delim, *ptr) == NULL) + ptr++; + if (*ptr != '\0') + *ptr++ = '\0'; + } else + *ptr++ = '\0'; + } + + *arg = ptr; + + for (i = 0; *options != NULL; options++, i++) + if (strcmp(*optp, *options) == 0) + return (i); + return (-1); +} + +int +main(int argc, char *argv[]) +{ + int opt; + FILE *fp; + int background = 1; + struct tport *p; + const char *prefix = "snmpd"; + struct lmodule *m; + char *value = NULL, *option; /* XXX */ + struct transport *t; + +#define DBG_DUMP 0 +#define DBG_EVENTS 1 +#define DBG_TRACE 2 + static const char *const debug_opts[] = { + "dump", + "events", + "trace", + NULL + }; + + snmp_printf = snmp_printf_func; + snmp_error = snmp_error_func; + snmp_debug = snmp_debug_func; + asn_error = asn_error_func; + + while ((opt = getopt(argc, argv, "c:dD:e:hI:l:m:p:")) != EOF) + switch (opt) { + + case 'c': + strlcpy(config_file, optarg, sizeof(config_file)); + break; + + case 'd': + background = 0; + break; + + case 'D': + while (*optarg) { + switch (getsubopt1(&optarg, debug_opts, + &value, &option)) { + + case DBG_DUMP: + debug.dump_pdus = 1; + break; + + case DBG_EVENTS: + debug.evdebug++; + break; + + case DBG_TRACE: + if (value == NULL) + syslog(LOG_ERR, + "no value for 'trace'"); + else + snmp_trace = strtoul(value, + NULL, 0); + break; + + case -1: + if (suboptarg) + syslog(LOG_ERR, + "unknown debug flag '%s'", + option); + else + syslog(LOG_ERR, + "missing debug flag"); + break; + } + } + break; + + case 'e': + strlcpy(engine_file, optarg, sizeof(engine_file)); + break; + case 'h': + fprintf(stderr, "%s", usgtxt); + exit(0); + + case 'I': + syspath = optarg; + break; + + case 'l': + prefix = optarg; + break; + + case 'm': + do_macro(optarg); + break; + + case 'p': + strlcpy(pid_file, optarg, sizeof(pid_file)); + break; + } + + openlog(prefix, LOG_PID | (background ? 0 : LOG_PERROR), LOG_USER); + setlogmask(LOG_UPTO(debug.logpri - 1)); + + if (background && daemon(0, 0) < 0) { + syslog(LOG_ERR, "daemon: %m"); + exit(1); + } + + argc -= optind; + argv += optind; + + progargs = argv; + nprogargs = argc; + + snmp_serial_no = arc4random(); + +#ifdef USE_TCPWRAPPERS + /* + * Initialize hosts_access(3) handler. + */ + request_init(&req, RQ_DAEMON, "snmpd", 0); + sock_methods(&req); +#endif + + /* + * Initialize the tree. + */ + if ((tree = malloc(sizeof(struct snmp_node) * CTREE_SIZE)) == NULL) { + syslog(LOG_ERR, "%m"); + exit(1); + } + memcpy(tree, ctree, sizeof(struct snmp_node) * CTREE_SIZE); + tree_size = CTREE_SIZE; + + /* + * Get standard communities + */ + comm_define(COMM_READ, "SNMP read", NULL, NULL); + comm_define(COMM_WRITE, "SNMP write", NULL, NULL); + community = COMM_INITIALIZE; + + trap_reqid = reqid_allocate(512, NULL); + + if (config_file[0] == '\0') + snprintf(config_file, sizeof(config_file), PATH_CONFIG, prefix); + + init_actvals(); + init_snmpd_engine(); + + this_tick = get_ticks(); + start_tick = this_tick; + + /* start transports */ + if (atexit(trans_stop) == -1) { + syslog(LOG_ERR, "atexit failed: %m"); + exit(1); + } + if (udp_trans.start() != SNMP_ERR_NOERROR) + syslog(LOG_WARNING, "cannot start UDP transport"); + if (lsock_trans.start() != SNMP_ERR_NOERROR) + syslog(LOG_WARNING, "cannot start LSOCK transport"); + if (inet_trans.start() != SNMP_ERR_NOERROR) + syslog(LOG_WARNING, "cannot start INET transport"); + +#ifdef USE_LIBBEGEMOT + if (debug.evdebug > 0) + rpoll_trace = 1; +#else + if (evCreate(&evctx)) { + syslog(LOG_ERR, "evCreate: %m"); + exit(1); + } + if (debug.evdebug > 0) + evSetDebug(evctx, 10, stderr); +#endif + + if (engine_file[0] == '\0') + snprintf(engine_file, sizeof(engine_file), PATH_ENGINE, prefix); + + if (read_config(config_file, NULL)) { + syslog(LOG_ERR, "error in config file"); + exit(1); + } + + TAILQ_FOREACH(t, &transport_list, link) + TAILQ_FOREACH(p, &t->table, link) + t->vtab->init_port(p); + + init_sigs(); + + if (pid_file[0] == '\0') + snprintf(pid_file, sizeof(pid_file), PATH_PID, prefix); + + if ((fp = fopen(pid_file, "w")) != NULL) { + fprintf(fp, "%u", getpid()); + fclose(fp); + if (atexit(term) == -1) { + syslog(LOG_ERR, "atexit failed: %m"); + (void)remove(pid_file); + exit(0); + } + } + + if (or_register(&oid_snmpMIB, "The MIB module for SNMPv2 entities.", + NULL) == 0) { + syslog(LOG_ERR, "cannot register SNMPv2 MIB"); + exit(1); + } + if (or_register(&oid_begemotSnmpd, "The MIB module for the Begemot SNMPd.", + NULL) == 0) { + syslog(LOG_ERR, "cannot register begemotSnmpd MIB"); + exit(1); + } + + while ((m = TAILQ_FIRST(&modules_start)) != NULL) { + m->flags &= ~LM_ONSTARTLIST; + TAILQ_REMOVE(&modules_start, m, start); + lm_start(m); + } + + snmp_send_trap(&oid_coldStart, (struct snmp_value *)NULL); + + for (;;) { +#ifndef USE_LIBBEGEMOT + evEvent event; +#endif + struct lmodule *mod; + + TAILQ_FOREACH(mod, &lmodules, link) + if (mod->config->idle != NULL) + (*mod->config->idle)(); + +#ifndef USE_LIBBEGEMOT + if (evGetNext(evctx, &event, EV_WAIT) == 0) { + if (evDispatch(evctx, event)) + syslog(LOG_ERR, "evDispatch: %m"); + } else if (errno != EINTR) { + syslog(LOG_ERR, "evGetNext: %m"); + exit(1); + } +#else + poll_dispatch(1); +#endif + + if (work != 0) { + block_sigs(); + if (work & WORK_DOINFO) { +#ifdef USE_LIBBEGEMOT + info_func(); +#else + if (evWaitFor(evctx, &work, info_func, + NULL, NULL) == -1) { + syslog(LOG_ERR, "evWaitFor: %m"); + exit(1); + } +#endif + } + if (work & WORK_RECONFIG) { +#ifdef USE_LIBBEGEMOT + config_func(); +#else + if (evWaitFor(evctx, &work, config_func, + NULL, NULL) == -1) { + syslog(LOG_ERR, "evWaitFor: %m"); + exit(1); + } +#endif + } + work = 0; + unblock_sigs(); +#ifndef USE_LIBBEGEMOT + if (evDo(evctx, &work) == -1) { + syslog(LOG_ERR, "evDo: %m"); + exit(1); + } +#endif + } + } + + return (0); +} + +uint64_t +get_ticks(void) +{ + struct timeval tv; + uint64_t ret; + + if (gettimeofday(&tv, NULL)) + abort(); + ret = tv.tv_sec * 100ULL + tv.tv_usec / 10000ULL; + return (ret); +} + +/* + * Timer support + */ + +/* + * Trampoline for the non-repeatable timers. + */ +#ifdef USE_LIBBEGEMOT +static void +tfunc(int tid __unused, void *uap) +#else +static void +tfunc(evContext ctx __unused, void *uap, struct timespec due __unused, + struct timespec inter __unused) +#endif +{ + struct timer *tp = uap; + + LIST_REMOVE(tp, link); + tp->func(tp->udata); + free(tp); +} + +/* + * Trampoline for the repeatable timers. + */ +#ifdef USE_LIBBEGEMOT +static void +trfunc(int tid __unused, void *uap) +#else +static void +trfunc(evContext ctx __unused, void *uap, struct timespec due __unused, + struct timespec inter __unused) +#endif +{ + struct timer *tp = uap; + + tp->func(tp->udata); +} + +/* + * Start a one-shot timer + */ +void * +timer_start(u_int ticks, void (*func)(void *), void *udata, struct lmodule *mod) +{ + struct timer *tp; +#ifndef USE_LIBBEGEMOT + struct timespec due; +#endif + + if ((tp = malloc(sizeof(struct timer))) == NULL) { + syslog(LOG_CRIT, "out of memory for timer"); + exit(1); + } + +#ifndef USE_LIBBEGEMOT + due = evAddTime(evNowTime(), + evConsTime(ticks / 100, (ticks % 100) * 10000)); +#endif + + tp->udata = udata; + tp->owner = mod; + tp->func = func; + + LIST_INSERT_HEAD(&timer_list, tp, link); + +#ifdef USE_LIBBEGEMOT + if ((tp->id = poll_start_timer(ticks * 10, 0, tfunc, tp)) < 0) { + syslog(LOG_ERR, "cannot set timer: %m"); + exit(1); + } +#else + if (evSetTimer(evctx, tfunc, tp, due, evConsTime(0, 0), &tp->id) + == -1) { + syslog(LOG_ERR, "cannot set timer: %m"); + exit(1); + } +#endif + return (tp); +} + +/* + * Start a repeatable timer. When used with USE_LIBBEGEMOT the first argument + * is currently ignored and the initial number of ticks is set to the + * repeat number of ticks. + */ +void * +timer_start_repeat(u_int ticks __unused, u_int repeat_ticks, + void (*func)(void *), void *udata, struct lmodule *mod) +{ + struct timer *tp; +#ifndef USE_LIBBEGEMOT + struct timespec due; + struct timespec inter; +#endif + + if ((tp = malloc(sizeof(struct timer))) == NULL) { + syslog(LOG_CRIT, "out of memory for timer"); + exit(1); + } + +#ifndef USE_LIBBEGEMOT + due = evAddTime(evNowTime(), + evConsTime(ticks / 100, (ticks % 100) * 10000)); + inter = evConsTime(repeat_ticks / 100, (repeat_ticks % 100) * 10000); +#endif + + tp->udata = udata; + tp->owner = mod; + tp->func = func; + + LIST_INSERT_HEAD(&timer_list, tp, link); + +#ifdef USE_LIBBEGEMOT + if ((tp->id = poll_start_timer(repeat_ticks * 10, 1, trfunc, tp)) < 0) { + syslog(LOG_ERR, "cannot set timer: %m"); + exit(1); + } +#else + if (evSetTimer(evctx, trfunc, tp, due, inter, &tp->id) == -1) { + syslog(LOG_ERR, "cannot set timer: %m"); + exit(1); + } +#endif + return (tp); +} + +/* + * Stop a timer. + */ +void +timer_stop(void *p) +{ + struct timer *tp = p; + + LIST_REMOVE(tp, link); +#ifdef USE_LIBBEGEMOT + poll_stop_timer(tp->id); +#else + if (evClearTimer(evctx, tp->id) == -1) { + syslog(LOG_ERR, "cannot stop timer: %m"); + exit(1); + } +#endif + free(p); +} + +static void +timer_flush(struct lmodule *mod) +{ + struct timer *t, *t1; + + t = LIST_FIRST(&timer_list); + while (t != NULL) { + t1 = LIST_NEXT(t, link); + if (t->owner == mod) + timer_stop(t); + t = t1; + } +} + +static void +snmp_printf_func(const char *fmt, ...) +{ + va_list ap; + static char *pend = NULL; + char *ret, *new; + + va_start(ap, fmt); + vasprintf(&ret, fmt, ap); + va_end(ap); + + if (ret == NULL) + return; + if (pend != NULL) { + if ((new = realloc(pend, strlen(pend) + strlen(ret) + 1)) + == NULL) { + free(ret); + return; + } + pend = new; + strcat(pend, ret); + free(ret); + } else + pend = ret; + + while ((ret = strchr(pend, '\n')) != NULL) { + *ret = '\0'; + syslog(LOG_DEBUG, "%s", pend); + if (strlen(ret + 1) == 0) { + free(pend); + pend = NULL; + break; + } + strcpy(pend, ret + 1); + } +} + +static void +snmp_error_func(const char *err, ...) +{ + char errbuf[1000]; + va_list ap; + + if (!(snmp_trace & LOG_SNMP_ERRORS)) + return; + + va_start(ap, err); + snprintf(errbuf, sizeof(errbuf), "SNMP: "); + vsnprintf(errbuf + strlen(errbuf), + sizeof(errbuf) - strlen(errbuf), err, ap); + va_end(ap); + + syslog(LOG_ERR, "%s", errbuf); +} + +static void +snmp_debug_func(const char *err, ...) +{ + char errbuf[1000]; + va_list ap; + + va_start(ap, err); + snprintf(errbuf, sizeof(errbuf), "SNMP: "); + vsnprintf(errbuf+strlen(errbuf), sizeof(errbuf)-strlen(errbuf), + err, ap); + va_end(ap); + + syslog(LOG_DEBUG, "%s", errbuf); +} + +static void +asn_error_func(const struct asn_buf *b, const char *err, ...) +{ + char errbuf[1000]; + va_list ap; + u_int i; + + if (!(snmp_trace & LOG_ASN1_ERRORS)) + return; + + va_start(ap, err); + snprintf(errbuf, sizeof(errbuf), "ASN.1: "); + vsnprintf(errbuf + strlen(errbuf), + sizeof(errbuf) - strlen(errbuf), err, ap); + va_end(ap); + + if (b != NULL) { + snprintf(errbuf + strlen(errbuf), + sizeof(errbuf) - strlen(errbuf), " at"); + for (i = 0; b->asn_len > i; i++) + snprintf(errbuf + strlen(errbuf), + sizeof(errbuf) - strlen(errbuf), + " %02x", b->asn_cptr[i]); + } + + syslog(LOG_ERR, "%s", errbuf); +} + +/* + * Create a new community + */ +struct community* +comm_define_ordered(u_int priv, const char *descr, struct asn_oid *idx, + struct lmodule *owner, const char *str) +{ + struct community *c, *p; + u_int ncomm; + + ncomm = idx->subs[idx->len - 1]; + + /* check that community doesn't already exist */ + TAILQ_FOREACH(c, &community_list, link) + if (c->value == ncomm) + return (c); + + if ((c = malloc(sizeof(struct community))) == NULL) { + syslog(LOG_ERR, "%s: %m", __func__); + return (NULL); + } + c->owner = owner; + c->value = ncomm; + c->descr = descr; + c->string = NULL; + c->private = priv; + + if (str != NULL) { + if((c->string = malloc(strlen(str)+1)) == NULL) { + free(c); + return (NULL); + } + strcpy(c->string, str); + } + /* + * Insert ordered + */ + c->index = *idx; + TAILQ_FOREACH(p, &community_list, link) { + if (asn_compare_oid(&p->index, &c->index) > 0) { + TAILQ_INSERT_BEFORE(p, c, link); + break; + } + } + if (p == NULL) + TAILQ_INSERT_TAIL(&community_list, c, link); + return (c); +} + +u_int +comm_define(u_int priv, const char *descr, struct lmodule *owner, + const char *str) +{ + struct asn_oid idx, *p; + struct community *c; + u_int ncomm; + + /* generate an identifier */ + do { + if ((ncomm = next_community_index++) == UINT_MAX) + next_community_index = 1; + TAILQ_FOREACH(c, &community_list, link) + if (c->value == ncomm) + break; + } while (c != NULL); + + /* make index */ + if (owner != NULL) + p = &owner->index; + else { + p = &idx; + p->len = 1; + p->subs[0] = 0; + } + p->subs[p->len++] = ncomm; + c = comm_define_ordered(priv, descr, p, owner, str); + if (c == NULL) + return (0); + return (c->value); +} + +const char * +comm_string(u_int ncomm) +{ + struct community *p; + + TAILQ_FOREACH(p, &community_list, link) + if (p->value == ncomm) + return (p->string); + return (NULL); +} + +/* + * Delete all communities allocated by a module + */ +static void +comm_flush(struct lmodule *mod) +{ + struct community *p, *p1; + + p = TAILQ_FIRST(&community_list); + while (p != NULL) { + p1 = TAILQ_NEXT(p, link); + if (p->owner == mod) { + free(p->string); + TAILQ_REMOVE(&community_list, p, link); + free(p); + } + p = p1; + } +} + +/* + * Request ID handling. + * + * Allocate a new range of request ids. Use a first fit algorithm. + */ +u_int +reqid_allocate(int size, struct lmodule *mod) +{ + u_int type; + struct idrange *r, *r1; + + if (size <= 0 || size > INT32_MAX) { + syslog(LOG_CRIT, "%s: size out of range: %d", __func__, size); + return (0); + } + /* allocate a type id */ + do { + if ((type = next_idrange++) == UINT_MAX) + next_idrange = 1; + TAILQ_FOREACH(r, &idrange_list, link) + if (r->type == type) + break; + } while(r != NULL); + + /* find a range */ + if (TAILQ_EMPTY(&idrange_list)) + r = NULL; + else { + r = TAILQ_FIRST(&idrange_list); + if (r->base < size) { + while((r1 = TAILQ_NEXT(r, link)) != NULL) { + if (r1->base - (r->base + r->size) >= size) + break; + r = r1; + } + r = r1; + } + if (r == NULL) { + r1 = TAILQ_LAST(&idrange_list, idrange_list); + if (INT32_MAX - size + 1 < r1->base + r1->size) { + syslog(LOG_ERR, "out of id ranges (%u)", size); + return (0); + } + } + } + + /* allocate structure */ + if ((r1 = malloc(sizeof(struct idrange))) == NULL) { + syslog(LOG_ERR, "%s: %m", __FUNCTION__); + return (0); + } + + r1->type = type; + r1->size = size; + r1->owner = mod; + if (TAILQ_EMPTY(&idrange_list) || r == TAILQ_FIRST(&idrange_list)) { + r1->base = 0; + TAILQ_INSERT_HEAD(&idrange_list, r1, link); + } else if (r == NULL) { + r = TAILQ_LAST(&idrange_list, idrange_list); + r1->base = r->base + r->size; + TAILQ_INSERT_TAIL(&idrange_list, r1, link); + } else { + r = TAILQ_PREV(r, idrange_list, link); + r1->base = r->base + r->size; + TAILQ_INSERT_AFTER(&idrange_list, r, r1, link); + } + r1->next = r1->base; + + return (type); +} + +int32_t +reqid_next(u_int type) +{ + struct idrange *r; + int32_t id; + + TAILQ_FOREACH(r, &idrange_list, link) + if (r->type == type) + break; + if (r == NULL) { + syslog(LOG_CRIT, "wrong idrange type"); + abort(); + } + if ((id = r->next++) == r->base + (r->size - 1)) + r->next = r->base; + return (id); +} + +int32_t +reqid_base(u_int type) +{ + struct idrange *r; + + TAILQ_FOREACH(r, &idrange_list, link) + if (r->type == type) + return (r->base); + syslog(LOG_CRIT, "wrong idrange type"); + abort(); +} + +u_int +reqid_type(int32_t reqid) +{ + struct idrange *r; + + TAILQ_FOREACH(r, &idrange_list, link) + if (reqid >= r->base && reqid <= r->base + (r->size - 1)) + return (r->type); + return (0); +} + +int +reqid_istype(int32_t reqid, u_int type) +{ + return (reqid_type(reqid) == type); +} + +/* + * Delete all communities allocated by a module + */ +static void +reqid_flush(struct lmodule *mod) +{ + struct idrange *p, *p1; + + p = TAILQ_FIRST(&idrange_list); + while (p != NULL) { + p1 = TAILQ_NEXT(p, link); + if (p->owner == mod) { + TAILQ_REMOVE(&idrange_list, p, link); + free(p); + } + p = p1; + } +} + +/* + * Merge the given tree for the given module into the main tree. + */ +static int +compare_node(const void *v1, const void *v2) +{ + const struct snmp_node *n1 = v1; + const struct snmp_node *n2 = v2; + + return (asn_compare_oid(&n1->oid, &n2->oid)); +} +static int +tree_merge(const struct snmp_node *ntree, u_int nsize, struct lmodule *mod) +{ + struct snmp_node *xtree; + u_int i; + + xtree = realloc(tree, sizeof(*tree) * (tree_size + nsize)); + if (xtree == NULL) { + syslog(LOG_ERR, "tree_merge: %m"); + return (-1); + } + tree = xtree; + memcpy(&tree[tree_size], ntree, sizeof(*tree) * nsize); + + for (i = 0; i < nsize; i++) + tree[tree_size + i].tree_data = mod; + + tree_size += nsize; + + qsort(tree, tree_size, sizeof(tree[0]), compare_node); + + return (0); +} + +/* + * Remove all nodes belonging to the loadable module + */ +static void +tree_unmerge(struct lmodule *mod) +{ + u_int s, d; + + for(s = d = 0; s < tree_size; s++) + if (tree[s].tree_data != mod) { + if (s != d) + tree[d] = tree[s]; + d++; + } + tree_size = d; +} + +/* + * Loadable modules + */ +struct lmodule * +lm_load(const char *path, const char *section) +{ + struct lmodule *m; + int err; + int i; + char *av[MAX_MOD_ARGS + 1]; + int ac; + u_int u; + + if ((m = malloc(sizeof(*m))) == NULL) { + syslog(LOG_ERR, "lm_load: %m"); + return (NULL); + } + m->handle = NULL; + m->flags = 0; + strlcpy(m->section, section, sizeof(m->section)); + + if ((m->path = strdup(path)) == NULL) { + syslog(LOG_ERR, "lm_load: %m"); + goto err; + } + + /* + * Make index + */ + m->index.subs[0] = strlen(section); + m->index.len = m->index.subs[0] + 1; + for (u = 0; u < m->index.subs[0]; u++) + m->index.subs[u + 1] = section[u]; + + /* + * Load the object file and locate the config structure + */ + if ((m->handle = dlopen(m->path, RTLD_NOW|RTLD_GLOBAL)) == NULL) { + syslog(LOG_ERR, "lm_load: open %s", dlerror()); + goto err; + } + + if ((m->config = dlsym(m->handle, "config")) == NULL) { + syslog(LOG_ERR, "lm_load: no 'config' symbol %s", dlerror()); + goto err; + } + + /* + * Insert it into the right place + */ + INSERT_OBJECT_OID(m, &lmodules); + + /* preserve order */ + if (community == COMM_INITIALIZE) { + m->flags |= LM_ONSTARTLIST; + TAILQ_INSERT_TAIL(&modules_start, m, start); + } + + /* + * make the argument vector. + */ + ac = 0; + for (i = 0; i < nprogargs; i++) { + if (strlen(progargs[i]) >= strlen(section) + 1 && + strncmp(progargs[i], section, strlen(section)) == 0 && + progargs[i][strlen(section)] == ':') { + if (ac == MAX_MOD_ARGS) { + syslog(LOG_WARNING, "too many arguments for " + "module '%s", section); + break; + } + av[ac++] = &progargs[i][strlen(section)+1]; + } + } + av[ac] = NULL; + + /* + * Run the initialization function + */ + if ((err = (*m->config->init)(m, ac, av)) != 0) { + syslog(LOG_ERR, "lm_load: init failed: %d", err); + TAILQ_REMOVE(&lmodules, m, link); + goto err; + } + + return (m); + + err: + if ((m->flags & LM_ONSTARTLIST) != 0) + TAILQ_REMOVE(&modules_start, m, start); + if (m->handle) + dlclose(m->handle); + free(m->path); + free(m); + return (NULL); +} + +/* + * Start a module + */ +void +lm_start(struct lmodule *mod) +{ + const struct lmodule *m; + + /* + * Merge tree. If this fails, unload the module. + */ + if (tree_merge(mod->config->tree, mod->config->tree_size, mod)) { + lm_unload(mod); + return; + } + + /* + * Read configuration + */ + if (read_config(config_file, mod)) { + syslog(LOG_ERR, "error in config file"); + lm_unload(mod); + return; + } + if (mod->config->start) + (*mod->config->start)(); + + mod->flags |= LM_STARTED; + + /* + * Inform other modules + */ + TAILQ_FOREACH(m, &lmodules, link) + if (m->config->loading) + (*m->config->loading)(mod, 1); +} + + +/* + * Unload a module. + */ +void +lm_unload(struct lmodule *m) +{ + int err; + const struct lmodule *mod; + + TAILQ_REMOVE(&lmodules, m, link); + if (m->flags & LM_ONSTARTLIST) + TAILQ_REMOVE(&modules_start, m, start); + tree_unmerge(m); + + if ((m->flags & LM_STARTED) && m->config->fini && + (err = (*m->config->fini)()) != 0) + syslog(LOG_WARNING, "lm_unload(%s): fini %d", m->section, err); + + comm_flush(m); + reqid_flush(m); + timer_flush(m); + fd_flush(m); + + dlclose(m->handle); + free(m->path); + + /* + * Inform other modules + */ + TAILQ_FOREACH(mod, &lmodules, link) + if (mod->config->loading) + (*mod->config->loading)(m, 0); + + free(m); +} + +/* + * Register an object resource and return the index (or 0 on failures) + */ +u_int +or_register(const struct asn_oid *or, const char *descr, struct lmodule *mod) +{ + struct objres *objres, *or1; + u_int idx; + + /* find a free index */ + idx = 1; + for (objres = TAILQ_FIRST(&objres_list); + objres != NULL; + objres = TAILQ_NEXT(objres, link)) { + if ((or1 = TAILQ_NEXT(objres, link)) == NULL || + or1->index > objres->index + 1) { + idx = objres->index + 1; + break; + } + } + + if ((objres = malloc(sizeof(*objres))) == NULL) + return (0); + + objres->index = idx; + objres->oid = *or; + strlcpy(objres->descr, descr, sizeof(objres->descr)); + objres->uptime = (uint32_t)(get_ticks() - start_tick); + objres->module = mod; + + INSERT_OBJECT_INT(objres, &objres_list); + + systemg.or_last_change = objres->uptime; + + return (idx); +} + +void +or_unregister(u_int idx) +{ + struct objres *objres; + + TAILQ_FOREACH(objres, &objres_list, link) + if (objres->index == idx) { + TAILQ_REMOVE(&objres_list, objres, link); + free(objres); + return; + } +} + +/* + * RFC 3414 User-based Security Model support + */ + +struct snmpd_usmstat * +bsnmpd_get_usm_stats(void) +{ + return (&snmpd_usmstats); +} + +void +bsnmpd_reset_usm_stats(void) +{ + memset(&snmpd_usmstats, 0, sizeof(snmpd_usmstats)); +} + +struct usm_user * +usm_first_user(void) +{ + return (SLIST_FIRST(&usm_userlist)); +} + +struct usm_user * +usm_next_user(struct usm_user *uuser) +{ + if (uuser == NULL) + return (NULL); + + return (SLIST_NEXT(uuser, up)); +} + +struct usm_user * +usm_find_user(uint8_t *engine, uint32_t elen, char *uname) +{ + struct usm_user *uuser; + + SLIST_FOREACH(uuser, &usm_userlist, up) + if (uuser->user_engine_len == elen && + memcmp(uuser->user_engine_id, engine, elen) == 0 && + strlen(uuser->suser.sec_name) == strlen(uname) && + strcmp(uuser->suser.sec_name, uname) == 0) + break; + + return (uuser); +} + +static int +usm_compare_user(struct usm_user *u1, struct usm_user *u2) +{ + uint32_t i; + + if (u1->user_engine_len < u2->user_engine_len) + return (-1); + if (u1->user_engine_len > u2->user_engine_len) + return (1); + + for (i = 0; i < u1->user_engine_len; i++) { + if (u1->user_engine_id[i] < u2->user_engine_id[i]) + return (-1); + if (u1->user_engine_id[i] > u2->user_engine_id[i]) + return (1); + } + + if (strlen(u1->suser.sec_name) < strlen(u2->suser.sec_name)) + return (-1); + if (strlen(u1->suser.sec_name) > strlen(u2->suser.sec_name)) + return (1); + + for (i = 0; i < strlen(u1->suser.sec_name); i++) { + if (u1->suser.sec_name[i] < u2->suser.sec_name[i]) + return (-1); + if (u1->suser.sec_name[i] > u2->suser.sec_name[i]) + return (1); + } + + return (0); +} + +struct usm_user * +usm_new_user(uint8_t *eid, uint32_t elen, char *uname) +{ + int cmp; + struct usm_user *uuser, *temp, *prev; + + for (uuser = usm_first_user(); uuser != NULL; + (uuser = usm_next_user(uuser))) { + if (uuser->user_engine_len == elen && + strlen(uname) == strlen(uuser->suser.sec_name) && + strcmp(uname, uuser->suser.sec_name) == 0 && + memcmp(eid, uuser->user_engine_id, elen) == 0) + return (NULL); + } + + if ((uuser = (struct usm_user *)malloc(sizeof(*uuser))) == NULL) + return (NULL); + + memset(uuser, 0, sizeof(*uuser)); + strlcpy(uuser->suser.sec_name, uname, SNMP_ADM_STR32_SIZ); + memcpy(uuser->user_engine_id, eid, elen); + uuser->user_engine_len = elen; + + if ((prev = SLIST_FIRST(&usm_userlist)) == NULL || + usm_compare_user(uuser, prev) < 0) { + SLIST_INSERT_HEAD(&usm_userlist, uuser, up); + return (uuser); + } + + SLIST_FOREACH(temp, &usm_userlist, up) { + if ((cmp = usm_compare_user(uuser, temp)) <= 0) + break; + prev = temp; + } + + if (temp == NULL || cmp < 0) + SLIST_INSERT_AFTER(prev, uuser, up); + else if (cmp > 0) + SLIST_INSERT_AFTER(temp, uuser, up); + else { + syslog(LOG_ERR, "User %s exists", uuser->suser.sec_name); + free(uuser); + return (NULL); + } + + return (uuser); +} + +void +usm_delete_user(struct usm_user *uuser) +{ + SLIST_REMOVE(&usm_userlist, uuser, usm_user, up); + free(uuser); +} + +void +usm_flush_users(void) +{ + struct usm_user *uuser; + + while ((uuser = SLIST_FIRST(&usm_userlist)) != NULL) { + SLIST_REMOVE_HEAD(&usm_userlist, up); + free(uuser); + } + + SLIST_INIT(&usm_userlist); +} + +/* + * RFC 3415 View-based Access Control Model support + */ +struct vacm_user * +vacm_first_user(void) +{ + return (SLIST_FIRST(&vacm_userlist)); +} + +struct vacm_user * +vacm_next_user(struct vacm_user *vuser) +{ + if (vuser == NULL) + return (NULL); + + return (SLIST_NEXT(vuser, vvu)); +} + +static int +vacm_compare_user(struct vacm_user *v1, struct vacm_user *v2) +{ + uint32_t i; + + if (v1->sec_model < v2->sec_model) + return (-1); + if (v1->sec_model > v2->sec_model) + return (1); + + if (strlen(v1->secname) < strlen(v2->secname)) + return (-1); + if (strlen(v1->secname) > strlen(v2->secname)) + return (1); + + for (i = 0; i < strlen(v1->secname); i++) { + if (v1->secname[i] < v2->secname[i]) + return (-1); + if (v1->secname[i] > v2->secname[i]) + return (1); + } + + return (0); +} + +struct vacm_user * +vacm_new_user(int32_t smodel, char *uname) +{ + int cmp; + struct vacm_user *user, *temp, *prev; + + SLIST_FOREACH(user, &vacm_userlist, vvu) + if (strcmp(uname, user->secname) == 0 && + smodel == user->sec_model) + return (NULL); + + if ((user = (struct vacm_user *)malloc(sizeof(*user))) == NULL) + return (NULL); + + memset(user, 0, sizeof(*user)); + user->group = &vacm_default_group; + SLIST_INSERT_HEAD(&vacm_default_group.group_users, user, vvg); + user->sec_model = smodel; + strlcpy(user->secname, uname, sizeof(user->secname)); + + if ((prev = SLIST_FIRST(&vacm_userlist)) == NULL || + vacm_compare_user(user, prev) < 0) { + SLIST_INSERT_HEAD(&vacm_userlist, user, vvu); + return (user); + } + + SLIST_FOREACH(temp, &vacm_userlist, vvu) { + if ((cmp = vacm_compare_user(user, temp)) <= 0) + break; + prev = temp; + } + + if (temp == NULL || cmp < 0) + SLIST_INSERT_AFTER(prev, user, vvu); + else if (cmp > 0) + SLIST_INSERT_AFTER(temp, user, vvu); + else { + syslog(LOG_ERR, "User %s exists", user->secname); + free(user); + return (NULL); + } + + return (user); +} + +int +vacm_delete_user(struct vacm_user *user) +{ + if (user->group != NULL && user->group != &vacm_default_group) { + SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg); + if (SLIST_EMPTY(&user->group->group_users)) { + SLIST_REMOVE(&vacm_grouplist, user->group, + vacm_group, vge); + free(user->group); + } + } + + SLIST_REMOVE(&vacm_userlist, user, vacm_user, vvu); + free(user); + + return (0); +} + +int +vacm_user_set_group(struct vacm_user *user, u_char *octets, u_int len) +{ + struct vacm_group *group; + + if (len >= SNMP_ADM_STR32_SIZ) + return (-1); + + SLIST_FOREACH(group, &vacm_grouplist, vge) + if (strlen(group->groupname) == len && + memcmp(octets, group->groupname, len) == 0) + break; + + if (group == NULL) { + if ((group = (struct vacm_group *)malloc(sizeof(*group))) == NULL) + return (-1); + memset(group, 0, sizeof(*group)); + memcpy(group->groupname, octets, len); + group->groupname[len] = '\0'; + SLIST_INSERT_HEAD(&vacm_grouplist, group, vge); + } + + SLIST_REMOVE(&user->group->group_users, user, vacm_user, vvg); + SLIST_INSERT_HEAD(&group->group_users, user, vvg); + user->group = group; + + return (0); +} + +void +vacm_groups_init(void) +{ + SLIST_INSERT_HEAD(&vacm_grouplist, &vacm_default_group, vge); +} + +struct vacm_access * +vacm_first_access_rule(void) +{ + return (TAILQ_FIRST(&vacm_accesslist)); +} + +struct vacm_access * +vacm_next_access_rule(struct vacm_access *acl) +{ + if (acl == NULL) + return (NULL); + + return (TAILQ_NEXT(acl, vva)); +} + +static int +vacm_compare_access_rule(struct vacm_access *v1, struct vacm_access *v2) +{ + uint32_t i; + + if (strlen(v1->group->groupname) < strlen(v2->group->groupname)) + return (-1); + if (strlen(v1->group->groupname) > strlen(v2->group->groupname)) + return (1); + + for (i = 0; i < strlen(v1->group->groupname); i++) { + if (v1->group->groupname[i] < v2->group->groupname[i]) + return (-1); + if (v1->group->groupname[i] > v2->group->groupname[i]) + return (1); + } + + if (strlen(v1->ctx_prefix) < strlen(v2->ctx_prefix)) + return (-1); + if (strlen(v1->ctx_prefix) > strlen(v2->ctx_prefix)) + return (1); + + for (i = 0; i < strlen(v1->ctx_prefix); i++) { + if (v1->ctx_prefix[i] < v2->ctx_prefix[i]) + return (-1); + if (v1->ctx_prefix[i] > v2->ctx_prefix[i]) + return (1); + } + + if (v1->sec_model < v2->sec_model) + return (-1); + if (v1->sec_model > v2->sec_model) + return (1); + + if (v1->sec_level < v2->sec_level) + return (-1); + if (v1->sec_level > v2->sec_level) + return (1); + + return (0); +} + +struct vacm_access * +vacm_new_access_rule(char *gname, char *cprefix, int32_t smodel, int32_t slevel) +{ + struct vacm_group *group; + struct vacm_access *acl, *temp; + + TAILQ_FOREACH(acl, &vacm_accesslist, vva) { + if (acl->group == NULL) + continue; + if (strcmp(gname, acl->group->groupname) == 0 && + strcmp(cprefix, acl->ctx_prefix) == 0 && + acl->sec_model == smodel && acl->sec_level == slevel) + return (NULL); + } + + /* Make sure the group exists */ + SLIST_FOREACH(group, &vacm_grouplist, vge) + if (strcmp(gname, group->groupname) == 0) + break; + + if (group == NULL) + return (NULL); + + if ((acl = (struct vacm_access *)malloc(sizeof(*acl))) == NULL) + return (NULL); + + memset(acl, 0, sizeof(*acl)); + acl->group = group; + strlcpy(acl->ctx_prefix, cprefix, sizeof(acl->ctx_prefix)); + acl->sec_model = smodel; + acl->sec_level = slevel; + + if ((temp = TAILQ_FIRST(&vacm_accesslist)) == NULL || + vacm_compare_access_rule(acl, temp) < 0) { + TAILQ_INSERT_HEAD(&vacm_accesslist, acl, vva); + return (acl); + } + + TAILQ_FOREACH(temp, &vacm_accesslist, vva) + if (vacm_compare_access_rule(acl, temp) < 0) { + TAILQ_INSERT_BEFORE(temp, acl, vva); + return (acl); + } + + TAILQ_INSERT_TAIL(&vacm_accesslist, acl, vva); + + return (acl); +} + +int +vacm_delete_access_rule(struct vacm_access *acl) +{ + TAILQ_REMOVE(&vacm_accesslist, acl, vva); + free(acl); + + return (0); +} + +struct vacm_view * +vacm_first_view(void) +{ + return (SLIST_FIRST(&vacm_viewlist)); +} + +struct vacm_view * +vacm_next_view(struct vacm_view *view) +{ + if (view == NULL) + return (NULL); + + return (SLIST_NEXT(view, vvl)); +} + +static int +vacm_compare_view(struct vacm_view *v1, struct vacm_view *v2) +{ + uint32_t i; + + if (strlen(v1->viewname) < strlen(v2->viewname)) + return (-1); + if (strlen(v1->viewname) > strlen(v2->viewname)) + return (1); + + for (i = 0; i < strlen(v1->viewname); i++) { + if (v1->viewname[i] < v2->viewname[i]) + return (-1); + if (v1->viewname[i] > v2->viewname[i]) + return (1); + } + + return (asn_compare_oid(&v1->subtree, &v2->subtree)); +} + +struct vacm_view * +vacm_new_view(char *vname, struct asn_oid *oid) +{ + int cmp; + struct vacm_view *view, *temp, *prev; + + SLIST_FOREACH(view, &vacm_viewlist, vvl) + if (strcmp(vname, view->viewname) == 0) + return (NULL); + + if ((view = (struct vacm_view *)malloc(sizeof(*view))) == NULL) + return (NULL); + + memset(view, 0, sizeof(*view)); + strlcpy(view->viewname, vname, sizeof(view->viewname)); + asn_append_oid(&view->subtree, oid); + + if ((prev = SLIST_FIRST(&vacm_viewlist)) == NULL || + vacm_compare_view(view, prev) < 0) { + SLIST_INSERT_HEAD(&vacm_viewlist, view, vvl); + return (view); + } + + SLIST_FOREACH(temp, &vacm_viewlist, vvl) { + if ((cmp = vacm_compare_view(view, temp)) <= 0) + break; + prev = temp; + } + + if (temp == NULL || cmp < 0) + SLIST_INSERT_AFTER(prev, view, vvl); + else if (cmp > 0) + SLIST_INSERT_AFTER(temp, view, vvl); + else { + syslog(LOG_ERR, "View %s exists", view->viewname); + free(view); + return (NULL); + } + + return (view); +} + +int +vacm_delete_view(struct vacm_view *view) +{ + SLIST_REMOVE(&vacm_viewlist, view, vacm_view, vvl); + free(view); + + return (0); +} + +struct vacm_context * +vacm_first_context(void) +{ + return (SLIST_FIRST(&vacm_contextlist)); +} + +struct vacm_context * +vacm_next_context(struct vacm_context *vacmctx) +{ + if (vacmctx == NULL) + return (NULL); + + return (SLIST_NEXT(vacmctx, vcl)); +} + +struct vacm_context * +vacm_add_context(char *ctxname, int regid) +{ + int cmp; + struct vacm_context *ctx, *temp, *prev; + + SLIST_FOREACH(ctx, &vacm_contextlist, vcl) + if (strcmp(ctxname, ctx->ctxname) == 0) { + syslog(LOG_ERR, "Context %s exists", ctx->ctxname); + return (NULL); + } + + if ((ctx = (struct vacm_context *)malloc(sizeof(*ctx))) == NULL) + return (NULL); + + memset(ctx, 0, sizeof(*ctx)); + strlcpy(ctx->ctxname, ctxname, sizeof(ctx->ctxname)); + ctx->regid = regid; + + if ((prev = SLIST_FIRST(&vacm_contextlist)) == NULL || + strlen(ctx->ctxname) < strlen(prev->ctxname) || + strcmp(ctx->ctxname, prev->ctxname) < 0) { + SLIST_INSERT_HEAD(&vacm_contextlist, ctx, vcl); + return (ctx); + } + + SLIST_FOREACH(temp, &vacm_contextlist, vcl) { + if (strlen(ctx->ctxname) < strlen(temp->ctxname) || + strcmp(ctx->ctxname, temp->ctxname) < 0) { + cmp = -1; + break; + } + prev = temp; + } + + if (temp == NULL || cmp < 0) + SLIST_INSERT_AFTER(prev, ctx, vcl); + else if (cmp > 0) + SLIST_INSERT_AFTER(temp, ctx, vcl); + else { + syslog(LOG_ERR, "Context %s exists", ctx->ctxname); + free(ctx); + return (NULL); + } + + return (ctx); +} + +void +vacm_flush_contexts(int regid) +{ + struct vacm_context *ctx, *temp; + + SLIST_FOREACH_SAFE(ctx, &vacm_contextlist, vcl, temp) + if (ctx->regid == regid) { + SLIST_REMOVE(&vacm_contextlist, ctx, vacm_context, vcl); + free(ctx); + } +} Property changes on: vendor/1.14/snmpd/main.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmpd/snmpd.config =================================================================== --- vendor/1.14/snmpd/snmpd.config (nonexistent) +++ vendor/1.14/snmpd/snmpd.config (revision 359491) @@ -0,0 +1,183 @@ +# +# Copyright (c) 2001-2003 +# Fraunhofer Institute for Open Communication Systems (FhG Fokus). +# All rights reserved. +# +# Author: Harti Brandt +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $Begemot: bsnmp/snmpd/snmpd.config,v 1.16 2006/02/14 09:04:20 brandt_h Exp $ +# +# Example configuration file for testing. +# + +# +# Set some common variables +# +host := foo.bar.com +location := "Room 200" +contact := "sysmeister@bar.com" +system := 1 # FreeBSD +traphost := localhost +trapport := 162 + +read := "public" +write := "geheim" # take care - this allows writing +trap := "mytrap" + +securityModelSNMPv1 := 1 +securityModelSNMPv2c := 2 + +noAuthNoPriv := 1 + +# +# Configuration +# +%snmpd +begemotSnmpdDebugDumpPdus = 2 +begemotSnmpdDebugSyslogPri = 7 +begemotSnmpdDebugSnmpTrace = 0 + +# +# Set community strings. +# +# Each community string has a permission attached to it - 1 for read only +# and 2 for read/write. Default is 1. Community strings must be unique. +# +# Be sure to understand the security implications of SNMPv2 - the community +# strings are readable on the wire! +# +begemotSnmpdCommunityString.0.1 = $(read) +begemotSnmpdCommunityPermission.0.1 = 1 +#begemotSnmpdCommunityString.0.2 = $(write) +#begemotSnmpdCommunityPermission.0.2 = 2 +#begemotSnmpdCommunityString.0.3 = "otherPublic" +begemotSnmpdCommunityDisable = 1 + +# open standard SNMP ports +# 0.0.0.0:161 +begemotSnmpdTransInetStatus.1.4.0.0.0.0.161.1 = 4 + +# test the port table; IPv4 address +# 127.0.0.1:10161 +begemotSnmpdTransInetStatus.1.4.127.0.0.1.10161.1 = 4 + +# test the port table; IPv6 address +# ::1:10162 +begemotSnmpdTransInetStatus.2.16.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.1.10162.1 = 4 +# :::10163 +begemotSnmpdTransInetStatus.2.16.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.10163.1 = 4 +# fe80::1%1:10164 - requires inet fe80::1%em0/64 +begemotSnmpdTransInetStatus.4.20.254.128.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.1.10164.1 = 4 +# fe80::1%2:10164 - requires inet fe80::1%em1/64 +begemotSnmpdTransInetStatus.4.20.254.128.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.2.10164.1 = 4 +# fe80::1:10170 - should fail (no scope index) +# begemotSnmpdTransInetStatus.2.16.254.128.0.0.0.0.0.0.0.0.0.0.0.0.0.1.10170.1 = 4 +# fe80::1%0:10170 - should fail (default scope index for link local address) +# begemotSnmpdTransInetStatus.4.20.254.128.0.0.0.0.0.0.0.0.0.0.0.0.0.1.0.0.0.0.10170.1 = 4 + +# test the port table; DNS address +# :10165 UDPv4 and UDPv6 +begemotSnmpdTransInetStatus.16.0.10165.1 = 4 +# 127.0.0.1:10166 +# ::1:10166 +begemotSnmpdTransInetStatus.16."localhost".10166.1 = 4 +# ::1:10167 +begemotSnmpdTransInetStatus.16."localhost6".10167.1 = 4 +# fe80::1%em0:10168 - requires inet fe80::$em0/64 +begemotSnmpdTransInetStatus.16."fe80::1%em0".10168.1 = 4 +# fe80::1%em1:10169 - requires inet fe80::$em1/64 +begemotSnmpdTransInetStatus.16."fe80::1%em1".10169.1 = 4 + +# open a unix domain socket +# begemotSnmpdLocalPortStatus."/var/run/snmpd.sock" = 1 +# begemotSnmpdLocalPortType."/var/run/snmpd.sock" = 4 + +# send traps to the traphost +begemotTrapSinkStatus.[$(traphost)].$(trapport) = 4 +begemotTrapSinkVersion.[$(traphost)].$(trapport) = 2 +begemotTrapSinkComm.[$(traphost)].$(trapport) = $(trap) + +sysContact = $(contact) +sysLocation = $(location) +sysObjectId = 1.3.6.1.4.1.12325.1.1.2.1.$(system) + +snmpEnableAuthenTraps = 2 + +# +# Load MIB-2 module +# +#begemotSnmpdModulePath."mibII" = "../snmp_mibII/.libs/snmp_mibII.so" +begemotSnmpdModulePath."mibII" = "/usr/local/lib/snmp_mibII.so" + +# +# SNMPv3 notification targets +# +#begemotSnmpdModulePath."target" = "../snmp_target/.libs/snmp_target.so" +begemotSnmpdModulePath."target" = "/usr/local/lib/snmp_target.so" + +# +# SNMPv3 user-based security module +# +#begemotSnmpdModulePath."usm" = "../snmp_usm/.libs/snmp_usm.so" +begemotSnmpdModulePath."usm" = "/usr/local/lib/snmp_usm.so" + +# +# SNMPv3 view-based access control module +# +#begemotSnmpdModulePath."vacm" = "../snmp_vacm/.libs/snmp_vacm.so" +begemotSnmpdModulePath."vacm" = "/usr/local/lib/snmp_vacm.so" + +# +# Netgraph module +# +# begemotSnmpdModulePath."netgraph" = "/usr/local/lib/snmp_netgraph.so" +# %netgraph +# begemotNgControlNodeName = "snmpd" + +%vacm + +internetoid := 1.3.6.1 +internetoidlen := 4 + +vacmSecurityToGroupStatus.$(securityModelSNMPv1).$(read) = 4 +vacmGroupName.$(securityModelSNMPv1).$(read) = $(read) + +vacmSecurityToGroupStatus.$(securityModelSNMPv2c).$(read) = 4 +vacmGroupName.$(securityModelSNMPv2c).$(read) = $(read) + +vacmSecurityToGroupStatus.$(securityModelSNMPv2c).$(write) = 4 +vacmGroupName.$(securityModelSNMPv2c).$(write) = $(write) + +vacmViewTreeFamilyStatus."internet".$(internetoidlen).$(internetoid) = 4 + +vacmAccessStatus.$(read)."".$(securityModelSNMPv1).$(noAuthNoPriv) = 4 +vacmAccessReadViewName.$(read)."".$(securityModelSNMPv1).$(noAuthNoPriv) = "internet" + +vacmAccessStatus.$(write)."".$(securityModelSNMPv2c).$(noAuthNoPriv) = 4 +vacmAccessStatus.$(read)."".$(securityModelSNMPv2c).$(noAuthNoPriv) = 4 +vacmAccessReadViewName.$(write)."".$(securityModelSNMPv2c).$(noAuthNoPriv) = "internet" +vacmAccessReadViewName.$(read)."".$(securityModelSNMPv2c).$(noAuthNoPriv) = "internet" +vacmAccessWriteViewName.$(write)."".$(securityModelSNMPv2c).$(noAuthNoPriv) = "internet" +vacmAccessWriteViewName.$(read)."".$(securityModelSNMPv2c).$(noAuthNoPriv) = "internet" + Property changes on: vendor/1.14/snmpd/snmpd.config ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmpd/snmpd.h =================================================================== --- vendor/1.14/snmpd/snmpd.h (nonexistent) +++ vendor/1.14/snmpd/snmpd.h (revision 359491) @@ -0,0 +1,346 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmpd/snmpd.h,v 1.24 2004/08/06 08:47:13 brandt Exp $ + * + * Private SNMPd data and functions. + */ + +#ifdef USE_LIBBEGEMOT +#include +#else +#include +#endif + +#define PATH_SYSCONFIG "/etc:/usr/etc:/usr/local/etc" + +#ifdef USE_LIBBEGEMOT +#define evTimerID int +#define evFileID int +#endif + +/************************************************************* + * + * Communities + */ +struct community { + struct lmodule *owner; /* who created the community */ + u_int private;/* private name for the module */ + u_int value; /* value of this community */ + u_char * string; /* the community string */ + const u_char * descr; /* description */ + TAILQ_ENTRY(community) link; + + struct asn_oid index; +}; +/* list of all known communities */ +extern TAILQ_HEAD(community_list, community) community_list; + +/************************************************************* + * + * Request IDs. + */ +struct idrange { + u_int type; /* type id */ + int32_t base; /* base of this range */ + int32_t size; /* size of this range */ + int32_t next; /* generator */ + struct lmodule *owner; /* owner module */ + TAILQ_ENTRY(idrange) link; +}; + +/* list of all known ranges */ +extern TAILQ_HEAD(idrange_list, idrange) idrange_list; + +/* identifier generator */ +extern u_int next_idrange; + +/* request id generator for traps */ +extern u_int trap_reqid; + +/************************************************************* + * + * Timers + */ +struct timer { + void (*func)(void *);/* user function */ + void *udata; /* user data */ + evTimerID id; /* timer id */ + struct lmodule *owner; /* owner of the timer */ + LIST_ENTRY(timer) link; +}; + +/* list of all current timers */ +extern LIST_HEAD(timer_list, timer) timer_list; + + +/************************************************************* + * + * File descriptors + */ +struct fdesc { + int fd; /* the file descriptor */ + void (*func)(int, void *);/* user function */ + void *udata; /* user data */ + evFileID id; /* file id */ + struct lmodule *owner; /* owner module of the file */ + LIST_ENTRY(fdesc) link; +}; + +/* list of all current selected files */ +extern LIST_HEAD(fdesc_list, fdesc) fdesc_list; + +/************************************************************* + * + * Loadable modules + */ +# define LM_SECTION_MAX 14 +struct lmodule { + char section[LM_SECTION_MAX + 1]; /* and index */ + char *path; + u_int flags; + void *handle; + const struct snmp_module *config; + + TAILQ_ENTRY(lmodule) link; + TAILQ_ENTRY(lmodule) start; + + struct asn_oid index; +}; +#define LM_STARTED 0x0001 +#define LM_ONSTARTLIST 0x0002 + +extern TAILQ_HEAD(lmodules, lmodule) lmodules; + +struct lmodule *lm_load(const char *, const char *); +void lm_unload(struct lmodule *); +void lm_start(struct lmodule *); + +/************************************************************* + * + * SNMP ports + */ +/* + * Common input stuff + */ +struct port_input { + int fd; /* socket */ + void *id; /* evSelect handle */ + + int stream : 1; /* stream socket */ + int cred : 1; /* want credentials */ + + struct sockaddr *peer; /* last received packet */ + socklen_t peerlen; + int priv : 1; /* peer is privileged */ + + u_char *buf; /* receive buffer */ + size_t buflen; /* buffer length */ + size_t length; /* received length */ + size_t consumed; /* how many bytes used */ +}; + +struct tport { + struct asn_oid index; /* table index of this tp point */ + TAILQ_ENTRY(tport) link; /* table link */ + struct transport *transport; /* who handles this */ +}; +TAILQ_HEAD(tport_list, tport); + +int snmpd_input(struct port_input *, struct tport *); +void snmpd_input_close(struct port_input *); +void snmpd_input_init(struct port_input *); + +/* + * Transport domain + */ +#define TRANS_NAMELEN 64 + +struct transport_def { + const char *name; /* name of this transport */ + struct asn_oid id; /* OBJID of this transport */ + + int (*start)(void); + int (*stop)(int); + + void (*close_port)(struct tport *); + int (*init_port)(struct tport *); + + ssize_t (*send)(struct tport *, const u_char *, size_t, + const struct sockaddr *, size_t); + ssize_t (*recv)(struct tport *, struct port_input *); + + /** send via a multi-socket port */ + ssize_t (*send2)(struct tport *, const u_char *, size_t, + struct port_input *); +}; +struct transport { + struct asn_oid index; /* transport table index */ + TAILQ_ENTRY(transport) link; /* ... and link */ + u_int or_index; /* registration index */ + + struct tport_list table; /* list of open ports */ + + const struct transport_def *vtab; +}; + +TAILQ_HEAD(transport_list, transport); +extern struct transport_list transport_list; + +void trans_insert_port(struct transport *, struct tport *); +void trans_remove_port(struct tport *); +struct tport *trans_find_port(struct transport *, + const struct asn_oid *, u_int); +struct tport *trans_next_port(struct transport *, + const struct asn_oid *, u_int); +struct tport *trans_first_port(struct transport *); +struct tport *trans_iter_port(struct transport *, + int (*)(struct tport *, intptr_t), intptr_t); + +int trans_register(const struct transport_def *, struct transport **); +int trans_unregister(struct transport *); + +/************************************************************* + * + * SNMPd scalar configuration. + */ +struct snmpd { + /* transmit buffer size */ + u_int32_t txbuf; + + /* receive buffer size */ + u_int32_t rxbuf; + + /* disable community table */ + int comm_dis; + + /* authentication traps */ + int auth_traps; + + /* source address for V1 traps */ + u_char trap1addr[4]; + + /* version enable flags */ + uint32_t version_enable; +}; +extern struct snmpd snmpd; + +#define VERS_ENABLE_V1 0x00000001 +#define VERS_ENABLE_V2C 0x00000002 +#define VERS_ENABLE_V3 0x00000004 +#define VERS_ENABLE_ALL (VERS_ENABLE_V1 | VERS_ENABLE_V2C | VERS_ENABLE_V3) + +/* + * The debug group + */ +struct debug { + u_int dump_pdus; + u_int logpri; + u_int evdebug; +}; +extern struct debug debug; + + +/* + * SNMPd statistics table + */ +struct snmpd_stats { + u_int32_t inPkts; /* total packets received */ + u_int32_t inBadVersions; /* unknown version number */ + u_int32_t inASNParseErrs; /* fatal parse errors */ + u_int32_t inBadCommunityNames; + u_int32_t inBadCommunityUses; + u_int32_t proxyDrops; /* dropped by proxy function */ + u_int32_t silentDrops; + + u_int32_t inBadPduTypes; + u_int32_t inTooLong; + u_int32_t noTxbuf; + u_int32_t noRxbuf; +}; +extern struct snmpd_stats snmpd_stats; + +/* + * SNMPd Engine + */ +extern struct snmp_engine snmpd_engine; + +/* + * OR Table + */ +struct objres { + TAILQ_ENTRY(objres) link; + u_int index; + struct asn_oid oid; /* the resource OID */ + char descr[256]; + u_int32_t uptime; + struct lmodule *module; +}; +TAILQ_HEAD(objres_list, objres); +extern struct objres_list objres_list; + +/* + * Trap Sink Table + */ +struct trapsink { + TAILQ_ENTRY(trapsink) link; + struct asn_oid index; + u_int status; + int socket; + u_char comm[SNMP_COMMUNITY_MAXLEN + 1]; + int version; +}; +enum { + TRAPSINK_ACTIVE = 1, + TRAPSINK_NOT_IN_SERVICE = 2, + TRAPSINK_NOT_READY = 3, + TRAPSINK_DESTROY = 6, + + TRAPSINK_V1 = 1, + TRAPSINK_V2 = 2, +}; +TAILQ_HEAD(trapsink_list, trapsink); +extern struct trapsink_list trapsink_list; + +extern const char *syspath; + +/* snmpSerialNo */ +extern int32_t snmp_serial_no; + +int init_actvals(void); + +extern char engine_file[]; +int init_snmpd_engine(void); +int set_snmpd_engine(void); +void update_snmpd_engine_time(void); + +int read_config(const char *, struct lmodule *); +int define_macro(const char *name, const char *value); + +#define LOG_ASN1_ERRORS 0x10000000 +#define LOG_SNMP_ERRORS 0x20000000 Property changes on: vendor/1.14/snmpd/snmpd.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmpd/snmpmod.h =================================================================== --- vendor/1.14/snmpd/snmpmod.h (nonexistent) +++ vendor/1.14/snmpd/snmpmod.h (revision 359491) @@ -0,0 +1,669 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Copyright (c) 2010 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Shteryana Sotirova Shopova + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmpd/snmpmod.h,v 1.32 2006/02/14 09:04:20 brandt_h Exp $ + * + * SNMP daemon data and functions exported to modules. + */ +#ifndef snmpmod_h_ +#define snmpmod_h_ + +#include +#include +#include +#include +#include +#include "asn1.h" +#include "snmp.h" +#include "snmpagent.h" + +#define MAX_MOD_ARGS 16 + +/* + * These macros help to handle object lists for SNMP tables. They use + * tail queues to hold the objects in ascending order in the list. + * ordering can be done either on an integer/unsigned field, an asn_oid + * or an ordering function. + */ + +/* + * First set of macros is used when the link is embedded into sub-struct + * and links these sub-structs. The sub-struct must be the first field. + * + * The list is a list of the subfield types. + */ +#define INSERT_OBJECT_OID_LINK_INDEX_TYPE(PTR, LIST, LINK, INDEX, SUBF) do {\ + typedef __typeof ((PTR)->SUBF) _subf_type; \ + _subf_type *_lelem; \ + \ + TAILQ_FOREACH(_lelem, (LIST), LINK) \ + if (asn_compare_oid(&_lelem->INDEX, &(PTR)->SUBF.INDEX) > 0)\ + break; \ + if (_lelem == NULL) \ + TAILQ_INSERT_TAIL((LIST), &(PTR)->SUBF, LINK); \ + else \ + TAILQ_INSERT_BEFORE(_lelem, &(PTR)->SUBF, LINK); \ + } while (0) + +#define NEXT_OBJECT_OID_LINK_INDEX_TYPE(LIST, OID, SUB, LINK, INDEX, TYPE) ({\ + __typeof (TAILQ_FIRST((LIST))) _lelem; \ + \ + TAILQ_FOREACH(_lelem, (LIST), LINK) \ + if (index_compare(OID, SUB, &_lelem->INDEX) < 0) \ + break; \ + (TYPE *)(_lelem); \ + }) + +#define FIND_OBJECT_OID_LINK_INDEX_TYPE(LIST, OID, SUB, LINK, INDEX, TYPE) ({\ + __typeof (TAILQ_FIRST((LIST))) _lelem; \ + \ + TAILQ_FOREACH(_lelem, (LIST), LINK) \ + if (index_compare(OID, SUB, &_lelem->INDEX) == 0) \ + break; \ + (TYPE *)(_lelem); \ + }) + +/* + * This set of macros allows specification of the link and index name. + * The index is an OID. + */ +#define INSERT_OBJECT_OID_LINK_INDEX(PTR, LIST, LINK, INDEX) do { \ + __typeof (PTR) _lelem; \ + \ + TAILQ_FOREACH(_lelem, (LIST), LINK) \ + if (asn_compare_oid(&_lelem->INDEX, &(PTR)->INDEX) > 0) \ + break; \ + if (_lelem == NULL) \ + TAILQ_INSERT_TAIL((LIST), (PTR), LINK); \ + else \ + TAILQ_INSERT_BEFORE(_lelem, (PTR), LINK); \ + } while (0) + +#define INSERT_OBJECT_INT_LINK_INDEX(PTR, LIST, LINK, INDEX) do { \ + __typeof (PTR) _lelem; \ + \ + TAILQ_FOREACH(_lelem, (LIST), LINK) \ + if ((asn_subid_t)_lelem->INDEX > (asn_subid_t)(PTR)->INDEX)\ + break; \ + if (_lelem == NULL) \ + TAILQ_INSERT_TAIL((LIST), (PTR), LINK); \ + else \ + TAILQ_INSERT_BEFORE(_lelem, (PTR), LINK); \ + } while (0) + +#define INSERT_OBJECT_FUNC_LINK(PTR, LIST, LINK, FUNC) do { \ + __typeof (PTR) _lelem; \ + \ + TAILQ_FOREACH(_lelem, (LIST), LINK) \ + if ((FUNC)(_lelem, (PTR)) > 0) \ + break; \ + if (_lelem == NULL) \ + TAILQ_INSERT_TAIL((LIST), (PTR), LINK); \ + else \ + TAILQ_INSERT_BEFORE(_lelem, (PTR), LINK); \ + } while (0) + +#define INSERT_OBJECT_FUNC_LINK_REV(PTR, LIST, HEAD, LINK, FUNC) do { \ + __typeof (PTR) _lelem; \ + \ + TAILQ_FOREACH_REVERSE(_lelem, (LIST), HEAD, LINK) \ + if ((FUNC)(_lelem, (PTR)) < 0) \ + break; \ + if (_lelem == NULL) \ + TAILQ_INSERT_HEAD((LIST), (PTR), LINK); \ + else \ + TAILQ_INSERT_AFTER((LIST), _lelem, (PTR), LINK); \ + } while (0) + +#define FIND_OBJECT_OID_LINK_INDEX(LIST, OID, SUB, LINK, INDEX) ({ \ + __typeof (TAILQ_FIRST(LIST)) _lelem; \ + \ + TAILQ_FOREACH(_lelem, (LIST), LINK) \ + if (index_compare(OID, SUB, &_lelem->INDEX) == 0) \ + break; \ + (_lelem); \ + }) + +#define NEXT_OBJECT_OID_LINK_INDEX(LIST, OID, SUB, LINK, INDEX) ({ \ + __typeof (TAILQ_FIRST(LIST)) _lelem; \ + \ + TAILQ_FOREACH(_lelem, (LIST), LINK) \ + if (index_compare(OID, SUB, &_lelem->INDEX) < 0) \ + break; \ + (_lelem); \ + }) + +#define FIND_OBJECT_INT_LINK_INDEX(LIST, OID, SUB, LINK, INDEX) ({ \ + __typeof (TAILQ_FIRST(LIST)) _lelem; \ + \ + if ((OID)->len - SUB != 1) \ + _lelem = NULL; \ + else \ + TAILQ_FOREACH(_lelem, (LIST), LINK) \ + if ((OID)->subs[SUB] == (asn_subid_t)_lelem->INDEX)\ + break; \ + (_lelem); \ + }) + +#define NEXT_OBJECT_INT_LINK_INDEX(LIST, OID, SUB, LINK, INDEX) ({ \ + __typeof (TAILQ_FIRST(LIST)) _lelem; \ + \ + if ((OID)->len - SUB == 0) \ + _lelem = TAILQ_FIRST(LIST); \ + else \ + TAILQ_FOREACH(_lelem, (LIST), LINK) \ + if ((OID)->subs[SUB] < (asn_subid_t)_lelem->INDEX)\ + break; \ + (_lelem); \ + }) + +#define FIND_OBJECT_FUNC_LINK(LIST, OID, SUB, LINK, FUNC) ({ \ + __typeof (TAILQ_FIRST(LIST)) _lelem; \ + \ + TAILQ_FOREACH(_lelem, (LIST), LINK) \ + if ((FUNC)(OID, SUB, _lelem) == 0) \ + break; \ + (_lelem); \ + }) + +#define NEXT_OBJECT_FUNC_LINK(LIST, OID, SUB, LINK, FUNC) ({ \ + __typeof (TAILQ_FIRST(LIST)) _lelem; \ + \ + TAILQ_FOREACH(_lelem, (LIST), LINK) \ + if ((FUNC)(OID, SUB, _lelem) < 0) \ + break; \ + (_lelem); \ + }) + +/* + * Macros for the case where the index field is called 'index' + */ +#define INSERT_OBJECT_OID_LINK(PTR, LIST, LINK) \ + INSERT_OBJECT_OID_LINK_INDEX(PTR, LIST, LINK, index) + +#define INSERT_OBJECT_INT_LINK(PTR, LIST, LINK) do { \ + INSERT_OBJECT_INT_LINK_INDEX(PTR, LIST, LINK, index) + +#define FIND_OBJECT_OID_LINK(LIST, OID, SUB, LINK) \ + FIND_OBJECT_OID_LINK_INDEX(LIST, OID, SUB, LINK, index) + +#define NEXT_OBJECT_OID_LINK(LIST, OID, SUB, LINK) \ + NEXT_OBJECT_OID_LINK_INDEX(LIST, OID, SUB, LINK, index) + +#define FIND_OBJECT_INT_LINK(LIST, OID, SUB, LINK) \ + FIND_OBJECT_INT_LINK_INDEX(LIST, OID, SUB, LINK, index) + +#define NEXT_OBJECT_INT_LINK(LIST, OID, SUB, LINK) \ + NEXT_OBJECT_INT_LINK_INDEX(LIST, OID, SUB, LINK, index) + +/* + * Macros for the case where the index field is called 'index' and the + * link field 'link'. + */ +#define INSERT_OBJECT_OID(PTR, LIST) \ + INSERT_OBJECT_OID_LINK_INDEX(PTR, LIST, link, index) + +#define INSERT_OBJECT_INT(PTR, LIST) \ + INSERT_OBJECT_INT_LINK_INDEX(PTR, LIST, link, index) + +#define INSERT_OBJECT_FUNC_REV(PTR, LIST, HEAD, FUNC) \ + INSERT_OBJECT_FUNC_LINK_REV(PTR, LIST, HEAD, link, FUNC) + +#define FIND_OBJECT_OID(LIST, OID, SUB) \ + FIND_OBJECT_OID_LINK_INDEX(LIST, OID, SUB, link, index) + +#define FIND_OBJECT_INT(LIST, OID, SUB) \ + FIND_OBJECT_INT_LINK_INDEX(LIST, OID, SUB, link, index) + +#define FIND_OBJECT_FUNC(LIST, OID, SUB, FUNC) \ + FIND_OBJECT_FUNC_LINK(LIST, OID, SUB, link, FUNC) + +#define NEXT_OBJECT_OID(LIST, OID, SUB) \ + NEXT_OBJECT_OID_LINK_INDEX(LIST, OID, SUB, link, index) + +#define NEXT_OBJECT_INT(LIST, OID, SUB) \ + NEXT_OBJECT_INT_LINK_INDEX(LIST, OID, SUB, link, index) + +#define NEXT_OBJECT_FUNC(LIST, OID, SUB, FUNC) \ + NEXT_OBJECT_FUNC_LINK(LIST, OID, SUB, link, FUNC) + +struct lmodule; + +/* The tick when the program was started. This is the absolute time of + * the start in 100th of a second. */ +extern uint64_t start_tick; + +/* The tick when the current packet was received. This is the absolute + * time in 100th of second. */ +extern uint64_t this_tick; + +/* Get the current absolute time in 100th of a second. */ +uint64_t get_ticks(void); + +/* + * Return code for proxy function + */ +enum snmpd_proxy_err { + /* proxy code will process the PDU */ + SNMPD_PROXY_OK, + /* proxy code does not process PDU */ + SNMPD_PROXY_REJ, + /* drop this PDU */ + SNMPD_PROXY_DROP, + /* drop because of bad community */ + SNMPD_PROXY_BADCOMM, + /* drop because of bad community use */ + SNMPD_PROXY_BADCOMMUSE +}; + +/* + * Input handling + */ +enum snmpd_input_err { + /* proceed with packet */ + SNMPD_INPUT_OK, + /* fatal error in packet, ignore it */ + SNMPD_INPUT_FAILED, + /* value encoding has wrong length in a SET operation */ + SNMPD_INPUT_VALBADLEN, + /* value encoding is out of range */ + SNMPD_INPUT_VALRANGE, + /* value has bad encoding */ + SNMPD_INPUT_VALBADENC, + /* need more data (truncated packet) */ + SNMPD_INPUT_TRUNC, + /* unknown community */ + SNMPD_INPUT_BAD_COMM, +}; + +/* + * Every loadable module must have one of this structures with + * the external name 'config'. + */ +struct snmp_module { + /* a comment describing what this module implements */ + const char *comment; + + /* the initialization function */ + int (*init)(struct lmodule *, int argc, char *argv[]); + + /* the finalisation function */ + int (*fini)(void); + + /* the idle function */ + void (*idle)(void); + + /* the dump function */ + void (*dump)(void); + + /* re-configuration function */ + void (*config)(void); + + /* start operation */ + void (*start)(void); + + /* proxy a PDU */ + enum snmpd_proxy_err (*proxy)(struct snmp_pdu *, void *, + const struct asn_oid *, const struct sockaddr *, socklen_t, + enum snmpd_input_err, int32_t, int); + + /* the tree this module is going to server */ + const struct snmp_node *tree; + u_int tree_size; + + /* function called, when another module was unloaded/loaded */ + void (*loading)(const struct lmodule *, int); +}; + +/* + * Stuff exported to modules + */ + +/* + * The system group. + */ +struct systemg { + u_char *descr; + struct asn_oid object_id; + u_char *contact; + u_char *name; + u_char *location; + uint32_t services; + uint32_t or_last_change; +}; +extern struct systemg systemg; + +/* + * Community support. + * + * We have 2 fixed communities for SNMP read and write access. Modules + * can create their communities dynamically. They are deleted automatically + * if the module is unloaded. + */ +#define COMM_INITIALIZE 0 +#define COMM_READ 1 +#define COMM_WRITE 2 + +u_int comm_define(u_int, const char *descr, struct lmodule *, const char *str); +struct community *comm_define_ordered(u_int priv, const char *descr, + struct asn_oid *index, struct lmodule *owner, const char *str); +const char * comm_string(u_int); + +/* community for current packet */ +extern u_int community; + +/* + * SNMP User-based Security Model data. Modified via the snmp_usm(3) module. + */ +struct snmpd_usmstat { + uint32_t unsupported_seclevels; + uint32_t not_in_time_windows; + uint32_t unknown_users; + uint32_t unknown_engine_ids; + uint32_t wrong_digests; + uint32_t decrypt_errors; +}; + +extern struct snmpd_usmstat snmpd_usmstats; +struct snmpd_usmstat *bsnmpd_get_usm_stats(void); +void bsnmpd_reset_usm_stats(void); + +struct usm_user { + struct snmp_user suser; + uint8_t user_engine_id[SNMP_ENGINE_ID_SIZ]; + uint32_t user_engine_len; + char user_public[SNMP_ADM_STR32_SIZ]; + uint32_t user_public_len; + int32_t status; + int32_t type; + SLIST_ENTRY(usm_user) up; +}; + +SLIST_HEAD(usm_userlist, usm_user); +struct usm_user *usm_first_user(void); +struct usm_user *usm_next_user(struct usm_user *); +struct usm_user *usm_find_user(uint8_t *, uint32_t, char *); +struct usm_user *usm_new_user(uint8_t *, uint32_t, char *); +void usm_delete_user(struct usm_user *); +void usm_flush_users(void); + +/* USM user for current packet */ +extern struct usm_user *usm_user; + +/* + * SNMP View-based Access Control Model data. Modified via the snmp_vacm(3) module. + */ +struct vacm_group; + +struct vacm_user { + /* Security user name from USM */ + char secname[SNMP_ADM_STR32_SIZ]; + int32_t sec_model; + /* Back pointer to user assigned group name */ + struct vacm_group *group; + int32_t type; + int32_t status; + SLIST_ENTRY(vacm_user) vvu; + SLIST_ENTRY(vacm_user) vvg; +}; + +SLIST_HEAD(vacm_userlist, vacm_user); + +struct vacm_group { + char groupname[SNMP_ADM_STR32_SIZ]; + struct vacm_userlist group_users; + SLIST_ENTRY(vacm_group) vge; +}; + +SLIST_HEAD(vacm_grouplist, vacm_group); + +struct vacm_access { + /* The group name is index, not a column in the table */ + struct vacm_group *group; + char ctx_prefix[SNMP_ADM_STR32_SIZ]; + int32_t sec_model; + int32_t sec_level; + int32_t ctx_match; + struct vacm_view *read_view; + struct vacm_view *write_view; + struct vacm_view *notify_view; + int32_t type; + int32_t status; + TAILQ_ENTRY(vacm_access) vva; +}; + +TAILQ_HEAD(vacm_accesslist, vacm_access); + +struct vacm_view { + char viewname[SNMP_ADM_STR32_SIZ]; /* key */ + struct asn_oid subtree; /* key */ + uint8_t mask[16]; + uint8_t exclude; + int32_t type; + int32_t status; + SLIST_ENTRY(vacm_view) vvl; +}; + +SLIST_HEAD(vacm_viewlist, vacm_view); + +struct vacm_context { + /* The ID of the module that registered this context */ + int32_t regid; + char ctxname[SNMP_ADM_STR32_SIZ]; + SLIST_ENTRY(vacm_context) vcl; +}; + +SLIST_HEAD(vacm_contextlist, vacm_context); + +void vacm_groups_init(void); +struct vacm_user *vacm_first_user(void); +struct vacm_user *vacm_next_user(struct vacm_user *); +struct vacm_user *vacm_new_user(int32_t, char *); +int vacm_delete_user(struct vacm_user *); +int vacm_user_set_group(struct vacm_user *, u_char *, u_int); +struct vacm_access *vacm_first_access_rule(void); +struct vacm_access *vacm_next_access_rule(struct vacm_access *); +struct vacm_access *vacm_new_access_rule(char *, char *, int32_t, int32_t); +int vacm_delete_access_rule(struct vacm_access *); +struct vacm_view *vacm_first_view(void); +struct vacm_view *vacm_next_view(struct vacm_view *); +struct vacm_view *vacm_new_view(char *, struct asn_oid *); +int vacm_delete_view(struct vacm_view *); +struct vacm_context *vacm_first_context(void); +struct vacm_context *vacm_next_context(struct vacm_context *); +struct vacm_context *vacm_add_context(char *, int32_t); +void vacm_flush_contexts(int32_t); + +/* + * RFC 3413 SNMP Management Target & Notification MIB + */ + +struct snmpd_target_stats { + uint32_t unavail_contexts; + uint32_t unknown_contexts; +}; + +#define SNMP_UDP_ADDR_SIZ 6 +#define SNMP_TAG_SIZ (255 + 1) + +struct target_address { + char name[SNMP_ADM_STR32_SIZ]; + uint8_t address[SNMP_UDP_ADDR_SIZ]; + int32_t timeout; + int32_t retry; + char taglist[SNMP_TAG_SIZ]; + char paramname[SNMP_ADM_STR32_SIZ]; + int32_t type; + int32_t socket; + int32_t status; + SLIST_ENTRY(target_address) ta; +}; + +SLIST_HEAD(target_addresslist, target_address); + +struct target_param { + char name[SNMP_ADM_STR32_SIZ]; + int32_t mpmodel; + int32_t sec_model; + char secname[SNMP_ADM_STR32_SIZ]; + enum snmp_usm_level sec_level; + int32_t type; + int32_t status; + SLIST_ENTRY(target_param) tp; +}; + +SLIST_HEAD(target_paramlist, target_param); + +struct target_notify { + char name[SNMP_ADM_STR32_SIZ]; + char taglist[SNMP_TAG_SIZ]; + int32_t notify_type; + int32_t type; + int32_t status; + SLIST_ENTRY(target_notify) tn; +}; + +SLIST_HEAD(target_notifylist, target_notify); + +extern struct snmpd_target_stats snmpd_target_stats; +struct snmpd_target_stats *bsnmpd_get_target_stats(void); +struct target_address *target_first_address(void); +struct target_address *target_next_address(struct target_address *); +struct target_address *target_new_address(char *); +int target_activate_address(struct target_address *); +int target_delete_address(struct target_address *); +struct target_param *target_first_param(void); +struct target_param *target_next_param(struct target_param *); +struct target_param *target_new_param(char *); +int target_delete_param(struct target_param *); +struct target_notify *target_first_notify(void); +struct target_notify *target_next_notify(struct target_notify *); +struct target_notify *target_new_notify(char *); +int target_delete_notify (struct target_notify *); +void target_flush_all(void); + +/* + * Well known OIDs + */ +extern const struct asn_oid oid_zeroDotZero; + +/* SNMPv3 Engine Discovery */ +extern const struct asn_oid oid_usmUnknownEngineIDs; +extern const struct asn_oid oid_usmNotInTimeWindows; + +/* + * Request ID ranges. + * + * A module can request a range of request ids and associate them with a + * type field. All ranges are deleted if a module is unloaded. + */ +u_int reqid_allocate(int size, struct lmodule *); +int32_t reqid_next(u_int type); +int32_t reqid_base(u_int type); +int reqid_istype(int32_t reqid, u_int type); +u_int reqid_type(int32_t reqid); + +/* + * Timers. + */ +void *timer_start(u_int, void (*)(void *), void *, struct lmodule *); +void *timer_start_repeat(u_int, u_int, void (*)(void *), void *, + struct lmodule *); +void timer_stop(void *); + +/* + * File descriptors + */ +void *fd_select(int, void (*)(int, void *), void *, struct lmodule *); +void fd_deselect(void *); +void fd_suspend(void *); +int fd_resume(void *); + +/* + * Object resources + */ +u_int or_register(const struct asn_oid *, const char *, struct lmodule *); +void or_unregister(u_int); + +/* + * Buffers + */ +void *buf_alloc(int tx); +size_t buf_size(int tx); + +/* decode PDU and find community */ +enum snmpd_input_err snmp_input_start(const u_char *, size_t, const char *, + struct snmp_pdu *, int32_t *, size_t *); + +/* process the pdu. returns either _OK or _FAILED */ +enum snmpd_input_err snmp_input_finish(struct snmp_pdu *, const u_char *, + size_t, u_char *, size_t *, const char *, enum snmpd_input_err, int32_t, + void *); + +void snmp_output(struct snmp_pdu *, u_char *, size_t *, const char *); +void snmp_send_port(void *, const struct asn_oid *, struct snmp_pdu *, + const struct sockaddr *, socklen_t); +enum snmp_code snmp_pdu_auth_access(struct snmp_pdu *, int32_t *); + +/* sending traps */ +void snmp_send_trap(const struct asn_oid *, ...); + +/* + * Action support + */ +int string_save(struct snmp_value *, struct snmp_context *, ssize_t, u_char **); +void string_commit(struct snmp_context *); +void string_rollback(struct snmp_context *, u_char **); +int string_get(struct snmp_value *, const u_char *, ssize_t); +int string_get_max(struct snmp_value *, const u_char *, ssize_t, size_t); +void string_free(struct snmp_context *); + +int ip_save(struct snmp_value *, struct snmp_context *, u_char *); +void ip_rollback(struct snmp_context *, u_char *); +void ip_commit(struct snmp_context *); +int ip_get(struct snmp_value *, u_char *); + +int oid_save(struct snmp_value *, struct snmp_context *, struct asn_oid *); +void oid_rollback(struct snmp_context *, struct asn_oid *); +void oid_commit(struct snmp_context *); +int oid_get(struct snmp_value *, const struct asn_oid *); + +int index_decode(const struct asn_oid *oid, u_int sub, u_int code, ...); +int index_compare(const struct asn_oid *, u_int, const struct asn_oid *); +int index_compare_off(const struct asn_oid *, u_int, const struct asn_oid *, + u_int); +void index_append(struct asn_oid *, u_int, const struct asn_oid *); +void index_append_off(struct asn_oid *, u_int, const struct asn_oid *, u_int); + +#endif Property changes on: vendor/1.14/snmpd/snmpmod.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmpd/trans_inet.c =================================================================== --- vendor/1.14/snmpd/trans_inet.c (nonexistent) +++ vendor/1.14/snmpd/trans_inet.c (revision 359491) @@ -0,0 +1,1341 @@ +/* + * Copyright (c) 2018 + * Hartmut Brandt. + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmpd/trans_udp.c,v 1.5 2005/10/04 08:46:56 brandt_h Exp $ + * + * Internet transport + */ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include "asn1.h" +#include "snmp.h" +#include "snmpmod.h" + +#include "snmpd.h" + +#define SNMPTREE_TYPES +#define SNMPENUM_FUNCS +#include "tree.h" +#include "oid.h" + +extern const struct transport_def inet_trans; + +struct inet_port; +struct inet_port_params; +struct port_sock; + +typedef int create_func(struct inet_port *, struct inet_port_params *); +typedef void input_func(int, void *); +typedef int activate_func(struct inet_port *); +typedef void deactivate_func(struct inet_port *); +typedef void parse_ctrl_func(struct port_sock *, const struct msghdr *); +typedef void setsrc_func(struct port_sock *, struct msghdr *); + +static create_func ipv4_create; +static input_func ipv4_input; +static activate_func ipv4_activate; +static deactivate_func ipv4_deactivate; +static parse_ctrl_func ipv4_parse_ctrl; +static setsrc_func ipv4_setsrc; + +static create_func ipv6_create; +static input_func ipv6_input; +static activate_func ipv6_activate; +static deactivate_func ipv6_deactivate; +static parse_ctrl_func ipv6_parse_ctrl; +static setsrc_func ipv6_setsrc; + +static create_func ipv6z_create; + +static create_func dns_create; +static activate_func dns_activate; +static deactivate_func dns_deactivate; + +struct port_sock { + /* common input stuff; must be first */ + struct port_input input; + + /** link field */ + TAILQ_ENTRY(port_sock) link; + + /** pointer to parent */ + struct inet_port *port; + + /** bind address */ + struct sockaddr_storage bind_addr; + + /** reply destination */ + struct sockaddr_storage ret_dest; + + /** need to set source address in reply; set for INADDR_ANY */ + bool set_ret_source; + + /** address of the receive interface */ + union { + /** IPv4 case */ + struct in_addr a4; + + /** IPv6 case */ + struct in6_pktinfo a6; + } ret_source; + + /** parse control message */ + parse_ctrl_func *parse_ctrl; + + /** set source address for a send() */ + setsrc_func *setsrc; +}; +static_assert(offsetof(struct port_sock, input) == 0, + "input not first in port_sock"); + +/** + * Table row for the inet ports. + * + * When actived each row can have one or several open sockets. For ipv6, + * ipv4 and ipv6z addresses it is always one, for dns addresses more than + * one socket can be open. + */ +struct inet_port { + /** common i/o port stuff (must be first) */ + struct tport tport; + + /** transport protocol */ + enum BegemotSnmpdTransportProto proto; + + /** row status */ + enum RowStatus row_status; + + /** socket list */ + TAILQ_HEAD(, port_sock) socks; + + /** value for InetAddressType::dns */ + char *dns_addr; + + /** port number in dns case; network byte order */ + uint16_t dns_port; + + /** create a port */ + create_func *create; + + /** activate a port */ + activate_func *activate; + + /** deactivate port */ + deactivate_func *deactivate; +}; +static_assert(offsetof(struct inet_port, tport) == 0, + "tport not first in inet_port"); + +/** to be used in bind_addr field */ +#define AF_DNS AF_VENDOR00 + +/** registered transport */ +static struct transport *my_trans; + +/** set operation */ +enum { + SET_CREATED, + SET_ACTIVATED, + SET_DEACTIVATE, + SET_DESTROY, +}; + +/** length of the control data buffer */ +static const size_t RECV_CBUF_SIZE = + MAX(CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) + + CMSG_SPACE(sizeof(struct in_addr)), + CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) + + CMSG_SPACE(sizeof(struct in6_pktinfo))); + +/** length of the control data buffer */ +static const size_t XMIT_CBUF_SIZE = + MAX(CMSG_SPACE(sizeof(struct in_addr)), + CMSG_SPACE(sizeof(struct in6_pktinfo))); + +/** + * Start the transport. This registers the transport with the + * transport table. + * + * \return SNMP error code + */ +static int +inet_start(void) +{ + return (trans_register(&inet_trans, &my_trans)); +} + +/** + * Stop the transport. This tries to unregister the transport which + * in turn fails if the list of ports is not empty. + * + * \return SNMP error code + */ +static int +inet_stop(int force __unused) +{ + if (my_trans != NULL) + if (trans_unregister(my_trans) != 0) + return (SNMP_ERR_GENERR); + return (SNMP_ERR_NOERROR); +} + +/** + * Deactivate SNMP port. + * + * \param tp port to close + */ +static void +deactivate_port(struct inet_port *p) +{ + p->deactivate(p); +} + +/* + * This function activates a port. For ports opened via the config files + * this is called just before entering the event loop. For ports create + * during runtime this is called when the RowStatus is set to Active or + * as second step for CreateAndGo. + * + * \param tp transport port + * + * \return SNMP error code + */ +static int +inet_activate(struct tport *tp) +{ + struct inet_port *port = (struct inet_port *)tp; + + return (port->activate(port)); +} + +/* + * Close the SNMP port if it is open and destroy it. + * + * \param tp port to close + */ +static void +inet_destroy_port(struct tport *tp) +{ + struct inet_port *port = (struct inet_port *)tp; + + deactivate_port(port); + + trans_remove_port(tp); + + free(port->dns_addr); + free(port); +} + +/** + * If the input struct has no buffer allocated yet, do it now. If allocation + * fails, read the data into a local buffer and drop it. + * + * \param pi input struct + * + * \return -1 if allocation fails, 0 otherwise + */ +static int +inet_alloc_buf(struct port_input *pi) +{ + char drop_buf[2000]; + + if (pi->buf == NULL) { + if ((pi->buf = buf_alloc(0)) == NULL) { + (void)recvfrom(pi->fd, drop_buf, sizeof(drop_buf), + 0, NULL, NULL); + return (-1); + } + pi->buflen = buf_size(0); + } + return (0); +} + +/** + * Read message into input buffer. Get also the source address and any + * control data that is available. If the message is truncated, increment + * corresponding statistics. + * + * \param pi input object + * \param msg message object to fill + * \param cbuf control data buffer + * + * \return -1 when something goes wrong, 0 othersise + */ +static int +inet_read_msg(struct port_input *pi, struct msghdr *msg, char *cbuf) +{ + struct iovec iov[1]; + + iov[0].iov_base = pi->buf; + iov[0].iov_len = pi->buflen; + + msg->msg_name = pi->peer; + msg->msg_namelen = pi->peerlen; + msg->msg_iov = iov; + msg->msg_iovlen = 1; + msg->msg_control = cbuf; + msg->msg_controllen = RECV_CBUF_SIZE; + msg->msg_flags = 0; + + memset(cbuf, 0, RECV_CBUF_SIZE); + + const ssize_t len = recvmsg(pi->fd, msg, 0); + + if (len == -1 || len == 0) + /* receive error */ + return (-1); + + if (msg->msg_flags & MSG_TRUNC) { + /* truncated - drop */ + snmpd_stats.silentDrops++; + snmpd_stats.inTooLong++; + return (-1); + } + + pi->length = (size_t)len; + + return (0); +} + +/* + * Input available on socket. + * + * \param tp transport port + * \param pi input struct + * + * \return number of bytes received + */ +static ssize_t +inet_recv(struct tport *tp, struct port_input *pi) +{ + struct inet_port *port = __containerof(tp, struct inet_port, tport); + struct port_sock *sock = __containerof(pi, struct port_sock, input); + + assert(port->proto == BegemotSnmpdTransportProto_udp); + + if (inet_alloc_buf(pi) == -1) + return (-1); + + char cbuf[RECV_CBUF_SIZE]; + struct msghdr msg; + + if (inet_read_msg(pi, &msg, cbuf) == -1) + return (-1); + + sock->parse_ctrl(sock, &msg); + + return (0); +} + +/* + * Send message. + * + * \param tp port + * \param buf data to send + * \param len number of bytes to send + * \param addr destination address + * \param addlen destination address length + * + * \return number of bytes sent + */ +static ssize_t +inet_send2(struct tport *tp, const u_char *buf, size_t len, + struct port_input *pi) +{ + struct inet_port *p = __containerof(tp, struct inet_port, tport); + struct port_sock *s = (pi == NULL) ? TAILQ_FIRST(&p->socks) : + __containerof(pi, struct port_sock, input); + + struct iovec iov; + + iov.iov_base = __DECONST(void*, buf); + iov.iov_len = len; + + struct msghdr msg; + + msg.msg_flags = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_name = (void *)pi->peer; + msg.msg_namelen = pi->peerlen; + + msg.msg_control = NULL; + msg.msg_controllen = 0; + + char cbuf[XMIT_CBUF_SIZE]; + if (s->set_ret_source) { + msg.msg_control = cbuf; + s->setsrc(s, &msg); + } + + return (sendmsg(s->input.fd, &msg, 0)); +} + +/** exported to daemon */ +const struct transport_def inet_trans = { + "inet", + OIDX_begemotSnmpdTransInet, + inet_start, + inet_stop, + inet_destroy_port, + inet_activate, + NULL, + inet_recv, + inet_send2, +}; + +struct inet_port_params { + /** index oid */ + struct asn_oid index; + + /** internet address type */ + enum InetAddressType type; + + /** internet address */ + u_char *addr; + + /** length of address */ + size_t addr_len; + + /** port number */ + uint32_t port; + + /** protocol */ + enum BegemotSnmpdTransportProto proto; +}; + +/** + * IPv4 creation stuff. Parse the index, fill socket address and creates + * a port_sock. + * + * \param port the port to create + * \param params parameters from the SNMP SET + * + * \return SNMP error + */ +static int +ipv4_create(struct inet_port *port, struct inet_port_params *params) +{ + + if (params->addr_len != 4) + return (SNMP_ERR_INCONS_VALUE); + + struct port_sock *sock = calloc(1, sizeof(struct port_sock)); + if (sock == NULL) + return (SNMP_ERR_GENERR); + + snmpd_input_init(&sock->input); + + TAILQ_INSERT_HEAD(&port->socks, sock, link); + + struct sockaddr_in *sin = + (struct sockaddr_in *)&sock->bind_addr; + + sin->sin_len = sizeof(struct sockaddr_in); + sin->sin_family = AF_INET; + sin->sin_port = htons(params->port); + memcpy(&sin->sin_addr, params->addr, 4); /* network byte order */ + + sock->port = port; + + return (SNMP_ERR_NOERROR); +} + +/* + * An IPv4 inet port is ready. Delegate to the generic code to read the data + * and react. + * + * \param fd file descriptor that is ready + * \param udata inet_port pointer + */ +static void +ipv4_input(int fd __unused, void *udata) +{ + struct port_sock *sock = udata; + + sock->input.peerlen = sizeof(struct sockaddr_in); + snmpd_input(&sock->input, &sock->port->tport); +} + +/** + * Activate an IPv4 socket. + * + * \param sock thhe socket to activate + * + * \return error code + */ +static int +ipv4_activate_sock(struct port_sock *sock) +{ + if ((sock->input.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { + syslog(LOG_ERR, "creating UDP4 socket: %m"); + return (SNMP_ERR_RES_UNAVAIL); + } + + const struct sockaddr_in *sin = + (const struct sockaddr_in *)&sock->bind_addr; + + if (sin->sin_addr.s_addr == INADDR_ANY) { + /* need to know from which address to return */ + static const int on = 1; + + if (setsockopt(sock->input.fd, IPPROTO_IP, IP_RECVDSTADDR, &on, + sizeof(on)) == -1) { + syslog(LOG_ERR, "setsockopt(IP_RECVDSTADDR): %m"); + (void)close(sock->input.fd); + sock->input.fd = -1; + return (SNMP_ERR_GENERR); + } + sock->set_ret_source = true; + } + + if (bind(sock->input.fd, (const struct sockaddr *)sin, sizeof(*sin))) { + if (errno == EADDRNOTAVAIL) { + (void)close(sock->input.fd); + sock->input.fd = -1; + return (SNMP_ERR_INCONS_NAME); + } + syslog(LOG_ERR, "bind: %s:%u %m", inet_ntoa(sin->sin_addr), + ntohs(sin->sin_port)); + (void)close(sock->input.fd); + sock->input.fd = -1; + return (SNMP_ERR_GENERR); + } + + if ((sock->input.id = fd_select(sock->input.fd, ipv4_input, + sock, NULL)) == NULL) { + (void)close(sock->input.fd); + sock->input.fd = -1; + return (SNMP_ERR_GENERR); + } + sock->input.peer = (struct sockaddr *)&sock->ret_dest; + + sock->parse_ctrl = ipv4_parse_ctrl; + sock->setsrc = ipv4_setsrc; + + return (SNMP_ERR_NOERROR); +} + +/** + * Open an IPv4 socket. Make the socket, bind it and put it on the select + * list. The socket struct has already been created during creation. + * + * \param p inet port + * + * \return SNMP error code + */ +static int +ipv4_activate(struct inet_port *p) +{ + struct port_sock *sock = TAILQ_FIRST(&p->socks); + assert(sock); + assert(!TAILQ_NEXT(sock, link)); + + const int ret = ipv4_activate_sock(sock); + if (ret == SNMP_ERR_NOERROR) + p->row_status = RowStatus_active; + + return (ret); +} + +/** + * Close an IPv4 socket. Keep the sock object. + * + * \param p inet port + */ +static void +ipv4_deactivate(struct inet_port *p) +{ + struct port_sock *sock = TAILQ_FIRST(&p->socks); + assert(sock); + assert(!TAILQ_NEXT(sock, link)); + + snmpd_input_close(&sock->input); + + p->row_status = RowStatus_notInService; +} + +/** + * Parse the control data received with a UDPv4 packet. This may contain + * credentials (for a local connection) and the address of the interface + * the message was received on. If there are credentials set the priv flag + * if the effective UID is zero. + * + * \param sock the sock object + * \param msg the received message + */ +static void +ipv4_parse_ctrl(struct port_sock *sock, const struct msghdr *msg) +{ + struct sockcred *cred = NULL; + + for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(msg, cmsg)) { + + if (cmsg->cmsg_level == IPPROTO_IP && + cmsg->cmsg_type == IP_RECVDSTADDR) { + memcpy(&sock->ret_source.a4, CMSG_DATA(cmsg), + sizeof(struct in_addr)); + + } else if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDS) { + cred = (struct sockcred *)(void *)CMSG_DATA(cmsg); + } + } + + sock->input.priv = 0; + if (sock->input.cred && cred) + /* remote end has sent credentials */ + sock->input.priv = (cred->sc_euid == 0); +} + +/** + * Set the source address option for IPv4 sockets. + * + * \param sock socket object + * \param msg message + */ +static void +ipv4_setsrc(struct port_sock *sock, struct msghdr *msg) +{ + struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); + + /* select outgoing interface by setting source address */ + cmsg->cmsg_level = IPPROTO_IP; + cmsg->cmsg_type = IP_SENDSRCADDR; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); + memcpy(CMSG_DATA(cmsg), &sock->ret_source.a4, + sizeof(struct in_addr)); + + msg->msg_controllen = CMSG_SPACE(sizeof(struct in_addr)); +} + +/** + * Common part of IPv6 creation. This is used by both ipv6_create() and + * ipv6z_create(). + * + * \param port the table row + * \param params creation parameters + * \param scope_id scope_id (0 or from index) + * + * \return SNMP_ERR_NOERROR if port has been created, error code otherwise + */ +static int +ipv6_create_common(struct inet_port *port, struct inet_port_params *params, + u_int scope_id) +{ + struct port_sock *sock = calloc(1, sizeof(struct port_sock)); + + if (sock == NULL) + return (SNMP_ERR_GENERR); + + struct sockaddr_in6 *sin = (struct sockaddr_in6 *)&sock->bind_addr; + + sin->sin6_len = sizeof(struct sockaddr_in6); + sin->sin6_family = AF_INET6; + sin->sin6_port = htons(params->port); + sin->sin6_flowinfo = 0; + sin->sin6_scope_id = scope_id; + + memcpy(sin->sin6_addr.s6_addr, params->addr, 16); + + if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) && scope_id == 0) { + char buf[INET6_ADDRSTRLEN]; + syslog(LOG_INFO, "%s: link local address used without scope " + "index: %s", __func__, inet_ntop(AF_INET6, + &sin->sin6_addr, buf, sizeof(buf))); + free(sock); + return (SNMP_ERR_NO_CREATION); + } + + sock->port = port; + + snmpd_input_init(&sock->input); + TAILQ_INSERT_HEAD(&port->socks, sock, link); + + return (SNMP_ERR_NOERROR); +} + +/** + * IPv6 creation stuff. Parse the index, fill socket address and creates + * a port_sock. + * + * \param port the port to create + * \param params parameters from the SNMP SET + * + * \return SNMP error + */ +static int +ipv6_create(struct inet_port *port, struct inet_port_params *params) +{ + if (params->addr_len != 16) + return (SNMP_ERR_INCONS_VALUE); + + const int ret = ipv6_create_common(port, params, 0); + if (ret != SNMP_ERR_NOERROR) + return (ret); + + return (SNMP_ERR_NOERROR); +} + +/* + * An IPv6 inet port is ready. Delegate to the generic code to read the data + * and react. + * + * \param fd file descriptor that is ready + * \param udata inet_port pointer + */ +static void +ipv6_input(int fd __unused, void *udata) +{ + struct port_sock *sock = udata; + + sock->input.peerlen = sizeof(struct sockaddr_in6); + snmpd_input(&sock->input, &sock->port->tport); +} + +/** + * Activate an IPv6 socket. + * + * \param sock thhe socket to activate + * + * \return error code + */ +static int +ipv6_activate_sock(struct port_sock *sock) +{ + if ((sock->input.fd = socket(PF_INET6, SOCK_DGRAM, 0)) == -1) { + syslog(LOG_ERR, "creating UDP6 socket: %m"); + return (SNMP_ERR_RES_UNAVAIL); + } + + const struct sockaddr_in6 *sin = + (const struct sockaddr_in6 *)&sock->bind_addr; + + if (memcmp(&sin->sin6_addr, &in6addr_any, sizeof(in6addr_any)) == 0) { + /* need to know from which address to return */ + static const int on = 1; + + if (setsockopt(sock->input.fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, + &on, sizeof(on)) == -1) { + syslog(LOG_ERR, "setsockopt(IP6_PKTINFO): %m"); + (void)close(sock->input.fd); + sock->input.fd = -1; + return (SNMP_ERR_GENERR); + } + sock->set_ret_source = true; + } + + if (bind(sock->input.fd, (const struct sockaddr *)sin, sizeof(*sin))) { + if (community != COMM_INITIALIZE && errno == EADDRNOTAVAIL) { + (void)close(sock->input.fd); + sock->input.fd = -1; + return (SNMP_ERR_INCONS_NAME); + } + char buf[INET6_ADDRSTRLEN]; + syslog(LOG_ERR, "bind: %s:%u:%u %m", inet_ntop(AF_INET6, + &sin->sin6_addr, buf, sizeof(buf)), sin->sin6_scope_id, + ntohs(sin->sin6_port)); + (void)close(sock->input.fd); + sock->input.fd = -1; + return (SNMP_ERR_GENERR); + } + if ((sock->input.id = fd_select(sock->input.fd, ipv6_input, + sock, NULL)) == NULL) { + (void)close(sock->input.fd); + sock->input.fd = -1; + return (SNMP_ERR_GENERR); + } + sock->input.peer = (struct sockaddr *)&sock->ret_dest; + + sock->parse_ctrl = ipv6_parse_ctrl; + sock->setsrc = ipv6_setsrc; + + return (SNMP_ERR_NOERROR); +} + +/** + * Open an IPv6 socket. + * + * \param port inet port + * + * \return SNMP error code + */ +static int +ipv6_activate(struct inet_port *p) +{ + struct port_sock *sock = TAILQ_FIRST(&p->socks); + assert(sock); + + const int ret = ipv6_activate_sock(sock); + + if (ret == SNMP_ERR_NOERROR) + p->row_status = RowStatus_active; + return (ret); +} + +/** + * Close an IPv6 socket. Keep the sock object. + * + * \param p inet port + */ +static void +ipv6_deactivate(struct inet_port *p) +{ + struct port_sock *sock = TAILQ_FIRST(&p->socks); + assert(sock); + assert(!TAILQ_NEXT(sock, link)); + + snmpd_input_close(&sock->input); + + p->row_status = RowStatus_notInService; +} + +/** + * IPv6 specific part of message processing. The control data may contain + * credentials and packet info that contains the destination address of + * the packet. + * + * \param sock the sock object + * \param msg the received message + */ +static void +ipv6_parse_ctrl(struct port_sock *sock, const struct msghdr *msg) +{ + struct sockcred *cred = NULL; + + for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(msg, cmsg)) { + + if (cmsg->cmsg_level == IPPROTO_IPV6 && + cmsg->cmsg_type == IPV6_PKTINFO) { + const struct in6_pktinfo *info = + (const struct in6_pktinfo *)(const void *) + CMSG_DATA(cmsg); + sock->ret_source.a6.ipi6_addr = info->ipi6_addr; + sock->ret_source.a6.ipi6_ifindex = + !IN6_IS_ADDR_LINKLOCAL(&info->ipi6_addr) ? 0: + info->ipi6_ifindex; + + } else if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDS) { + cred = (struct sockcred *)(void *)CMSG_DATA(cmsg); + } + } + + sock->input.priv = 0; + if (sock->input.cred && cred) + /* remote end has sent credentials */ + sock->input.priv = (cred->sc_euid == 0); +} + +/** + * Set the source address option for IPv4 sockets. + * + * \param sock socket object + * \param msg message + */ +static void +ipv6_setsrc(struct port_sock *sock, struct msghdr *msg) +{ + struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg); + + /* select outgoing interface by setting source address */ + cmsg->cmsg_level = IPPROTO_IPV6; + cmsg->cmsg_type = IPV6_PKTINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in6_pktinfo)); + memcpy(CMSG_DATA(cmsg), &sock->ret_source.a6, + sizeof(struct in6_pktinfo)); + + msg->msg_controllen = CMSG_SPACE(sizeof(struct in6_pktinfo)); +} + +/** + * IPv6z creation stuff. Parse the index, fill socket address and creates + * a port_sock. + * + * \param port the port to create + * \param params parameters from the SNMP SET + * + * \return SNMP error + */ +static int +ipv6z_create(struct inet_port *port, struct inet_port_params *params) +{ + if (params->addr_len != 20) + return (SNMP_ERR_INCONS_VALUE); + + u_int scope_id = 0; + for (u_int i = 16; i < 20; i++) { + scope_id <<= 8; + scope_id |= params->addr[i]; + } + + const int ret = ipv6_create_common(port, params, scope_id); + if (ret != SNMP_ERR_NOERROR) + return (ret); + + return (SNMP_ERR_NOERROR); +} + +/** + * DNS name creation stuff. Parse the index and save the string. + * This does not create a socket struct. + * + * \param port the port to create + * \param params parameters from the SNMP SET + * + * \return SNMP error + */ +static int +dns_create(struct inet_port *port, struct inet_port_params *params) +{ + if (params->addr_len > 64) + return (SNMP_ERR_INCONS_VALUE); + + if (strnlen(params->addr, params->addr_len) != + params->addr_len) + return (SNMP_ERR_INCONS_VALUE); + + if ((port->dns_addr = realloc(params->addr, + params->addr_len + 1)) == NULL) + return (SNMP_ERR_GENERR); + + port->dns_addr[params->addr_len] = '\0'; + params->addr = NULL; + + port->dns_port = htons(params->port); + + return (SNMP_ERR_NOERROR); +} + +/** + * Open sockets. This loops through all the addresses returned by getaddrinfo + * and opens a socket for each of them. + * + * \param port inet port + * + * \return SNMP error code + */ +static int +dns_activate(struct inet_port *port) +{ + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_DGRAM; // XXX udp-only + hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE | AI_NUMERICSERV; + + char portbuf[8]; + sprintf(portbuf, "%hu", ntohs(port->dns_port)); + + struct addrinfo *res0; + int error = getaddrinfo(port->dns_addr[0] == '\0' + ? NULL : port->dns_addr, + portbuf, &hints, &res0); + + if (error) { + syslog(LOG_ERR, "cannot resolve address '%s': %s", + port->dns_addr, gai_strerror(error)); + return (SNMP_ERR_GENERR); + } + + for (struct addrinfo *res = res0; res != NULL; res = res->ai_next) { + if (res->ai_family != AF_INET && res->ai_family != AF_INET6) + continue; + + struct port_sock *sock = calloc(1, sizeof(struct port_sock)); + if (sock == NULL) + return (SNMP_ERR_GENERR); + + snmpd_input_init(&sock->input); + sock->port = port; + + int ret = SNMP_ERR_NOERROR; + + if (res->ai_family == AF_INET) { + *(struct sockaddr_in *)&sock->bind_addr = + *(struct sockaddr_in *)(void *)res->ai_addr; + ret = ipv4_activate_sock(sock); + } else { + *(struct sockaddr_in6 *)&sock->bind_addr = + *(struct sockaddr_in6 *)(void *)res->ai_addr; + ret = ipv6_activate_sock(sock); + } + + if (ret != SNMP_ERR_NOERROR) + free(sock); + else + TAILQ_INSERT_HEAD(&port->socks, sock, link); + } + + if (!TAILQ_EMPTY(&port->socks)) + port->row_status = RowStatus_active; + + freeaddrinfo(res0); + return (SNMP_ERR_GENERR); +} + +/** + * Deactive the socket. Close all open sockets and delete all sock objects. + * + * \param port inet port + */ +static void +dns_deactivate(struct inet_port *port) +{ + while (!TAILQ_EMPTY(&port->socks)) { + struct port_sock *sock = TAILQ_FIRST(&port->socks); + TAILQ_REMOVE(&port->socks, sock, link); + snmpd_input_close(&sock->input); + free(sock); + } + port->row_status = RowStatus_notInService; +} + +static int +inet_create(struct inet_port_params *params, struct inet_port **pp) +{ + int err = SNMP_ERR_NOERROR; + struct inet_port *port = NULL; + + if (params->port > 0xffff) { + err = SNMP_ERR_NO_CREATION; + goto fail; + } + + if ((port = malloc(sizeof(*port))) == NULL) { + err = SNMP_ERR_GENERR; + goto fail; + } + memset(port, 0, sizeof(*port)); + TAILQ_INIT(&port->socks); + + port->proto = params->proto; + port->tport.index = params->index; + + switch (params->type) { + + case InetAddressType_ipv4: + port->create = ipv4_create; + port->activate = ipv4_activate; + port->deactivate = ipv4_deactivate; + break; + + case InetAddressType_ipv6: + port->create = ipv6_create; + port->activate = ipv6_activate; + port->deactivate = ipv6_deactivate; + break; + + case InetAddressType_ipv6z: + port->create = ipv6z_create; + port->activate = ipv6_activate; + port->deactivate = ipv6_deactivate; + break; + + case InetAddressType_dns: + port->create = dns_create; + port->activate = dns_activate; + port->deactivate = dns_deactivate; + break; + + default: + err = SNMP_ERR_NO_CREATION; + goto fail; + } + + if ((err = port->create(port, params)) != SNMP_ERR_NOERROR) + goto fail; + + *pp = port; + trans_insert_port(my_trans, &port->tport); + return (err); + +fail: + free(port->dns_addr); + free(port); + return (err); +} + +static int +create_and_go(struct snmp_context *ctx, struct inet_port_params *params) +{ + int err; + struct inet_port *port; + + if ((err = inet_create(params, &port)) != SNMP_ERR_NOERROR) + return (err); + + port->row_status = RowStatus_createAndGo; + ctx->scratch->ptr1 = port; + + if (community == COMM_INITIALIZE) + return (err); + + return (inet_activate(&port->tport)); +} + +static int +create_and_wait(struct snmp_context *ctx, struct inet_port_params *params) +{ + int err; + struct inet_port *port; + + if ((err = inet_create(params, &port)) != SNMP_ERR_NOERROR) + return (err); + + port->row_status = RowStatus_createAndWait; + ctx->scratch->ptr1 = port; + + return (err); +} + +/** + * This is called to set a RowStatus value in the port table during + * SET processing. + * + * When this is called during initialization time and the RowStatus is set + * to CreateAndGo, the port is actually not activated. This is done when + * the main code calls the init() for all ports later. + */ +static int +inet_port_set(struct snmp_context *ctx, struct inet_port *port, + struct inet_port_params *params, enum RowStatus nstatus) +{ + switch (nstatus) { + + case RowStatus_createAndGo: + if (port != NULL) + return (SNMP_ERR_INCONS_VALUE); + ctx->scratch->int1 = SET_CREATED; + return (create_and_go(ctx, params)); + + case RowStatus_createAndWait: + if (port != NULL) + return (SNMP_ERR_INCONS_VALUE); + ctx->scratch->int1 = SET_CREATED; + return (create_and_wait(ctx, params)); + + case RowStatus_active: + if (port == NULL) + return (SNMP_ERR_INCONS_VALUE); + + switch (port->row_status) { + + case RowStatus_notReady: + /* this can not happend */ + abort(); + + case RowStatus_notInService: + ctx->scratch->int1 = SET_ACTIVATED; + return (inet_activate(&port->tport)); + + case RowStatus_active: + return (SNMP_ERR_NOERROR); + + case RowStatus_createAndGo: + case RowStatus_createAndWait: + case RowStatus_destroy: + abort(); + } + break; + + case RowStatus_notInService: + if (port == NULL) + return (SNMP_ERR_INCONS_VALUE); + + switch (port->row_status) { + + case RowStatus_notReady: + /* this can not happend */ + abort(); + + case RowStatus_notInService: + return (SNMP_ERR_NOERROR); + + case RowStatus_active: + /* this is done during commit */ + ctx->scratch->int1 = SET_DEACTIVATE; + return (SNMP_ERR_NOERROR); + + case RowStatus_createAndGo: + case RowStatus_createAndWait: + case RowStatus_destroy: + abort(); + } + break; + + case RowStatus_destroy: + /* this is done during commit */ + ctx->scratch->int1 = SET_DESTROY; + return (SNMP_ERR_NOERROR); + + case RowStatus_notReady: + return (SNMP_ERR_WRONG_VALUE); + } + abort(); +} + +/* + * Port table + */ +int +op_snmp_trans_inet(struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + asn_subid_t which = value->var.subs[sub - 1]; + struct inet_port *port; + struct inet_port_params params; + int ret; + + switch (op) { + + case SNMP_OP_GETNEXT: + if ((port = (struct inet_port *)trans_next_port(my_trans, + &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + index_append(&value->var, sub, &port->tport.index); + goto fetch; + + case SNMP_OP_GET: + if ((port = (struct inet_port *)trans_find_port(my_trans, + &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + goto fetch; + + case SNMP_OP_SET: + port = (struct inet_port *)trans_find_port(my_trans, + &value->var, sub); + + if (which != LEAF_begemotSnmpdTransInetStatus) + abort(); + if (!isok_RowStatus(value->v.integer)) + return (SNMP_ERR_WRONG_VALUE); + + if (index_decode(&value->var, sub, iidx, ¶ms.type, + ¶ms.addr, ¶ms.addr_len, ¶ms.port, + ¶ms.proto)) + return (SNMP_ERR_NO_CREATION); + + asn_slice_oid(¶ms.index, &value->var, sub, value->var.len); + + ret = inet_port_set(ctx, port, ¶ms, + (enum RowStatus)value->v.integer); + + free(params.addr); + return (ret); + + case SNMP_OP_ROLLBACK: + if ((port = (struct inet_port *)trans_find_port(my_trans, + &value->var, sub)) == NULL) + /* cannot happen */ + abort(); + + switch (ctx->scratch->int1) { + + case SET_CREATED: + /* newly created */ + assert(port != NULL); + inet_destroy_port(&port->tport); + return (SNMP_ERR_NOERROR); + + case SET_DESTROY: + /* do it now */ + assert(port != NULL); + return (SNMP_ERR_NOERROR); + + case SET_ACTIVATED: + deactivate_port(port); + return (SNMP_ERR_NOERROR); + + case SET_DEACTIVATE: + return (SNMP_ERR_NOERROR); + } + abort(); + + case SNMP_OP_COMMIT: + if ((port = (struct inet_port *)trans_find_port(my_trans, + &value->var, sub)) == NULL) + /* cannot happen */ + abort(); + + switch (ctx->scratch->int1) { + + case SET_CREATED: + /* newly created */ + assert(port != NULL); + return (SNMP_ERR_NOERROR); + + case SET_DESTROY: + /* do it now */ + assert(port != NULL); + inet_destroy_port(&port->tport); + return (SNMP_ERR_NOERROR); + + case SET_ACTIVATED: + return (SNMP_ERR_NOERROR); + + case SET_DEACTIVATE: + deactivate_port(port); + return (SNMP_ERR_NOERROR); + } + abort(); + } + abort(); + + fetch: + switch (which) { + + case LEAF_begemotSnmpdTransInetStatus: + value->v.integer = port->row_status; + break; + + default: + abort(); + } + + return (SNMP_ERR_NOERROR); +} Property changes on: vendor/1.14/snmpd/trans_inet.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/1.14/snmpd/trans_inet.h =================================================================== --- vendor/1.14/snmpd/trans_inet.h (nonexistent) +++ vendor/1.14/snmpd/trans_inet.h (revision 359491) @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2018 + * Hartmut Brandt. + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Id$ + */ + +#ifndef trans_inet_h_1530971397 +#define trans_inet_h_1530971397 + +/* transport declaration */ +extern const struct transport_def inet_trans; + +#endif Property changes on: vendor/1.14/snmpd/trans_inet.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/1.14/snmpd/trans_lsock.c =================================================================== --- vendor/1.14/snmpd/trans_lsock.c (nonexistent) +++ vendor/1.14/snmpd/trans_lsock.c (revision 359491) @@ -0,0 +1,670 @@ +/* + * Copyright (c) 2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmpd/trans_lsock.c,v 1.6 2005/02/25 11:50:25 brandt_h Exp $ + * + * Local domain socket transport + */ +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "snmpmod.h" +#include "snmpd.h" +#include "trans_lsock.h" +#include "tree.h" +#include "oid.h" + +static const struct asn_oid + oid_begemotSnmpdLocalPortTable = OIDX_begemotSnmpdLocalPortTable; + +static int lsock_start(void); +static int lsock_stop(int); +static void lsock_close_port(struct tport *); +static int lsock_init_port(struct tport *); +static ssize_t lsock_send(struct tport *, const u_char *, size_t, + const struct sockaddr *, size_t); +static ssize_t lsock_recv(struct tport *, struct port_input *); + +/* exported */ +const struct transport_def lsock_trans = { + "lsock", + OIDX_begemotSnmpdTransLsock, + lsock_start, + lsock_stop, + lsock_close_port, + lsock_init_port, + lsock_send, + lsock_recv, + NULL +}; +static struct transport *my_trans; + +static int +lsock_remove(struct tport *tp, intptr_t arg __unused) +{ + struct lsock_port *port = (struct lsock_port *)tp; + + (void)remove(port->name); + + return (-1); +} + +static int +lsock_stop(int force) +{ + + if (my_trans != NULL) { + if (!force && trans_first_port(my_trans) != NULL) + return (SNMP_ERR_GENERR); + trans_iter_port(my_trans, lsock_remove, 0); + return (trans_unregister(my_trans)); + } + return (SNMP_ERR_NOERROR); +} + +static int +lsock_start(void) +{ + return (trans_register(&lsock_trans, &my_trans)); +} + +/* + * Open a local port. If this is a datagram socket create also the + * one and only peer. + */ +static int +lsock_open_port(u_char *name, size_t namelen, struct lsock_port **pp, + int type) +{ + struct lsock_port *port; + struct lsock_peer *peer = NULL; + int is_stream, need_cred; + size_t u; + int err; + struct sockaddr_un sa; + + if (namelen == 0 || namelen + 1 > sizeof(sa.sun_path)) + return (SNMP_ERR_BADVALUE); + + switch (type) { + case LOCP_DGRAM_UNPRIV: + is_stream = 0; + need_cred = 0; + break; + + case LOCP_DGRAM_PRIV: + is_stream = 0; + need_cred = 1; + break; + + case LOCP_STREAM_UNPRIV: + is_stream = 1; + need_cred = 0; + break; + + case LOCP_STREAM_PRIV: + is_stream = 1; + need_cred = 1; + break; + + default: + return (SNMP_ERR_BADVALUE); + } + + if ((port = calloc(1, sizeof(*port))) == NULL) + return (SNMP_ERR_GENERR); + + if (!is_stream) { + if ((peer = calloc(1, sizeof(*peer))) == NULL) { + free(port); + return (SNMP_ERR_GENERR); + } + } + if ((port->name = malloc(namelen + 1)) == NULL) { + free(port); + if (!is_stream) + free(peer); + return (SNMP_ERR_GENERR); + } + strncpy(port->name, name, namelen); + port->name[namelen] = '\0'; + + port->type = type; + port->str_sock = -1; + LIST_INIT(&port->peers); + + port->tport.index.len = namelen + 1; + port->tport.index.subs[0] = namelen; + for (u = 0; u < namelen; u++) + port->tport.index.subs[u + 1] = name[u]; + + if (peer != NULL) { + LIST_INSERT_HEAD(&port->peers, peer, link); + + peer->port = port; + + peer->input.fd = -1; + peer->input.id = NULL; + peer->input.stream = is_stream; + peer->input.cred = need_cred; + peer->input.peer = (struct sockaddr *)&peer->peer; + } + + trans_insert_port(my_trans, &port->tport); + + if (community != COMM_INITIALIZE && + (err = lsock_init_port(&port->tport)) != SNMP_ERR_NOERROR) { + lsock_close_port(&port->tport); + return (err); + } + + *pp = port; + + return (SNMP_ERR_NOERROR); +} + +/* + * Close a local domain peer + */ +static void +lsock_peer_close(struct lsock_peer *peer) +{ + + LIST_REMOVE(peer, link); + snmpd_input_close(&peer->input); + free(peer); +} + +/* + * Close a local port + */ +static void +lsock_close_port(struct tport *tp) +{ + struct lsock_port *port = (struct lsock_port *)tp; + struct lsock_peer *peer; + + if (port->str_id != NULL) + fd_deselect(port->str_id); + if (port->str_sock >= 0) + (void)close(port->str_sock); + (void)remove(port->name); + + trans_remove_port(tp); + + while ((peer = LIST_FIRST(&port->peers)) != NULL) + lsock_peer_close(peer); + + free(port->name); + free(port); +} + +/* + * Input on a local socket (either datagram or stream) + */ +static void +lsock_input(int fd __unused, void *udata) +{ + struct lsock_peer *peer = udata; + struct lsock_port *p = peer->port; + + peer->input.peerlen = sizeof(peer->peer); + if (snmpd_input(&peer->input, &p->tport) == -1 && peer->input.stream) + /* framing or other input error */ + lsock_peer_close(peer); +} + +/* + * A UNIX domain listening socket is ready. This means we have a peer + * that we need to accept + */ +static void +lsock_listen_input(int fd, void *udata) +{ + struct lsock_port *p = udata; + struct lsock_peer *peer; + + if ((peer = calloc(1, sizeof(*peer))) == NULL) { + syslog(LOG_WARNING, "%s: peer malloc failed", p->name); + (void)close(accept(fd, NULL, NULL)); + return; + } + + peer->port = p; + + peer->input.stream = 1; + peer->input.cred = (p->type == LOCP_DGRAM_PRIV || + p->type == LOCP_STREAM_PRIV); + peer->input.peerlen = sizeof(peer->peer); + peer->input.peer = (struct sockaddr *)&peer->peer; + + peer->input.fd = accept(fd, peer->input.peer, &peer->input.peerlen); + if (peer->input.fd == -1) { + syslog(LOG_WARNING, "%s: accept failed: %m", p->name); + free(peer); + return; + } + + if ((peer->input.id = fd_select(peer->input.fd, lsock_input, + peer, NULL)) == NULL) { + close(peer->input.fd); + free(peer); + return; + } + + LIST_INSERT_HEAD(&p->peers, peer, link); +} + +/* + * Create a local socket + */ +static int +lsock_init_port(struct tport *tp) +{ + struct lsock_port *p = (struct lsock_port *)tp; + struct sockaddr_un sa; + + if (p->type == LOCP_STREAM_PRIV || p->type == LOCP_STREAM_UNPRIV) { + if ((p->str_sock = socket(PF_LOCAL, SOCK_STREAM, 0)) < 0) { + syslog(LOG_ERR, "creating local socket: %m"); + return (SNMP_ERR_RES_UNAVAIL); + } + + strlcpy(sa.sun_path, p->name, sizeof(sa.sun_path)); + sa.sun_family = AF_LOCAL; + sa.sun_len = SUN_LEN(&sa); + + (void)remove(p->name); + + if (bind(p->str_sock, (struct sockaddr *)&sa, sizeof(sa))) { + if (errno == EADDRNOTAVAIL) { + close(p->str_sock); + p->str_sock = -1; + return (SNMP_ERR_INCONS_NAME); + } + syslog(LOG_ERR, "bind: %s %m", p->name); + close(p->str_sock); + p->str_sock = -1; + return (SNMP_ERR_GENERR); + } + if (chmod(p->name, 0666) == -1) + syslog(LOG_WARNING, "chmod(%s,0666): %m", p->name); + + if (listen(p->str_sock, 10) == -1) { + syslog(LOG_ERR, "listen: %s %m", p->name); + (void)remove(p->name); + close(p->str_sock); + p->str_sock = -1; + return (SNMP_ERR_GENERR); + } + + p->str_id = fd_select(p->str_sock, lsock_listen_input, p, NULL); + if (p->str_id == NULL) { + (void)remove(p->name); + close(p->str_sock); + p->str_sock = -1; + return (SNMP_ERR_GENERR); + } + } else { + struct lsock_peer *peer; + const int on = 1; + + peer = LIST_FIRST(&p->peers); + + if ((peer->input.fd = socket(PF_LOCAL, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "creating local socket: %m"); + return (SNMP_ERR_RES_UNAVAIL); + } + + if (setsockopt(peer->input.fd, 0, LOCAL_CREDS, &on, + sizeof(on)) == -1) { + syslog(LOG_ERR, "setsockopt(LOCAL_CREDS): %m"); + close(peer->input.fd); + peer->input.fd = -1; + return (SNMP_ERR_GENERR); + } + + strlcpy(sa.sun_path, p->name, sizeof(sa.sun_path)); + sa.sun_family = AF_LOCAL; + sa.sun_len = SUN_LEN(&sa); + + (void)remove(p->name); + + if (bind(peer->input.fd, (struct sockaddr *)&sa, sizeof(sa))) { + if (errno == EADDRNOTAVAIL) { + close(peer->input.fd); + peer->input.fd = -1; + return (SNMP_ERR_INCONS_NAME); + } + syslog(LOG_ERR, "bind: %s %m", p->name); + close(peer->input.fd); + peer->input.fd = -1; + return (SNMP_ERR_GENERR); + } + if (chmod(p->name, 0666) == -1) + syslog(LOG_WARNING, "chmod(%s,0666): %m", p->name); + + peer->input.id = fd_select(peer->input.fd, lsock_input, + peer, NULL); + if (peer->input.id == NULL) { + (void)remove(p->name); + close(peer->input.fd); + peer->input.fd = -1; + return (SNMP_ERR_GENERR); + } + } + return (SNMP_ERR_NOERROR); +} + +/* + * Send something + */ +static ssize_t +lsock_send(struct tport *tp, const u_char *buf, size_t len, + const struct sockaddr *addr, size_t addrlen) +{ + struct lsock_port *p = (struct lsock_port *)tp; + struct lsock_peer *peer; + + if (p->type == LOCP_DGRAM_PRIV || p->type == LOCP_DGRAM_UNPRIV) { + peer = LIST_FIRST(&p->peers); + + } else { + /* search for the peer */ + LIST_FOREACH(peer, &p->peers, link) + if (peer->input.peerlen == addrlen && + memcmp(peer->input.peer, addr, addrlen) == 0) + break; + if (peer == NULL) { + errno = ENOTCONN; + return (-1); + } + } + + return (sendto(peer->input.fd, buf, len, 0, addr, addrlen)); +} + +static void +check_priv_stream(struct port_input *pi) +{ + struct xucred ucred; + socklen_t ucredlen; + + /* obtain the accept time credentials */ + ucredlen = sizeof(ucred); + + if (getsockopt(pi->fd, 0, LOCAL_PEERCRED, &ucred, &ucredlen) == 0 && + ucredlen >= sizeof(ucred) && ucred.cr_version == XUCRED_VERSION) + pi->priv = (ucred.cr_uid == 0); + else + pi->priv = 0; +} + +/* + * Receive something + */ +static ssize_t +lsock_recv(struct tport *tp __unused, struct port_input *pi) +{ + struct msghdr msg; + struct iovec iov[1]; + ssize_t len; + + msg.msg_control = NULL; + msg.msg_controllen = 0; + + if (pi->buf == NULL) { + /* no buffer yet - allocate one */ + if ((pi->buf = buf_alloc(0)) == NULL) { + /* ups - could not get buffer. Return an error + * the caller must close the transport. */ + return (-1); + } + pi->buflen = buf_size(0); + pi->consumed = 0; + pi->length = 0; + } + + /* try to get a message */ + msg.msg_name = pi->peer; + msg.msg_namelen = pi->peerlen; + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + iov[0].iov_base = pi->buf + pi->length; + iov[0].iov_len = pi->buflen - pi->length; + + len = recvmsg(pi->fd, &msg, 0); + + if (len == -1 || len == 0) + /* receive error */ + return (-1); + + pi->length += len; + + if (pi->cred) + check_priv_stream(pi); + + return (0); +} + +/* + * Dependency to create a lsock port + */ +struct lsock_dep { + struct snmp_dependency dep; + + /* index (path name) */ + u_char *path; + size_t pathlen; + + /* the port */ + struct lsock_port *port; + + /* which of the fields are set */ + u_int set; + + /* type of the port */ + int type; + + /* status */ + int status; +}; +#define LD_TYPE 0x01 +#define LD_STATUS 0x02 +#define LD_CREATE 0x04 /* rollback create */ +#define LD_DELETE 0x08 /* rollback delete */ + +/* + * dependency handler for lsock ports + */ +static int +lsock_func(struct snmp_context *ctx, struct snmp_dependency *dep, + enum snmp_depop op) +{ + struct lsock_dep *ld = (struct lsock_dep *)(void *)dep; + int err = SNMP_ERR_NOERROR; + + switch (op) { + + case SNMP_DEPOP_COMMIT: + if (!(ld->set & LD_STATUS)) + err = SNMP_ERR_BADVALUE; + else if (ld->port == NULL) { + if (!ld->status) + err = SNMP_ERR_BADVALUE; + + else { + /* create */ + err = lsock_open_port(ld->path, ld->pathlen, + &ld->port, ld->type); + if (err == SNMP_ERR_NOERROR) + ld->set |= LD_CREATE; + } + } else if (!ld->status) { + /* delete - hard to roll back so defer to finalizer */ + ld->set |= LD_DELETE; + } else + /* modify - read-only */ + err = SNMP_ERR_READONLY; + + return (err); + + case SNMP_DEPOP_ROLLBACK: + if (ld->set & LD_CREATE) { + /* was create */ + lsock_close_port(&ld->port->tport); + } + return (SNMP_ERR_NOERROR); + + case SNMP_DEPOP_FINISH: + if ((ld->set & LD_DELETE) && ctx->code == SNMP_RET_OK) + lsock_close_port(&ld->port->tport); + free(ld->path); + return (SNMP_ERR_NOERROR); + } + abort(); +} + +/* + * Local port table + */ +int +op_lsock_port(struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int iidx, enum snmp_op op) +{ + asn_subid_t which = value->var.subs[sub-1]; + struct lsock_port *p; + u_char *name; + size_t namelen; + struct lsock_dep *ld; + struct asn_oid didx; + + switch (op) { + + case SNMP_OP_GETNEXT: + if ((p = (struct lsock_port *)trans_next_port(my_trans, + &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + index_append(&value->var, sub, &p->tport.index); + break; + + case SNMP_OP_GET: + if ((p = (struct lsock_port *)trans_find_port(my_trans, + &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + p = (struct lsock_port *)trans_find_port(my_trans, + &value->var, sub); + + if (index_decode(&value->var, sub, iidx, &name, &namelen)) + return (SNMP_ERR_NO_CREATION); + + asn_slice_oid(&didx, &value->var, sub, value->var.len); + if ((ld = (struct lsock_dep *)(void *)snmp_dep_lookup(ctx, + &oid_begemotSnmpdLocalPortTable, &didx, sizeof(*ld), + lsock_func)) == NULL) { + free(name); + return (SNMP_ERR_GENERR); + } + + if (ld->path == NULL) { + ld->path = name; + ld->pathlen = namelen; + } else { + free(name); + } + ld->port = p; + + switch (which) { + + case LEAF_begemotSnmpdLocalPortStatus: + if (ld->set & LD_STATUS) + return (SNMP_ERR_INCONS_VALUE); + if (!TRUTH_OK(value->v.integer)) + return (SNMP_ERR_WRONG_VALUE); + + ld->status = TRUTH_GET(value->v.integer); + ld->set |= LD_STATUS; + break; + + case LEAF_begemotSnmpdLocalPortType: + if (ld->set & LD_TYPE) + return (SNMP_ERR_INCONS_VALUE); + if (value->v.integer < 1 || value->v.integer > 4) + return (SNMP_ERR_WRONG_VALUE); + + ld->type = value->v.integer; + ld->set |= LD_TYPE; + break; + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + return (SNMP_ERR_NOERROR); + + default: + abort(); + } + + /* + * Come here to fetch the value + */ + switch (which) { + + case LEAF_begemotSnmpdLocalPortStatus: + value->v.integer = 1; + break; + + case LEAF_begemotSnmpdLocalPortType: + value->v.integer = p->type; + break; + + default: + abort(); + } + + return (SNMP_ERR_NOERROR); +} Property changes on: vendor/1.14/snmpd/trans_lsock.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmpd/trans_udp.c =================================================================== --- vendor/1.14/snmpd/trans_udp.c (nonexistent) +++ vendor/1.14/snmpd/trans_udp.c (revision 359491) @@ -0,0 +1,439 @@ +/* + * Copyright (c) 2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmpd/trans_udp.c,v 1.5 2005/10/04 08:46:56 brandt_h Exp $ + * + * UDP transport + */ +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "snmpmod.h" +#include "snmpd.h" +#include "trans_udp.h" +#include "tree.h" +#include "oid.h" + +static int udp_start(void); +static int udp_stop(int); +static void udp_close_port(struct tport *); +static int udp_init_port(struct tport *); +static ssize_t udp_send(struct tport *, const u_char *, size_t, + const struct sockaddr *, size_t); +static ssize_t udp_recv(struct tport *, struct port_input *); + +/* exported */ +const struct transport_def udp_trans = { + "udp", + OIDX_begemotSnmpdTransUdp, + udp_start, + udp_stop, + udp_close_port, + udp_init_port, + udp_send, + udp_recv, + NULL +}; +static struct transport *my_trans; + +static int +udp_start(void) +{ + return (trans_register(&udp_trans, &my_trans)); +} + +static int +udp_stop(int force __unused) +{ + if (my_trans != NULL) + if (trans_unregister(my_trans) != 0) + return (SNMP_ERR_GENERR); + return (SNMP_ERR_NOERROR); +} + +/* + * A UDP port is ready + */ +static void +udp_input(int fd __unused, void *udata) +{ + struct udp_port *p = udata; + + p->input.peerlen = sizeof(p->ret); + snmpd_input(&p->input, &p->tport); +} + +/* + * Create a UDP socket and bind it to the given port + */ +static int +udp_init_port(struct tport *tp) +{ + struct udp_port *p = (struct udp_port *)tp; + struct sockaddr_in addr; + u_int32_t ip; + const int on = 1; + + if ((p->input.fd = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + syslog(LOG_ERR, "creating UDP socket: %m"); + return (SNMP_ERR_RES_UNAVAIL); + } + ip = (p->addr[0] << 24) | (p->addr[1] << 16) | (p->addr[2] << 8) | + p->addr[3]; + memset(&addr, 0, sizeof(addr)); + addr.sin_addr.s_addr = htonl(ip); + addr.sin_port = htons(p->port); + addr.sin_family = AF_INET; + addr.sin_len = sizeof(addr); + if (addr.sin_addr.s_addr == INADDR_ANY) { + if (setsockopt(p->input.fd, IPPROTO_IP, IP_RECVDSTADDR, &on, + sizeof(on)) == -1) { + syslog(LOG_ERR, "setsockopt(IP_RECVDSTADDR): %m"); + close(p->input.fd); + p->input.fd = -1; + return (SNMP_ERR_GENERR); + } + p->recvdstaddr = true; + } + if (bind(p->input.fd, (struct sockaddr *)&addr, sizeof(addr))) { + if (errno == EADDRNOTAVAIL) { + close(p->input.fd); + p->input.fd = -1; + return (SNMP_ERR_INCONS_NAME); + } + syslog(LOG_ERR, "bind: %s:%u %m", inet_ntoa(addr.sin_addr), + p->port); + close(p->input.fd); + p->input.fd = -1; + return (SNMP_ERR_GENERR); + } + if ((p->input.id = fd_select(p->input.fd, udp_input, + p, NULL)) == NULL) { + close(p->input.fd); + p->input.fd = -1; + return (SNMP_ERR_GENERR); + } + return (SNMP_ERR_NOERROR); +} + +/* + * Create a new SNMP Port object and start it, if we are not + * in initialization mode. The arguments are in host byte order. + */ +static int +udp_open_port(u_int8_t *addr, u_int32_t udp_port, struct udp_port **pp) +{ + struct udp_port *port; + int err; + + if (udp_port > 0xffff) + return (SNMP_ERR_NO_CREATION); + if ((port = malloc(sizeof(*port))) == NULL) + return (SNMP_ERR_GENERR); + memset(port, 0, sizeof(*port)); + + /* initialize common part */ + port->tport.index.len = 5; + port->tport.index.subs[0] = addr[0]; + port->tport.index.subs[1] = addr[1]; + port->tport.index.subs[2] = addr[2]; + port->tport.index.subs[3] = addr[3]; + port->tport.index.subs[4] = udp_port; + + port->addr[0] = addr[0]; + port->addr[1] = addr[1]; + port->addr[2] = addr[2]; + port->addr[3] = addr[3]; + port->port = udp_port; + + port->input.fd = -1; + port->input.id = NULL; + port->input.stream = 0; + port->input.cred = 0; + port->input.peer = (struct sockaddr *)&port->ret; + port->input.peerlen = sizeof(port->ret); + + trans_insert_port(my_trans, &port->tport); + + if (community != COMM_INITIALIZE && + (err = udp_init_port(&port->tport)) != SNMP_ERR_NOERROR) { + udp_close_port(&port->tport); + return (err); + } + *pp = port; + return (SNMP_ERR_NOERROR); +} + +/* + * Close an SNMP port + */ +static void +udp_close_port(struct tport *tp) +{ + struct udp_port *port = (struct udp_port *)tp; + + snmpd_input_close(&port->input); + trans_remove_port(tp); + free(port); +} + +/* + * Send something + */ +static ssize_t +udp_send(struct tport *tp, const u_char *buf, size_t len, + const struct sockaddr *addr, size_t addrlen) +{ + struct udp_port *p = (struct udp_port *)tp; + struct cmsghdr *cmsg; + struct msghdr msg; + char cbuf[CMSG_SPACE(sizeof(struct in_addr))]; + struct iovec iov; + + iov.iov_base = __DECONST(void*, buf); + iov.iov_len = len; + + msg.msg_flags = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_name = __DECONST(void *, addr); + msg.msg_namelen = addrlen; + + if (p->recvdstaddr) { + msg.msg_control = cbuf; + msg.msg_controllen = sizeof(cbuf); + + cmsg = CMSG_FIRSTHDR(&msg); + cmsg->cmsg_level = IPPROTO_IP; + cmsg->cmsg_type = IP_SENDSRCADDR; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct in_addr)); + memcpy(CMSG_DATA(cmsg), &p->dstaddr, sizeof(struct in_addr)); + } else { + msg.msg_control = NULL; + msg.msg_controllen = 0; + } + + return (sendmsg(p->input.fd, &msg, 0)); +} + +static void +check_priv_dgram(struct port_input *pi, struct sockcred *cred) +{ + + /* process explicitly sends credentials */ + if (cred) + pi->priv = (cred->sc_euid == 0); + else + pi->priv = 0; +} + +/* + * Input from a datagram socket. + * Each receive should return one datagram. + */ +static ssize_t +udp_recv(struct tport *tp, struct port_input *pi) +{ + u_char embuf[1000]; + char cbuf[CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) + + CMSG_SPACE(sizeof(struct in_addr))]; + struct udp_port *p = (struct udp_port *)tp; + struct msghdr msg; + struct iovec iov[1]; + ssize_t len; + struct cmsghdr *cmsg; + struct sockcred *cred = NULL; + + if (pi->buf == NULL) { + /* no buffer yet - allocate one */ + if ((pi->buf = buf_alloc(0)) == NULL) { + /* ups - could not get buffer. Read away input + * and drop it */ + (void)recvfrom(pi->fd, embuf, sizeof(embuf), + 0, NULL, NULL); + /* return error */ + return (-1); + } + pi->buflen = buf_size(0); + } + + /* try to get a message */ + msg.msg_name = pi->peer; + msg.msg_namelen = pi->peerlen; + msg.msg_iov = iov; + msg.msg_iovlen = 1; + memset(cbuf, 0, sizeof(cbuf)); + msg.msg_control = cbuf; + msg.msg_controllen = sizeof(cbuf); + msg.msg_flags = 0; + + iov[0].iov_base = pi->buf; + iov[0].iov_len = pi->buflen; + + len = recvmsg(pi->fd, &msg, 0); + + if (len == -1 || len == 0) + /* receive error */ + return (-1); + + if (msg.msg_flags & MSG_TRUNC) { + /* truncated - drop */ + snmpd_stats.silentDrops++; + snmpd_stats.inTooLong++; + return (-1); + } + + pi->length = (size_t)len; + + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level == IPPROTO_IP && + cmsg->cmsg_type == IP_RECVDSTADDR) + memcpy(&p->dstaddr, CMSG_DATA(cmsg), + sizeof(struct in_addr)); + if (cmsg->cmsg_level == SOL_SOCKET && + cmsg->cmsg_type == SCM_CREDS) + cred = (struct sockcred *)(void *)CMSG_DATA(cmsg); + } + + if (pi->cred) + check_priv_dgram(pi, cred); + + return (0); +} + +/* + * Port table + */ +int +op_snmp_port(struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int iidx, enum snmp_op op) +{ + asn_subid_t which = value->var.subs[sub-1]; + struct udp_port *p; + u_int8_t addr[4]; + u_int32_t port; + + switch (op) { + + case SNMP_OP_GETNEXT: + if ((p = (struct udp_port *)trans_next_port(my_trans, + &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + index_append(&value->var, sub, &p->tport.index); + break; + + case SNMP_OP_GET: + if ((p = (struct udp_port *)trans_find_port(my_trans, + &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + p = (struct udp_port *)trans_find_port(my_trans, + &value->var, sub); + ctx->scratch->int1 = (p != NULL); + + if (which != LEAF_begemotSnmpdPortStatus) + abort(); + if (!TRUTH_OK(value->v.integer)) + return (SNMP_ERR_WRONG_VALUE); + + ctx->scratch->int2 = TRUTH_GET(value->v.integer); + + if (ctx->scratch->int2) { + /* open an SNMP port */ + if (p != NULL) + /* already open - do nothing */ + return (SNMP_ERR_NOERROR); + + if (index_decode(&value->var, sub, iidx, addr, &port)) + return (SNMP_ERR_NO_CREATION); + return (udp_open_port(addr, port, &p)); + + } else { + /* close SNMP port - do in commit */ + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_ROLLBACK: + p = (struct udp_port *)trans_find_port(my_trans, + &value->var, sub); + if (ctx->scratch->int1 == 0) { + /* did not exist */ + if (ctx->scratch->int2 == 1) { + /* created */ + if (p != NULL) + udp_close_port(&p->tport); + } + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_COMMIT: + p = (struct udp_port *)trans_find_port(my_trans, + &value->var, sub); + if (ctx->scratch->int1 == 1) { + /* did exist */ + if (ctx->scratch->int2 == 0) { + /* delete */ + if (p != NULL) + udp_close_port(&p->tport); + } + } + return (SNMP_ERR_NOERROR); + + default: + abort(); + } + + /* + * Come here to fetch the value + */ + switch (which) { + + case LEAF_begemotSnmpdPortStatus: + value->v.integer = 1; + break; + + default: + abort(); + } + + return (SNMP_ERR_NOERROR); +} Property changes on: vendor/1.14/snmpd/trans_udp.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmpd/trap.c =================================================================== --- vendor/1.14/snmpd/trap.c (nonexistent) +++ vendor/1.14/snmpd/trap.c (revision 359491) @@ -0,0 +1,910 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Copyright (c) 2010 The FreeBSD Foundation + * All rights reserved. + * + * Portions of this software were developed by Shteryana Sotirova Shopova + * under sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmpd/trap.c,v 1.9 2005/10/04 11:21:39 brandt_h Exp $ + * + * TrapSinkTable + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "snmpmod.h" +#include "snmpd.h" + +#define SNMPTREE_TYPES +#include "tree.h" +#include "oid.h" + +struct trapsink_list trapsink_list = TAILQ_HEAD_INITIALIZER(trapsink_list); + +/* List of target addresses */ +static struct target_addresslist target_addresslist = + SLIST_HEAD_INITIALIZER(target_addresslist); + +/* List of target parameters */ +static struct target_paramlist target_paramlist = + SLIST_HEAD_INITIALIZER(target_paramlist); + +/* List of notification targets */ +static struct target_notifylist target_notifylist = + SLIST_HEAD_INITIALIZER(target_notifylist); + +static const struct asn_oid oid_begemotTrapSinkTable = + OIDX_begemotTrapSinkTable; +static const struct asn_oid oid_sysUpTime = OIDX_sysUpTime; +static const struct asn_oid oid_snmpTrapOID = OIDX_snmpTrapOID; + +struct trapsink_dep { + struct snmp_dependency dep; + u_int set; + u_int status; + u_char comm[SNMP_COMMUNITY_MAXLEN + 1]; + u_int version; + u_int rb; + u_int rb_status; + u_int rb_version; + u_char rb_comm[SNMP_COMMUNITY_MAXLEN + 1]; +}; +enum { + TDEP_STATUS = 0x0001, + TDEP_COMM = 0x0002, + TDEP_VERSION = 0x0004, + + TDEP_CREATE = 0x0001, + TDEP_MODIFY = 0x0002, + TDEP_DESTROY = 0x0004, +}; + +static int +trapsink_create(struct trapsink_dep *tdep) +{ + struct trapsink *t; + struct sockaddr_in sa; + + if ((t = malloc(sizeof(*t))) == NULL) + return (SNMP_ERR_RES_UNAVAIL); + + t->index = tdep->dep.idx; + t->status = TRAPSINK_NOT_READY; + t->comm[0] = '\0'; + t->version = TRAPSINK_V2; + + if ((t->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { + syslog(LOG_ERR, "socket(UDP): %m"); + free(t); + return (SNMP_ERR_RES_UNAVAIL); + } + (void)shutdown(t->socket, SHUT_RD); + memset(&sa, 0, sizeof(sa)); + sa.sin_len = sizeof(sa); + sa.sin_family = AF_INET; + sa.sin_addr.s_addr = htonl((t->index.subs[0] << 24) | + (t->index.subs[1] << 16) | (t->index.subs[2] << 8) | + (t->index.subs[3] << 0)); + sa.sin_port = htons(t->index.subs[4]); + + if (connect(t->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) { + syslog(LOG_ERR, "connect(%s,%u): %m", + inet_ntoa(sa.sin_addr), ntohs(sa.sin_port)); + (void)close(t->socket); + free(t); + return (SNMP_ERR_GENERR); + } + + if (tdep->set & TDEP_VERSION) + t->version = tdep->version; + if (tdep->set & TDEP_COMM) + strcpy(t->comm, tdep->comm); + + if (t->comm[0] != '\0') + t->status = TRAPSINK_NOT_IN_SERVICE; + + /* look whether we should activate */ + if (tdep->status == 4) { + if (t->status == TRAPSINK_NOT_READY) { + if (t->socket != -1) + (void)close(t->socket); + free(t); + return (SNMP_ERR_INCONS_VALUE); + } + t->status = TRAPSINK_ACTIVE; + } + + INSERT_OBJECT_OID(t, &trapsink_list); + + tdep->rb |= TDEP_CREATE; + + return (SNMP_ERR_NOERROR); +} + +static void +trapsink_free(struct trapsink *t) +{ + TAILQ_REMOVE(&trapsink_list, t, link); + if (t->socket != -1) + (void)close(t->socket); + free(t); +} + +static int +trapsink_modify(struct trapsink *t, struct trapsink_dep *tdep) +{ + tdep->rb_status = t->status; + tdep->rb_version = t->version; + strcpy(tdep->rb_comm, t->comm); + + if (tdep->set & TDEP_STATUS) { + /* if we are active and should move to not_in_service do + * this first */ + if (tdep->status == 2 && tdep->rb_status == TRAPSINK_ACTIVE) { + t->status = TRAPSINK_NOT_IN_SERVICE; + tdep->rb |= TDEP_MODIFY; + } + } + + if (tdep->set & TDEP_VERSION) + t->version = tdep->version; + if (tdep->set & TDEP_COMM) + strcpy(t->comm, tdep->comm); + + if (tdep->set & TDEP_STATUS) { + /* if we were inactive and should go active - do this now */ + if (tdep->status == 1 && tdep->rb_status != TRAPSINK_ACTIVE) { + if (t->comm[0] == '\0') { + t->status = tdep->rb_status; + t->version = tdep->rb_version; + strcpy(t->comm, tdep->rb_comm); + return (SNMP_ERR_INCONS_VALUE); + } + t->status = TRAPSINK_ACTIVE; + tdep->rb |= TDEP_MODIFY; + } + } + return (SNMP_ERR_NOERROR); +} + +static int +trapsink_unmodify(struct trapsink *t, struct trapsink_dep *tdep) +{ + if (tdep->set & TDEP_STATUS) + t->status = tdep->rb_status; + if (tdep->set & TDEP_VERSION) + t->version = tdep->rb_version; + if (tdep->set & TDEP_COMM) + strcpy(t->comm, tdep->rb_comm); + + return (SNMP_ERR_NOERROR); +} + +static int +trapsink_destroy(struct snmp_context *ctx __unused, struct trapsink *t, + struct trapsink_dep *tdep) +{ + t->status = TRAPSINK_DESTROY; + tdep->rb_status = t->status; + tdep->rb |= TDEP_DESTROY; + return (SNMP_ERR_NOERROR); +} + +static int +trapsink_undestroy(struct trapsink *t, struct trapsink_dep *tdep) +{ + t->status = tdep->rb_status; + return (SNMP_ERR_NOERROR); +} + +static int +trapsink_dep(struct snmp_context *ctx, struct snmp_dependency *dep, + enum snmp_depop op) +{ + struct trapsink_dep *tdep = (struct trapsink_dep *)dep; + struct trapsink *t; + + t = FIND_OBJECT_OID(&trapsink_list, &dep->idx, 0); + + switch (op) { + + case SNMP_DEPOP_COMMIT: + if (tdep->set & TDEP_STATUS) { + switch (tdep->status) { + + case 1: + case 2: + if (t == NULL) + return (SNMP_ERR_INCONS_VALUE); + return (trapsink_modify(t, tdep)); + + case 4: + case 5: + if (t != NULL) + return (SNMP_ERR_INCONS_VALUE); + return (trapsink_create(tdep)); + + case 6: + if (t == NULL) + return (SNMP_ERR_NOERROR); + return (trapsink_destroy(ctx, t, tdep)); + } + } else if (tdep->set != 0) + return (trapsink_modify(t, tdep)); + + return (SNMP_ERR_NOERROR); + + case SNMP_DEPOP_ROLLBACK: + if (tdep->rb & TDEP_CREATE) { + trapsink_free(t); + return (SNMP_ERR_NOERROR); + } + if (tdep->rb & TDEP_MODIFY) + return (trapsink_unmodify(t, tdep)); + if(tdep->rb & TDEP_DESTROY) + return (trapsink_undestroy(t, tdep)); + return (SNMP_ERR_NOERROR); + + case SNMP_DEPOP_FINISH: + if ((tdep->rb & TDEP_DESTROY) && t != NULL && + ctx->code == SNMP_RET_OK) + trapsink_free(t); + return (SNMP_ERR_NOERROR); + } + abort(); +} + +int +op_trapsink(struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int iidx, enum snmp_op op) +{ + struct trapsink *t; + u_char ipa[4]; + int32_t port; + struct asn_oid idx; + struct trapsink_dep *tdep; + u_char *p; + + t = NULL; /* gcc */ + + switch (op) { + + case SNMP_OP_GETNEXT: + if ((t = NEXT_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + index_append(&value->var, sub, &t->index); + break; + + case SNMP_OP_GET: + if ((t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + if (index_decode(&value->var, sub, iidx, ipa, &port) || + port == 0 || port > 65535) + return (SNMP_ERR_NO_CREATION); + t = FIND_OBJECT_OID(&trapsink_list, &value->var, sub); + + asn_slice_oid(&idx, &value->var, sub, value->var.len); + + tdep = (struct trapsink_dep *)snmp_dep_lookup(ctx, + &oid_begemotTrapSinkTable, &idx, + sizeof(*tdep), trapsink_dep); + if (tdep == NULL) + return (SNMP_ERR_RES_UNAVAIL); + + switch (value->var.subs[sub - 1]) { + + case LEAF_begemotTrapSinkStatus: + if (tdep->set & TDEP_STATUS) + return (SNMP_ERR_INCONS_VALUE); + switch (value->v.integer) { + + case 1: + case 2: + if (t == NULL) + return (SNMP_ERR_INCONS_VALUE); + break; + + case 4: + case 5: + if (t != NULL) + return (SNMP_ERR_INCONS_VALUE); + break; + + case 6: + break; + + default: + return (SNMP_ERR_WRONG_VALUE); + } + tdep->status = value->v.integer; + tdep->set |= TDEP_STATUS; + return (SNMP_ERR_NOERROR); + + case LEAF_begemotTrapSinkComm: + if (tdep->set & TDEP_COMM) + return (SNMP_ERR_INCONS_VALUE); + if (value->v.octetstring.len == 0 || + value->v.octetstring.len > SNMP_COMMUNITY_MAXLEN) + return (SNMP_ERR_WRONG_VALUE); + for (p = value->v.octetstring.octets; + p < value->v.octetstring.octets + value->v.octetstring.len; + p++) { + if (!isascii(*p) || !isprint(*p)) + return (SNMP_ERR_WRONG_VALUE); + } + tdep->set |= TDEP_COMM; + strncpy(tdep->comm, value->v.octetstring.octets, + value->v.octetstring.len); + tdep->comm[value->v.octetstring.len] = '\0'; + return (SNMP_ERR_NOERROR); + + case LEAF_begemotTrapSinkVersion: + if (tdep->set & TDEP_VERSION) + return (SNMP_ERR_INCONS_VALUE); + if (value->v.integer != TRAPSINK_V1 && + value->v.integer != TRAPSINK_V2) + return (SNMP_ERR_WRONG_VALUE); + tdep->version = value->v.integer; + tdep->set |= TDEP_VERSION; + return (SNMP_ERR_NOERROR); + } + if (t == NULL) + return (SNMP_ERR_INCONS_NAME); + else + return (SNMP_ERR_NOT_WRITEABLE); + + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + return (SNMP_ERR_NOERROR); + } + + switch (value->var.subs[sub - 1]) { + + case LEAF_begemotTrapSinkStatus: + value->v.integer = t->status; + break; + + case LEAF_begemotTrapSinkComm: + return (string_get(value, t->comm, -1)); + + case LEAF_begemotTrapSinkVersion: + value->v.integer = t->version; + break; + + } + return (SNMP_ERR_NOERROR); +} + +static void +snmp_create_v1_trap(struct snmp_pdu *pdu, char *com, + const struct asn_oid *trap_oid) +{ + memset(pdu, 0, sizeof(*pdu)); + strlcpy(pdu->community, com, sizeof(pdu->community)); + + pdu->version = SNMP_V1; + pdu->type = SNMP_PDU_TRAP; + pdu->enterprise = systemg.object_id; + memcpy(pdu->agent_addr, snmpd.trap1addr, 4); + pdu->generic_trap = trap_oid->subs[trap_oid->len - 1] - 1; + pdu->specific_trap = 0; + pdu->time_stamp = get_ticks() - start_tick; + pdu->nbindings = 0; +} + +static void +snmp_create_v2_trap(struct snmp_pdu *pdu, char *com, + const struct asn_oid *trap_oid) +{ + memset(pdu, 0, sizeof(*pdu)); + strlcpy(pdu->community, com, sizeof(pdu->community)); + + pdu->version = SNMP_V2c; + pdu->type = SNMP_PDU_TRAP2; + pdu->request_id = reqid_next(trap_reqid); + pdu->error_index = 0; + pdu->error_status = SNMP_ERR_NOERROR; + + pdu->bindings[0].var = oid_sysUpTime; + pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0; + pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS; + pdu->bindings[0].v.uint32 = get_ticks() - start_tick; + + pdu->bindings[1].var = oid_snmpTrapOID; + pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0; + pdu->bindings[1].syntax = SNMP_SYNTAX_OID; + pdu->bindings[1].v.oid = *trap_oid; + + pdu->nbindings = 2; +} + +static void +snmp_create_v3_trap(struct snmp_pdu *pdu, struct target_param *target, + const struct asn_oid *trap_oid) +{ + struct usm_user *usmuser; + + memset(pdu, 0, sizeof(*pdu)); + + pdu->version = SNMP_V3; + pdu->type = SNMP_PDU_TRAP2; + pdu->request_id = reqid_next(trap_reqid); + pdu->error_index = 0; + pdu->error_status = SNMP_ERR_NOERROR; + + pdu->bindings[0].var = oid_sysUpTime; + pdu->bindings[0].var.subs[pdu->bindings[0].var.len++] = 0; + pdu->bindings[0].syntax = SNMP_SYNTAX_TIMETICKS; + pdu->bindings[0].v.uint32 = get_ticks() - start_tick; + + pdu->bindings[1].var = oid_snmpTrapOID; + pdu->bindings[1].var.subs[pdu->bindings[1].var.len++] = 0; + pdu->bindings[1].syntax = SNMP_SYNTAX_OID; + pdu->bindings[1].v.oid = *trap_oid; + + pdu->nbindings = 2; + + update_snmpd_engine_time(); + + memcpy(pdu->engine.engine_id, snmpd_engine.engine_id, + snmpd_engine.engine_len); + pdu->engine.engine_len = snmpd_engine.engine_len; + pdu->engine.engine_boots = snmpd_engine.engine_boots; + pdu->engine.engine_time = snmpd_engine.engine_time; + pdu->engine.max_msg_size = snmpd_engine.max_msg_size; + strlcpy(pdu->user.sec_name, target->secname, + sizeof(pdu->user.sec_name)); + pdu->security_model = target->sec_model; + + pdu->context_engine_len = snmpd_engine.engine_len; + memcpy(pdu->context_engine, snmpd_engine.engine_id, + snmpd_engine.engine_len); + + if (target->sec_model == SNMP_SECMODEL_USM && + target->sec_level != SNMP_noAuthNoPriv) { + usmuser = usm_find_user(pdu->engine.engine_id, + pdu->engine.engine_len, pdu->user.sec_name); + if (usmuser != NULL) { + pdu->user.auth_proto = usmuser->suser.auth_proto; + pdu->user.priv_proto = usmuser->suser.priv_proto; + memcpy(pdu->user.auth_key, usmuser->suser.auth_key, + sizeof(pdu->user.auth_key)); + memcpy(pdu->user.priv_key, usmuser->suser.priv_key, + sizeof(pdu->user.priv_key)); + } + snmp_pdu_init_secparams(pdu); + } +} + +void +snmp_send_trap(const struct asn_oid *trap_oid, ...) +{ + struct snmp_pdu pdu; + struct trapsink *t; + const struct snmp_value *v; + struct target_notify *n; + struct target_address *ta; + struct target_param *tp; + + va_list ap; + u_char *sndbuf; + char *tag; + size_t sndlen; + ssize_t len; + int32_t ip; + + TAILQ_FOREACH(t, &trapsink_list, link) { + if (t->status != TRAPSINK_ACTIVE) + continue; + + if (t->version == TRAPSINK_V1) + snmp_create_v1_trap(&pdu, t->comm, trap_oid); + else + snmp_create_v2_trap(&pdu, t->comm, trap_oid); + + va_start(ap, trap_oid); + while ((v = va_arg(ap, const struct snmp_value *)) != NULL) + pdu.bindings[pdu.nbindings++] = *v; + va_end(ap); + + if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) { + syslog(LOG_DEBUG, "send trap to %s failed: no access", + t->comm); + continue; + } + + if ((sndbuf = buf_alloc(1)) == NULL) { + syslog(LOG_ERR, "trap send buffer: %m"); + return; + } + + snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); + + if ((len = send(t->socket, sndbuf, sndlen, 0)) == -1) + syslog(LOG_ERR, "send: %m"); + else if ((size_t)len != sndlen) + syslog(LOG_ERR, "send: short write %zu/%zu", + sndlen, (size_t)len); + + free(sndbuf); + } + + SLIST_FOREACH(n, &target_notifylist, tn) { + if (n->status != RowStatus_active || n->taglist[0] == '\0') + continue; + + SLIST_FOREACH(ta, &target_addresslist, ta) + if ((tag = strstr(ta->taglist, n->taglist)) != NULL && + (tag[strlen(n->taglist)] == ' ' || + tag[strlen(n->taglist)] == '\0' || + tag[strlen(n->taglist)] == '\t' || + tag[strlen(n->taglist)] == '\r' || + tag[strlen(n->taglist)] == '\n') && + ta->status == RowStatus_active) + break; + if (ta == NULL) + continue; + + SLIST_FOREACH(tp, &target_paramlist, tp) + if (strcmp(tp->name, ta->paramname) == 0 && + tp->status == 1) + break; + if (tp == NULL) + continue; + + switch (tp->mpmodel) { + case SNMP_MPM_SNMP_V1: + snmp_create_v1_trap(&pdu, tp->secname, trap_oid); + break; + + case SNMP_MPM_SNMP_V2c: + snmp_create_v2_trap(&pdu, tp->secname, trap_oid); + break; + + case SNMP_MPM_SNMP_V3: + snmp_create_v3_trap(&pdu, tp, trap_oid); + break; + + default: + continue; + } + + va_start(ap, trap_oid); + while ((v = va_arg(ap, const struct snmp_value *)) != NULL) + pdu.bindings[pdu.nbindings++] = *v; + va_end(ap); + + if (snmp_pdu_auth_access(&pdu, &ip) != SNMP_CODE_OK) { + syslog(LOG_DEBUG, "send trap to %s failed: no access", + t->comm); + continue; + } + + if ((sndbuf = buf_alloc(1)) == NULL) { + syslog(LOG_ERR, "trap send buffer: %m"); + return; + } + + snmp_output(&pdu, sndbuf, &sndlen, "TRAP"); + + if ((len = send(ta->socket, sndbuf, sndlen, 0)) == -1) + syslog(LOG_ERR, "send: %m"); + else if ((size_t)len != sndlen) + syslog(LOG_ERR, "send: short write %zu/%zu", + sndlen, (size_t)len); + + free(sndbuf); + } +} + +/* + * RFC 3413 SNMP Management Target MIB + */ +struct snmpd_target_stats * +bsnmpd_get_target_stats(void) +{ + return (&snmpd_target_stats); +} + +struct target_address * +target_first_address(void) +{ + return (SLIST_FIRST(&target_addresslist)); +} + +struct target_address * +target_next_address(struct target_address *addrs) +{ + if (addrs == NULL) + return (NULL); + + return (SLIST_NEXT(addrs, ta)); +} + +struct target_address * +target_new_address(char *aname) +{ + int cmp; + struct target_address *addrs, *temp, *prev; + + SLIST_FOREACH(addrs, &target_addresslist, ta) + if (strcmp(aname, addrs->name) == 0) + return (NULL); + + if ((addrs = (struct target_address *)malloc(sizeof(*addrs))) == NULL) + return (NULL); + + memset(addrs, 0, sizeof(*addrs)); + strlcpy(addrs->name, aname, sizeof(addrs->name)); + addrs->timeout = 150; + addrs->retry = 3; /* XXX */ + + if ((prev = SLIST_FIRST(&target_addresslist)) == NULL || + strcmp(aname, prev->name) < 0) { + SLIST_INSERT_HEAD(&target_addresslist, addrs, ta); + return (addrs); + } + + SLIST_FOREACH(temp, &target_addresslist, ta) { + if ((cmp = strcmp(aname, temp->name)) <= 0) + break; + prev = temp; + } + + if (temp == NULL || cmp < 0) + SLIST_INSERT_AFTER(prev, addrs, ta); + else if (cmp > 0) + SLIST_INSERT_AFTER(temp, addrs, ta); + else { + syslog(LOG_ERR, "Target address %s exists", addrs->name); + free(addrs); + return (NULL); + } + + return (addrs); +} + +int +target_activate_address(struct target_address *addrs) +{ + struct sockaddr_in sa; + + if ((addrs->socket = socket(PF_INET, SOCK_DGRAM, 0)) == -1) { + syslog(LOG_ERR, "socket(UDP): %m"); + return (SNMP_ERR_RES_UNAVAIL); + } + + (void)shutdown(addrs->socket, SHUT_RD); + memset(&sa, 0, sizeof(sa)); + sa.sin_len = sizeof(sa); + sa.sin_family = AF_INET; + + sa.sin_addr.s_addr = htonl((addrs->address[0] << 24) | + (addrs->address[1] << 16) | (addrs->address[2] << 8) | + (addrs->address[3] << 0)); + sa.sin_port = htons(addrs->address[4] << 8 | addrs->address[5]); + + if (connect(addrs->socket, (struct sockaddr *)&sa, sa.sin_len) == -1) { + syslog(LOG_ERR, "connect(%s,%u): %m", + inet_ntoa(sa.sin_addr), ntohs(sa.sin_port)); + (void)close(addrs->socket); + return (SNMP_ERR_GENERR); + } + + addrs->status = RowStatus_active; + + return (SNMP_ERR_NOERROR); +} + +int +target_delete_address(struct target_address *addrs) +{ + SLIST_REMOVE(&target_addresslist, addrs, target_address, ta); + if (addrs->status == RowStatus_active) + close(addrs->socket); + free(addrs); + + return (0); +} + +struct target_param * +target_first_param(void) +{ + return (SLIST_FIRST(&target_paramlist)); +} + +struct target_param * +target_next_param(struct target_param *param) +{ + if (param == NULL) + return (NULL); + + return (SLIST_NEXT(param, tp)); +} + +struct target_param * +target_new_param(char *pname) +{ + int cmp; + struct target_param *param, *temp, *prev; + + SLIST_FOREACH(param, &target_paramlist, tp) + if (strcmp(pname, param->name) == 0) + return (NULL); + + if ((param = (struct target_param *)malloc(sizeof(*param))) == NULL) + return (NULL); + + memset(param, 0, sizeof(*param)); + strlcpy(param->name, pname, sizeof(param->name)); + + if ((prev = SLIST_FIRST(&target_paramlist)) == NULL || + strcmp(pname, prev->name) < 0) { + SLIST_INSERT_HEAD(&target_paramlist, param, tp); + return (param); + } + + SLIST_FOREACH(temp, &target_paramlist, tp) { + if ((cmp = strcmp(pname, temp->name)) <= 0) + break; + prev = temp; + } + + if (temp == NULL || cmp < 0) + SLIST_INSERT_AFTER(prev, param, tp); + else if (cmp > 0) + SLIST_INSERT_AFTER(temp, param, tp); + else { + syslog(LOG_ERR, "Target parameter %s exists", param->name); + free(param); + return (NULL); + } + + return (param); +} + +int +target_delete_param(struct target_param *param) +{ + SLIST_REMOVE(&target_paramlist, param, target_param, tp); + free(param); + + return (0); +} + +struct target_notify * +target_first_notify(void) +{ + return (SLIST_FIRST(&target_notifylist)); +} + +struct target_notify * +target_next_notify(struct target_notify *notify) +{ + if (notify == NULL) + return (NULL); + + return (SLIST_NEXT(notify, tn)); +} + +struct target_notify * +target_new_notify(char *nname) +{ + int cmp; + struct target_notify *notify, *temp, *prev; + + SLIST_FOREACH(notify, &target_notifylist, tn) + if (strcmp(nname, notify->name) == 0) + return (NULL); + + if ((notify = (struct target_notify *)malloc(sizeof(*notify))) == NULL) + return (NULL); + + memset(notify, 0, sizeof(*notify)); + strlcpy(notify->name, nname, sizeof(notify->name)); + + if ((prev = SLIST_FIRST(&target_notifylist)) == NULL || + strcmp(nname, prev->name) < 0) { + SLIST_INSERT_HEAD(&target_notifylist, notify, tn); + return (notify); + } + + SLIST_FOREACH(temp, &target_notifylist, tn) { + if ((cmp = strcmp(nname, temp->name)) <= 0) + break; + prev = temp; + } + + if (temp == NULL || cmp < 0) + SLIST_INSERT_AFTER(prev, notify, tn); + else if (cmp > 0) + SLIST_INSERT_AFTER(temp, notify, tn); + else { + syslog(LOG_ERR, "Notification target %s exists", notify->name); + free(notify); + return (NULL); + } + + return (notify); +} + +int +target_delete_notify(struct target_notify *notify) +{ + SLIST_REMOVE(&target_notifylist, notify, target_notify, tn); + free(notify); + + return (0); +} + +void +target_flush_all(void) +{ + struct target_address *addrs; + struct target_param *param; + struct target_notify *notify; + + while ((addrs = SLIST_FIRST(&target_addresslist)) != NULL) { + SLIST_REMOVE_HEAD(&target_addresslist, ta); + if (addrs->status == RowStatus_active) + close(addrs->socket); + free(addrs); + } + SLIST_INIT(&target_addresslist); + + while ((param = SLIST_FIRST(&target_paramlist)) != NULL) { + SLIST_REMOVE_HEAD(&target_paramlist, tp); + free(param); + } + SLIST_INIT(&target_paramlist); + + while ((notify = SLIST_FIRST(&target_notifylist)) != NULL) { + SLIST_REMOVE_HEAD(&target_notifylist, tn); + free(notify); + } + SLIST_INIT(&target_notifylist); +} Property changes on: vendor/1.14/snmpd/trap.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmpd/tree.def =================================================================== --- vendor/1.14/snmpd/tree.def (nonexistent) +++ vendor/1.14/snmpd/tree.def (revision 359491) @@ -0,0 +1,233 @@ +# +# Copyright (c) 2001-2003 +# Fraunhofer Institute for Open Communication Systems (FhG Fokus). +# All rights reserved. +# +# Copyright (c) 2018 +# Hartmut Brandt. +# All rights reserved. +# +# Author: Harti Brandt +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $Begemot: tree.def 517 2006-10-31 08:52:04Z brandt_h $ +# +# System group and private Begemot SNMPd MIB. +# + +include "tc.def" + +typedef BegemotSnmpdTransportProto ENUM ( + 1 udp +) + +(1 internet + (2 mgmt + (1 mibII + (1 system +# +# The standard System group +# + (1 sysDescr OCTETSTRING op_system_group GET) + (2 sysObjectId OID op_system_group GET) + (3 sysUpTime TIMETICKS op_system_group GET) + (4 sysContact OCTETSTRING op_system_group GET SET) + (5 sysName OCTETSTRING op_system_group GET SET) + (6 sysLocation OCTETSTRING op_system_group GET SET) + (7 sysServices INTEGER op_system_group GET) + (8 sysORLastChange TIMETICKS op_system_group GET) + (9 sysORTable + (1 sysOREntry : INTEGER op_or_table + (1 sysORIndex INTEGER) + (2 sysORID OID GET) + (3 sysORDescr OCTETSTRING GET) + (4 sysORUpTime TIMETICKS GET) + )) + ) + (11 snmp + (1 snmpInPkts COUNTER op_snmp GET) + (3 snmpInBadVersions COUNTER op_snmp GET) + (4 snmpInBadCommunityNames COUNTER op_snmp GET) + (5 snmpInBadCommunityUses COUNTER op_snmp GET) + (6 snmpInASNParseErrs COUNTER op_snmp GET) + (30 snmpEnableAuthenTraps INTEGER op_snmp GET SET) + (31 snmpSilentDrops COUNTER op_snmp GET) + (32 snmpProxyDrops COUNTER op_snmp GET) + ) + )) + + (4 private + (1 enterprises +# +# FreeBSD stuff +# + (2238 freeBSD + (4 freeBSDVersion) + ) + +# +# Private Begemot Stuff +# + (12325 fokus + (1 begemot + +# +# Daemon infrastructure +# + (1 begemotSnmpd + (1 begemotSnmpdObjects + +# +# Configuration +# + (1 begemotSnmpdConfig + (1 begemotSnmpdTransmitBuffer INTEGER op_snmpd_config GET SET) + (2 begemotSnmpdReceiveBuffer INTEGER op_snmpd_config GET SET) + (3 begemotSnmpdCommunityDisable INTEGER op_snmpd_config GET SET) + (4 begemotSnmpdTrap1Addr IPADDRESS op_snmpd_config GET SET) + (5 begemotSnmpdVersionEnable UNSIGNED32 op_snmpd_config GET SET) + ) + (2 begemotTrapSinkTable + (1 begemotTrapSinkEntry : IPADDRESS INTEGER op_trapsink + (1 begemotTrapSinkAddr IPADDRESS) + (2 begemotTrapSinkPort INTEGER) + (3 begemotTrapSinkStatus INTEGER GET SET) + (4 begemotTrapSinkComm OCTETSTRING GET SET) + (5 begemotTrapSinkVersion INTEGER GET SET) + ) + ) +# +# Port table +# + (4 begemotSnmpdPortTable + (1 begemotSnmpdPortEntry : IPADDRESS INTEGER op_snmp_port + (1 begemotSnmpdPortAddress IPADDRESS) + (2 begemotSnmpdPortPort UNSIGNED32) + (3 begemotSnmpdPortStatus INTEGER GET SET) + )) +# +# Community table +# + (5 begemotSnmpdCommunityTable + (1 begemotSnmpdCommunityEntry : OCTETSTRING UNSIGNED32 op_community + (1 begemotSnmpdCommunityModule OCTETSTRING) + (2 begemotSnmpdCommunityIndex UNSIGNED32) + (3 begemotSnmpdCommunityString OCTETSTRING GET SET) + (4 begemotSnmpdCommunityDescr OCTETSTRING GET) + (5 begemotSnmpdCommunityPermission INTEGER GET SET) + )) +# +# Module table +# + (6 begemotSnmpdModuleTable + (1 begemotSnmpdModuleEntry : OCTETSTRING op_modules + (1 begemotSnmpdModuleSection OCTETSTRING) + (2 begemotSnmpdModulePath OCTETSTRING GET SET) + (3 begemotSnmpdModuleComment OCTETSTRING GET) + )) +# +# Statistics +# + (7 begemotSnmpdStats + (1 begemotSnmpdStatsNoRxBufs COUNTER op_snmpd_stats GET) + (2 begemotSnmpdStatsNoTxBufs COUNTER op_snmpd_stats GET) + (3 begemotSnmpdStatsInTooLongPkts COUNTER op_snmpd_stats GET) + (4 begemotSnmpdStatsInBadPduTypes COUNTER op_snmpd_stats GET)) +# +# Debugging +# + (8 begemotSnmpdDebug + (1 begemotSnmpdDebugDumpPdus INTEGER op_debug GET SET) + (2 begemotSnmpdDebugSnmpTrace UNSIGNED32 op_debug GET SET) + (3 begemotSnmpdDebugSyslogPri INTEGER op_debug GET SET)) + +# +# Local (UNIX domain) port table +# + (9 begemotSnmpdLocalPortTable + (1 begemotSnmpdLocalPortEntry : OCTETSTRING op_lsock_port + (1 begemotSnmpdLocalPortPath OCTETSTRING) + (2 begemotSnmpdLocalPortStatus INTEGER GET SET) + (3 begemotSnmpdLocalPortType INTEGER GET SET) + )) + + (10 begemotSnmpdTransportMappings + (1 begemotSnmpdTransportTable + (1 begemotSnmpdTransportEntry : OCTETSTRING op_transport_table + (1 begemotSnmpdTransportName OCTETSTRING) + (2 begemotSnmpdTransportStatus INTEGER GET) + (3 begemotSnmpdTransportOid OID GET) + )) + (2 begemotSnmpdTransUdp OID op_transport_dummy) + (3 begemotSnmpdTransLsock OID op_transport_dummy) + (4 begemotSnmpdTransInet OID op_transport_dummy) + ) + (11 begemotSnmpdTransInetTable + (1 begemotSnmpdTransInetEntry : INTEGER OCTETSTRING INTEGER INTEGER op_snmp_trans_inet + (1 begemotSnmpdTransInetAddressType InetAddressType) + (2 begemotSnmpdTransInetAddress OCTETSTRING) + (3 begemotSnmpdTransInetPort INTEGER) + (4 begemotSnmpdTransInetProto BegemotSnmpdTransportProto) + (5 begemotSnmpdTransInetStatus RowStatus GET SET) + + )) + ) + (2 begemotSnmpdDefs + (1 begemotSnmpdAgent + (1 begemotSnmpdAgentFreeBSD OID op_dummy) + ) + ) + (3 begemotSnmpdCompliance) + ) + )) + ) + ) + (6 snmpV2 + (3 snmpModules + (1 snmpMIB + (1 snmpMIBObjects + (4 snmpTrap + (1 snmpTrapOID OID op_snmp_trap) + ) + (5 snmpTraps + (1 coldStart OID op_snmp_trap) + (2 warmStart OID op_snmp_trap) + (5 authenticationFailure OID op_snmp_trap) + ) + (6 snmpSet + (1 snmpSetSerialNo INTEGER op_snmp_set GET SET) + ) + ) + ) + (10 snmpFrameworkMIB + (2 snmpFrameworkMIBObjects + (1 snmpEngine + (1 snmpEngineID OCTETSTRING | SnmpEngineID op_snmp_engine GET) + (2 snmpEngineBoots INTEGER op_snmp_engine GET) + (3 snmpEngineTime INTEGER op_snmp_engine GET) + (4 snmpEngineMaxMessageSize INTEGER op_snmp_engine GET) + ) + ) + ) + )) +) Property changes on: vendor/1.14/snmpd/tree.def ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmpd/BEGEMOT-MIB.txt =================================================================== --- vendor/1.14/snmpd/BEGEMOT-MIB.txt (nonexistent) +++ vendor/1.14/snmpd/BEGEMOT-MIB.txt (revision 359491) @@ -0,0 +1,62 @@ +-- +-- Copyright (c) 2001-2003 +-- Fraunhofer Institute for Open Communication Systems (FhG Fokus). +-- All rights reserved. +-- +-- Author: Harti Brandt +-- +-- Redistribution and use in source and binary forms, with or without +-- modification, are permitted provided that the following conditions +-- are met: +-- 1. Redistributions of source code must retain the above copyright +-- notice, this list of conditions and the following disclaimer. +-- 2. Redistributions in binary form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +-- ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +-- SUCH DAMAGE. +-- +-- $Begemot: bsnmp/snmpd/BEGEMOT-MIB.txt,v 1.5 2004/08/06 08:47:07 brandt Exp $ +-- +-- Begemot private definitions and root. +-- +BEGEMOT-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY + FROM SNMPv2-SMI + fokus + FROM FOKUS-MIB; + +begemot MODULE-IDENTITY + LAST-UPDATED "200201300000Z" + ORGANIZATION "Fraunhofer FOKUS, CATS" + CONTACT-INFO + " Hartmut Brandt + + Postal: Fraunhofer Institute for Open Communication Systems + Kaiserin-Augusta-Allee 31 + 10589 Berlin + Germany + + Fax: +49 30 3463 7352 + + E-mail: harti@freebsd.org" + DESCRIPTION + "The root of the Begemot subtree of the fokus tree." + REVISION "200201300000Z" + DESCRIPTION + "Initial revision." + ::= { fokus 1 } + +END Property changes on: vendor/1.14/snmpd/BEGEMOT-MIB.txt ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmpd/FOKUS-MIB.txt =================================================================== --- vendor/1.14/snmpd/FOKUS-MIB.txt (nonexistent) +++ vendor/1.14/snmpd/FOKUS-MIB.txt (revision 359491) @@ -0,0 +1,60 @@ +-- +-- Copyright (c) 2001-2003 +-- Fraunhofer Institute for Open Communication Systems (FhG Fokus). +-- All rights reserved. +-- +-- Author: Harti Brandt +-- +-- Redistribution and use in source and binary forms, with or without +-- modification, are permitted provided that the following conditions +-- are met: +-- 1. Redistributions of source code must retain the above copyright +-- notice, this list of conditions and the following disclaimer. +-- 2. Redistributions in binary form must reproduce the above copyright +-- notice, this list of conditions and the following disclaimer in the +-- documentation and/or other materials provided with the distribution. +-- +-- THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +-- ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +-- IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +-- ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +-- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +-- DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +-- OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +-- HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +-- LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +-- OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +-- SUCH DAMAGE. +-- +-- $Begemot: bsnmp/snmpd/FOKUS-MIB.txt,v 1.5 2004/08/06 08:47:08 brandt Exp $ +-- +-- Begemot private definitions and fokus root. +-- +FOKUS-MIB DEFINITIONS ::= BEGIN + +IMPORTS + MODULE-IDENTITY, enterprises + FROM SNMPv2-SMI; + +fokus MODULE-IDENTITY + LAST-UPDATED "200202050000Z" + ORGANIZATION "Fraunhofer FOKUS, CATS" + CONTACT-INFO + " Hartmut Brandt + + Postal: Fraunhofer Institute for Open Communication Systems + Kaiserin-Augusta-Allee 31 + 10589 Berlin + Germany + + Fax: +49 30 3463 7352 + + E-mail: harti@freebsd.org" + DESCRIPTION + "The root of the Fokus enterprises tree." + REVISION "200202050000Z" + DESCRIPTION + "Initial revision." + ::= { enterprises 12325 } + +END Property changes on: vendor/1.14/snmpd/FOKUS-MIB.txt ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmpd/action.c =================================================================== --- vendor/1.14/snmpd/action.c (nonexistent) +++ vendor/1.14/snmpd/action.c (revision 359491) @@ -0,0 +1,1270 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * Copyright (c) 2004-2006 + * Hartmut Brandt. + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: action.c 517 2006-10-31 08:52:04Z brandt_h $ + * + * Variable access for SNMPd + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "snmpmod.h" +#include "snmpd.h" +#include "tree.h" +#include "oid.h" + +static const struct asn_oid + oid_begemotSnmpdModuleTable = OIDX_begemotSnmpdModuleTable; + +#ifdef __FreeBSD__ +static const struct asn_oid + oid_freeBSDVersion = OIDX_freeBSDVersion; +#endif + +/* + * Get an integer value from the KERN sysctl subtree. + */ +static char * +act_getkernint(int id) +{ + int mib[2]; + size_t len; + u_long value; + char *string; + + mib[0] = CTL_KERN; + mib[1] = id; + len = sizeof(value); + if (sysctl(mib, 2, &value, &len, NULL, 0) != 0) + return (NULL); + + if ((string = malloc(20)) == NULL) + return (NULL); + sprintf(string, "%lu", value); + return (string); +} + +/* + * Initialize global variables of the system group. + */ +int +init_actvals(void) +{ + struct utsname uts; + char *hostid; + size_t len; +#ifdef __FreeBSD__ + char *rel, *p, *end; + u_long num; +#endif + + if (uname(&uts) == -1) + return (-1); + + if ((systemg.name = strdup(uts.nodename)) == NULL) + return (-1); + + if ((hostid = act_getkernint(KERN_HOSTID)) == NULL) + return (-1); + + len = strlen(uts.nodename) + 1; + len += strlen(hostid) + 1; + len += strlen(uts.sysname) + 1; + len += strlen(uts.release) + 1; + + if ((systemg.descr = malloc(len)) == NULL) { + free(hostid); + return (-1); + } + sprintf(systemg.descr, "%s %s %s %s", uts.nodename, hostid, uts.sysname, + uts.release); + +#ifdef __FreeBSD__ + /* + * Construct a FreeBSD oid + */ + systemg.object_id = oid_freeBSDVersion; + rel = uts.release; + while ((p = strsep(&rel, ".")) != NULL && + systemg.object_id.len < ASN_MAXOIDLEN) { + systemg.object_id.subs[systemg.object_id.len] = 0; + if (*p != '\0') { + num = strtoul(p, &end, 10); + if (end == p) + break; + systemg.object_id.subs[systemg.object_id.len] = num; + } + systemg.object_id.len++; + } +#endif + + free(hostid); + + return (0); +} + +/* + * Initialize global variables of the snmpEngine group. + */ +int +init_snmpd_engine(void) +{ + char *hostid; + + snmpd_engine.engine_boots = 1; + snmpd_engine.engine_time = 1; + snmpd_engine.max_msg_size = 1500; /* XXX */ + + snmpd_engine.engine_id[0] = ((OID_freeBSD & 0xff000000) >> 24) | 0x80; + snmpd_engine.engine_id[1] = (OID_freeBSD & 0xff0000) >> 16; + snmpd_engine.engine_id[2] = (OID_freeBSD & 0xff00) >> 8; + snmpd_engine.engine_id[3] = OID_freeBSD & 0xff; + snmpd_engine.engine_id[4] = 128; + snmpd_engine.engine_len = 5; + + if ((hostid = act_getkernint(KERN_HOSTID)) == NULL) + return (-1); + + if (strlen(hostid) > SNMP_ENGINE_ID_SIZ - snmpd_engine.engine_len) { + memcpy(snmpd_engine.engine_id + snmpd_engine.engine_len, + hostid, SNMP_ENGINE_ID_SIZ - snmpd_engine.engine_len); + snmpd_engine.engine_len = SNMP_ENGINE_ID_SIZ; + } else { + memcpy(snmpd_engine.engine_id + snmpd_engine.engine_len, + hostid, strlen(hostid)); + snmpd_engine.engine_len += strlen(hostid); + } + + free(hostid); + + return (0); +} + +int +set_snmpd_engine(void) +{ + FILE *fp; + uint32_t i; + uint8_t *cptr, engine[2 * SNMP_ENGINE_ID_SIZ + 2]; + uint8_t myengine[2 * SNMP_ENGINE_ID_SIZ + 2]; + + if (engine_file[0] == '\0') + return (-1); + + cptr = myengine; + for (i = 0; i < snmpd_engine.engine_len; i++) + cptr += sprintf(cptr, "%.2x", snmpd_engine.engine_id[i]); + *cptr++ = '\n'; + *cptr++ = '\0'; + + if ((fp = fopen(engine_file, "r+")) != NULL) { + if (fgets(engine, sizeof(engine) - 1, fp) == NULL || + fscanf(fp, "%u", &snmpd_engine.engine_boots) <= 0) { + fclose(fp); + goto save_boots; + } + + fclose(fp); + if (strcmp(myengine, engine) != 0) + snmpd_engine.engine_boots = 1; + else + snmpd_engine.engine_boots++; + } else if (errno != ENOENT) + return (-1); + +save_boots: + if ((fp = fopen(engine_file, "w+")) == NULL) + return (-1); + fprintf(fp, "%s%u\n", myengine, snmpd_engine.engine_boots); + fclose(fp); + + return (0); +} + +void +update_snmpd_engine_time(void) +{ + uint64_t etime; + + etime = (get_ticks() - start_tick) / 100ULL; + if (etime < INT32_MAX) + snmpd_engine.engine_time = etime; + else { + start_tick = get_ticks(); + (void)set_snmpd_engine(); + snmpd_engine.engine_time = start_tick; + } +} + +/************************************************************* + * + * System group + */ +int +op_system_group(struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + asn_subid_t which = value->var.subs[sub - 1]; + + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + break; + + case SNMP_OP_SET: + switch (which) { + + case LEAF_sysDescr: + if (community != COMM_INITIALIZE) + return (SNMP_ERR_NOT_WRITEABLE); + return (string_save(value, ctx, -1, &systemg.descr)); + + case LEAF_sysObjectId: + if (community != COMM_INITIALIZE) + return (SNMP_ERR_NOT_WRITEABLE); + return (oid_save(value, ctx, &systemg.object_id)); + + case LEAF_sysContact: + return (string_save(value, ctx, -1, &systemg.contact)); + + case LEAF_sysName: + return (string_save(value, ctx, -1, &systemg.name)); + + case LEAF_sysLocation: + return (string_save(value, ctx, -1, &systemg.location)); + } + return (SNMP_ERR_NO_CREATION); + + case SNMP_OP_ROLLBACK: + switch (which) { + + case LEAF_sysDescr: + string_rollback(ctx, &systemg.descr); + return (SNMP_ERR_NOERROR); + case LEAF_sysObjectId: + oid_rollback(ctx, &systemg.object_id); + return (SNMP_ERR_NOERROR); + case LEAF_sysContact: + string_rollback(ctx, &systemg.contact); + return (SNMP_ERR_NOERROR); + case LEAF_sysName: + string_rollback(ctx, &systemg.name); + return (SNMP_ERR_NOERROR); + case LEAF_sysLocation: + string_rollback(ctx, &systemg.location); + return (SNMP_ERR_NOERROR); + } + abort(); + + case SNMP_OP_COMMIT: + switch (which) { + + case LEAF_sysDescr: + string_commit(ctx); + return (SNMP_ERR_NOERROR); + case LEAF_sysObjectId: + oid_commit(ctx); + return (SNMP_ERR_NOERROR); + case LEAF_sysContact: + string_commit(ctx); + return (SNMP_ERR_NOERROR); + case LEAF_sysName: + string_commit(ctx); + return (SNMP_ERR_NOERROR); + case LEAF_sysLocation: + string_commit(ctx); + return (SNMP_ERR_NOERROR); + } + abort(); + } + + /* + * Come here for GET. + */ + switch (which) { + + case LEAF_sysDescr: + return (string_get(value, systemg.descr, -1)); + case LEAF_sysObjectId: + return (oid_get(value, &systemg.object_id)); + case LEAF_sysUpTime: + value->v.uint32 = get_ticks() - start_tick; + break; + case LEAF_sysContact: + return (string_get(value, systemg.contact, -1)); + case LEAF_sysName: + return (string_get(value, systemg.name, -1)); + case LEAF_sysLocation: + return (string_get(value, systemg.location, -1)); + case LEAF_sysServices: + value->v.integer = systemg.services; + break; + case LEAF_sysORLastChange: + value->v.uint32 = systemg.or_last_change; + break; + } + return (SNMP_ERR_NOERROR); +} + +/************************************************************* + * + * Debug group + */ +int +op_debug(struct snmp_context *ctx, struct snmp_value *value, u_int sub, + u_int iidx __unused, enum snmp_op op) +{ + asn_subid_t which = value->var.subs[sub - 1]; + + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + switch (which) { + + case LEAF_begemotSnmpdDebugDumpPdus: + value->v.integer = TRUTH_MK(debug.dump_pdus); + break; + + case LEAF_begemotSnmpdDebugSnmpTrace: + value->v.uint32 = snmp_trace; + break; + + case LEAF_begemotSnmpdDebugSyslogPri: + value->v.integer = debug.logpri; + break; + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_SET: + switch (which) { + + case LEAF_begemotSnmpdDebugDumpPdus: + if (!TRUTH_OK(value->v.integer)) + return (SNMP_ERR_WRONG_VALUE); + ctx->scratch->int1 = debug.dump_pdus; + debug.dump_pdus = TRUTH_GET(value->v.integer); + return (SNMP_ERR_NOERROR); + + case LEAF_begemotSnmpdDebugSnmpTrace: + ctx->scratch->int1 = snmp_trace; + snmp_trace = value->v.uint32; + return (SNMP_ERR_NOERROR); + + case LEAF_begemotSnmpdDebugSyslogPri: + if (value->v.integer < 0 || value->v.integer > 8) + return (SNMP_ERR_WRONG_VALUE); + ctx->scratch->int1 = debug.logpri; + debug.logpri = (u_int)value->v.integer; + return (SNMP_ERR_NOERROR); + } + return (SNMP_ERR_NO_CREATION); + + case SNMP_OP_ROLLBACK: + switch (which) { + + case LEAF_begemotSnmpdDebugDumpPdus: + debug.dump_pdus = ctx->scratch->int1; + return (SNMP_ERR_NOERROR); + + case LEAF_begemotSnmpdDebugSnmpTrace: + snmp_trace = ctx->scratch->int1; + return (SNMP_ERR_NOERROR); + + case LEAF_begemotSnmpdDebugSyslogPri: + debug.logpri = ctx->scratch->int1; + return (SNMP_ERR_NOERROR); + } + abort(); + + case SNMP_OP_COMMIT: + switch (which) { + + case LEAF_begemotSnmpdDebugDumpPdus: + case LEAF_begemotSnmpdDebugSnmpTrace: + return (SNMP_ERR_NOERROR); + + case LEAF_begemotSnmpdDebugSyslogPri: + if (debug.logpri == 0) + setlogmask(0); + else + setlogmask(LOG_UPTO(debug.logpri - 1)); + return (SNMP_ERR_NOERROR); + } + abort(); + } + abort(); +} + +/************************************************************* + * + * OR Table + */ +int +op_or_table(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + struct objres *objres; + + switch (op) { + + case SNMP_OP_GETNEXT: + if ((objres = NEXT_OBJECT_INT(&objres_list, &value->var, sub)) + == NULL) + return (SNMP_ERR_NOSUCHNAME); + value->var.subs[sub] = objres->index; + value->var.len = sub + 1; + break; + + case SNMP_OP_GET: + if ((objres = FIND_OBJECT_INT(&objres_list, &value->var, sub)) + == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + if ((objres = FIND_OBJECT_INT(&objres_list, &value->var, sub)) + == NULL) + return (SNMP_ERR_NO_CREATION); + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + default: + abort(); + } + + /* + * Come here for GET, GETNEXT. + */ + switch (value->var.subs[sub - 1]) { + + case LEAF_sysORID: + value->v.oid = objres->oid; + break; + + case LEAF_sysORDescr: + return (string_get(value, objres->descr, -1)); + + case LEAF_sysORUpTime: + value->v.uint32 = objres->uptime; + break; + } + return (SNMP_ERR_NOERROR); +} + +/************************************************************* + * + * mib-2 snmp + */ +int +op_snmp(struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + switch (value->var.subs[sub - 1]) { + + case LEAF_snmpInPkts: + value->v.uint32 = snmpd_stats.inPkts; + break; + + case LEAF_snmpInBadVersions: + value->v.uint32 = snmpd_stats.inBadVersions; + break; + + case LEAF_snmpInBadCommunityNames: + value->v.uint32 = snmpd_stats.inBadCommunityNames; + break; + + case LEAF_snmpInBadCommunityUses: + value->v.uint32 = snmpd_stats.inBadCommunityUses; + break; + + case LEAF_snmpInASNParseErrs: + value->v.uint32 = snmpd_stats.inASNParseErrs; + break; + + case LEAF_snmpEnableAuthenTraps: + value->v.integer = TRUTH_MK(snmpd.auth_traps); + break; + + case LEAF_snmpSilentDrops: + value->v.uint32 = snmpd_stats.silentDrops; + break; + + case LEAF_snmpProxyDrops: + value->v.uint32 = snmpd_stats.proxyDrops; + break; + + default: + return (SNMP_ERR_NOSUCHNAME); + + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_SET: + switch (value->var.subs[sub - 1]) { + case LEAF_snmpEnableAuthenTraps: + if (!TRUTH_OK(value->v.integer)) + return (SNMP_ERR_WRONG_VALUE); + ctx->scratch->int1 = value->v.integer; + snmpd.auth_traps = TRUTH_GET(value->v.integer); + return (SNMP_ERR_NOERROR); + } + abort(); + + case SNMP_OP_ROLLBACK: + switch (value->var.subs[sub - 1]) { + case LEAF_snmpEnableAuthenTraps: + snmpd.auth_traps = ctx->scratch->int1; + return (SNMP_ERR_NOERROR); + } + abort(); + + case SNMP_OP_COMMIT: + switch (value->var.subs[sub - 1]) { + case LEAF_snmpEnableAuthenTraps: + return (SNMP_ERR_NOERROR); + } + abort(); + } + abort(); +} + +/************************************************************* + * + * SNMPd statistics group + */ +int +op_snmpd_stats(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + switch (op) { + + case SNMP_OP_GET: + switch (value->var.subs[sub - 1]) { + + case LEAF_begemotSnmpdStatsNoRxBufs: + value->v.uint32 = snmpd_stats.noRxbuf; + break; + + case LEAF_begemotSnmpdStatsNoTxBufs: + value->v.uint32 = snmpd_stats.noTxbuf; + break; + + case LEAF_begemotSnmpdStatsInTooLongPkts: + value->v.uint32 = snmpd_stats.inTooLong; + break; + + case LEAF_begemotSnmpdStatsInBadPduTypes: + value->v.uint32 = snmpd_stats.inBadPduTypes; + break; + + default: + return (SNMP_ERR_NOSUCHNAME); + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_SET: + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + case SNMP_OP_GETNEXT: + abort(); + } + abort(); +} + +/* + * SNMPd configuration scalars + */ +int +op_snmpd_config(struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + asn_subid_t which = value->var.subs[sub - 1]; + + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + switch (which) { + + case LEAF_begemotSnmpdTransmitBuffer: + value->v.integer = snmpd.txbuf; + break; + case LEAF_begemotSnmpdReceiveBuffer: + value->v.integer = snmpd.rxbuf; + break; + case LEAF_begemotSnmpdCommunityDisable: + value->v.integer = TRUTH_MK(snmpd.comm_dis); + break; + case LEAF_begemotSnmpdTrap1Addr: + return (ip_get(value, snmpd.trap1addr)); + case LEAF_begemotSnmpdVersionEnable: + value->v.uint32 = snmpd.version_enable; + break; + default: + return (SNMP_ERR_NOSUCHNAME); + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_SET: + switch (which) { + + case LEAF_begemotSnmpdTransmitBuffer: + ctx->scratch->int1 = snmpd.txbuf; + if (value->v.integer < 484 || + value->v.integer > 65535) + return (SNMP_ERR_WRONG_VALUE); + snmpd.txbuf = value->v.integer; + return (SNMP_ERR_NOERROR); + + case LEAF_begemotSnmpdReceiveBuffer: + ctx->scratch->int1 = snmpd.rxbuf; + if (value->v.integer < 484 || + value->v.integer > 65535) + return (SNMP_ERR_WRONG_VALUE); + snmpd.rxbuf = value->v.integer; + return (SNMP_ERR_NOERROR); + + case LEAF_begemotSnmpdCommunityDisable: + ctx->scratch->int1 = snmpd.comm_dis; + if (!TRUTH_OK(value->v.integer)) + return (SNMP_ERR_WRONG_VALUE); + if (TRUTH_GET(value->v.integer)) { + snmpd.comm_dis = 1; + } else { + if (snmpd.comm_dis) + return (SNMP_ERR_WRONG_VALUE); + } + return (SNMP_ERR_NOERROR); + + case LEAF_begemotSnmpdTrap1Addr: + return (ip_save(value, ctx, snmpd.trap1addr)); + + case LEAF_begemotSnmpdVersionEnable: + if (community != COMM_INITIALIZE) + return (SNMP_ERR_NOT_WRITEABLE); + ctx->scratch->int1 = snmpd.version_enable; + if (value->v.uint32 == 0 || + (value->v.uint32 & ~VERS_ENABLE_ALL)) + return (SNMP_ERR_WRONG_VALUE); + snmpd.version_enable = value->v.uint32; + return (SNMP_ERR_NOERROR); + } + abort(); + + case SNMP_OP_ROLLBACK: + switch (which) { + + case LEAF_begemotSnmpdTransmitBuffer: + snmpd.rxbuf = ctx->scratch->int1; + return (SNMP_ERR_NOERROR); + case LEAF_begemotSnmpdReceiveBuffer: + snmpd.txbuf = ctx->scratch->int1; + return (SNMP_ERR_NOERROR); + case LEAF_begemotSnmpdCommunityDisable: + snmpd.comm_dis = ctx->scratch->int1; + return (SNMP_ERR_NOERROR); + case LEAF_begemotSnmpdTrap1Addr: + ip_rollback(ctx, snmpd.trap1addr); + return (SNMP_ERR_NOERROR); + case LEAF_begemotSnmpdVersionEnable: + snmpd.version_enable = ctx->scratch->int1; + return (SNMP_ERR_NOERROR); + } + abort(); + + case SNMP_OP_COMMIT: + switch (which) { + + case LEAF_begemotSnmpdTransmitBuffer: + case LEAF_begemotSnmpdReceiveBuffer: + case LEAF_begemotSnmpdCommunityDisable: + return (SNMP_ERR_NOERROR); + case LEAF_begemotSnmpdTrap1Addr: + ip_commit(ctx); + return (SNMP_ERR_NOERROR); + case LEAF_begemotSnmpdVersionEnable: + return (SNMP_ERR_NOERROR); + } + abort(); + } + abort(); +} + +/* + * The community table + */ +int +op_community(struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + struct asn_oid idx; + struct community *c; + asn_subid_t which = value->var.subs[sub - 1]; + + switch (op) { + + case SNMP_OP_GETNEXT: + if ((community != COMM_INITIALIZE && snmpd.comm_dis) || + (c = NEXT_OBJECT_OID(&community_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + index_append(&value->var, sub, &c->index); + break; + + case SNMP_OP_GET: + if ((community != COMM_INITIALIZE && snmpd.comm_dis) || + (c = FIND_OBJECT_OID(&community_list, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + if (community != COMM_INITIALIZE && snmpd.comm_dis) + return (SNMP_ERR_NOT_WRITEABLE); + idx.len = 2; + idx.subs[0] = 0; + idx.subs[1] = value->var.subs[value->var.len - 1]; + switch (which) { + case LEAF_begemotSnmpdCommunityString: + /* check that given string is unique */ + TAILQ_FOREACH(c, &community_list, link) { + if (!asn_compare_oid(&idx, &c->index)) + continue; + if (c->string != NULL && strcmp(c->string, + value->v.octetstring.octets) == 0) + return (SNMP_ERR_WRONG_VALUE); + } + case LEAF_begemotSnmpdCommunityPermission: + break; + default: + return (SNMP_ERR_NOT_WRITEABLE); + } + if ((c = FIND_OBJECT_OID(&community_list, &value->var, + sub)) == NULL) { + /* create new community and use user sepcified index */ + c = comm_define_ordered(COMM_READ, "SNMP Custom Community", + &idx, NULL, NULL); + if (c == NULL) + return (SNMP_ERR_NO_CREATION); + } + switch (which) { + case LEAF_begemotSnmpdCommunityString: + return (string_save(value, ctx, -1, &c->string)); + case LEAF_begemotSnmpdCommunityPermission: + if (value->v.integer != COMM_READ && + value->v.integer != COMM_WRITE) + return (SNMP_ERR_WRONG_VALUE); + c->private = value->v.integer; + break; + default: + return (SNMP_ERR_NOT_WRITEABLE); + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_ROLLBACK: + if (which == LEAF_begemotSnmpdCommunityString) { + if ((c = FIND_OBJECT_OID(&community_list, &value->var, + sub)) == NULL) + string_free(ctx); + else + string_rollback(ctx, &c->string); + return (SNMP_ERR_NOERROR); + } + if (which == LEAF_begemotSnmpdCommunityPermission) + return (SNMP_ERR_NOERROR); + abort(); + + case SNMP_OP_COMMIT: + if (which == LEAF_begemotSnmpdCommunityString) { + if ((c = FIND_OBJECT_OID(&community_list, &value->var, + sub)) == NULL) + string_free(ctx); + else + string_commit(ctx); + return (SNMP_ERR_NOERROR); + } + if (which == LEAF_begemotSnmpdCommunityPermission) + return (SNMP_ERR_NOERROR); + abort(); + + default: + abort(); + } + + switch (which) { + + case LEAF_begemotSnmpdCommunityString: + return (string_get(value, c->string, -1)); + + case LEAF_begemotSnmpdCommunityDescr: + return (string_get(value, c->descr, -1)); + + case LEAF_begemotSnmpdCommunityPermission: + value->v.integer = c->private; + return (SNMP_ERR_NOERROR); + default: + return (SNMP_ERR_NOT_WRITEABLE); + } + abort(); +} + +/* + * Module table. + */ +struct module_dep { + struct snmp_dependency dep; + u_char section[LM_SECTION_MAX + 1]; + u_char *path; + struct lmodule *m; +}; + +static int +dep_modules(struct snmp_context *ctx, struct snmp_dependency *dep, + enum snmp_depop op) +{ + struct module_dep *mdep = (struct module_dep *)(void *)dep; + + switch (op) { + + case SNMP_DEPOP_COMMIT: + if (mdep->path == NULL) { + /* unload - find the module */ + TAILQ_FOREACH(mdep->m, &lmodules, link) + if (strcmp(mdep->m->section, + mdep->section) == 0) + break; + if (mdep->m == NULL) + /* no such module - that's ok */ + return (SNMP_ERR_NOERROR); + + /* handle unloading in the finalizer */ + return (SNMP_ERR_NOERROR); + } + /* load */ + if ((mdep->m = lm_load(mdep->path, mdep->section)) == NULL) { + /* could not load */ + return (SNMP_ERR_RES_UNAVAIL); + } + /* start in finalizer */ + return (SNMP_ERR_NOERROR); + + case SNMP_DEPOP_ROLLBACK: + if (mdep->path == NULL) { + /* rollback unload - the finalizer takes care */ + return (SNMP_ERR_NOERROR); + } + /* rollback load */ + lm_unload(mdep->m); + return (SNMP_ERR_NOERROR); + + case SNMP_DEPOP_FINISH: + if (mdep->path == NULL) { + if (mdep->m != NULL && ctx->code == SNMP_RET_OK) + lm_unload(mdep->m); + } else { + if (mdep->m != NULL && ctx->code == SNMP_RET_OK && + community != COMM_INITIALIZE) + lm_start(mdep->m); + free(mdep->path); + } + return (SNMP_ERR_NOERROR); + } + abort(); +} + +int +op_modules(struct snmp_context *ctx, struct snmp_value *value, + u_int sub, u_int iidx, enum snmp_op op) +{ + asn_subid_t which = value->var.subs[sub - 1]; + struct lmodule *m; + u_char *section, *ptr; + size_t seclen; + struct module_dep *mdep; + struct asn_oid idx; + + switch (op) { + + case SNMP_OP_GETNEXT: + if ((m = NEXT_OBJECT_OID(&lmodules, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + index_append(&value->var, sub, &m->index); + break; + + case SNMP_OP_GET: + if ((m = FIND_OBJECT_OID(&lmodules, &value->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + m = FIND_OBJECT_OID(&lmodules, &value->var, sub); + if (which != LEAF_begemotSnmpdModulePath) { + if (m == NULL) + return (SNMP_ERR_NO_CREATION); + return (SNMP_ERR_NOT_WRITEABLE); + } + + /* the errors in the next few statements can only happen when + * m is NULL, hence the NO_CREATION error. */ + if (index_decode(&value->var, sub, iidx, + §ion, &seclen)) + return (SNMP_ERR_NO_CREATION); + + /* check the section name */ + if (seclen > LM_SECTION_MAX || seclen == 0) { + free(section); + return (SNMP_ERR_NO_CREATION); + } + for (ptr = section; ptr < section + seclen; ptr++) + if (!isascii(*ptr) || !isalnum(*ptr)) { + free(section); + return (SNMP_ERR_NO_CREATION); + } + if (!isalpha(section[0])) { + free(section); + return (SNMP_ERR_NO_CREATION); + } + + /* check the path */ + for (ptr = value->v.octetstring.octets; + ptr < value->v.octetstring.octets + value->v.octetstring.len; + ptr++) { + if (*ptr == '\0') { + free(section); + return (SNMP_ERR_WRONG_VALUE); + } + } + + if (m == NULL) { + if (value->v.octetstring.len == 0) { + free(section); + return (SNMP_ERR_INCONS_VALUE); + } + } else { + if (value->v.octetstring.len != 0) { + free(section); + return (SNMP_ERR_INCONS_VALUE); + } + } + + asn_slice_oid(&idx, &value->var, sub, value->var.len); + + /* so far, so good */ + mdep = (struct module_dep *)(void *)snmp_dep_lookup(ctx, + &oid_begemotSnmpdModuleTable, &idx, + sizeof(*mdep), dep_modules); + if (mdep == NULL) { + free(section); + return (SNMP_ERR_RES_UNAVAIL); + } + + if (mdep->section[0] != '\0') { + /* two writes to the same entry - bad */ + free(section); + return (SNMP_ERR_INCONS_VALUE); + } + + strncpy(mdep->section, section, seclen); + mdep->section[seclen] = '\0'; + free(section); + + if (value->v.octetstring.len == 0) + mdep->path = NULL; + else { + if ((mdep->path = malloc(value->v.octetstring.len + 1)) == NULL) + return (SNMP_ERR_RES_UNAVAIL); + strncpy(mdep->path, value->v.octetstring.octets, + value->v.octetstring.len); + mdep->path[value->v.octetstring.len] = '\0'; + } + ctx->scratch->ptr1 = mdep; + return (SNMP_ERR_NOERROR); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + return (SNMP_ERR_NOERROR); + + default: + abort(); + } + + switch (which) { + + case LEAF_begemotSnmpdModulePath: + return (string_get(value, m->path, -1)); + + case LEAF_begemotSnmpdModuleComment: + return (string_get(value, m->config->comment, -1)); + } + abort(); +} + +int +op_snmp_set(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + switch (op) { + + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + switch (value->var.subs[sub - 1]) { + + case LEAF_snmpSetSerialNo: + value->v.integer = snmp_serial_no; + break; + + default: + abort(); + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_SET: + switch (value->var.subs[sub - 1]) { + + case LEAF_snmpSetSerialNo: + if (value->v.integer != snmp_serial_no) + return (SNMP_ERR_INCONS_VALUE); + break; + + default: + abort(); + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_ROLLBACK: + return (SNMP_ERR_NOERROR); + + case SNMP_OP_COMMIT: + if (snmp_serial_no++ == 2147483647) + snmp_serial_no = 0; + return (SNMP_ERR_NOERROR); + } + abort(); +} + +/* + * SNMP Engine + */ +int +op_snmp_engine(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx __unused, enum snmp_op op) +{ + asn_subid_t which = value->var.subs[sub - 1]; + + switch (op) { + case SNMP_OP_GETNEXT: + abort(); + + case SNMP_OP_GET: + break; + + case SNMP_OP_SET: + if (community != COMM_INITIALIZE) + return (SNMP_ERR_NOT_WRITEABLE); + switch (which) { + case LEAF_snmpEngineID: + if (value->v.octetstring.len > SNMP_ENGINE_ID_SIZ) + return (SNMP_ERR_WRONG_VALUE); + ctx->scratch->ptr1 = malloc(snmpd_engine.engine_len); + if (ctx->scratch->ptr1 == NULL) + return (SNMP_ERR_GENERR); + memcpy(ctx->scratch->ptr1, snmpd_engine.engine_id, + snmpd_engine.engine_len); + ctx->scratch->int1 = snmpd_engine.engine_len; + snmpd_engine.engine_len = value->v.octetstring.len; + memcpy(snmpd_engine.engine_id, + value->v.octetstring.octets, + value->v.octetstring.len); + break; + + case LEAF_snmpEngineMaxMessageSize: + ctx->scratch->int1 = snmpd_engine.max_msg_size; + snmpd_engine.max_msg_size = value->v.integer; + break; + + default: + return (SNMP_ERR_NOT_WRITEABLE); + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_ROLLBACK: + switch (which) { + case LEAF_snmpEngineID: + snmpd_engine.engine_len = ctx->scratch->int1; + memcpy(snmpd_engine.engine_id, ctx->scratch->ptr1, + snmpd_engine.engine_len); + free(ctx->scratch->ptr1); + break; + + case LEAF_snmpEngineMaxMessageSize: + snmpd_engine.max_msg_size = ctx->scratch->int1; + break; + + default: + abort(); + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_COMMIT: + if (which == LEAF_snmpEngineID) { + if (set_snmpd_engine() < 0) { + snmpd_engine.engine_len = ctx->scratch->int1; + memcpy(snmpd_engine.engine_id, + ctx->scratch->ptr1, ctx->scratch->int1); + } + free(ctx->scratch->ptr1); + } + return (SNMP_ERR_NOERROR); + } + + + switch (which) { + case LEAF_snmpEngineID: + return (string_get(value, snmpd_engine.engine_id, + snmpd_engine.engine_len)); + case LEAF_snmpEngineBoots: + value->v.integer = snmpd_engine.engine_boots; + break; + case LEAF_snmpEngineTime: + update_snmpd_engine_time(); + value->v.integer = snmpd_engine.engine_time; + break; + case LEAF_snmpEngineMaxMessageSize: + value->v.integer = snmpd_engine.max_msg_size; + break; + default: + return (SNMP_ERR_NOSUCHNAME); + } + + return (SNMP_ERR_NOERROR); +} + +/* + * Transport table + */ +int +op_transport_table(struct snmp_context *ctx __unused, struct snmp_value *value, + u_int sub, u_int iidx, enum snmp_op op) +{ + asn_subid_t which = value->var.subs[sub - 1]; + struct transport *t; + u_char *tname, *ptr; + size_t tnamelen; + + switch (op) { + + case SNMP_OP_GETNEXT: + if ((t = NEXT_OBJECT_OID(&transport_list, &value->var, sub)) + == NULL) + return (SNMP_ERR_NOSUCHNAME); + index_append(&value->var, sub, &t->index); + break; + + case SNMP_OP_GET: + if ((t = FIND_OBJECT_OID(&transport_list, &value->var, sub)) + == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_SET: + t = FIND_OBJECT_OID(&transport_list, &value->var, sub); + if (which != LEAF_begemotSnmpdTransportStatus) { + if (t == NULL) + return (SNMP_ERR_NO_CREATION); + return (SNMP_ERR_NOT_WRITEABLE); + } + + /* the errors in the next few statements can only happen when + * t is NULL, hence the NO_CREATION error. */ + if (index_decode(&value->var, sub, iidx, + &tname, &tnamelen)) + return (SNMP_ERR_NO_CREATION); + + /* check the section name */ + if (tnamelen >= TRANS_NAMELEN || tnamelen == 0) { + free(tname); + return (SNMP_ERR_NO_CREATION); + } + for (ptr = tname; ptr < tname + tnamelen; ptr++) { + if (!isascii(*ptr) || !isalnum(*ptr)) { + free(tname); + return (SNMP_ERR_NO_CREATION); + } + } + + /* for now */ + return (SNMP_ERR_NOT_WRITEABLE); + + case SNMP_OP_ROLLBACK: + case SNMP_OP_COMMIT: + return (SNMP_ERR_NOERROR); + default: + abort(); + } + + switch (which) { + + case LEAF_begemotSnmpdTransportStatus: + value->v.integer = 1; + break; + + case LEAF_begemotSnmpdTransportOid: + memcpy(&value->v.oid, &t->vtab->id, sizeof(t->vtab->id)); + break; + } + return (SNMP_ERR_NOERROR); +} Property changes on: vendor/1.14/snmpd/action.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmpd/bsnmpd.1 =================================================================== --- vendor/1.14/snmpd/bsnmpd.1 (nonexistent) +++ vendor/1.14/snmpd/bsnmpd.1 (revision 359491) @@ -0,0 +1,280 @@ +.\" +.\" Copyright (c) 2004-2005 +.\" Hartmut Brandt. +.\" All rights reserved. +.\" Copyright (c) 2001-2003 +.\" Fraunhofer Institute for Open Communication Systems (FhG Fokus). +.\" All rights reserved. +.\" +.\" Author: Harti Brandt +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Begemot: bsnmp/snmpd/bsnmpd.1,v 1.12 2006/02/27 09:50:03 brandt_h Exp $ +.\" +.Dd May 14, 2016 +.Dt BSNMPD 1 +.Os +.Sh NAME +.Nm bsnmpd +.Nd "simple and extensible SNMP daemon" +.Sh SYNOPSIS +.Nm +.Op Fl dh +.Op Fl c Ar file +.Op Fl D Ar options +.Op Fl e Ar file +.Op Fl I Ar paths +.Op Fl l Ar prefix +.Op Fl m Ar variable Ns Op = Ns Ar value +.Op Fl p Ar file +.Sh DESCRIPTION +The +.Nm +daemon serves the internet SNMP (Simple Network Management Protocol). +It is intended to serve only the absolute basic MIBs and implement all other +MIBs through loadable modules. +In this way the +.Nm +can be used in unexpected ways. +.Pp +The options are as follows: +.Bl -tag -width ".It Fl D Ar options" +.It Fl d +Do not daemonize. +Used for debugging. +.It Fl h +Print a short usage message. +.It Fl c Ar file +Use +.Ar file +as configuration file instead of the standard one. +.It Fl D Ar options +Debugging options are specified with a +.Fl o +flag followed by a comma separated string of options. +The following options are available. +.Bl -tag -width ".It Cm trace Ns Cm = Ns Cm level" +.It Cm dump +Dump all sent and received PDUs to the terminal. +.It Cm events +Set the debugging level of the event library (see +.Xr eventlib 3 ) +to 10. +.It Cm trace Ns Cm = Ns Cm level +Set the snmp library trace flag to the specified +value. +.El +The value can be specified in the usual C-syntax for numbers. +.It Fl e Ar file +Specify an alternate file where the agent's engine id and number of boots +are saved. +.It Fl I Ar paths +Specify a colon separated list of directories to search for configuration +include files. +The default is +.Pa /etc:/usr/etc/:/usr/local/etc . +These paths are only searched for include specified within <> parentheses. +.It Fl l Ar prefix +Use +.Ar prefix +as the default basename for the pid and the configuration files. +.It Fl m Ar variable Ns Op = Ns Ar value +Define a configuration variable. +.It Fl p Ar file +Specify an alternate pid file instead of the default one. +.El +.Sh CONFIGURATION +.Nm +reads its configuration from either the default or the user specified +configuration file. +The configuration file consists of the following types of lines: +.Bl -bullet -offset indent +.It +variable assignments +.It +section separators +.It +include directives +.It +MIB variable assignments +.El +.Pp +If a line is too long it can be continued on the next line by ending it with +a backslash. +Empty lines and lines in which the first non-blank character is a +.Dq # +sign are ignored. +.Pp +All MIB variable assignments of the entire configuration (including nested +configuration files) are handled as one transaction, i.e., as if they arrived +in a single SET PDU. +Any failure during the initial configuration read causes +.Nm +to exit. +A failure during the configuration read caused by a module load +causes the loading of the module to fail. +.Pp +The configuration is read during initialization of +.Nm , +when a module is loaded and when +.Nm +receives a SIGHUP. +.Ss VARIABLE ASSIGNMENTS +Variable assignments can take one of two forms: +.Bd -unfilled -offset indent +variable := string +variable ?= string +.Ed +.Pp +The string reaches from the first non-blank character after the +equal sign until the first new line or +.Dq # +character. +In the first case +the string is assigned to the variable unconditionally, in the second case the +variable is only assigned if it does not exist yet. +.Pp +Variable names must begin with a letter or underscore and contain only letters, +digits or underscores. +.Ss SECTION SEPARATORS +The configuration consists of named sections. +The MIB variable assignments in the section named +.Dq snmpd +are executed only during initial setup or when +.Nm +receives a SIGHUP. +All other sections are executed when either a module +with the same name as the section is loaded or +.Nm +receives a SIGHUP and that module is already loaded. +The default section at the start of the configuration is +.Dq snmpd . +One can switch to another section with the syntax +.Bd -unfilled -offset indent +%secname +.Ed +.Pp +Where +.Ar secname +is the name of the section. +The same +.Ar secname +can be used in more than one place in the configuration. +All of these parts are collected into one section. +.Ss INCLUDE DIRECTIVES +Another configuration file can be included into the current one with the +include directive that takes one of two forms: +.Bd -unfilled -offset indent +\&.include "file" +\&.include <"file"> +.Ed +.Pp +The first form causes the file to be searched in the current directory, the +second form causes the file to be searched in the directories specified in +the system include path. +Nesting depth is only restricted by available memory. +.Ss MIB VARIABLE ASSIGNMENTS +A MIB variable is assigned with the syntax +.Bd -unfilled -offset indent +oid [ suboids ] = value +.Ed +.Pp +.Va oid +is the name of the variable to be set. +Only the last component of the entire name is used here. +If the variable is a scalar, the index (.0) is automatically +appended and need not to be specified. +If the variable is a table column, the index +.Pq Va suboids +must be specified. +The index consist of elements each separated from the +previous one by a dot. +Elements may be either numbers, strings or hostnames +enclosed in [] brackets. +If the element is a number it is appended +to the current oid. +If the element is a string, its length and the +.Tn ASCII +code of each of its characters are appended to the current oid. +If the +element is a hostname, the IP address of the host is looked up and the four +elements of the IP address are appended to the oid. +.Pp +For example, an oid of +.Bd -unfilled -offset indent +myvariable.27.foooll.[localhost]."&^!" +.Ed +.Pp +results in the oid +.Bd -unfilled -offset indent +myvariable.27.102.111.111.111.108.108.127.0.0.1.38.94.33 +.Ed +.Pp +The value of the assignment may be either empty, a string or a number. +If a string starts with a letter or an underscore and consists only of +letters, digits, underscores and minus signs, it can be written without +quotes. +In all other cases the string must be enclosed in double quotes. +.Sh SUBSTITUTIONS +A variable substitution is written as +.Bd -unfilled -offset indent +$(variable) +.Ed +.Pp +where +.Ar variable +is the name of the variable to substitute. +Using an undefined variable is considered an error. +.Sh FILES +.Bl -tag -width ".It Pa /var/run/ Ns Ao Ar prefix Ac Ns \&.pid" -compact +.It Pa /etc/ Ns Ao Ar prefix Ac Ns \&.config +Default configuration file, where the default +.Aq prefix +is +.Dq snmpd . +.It Pa /var/ Ns Ao Ar prefix Ac Ns \&.engine +Default engine id file. +.It Pa /var/run/ Ns Ao Ar prefix Ac Ns \&.pid +Default pid file. +.It Pa /etc:/usr/etc/:/usr/local/etc +Default search path for system include files. +.It Pa @MIBSPATH@FOKUS-MIB.txt +.It Pa @MIBSPATH@BEGEMOT-MIB.txt +.It Pa @MIBSPATH@BEGEMOT-SNMPD.txt +Definitions for the MIBs implemented in the daemon. +.It Pa /etc/hosts.allow, /etc/hosts.deny +Access controls that should be enforced by TCP wrappers are defined here. +Further details are described in +.Xr hosts_access 5 . +.El +.Sh SEE ALSO +.Xr gensnmptree 1 , +.Xr hosts_access 5 +.Sh STANDARDS +The +.Nm +conforms to the applicable IETF RFCs. +.Sh AUTHORS +.An Hartmut Brandt Aq harti@FreeBSD.org +.Sh BUGS +Sure. Property changes on: vendor/1.14/snmpd/bsnmpd.1 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmpd/config.c =================================================================== --- vendor/1.14/snmpd/config.c (nonexistent) +++ vendor/1.14/snmpd/config.c (revision 359491) @@ -0,0 +1,1383 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmpd/config.c,v 1.25 2006/02/14 09:04:20 brandt_h Exp $ + * + * Parse configuration file. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "snmpmod.h" +#include "snmpd.h" +#include "tree.h" + +/* +#define DEBUGGING +*/ + +/* + * config_file: EMPTY | config_file line + * + * line: oid '=' value + * | '%' STRING + * | STRING := REST_OF_LINE + * | STRING ?= REST_OF_LINE + * | . INCLUDE STRING + * + * oid: STRING suboid + * + * suboid: EMPTY | suboid '.' subid + * + * subid: NUM | STRING | '[' STRING ']' + * + * value: EMPTY | STRING | NUM + */ + +/* + * Input context for macros and includes + */ +enum input_type { + INPUT_FILE = 1, + INPUT_STRING +}; +struct input { + enum input_type type; + union { + struct { + FILE *fp; + char *filename; + u_int lno; + } file; + struct { + char *macro; + char *str; + char *ptr; + size_t left; + } str; + } u; + LIST_ENTRY(input) link; +}; +static LIST_HEAD(, input) inputs; + +#define input_fp u.file.fp +#define input_filename u.file.filename +#define input_lno u.file.lno +#define input_macro u.str.macro +#define input_str u.str.str +#define input_ptr u.str.ptr +#define input_left u.str.left + +static int input_push; +static int input_buf[2]; + +/* + * Configuration data. The configuration file is handled as one single + * SNMP transaction. So we need to keep the assignment data for the + * commit or rollback pass. Note, that dependencies and finish functions + * are NOT allowed here. + */ +struct assign { + struct snmp_value value; + struct snmp_scratch scratch; + const char *node_name; + + TAILQ_ENTRY(assign) link; +}; +static TAILQ_HEAD(assigns, assign) assigns = TAILQ_HEAD_INITIALIZER(assigns); + + +static struct snmp_context *snmp_ctx; + +struct macro { + char *name; + char *value; + size_t length; + LIST_ENTRY(macro) link; + int perm; +}; +static LIST_HEAD(, macro) macros = LIST_HEAD_INITIALIZER(macros); + +enum { + TOK_EOF = 0200, + TOK_EOL, + TOK_NUM, + TOK_STR, + TOK_HOST, + TOK_ASSIGN, + TOK_QASSIGN, +}; + +/* lexer values and last token */ +static uint64_t numval; +static char strval[_POSIX2_LINE_MAX]; +static size_t strvallen; +static int token; + +/* error return */ +static jmp_buf errjmp[4]; +static volatile int errstk; + +# define ERRPUSH() (setjmp(errjmp[errstk++])) +# define ERRPOP() ((void)(errstk--)) +# define ERRNEXT() (longjmp(errjmp[--errstk], 1)) +# define ERR() (longjmp(errjmp[--errstk], 1)) + +/* section context */ +static int ignore; + +/* + * Report an error and jump to the error label + */ +static void report(const char *fmt, ...) __dead2 __printflike(1, 2); + +static void +report(const char *fmt, ...) +{ + va_list ap; + const struct input *input; + + va_start(ap, fmt); + vsyslog(LOG_ERR, fmt, ap); + va_end(ap); + + LIST_FOREACH(input, &inputs, link) { + switch (input->type) { + + case INPUT_FILE: + syslog(LOG_ERR, " in file %s line %u", + input->input_filename, input->input_lno); + break; + + case INPUT_STRING: + syslog(LOG_ERR, " in macro %s pos %td", + input->input_macro, + input->input_ptr - input->input_str); + break; + } + } + ERR(); +} + +/* + * Open a file for input + */ +static int +input_open_file(const char *fname, int sysdir) +{ + struct input *input; + FILE *fp; + char path[PATH_MAX + 1]; + const char *col; + const char *ptr; + + if (sysdir) { + ptr = syspath; + fp = NULL; + while (*ptr != '\0') { + if ((col = strchr(ptr, ':')) == NULL) { + snprintf(path, sizeof(path), "%s/%s", + ptr, fname); + col = ptr + strlen(ptr) - 1; + } else if (col == ptr) + snprintf(path, sizeof(path), "./%s", fname); + else + snprintf(path, sizeof(path), "%.*s/%s", + (int)(col - ptr), ptr, fname); + if ((fp = fopen(path, "r")) != NULL) + break; + ptr = col + 1; + } + } else + fp = fopen(fname, "r"); + + if (fp == NULL) + report("%s: %m", fname); + + if ((input = malloc(sizeof(*input))) == NULL) { + fclose(fp); + return (-1); + } + if ((input->input_filename = malloc(strlen(fname) + 1)) == NULL) { + fclose(fp); + free(input); + return (-1); + } + strcpy(input->input_filename, fname); + input->input_fp = fp; + input->input_lno = 1; + input->type = INPUT_FILE; + LIST_INSERT_HEAD(&inputs, input, link); + return (0); +} + +/* + * Make a macro the next input + */ +static void +input_open_macro(struct macro *m) +{ + struct input *input; + + if ((input = malloc(sizeof(*input))) == NULL) + report("%m"); + input->type = INPUT_STRING; + input->input_macro = m->name; + if ((input->input_str = malloc(m->length)) == NULL) { + free(input); + report("%m"); + } + memcpy(input->input_str, m->value, m->length); + input->input_ptr = input->input_str; + input->input_left = m->length; + LIST_INSERT_HEAD(&inputs, input, link); +} + +/* + * Close top input source + */ +static void +input_close(void) +{ + struct input *input; + + if ((input = LIST_FIRST(&inputs)) == NULL) + abort(); + switch (input->type) { + + case INPUT_FILE: + fclose(input->input_fp); + free(input->input_filename); + break; + + case INPUT_STRING: + free(input->input_str); + break; + } + LIST_REMOVE(input, link); + free(input); +} + +/* + * Close all inputs + */ +static void +input_close_all(void) +{ + while (!LIST_EMPTY(&inputs)) + input_close(); +} + +/* + * Push back one character + */ +static void +input_ungetc(int c) +{ + if (c == EOF) + report("pushing EOF"); + if (input_push == 2) + report("pushing third char"); + input_buf[input_push++] = c; +} + + +/* + * Return next character from the input without preprocessing. + */ +static int +input_getc_raw(void) +{ + int c; + struct input *input; + + if (input_push != 0) { + c = input_buf[--input_push]; + goto ok; + } + while ((input = LIST_FIRST(&inputs)) != NULL) { + switch (input->type) { + + case INPUT_FILE: + if ((c = getc(input->input_fp)) == EOF) { + if (ferror(input->input_fp)) + report("read error: %m"); + input_close(); + break; + } + if (c == '\n') + input->input_lno++; + goto ok; + + case INPUT_STRING: + if (input->input_left-- == 0) { + input_close(); + break; + } + c = *input->input_ptr++; + goto ok; + } + } +# ifdef DEBUGGING + fprintf(stderr, "EOF"); +# endif + return (EOF); + + ok: +# ifdef DEBUGGING + if (!isascii(c) || !isprint(c)) + fprintf(stderr, "'%#2x'", c); + else + fprintf(stderr, "'%c'", c); +# endif + return (c); +} + +/* + * Get character with and \\n -> processing. + */ +static int +input_getc_plain(void) +{ + int c; + + again: + if ((c = input_getc_raw()) == '\\') { + if ((c = input_getc_raw()) == '\n') + goto again; + if (c != EOF) + input_ungetc(c); + return ('\\'); + } + return (c); +} + +/* + * Get next character with substitution of macros + */ +static int +input_getc(void) +{ + int c; + struct macro *m; + char name[_POSIX2_LINE_MAX]; + size_t namelen; + + again: + if ((c = input_getc_plain()) != '$') + return (c); + + if ((c = input_getc()) == EOF) + report("unexpected EOF"); + if (c != '(') + report("expecting '(' after '$'"); + + namelen = 0; + while ((c = input_getc()) != EOF && c != ')') { + if (isalpha(c) || c == '_' || (namelen != 0 && isdigit(c))) + name[namelen++] = c; + else + goto badchar; + } + if (c == EOF) + report("unexpected EOF"); + name[namelen++] = '\0'; + + LIST_FOREACH(m, ¯os, link) + if (strcmp(m->name, name) == 0) + break; + if (m == NULL) + report("undefined macro '%s'", name); + + input_open_macro(m); + goto again; + + badchar: + if (!isascii(c) || !isprint(c)) + report("unexpected character %#2x", (u_int)c); + else + report("bad character '%c'", c); +} + + +static void +input_getnum(u_int base, u_int flen) +{ + int c; + u_int cnt; + + cnt = 0; + numval = 0; + while (flen == 0 || cnt < flen) { + if ((c = input_getc()) == EOF) { + if (cnt == 0) + report("bad number"); + return; + } + if (isdigit(c)) { + if (base == 8 && (c == '8' || c == '9')) { + input_ungetc(c); + if (cnt == 0) + report("bad number"); + return; + } + numval = numval * base + (c - '0'); + } else if (base == 16 && isxdigit(c)) { + if (islower(c)) + numval = numval * base + (c - 'a' + 10); + else + numval = numval * base + (c - 'A' + 10); + } else { + input_ungetc(c); + if (cnt == 0) + report("bad number"); + return; + } + cnt++; + } +} + +static int +# ifdef DEBUGGING +_gettoken(void) +# else +gettoken(void) +# endif +{ + int c; + char *end; + static const char esc[] = "abfnrtv"; + static const char chr[] = "\a\b\f\n\r\t\v"; + + /* + * Skip any whitespace before the next token + */ + while ((c = input_getc()) != EOF) { + if (!isspace(c) || c == '\n') + break; + } + if (c == EOF) + return (token = TOK_EOF); + if (!isascii(c)) + goto badchar; + + /* + * Skip comments + */ + if (c == '#') { + while ((c = input_getc_plain()) != EOF) { + if (c == '\n') + return (token = TOK_EOL); + } + goto badeof; + } + + /* + * Single character tokens + */ + if (c == '\n') + return (token = TOK_EOL); + if (c == '.' || c == '%' || c == '=' || c == '<' || c == '>') + return (token = c); + if (c == ':') { + if ((c = input_getc()) == '=') + return (token = TOK_ASSIGN); + input_ungetc(c); + return (token = ':'); + } + if (c == '?') { + if ((c = input_getc()) == '=') + return (token = TOK_QASSIGN); + input_ungetc(c); + goto badchar; + } + + /* + * Sort out numbers + */ + if (isdigit(c)) { + if (c == '0') { + if ((c = input_getc()) == 'x' || c == 'X') { + input_getnum(16, 0); + } else if (isdigit(c)) { + input_ungetc(c); + input_getnum(8, 0); + } else { + if (c != EOF) + input_ungetc(c); + numval = 0; + c = 1; + } + } else { + input_ungetc(c); + input_getnum(10, 0); + } + return (token = TOK_NUM); + } + + /* + * Must be a string then + */ + strvallen = 0; + +# define GETC(C) do { \ + if ((c = input_getc()) == EOF) \ + goto badeof; \ + if (!isascii(c) || (!isprint(c) && c != '\t')) \ + goto badchar; \ +} while(0) + + if (c == '"') { + for(;;) { + GETC(c); + if (c == '"') { + strval[strvallen] = '\0'; + break; + } + if (c != '\\') { + strval[strvallen++] = c; + continue; + } + GETC(c); + if ((end = strchr(esc, c)) != NULL) { + strval[strvallen++] = chr[end - esc]; + continue; + } + if (c == 'x') { + input_getnum(16, 2); + c = numval; + } else if (c >= '0' && c <= '7') { + input_ungetc(c); + input_getnum(8, 3); + c = numval; + } + strval[strvallen++] = c; + } +# undef GETC + + } else if (c == '[') { + /* + * Skip leading space + */ + while ((c = input_getc()) != EOF && isspace(c)) + ; + if (c == EOF) + goto badeof; + while (c != ']' && !isspace(c)) { + if (!isalnum(c) && c != '.' && c != '-') + goto badchar; + strval[strvallen++] = c; + if ((c = input_getc()) == EOF) + goto badeof; + } + while (c != ']' && isspace(c)) { + if ((c = input_getc()) == EOF) + goto badeof; + } + if (c != ']') + goto badchar; + strval[strvallen] = '\0'; + return (token = TOK_HOST); + + } else if (!isalpha(c) && c != '_') { + goto badchar; + + } else { + for (;;) { + strval[strvallen++] = c; + if ((c = input_getc()) == EOF) + goto badeof; + if (!isalnum(c) && c != '_' && c != '-') { + input_ungetc(c); + strval[strvallen] = '\0'; + break; + } + } + } + + return (token = TOK_STR); + + badeof: + report("unexpected EOF"); + + badchar: + if (!isascii(c) || !isprint(c)) + report("unexpected character %#2x", (u_int)c); + else + report("bad character '%c'", c); +} + +# ifdef DEBUGGING +static int +gettoken() +{ + _gettoken(); + if (isascii(token) && isprint(token)) + printf("(%c)", token); + else { + switch (token) { + + case TOK_EOF: + printf("(EOF)"); + break; + case TOK_EOL: + printf("(EOL)"); + break; + case TOK_NUM: + printf("(NUM %ju)", (uintmax_t)numval); + break; + case TOK_STR: + printf("(STR %.*s)", (int)strvallen, strval); + break; + case TOK_HOST: + printf("(HOST %s)", strval); + break; + default: + printf("(%#2x)", token); + break; + } + } + return (token); +} +#endif + + +/* + * Try to execute the assignment. + */ +static void +handle_assignment(const struct snmp_node *node, struct asn_oid *vindex, + const struct snmp_value *value) +{ + u_int i; + int err; + struct assign *tp; + char nodename[100]; + + if (node->type == SNMP_NODE_LEAF) { + /* index must be one single zero or no index at all */ + if (vindex->len > 1 || (vindex->len == 1 && + vindex->subs[0] != 0)) + report("bad index on leaf node"); + vindex->len = 1; + vindex->subs[0] = 0; + } else { + /* resulting oid must not be too long */ + if (node->oid.len + vindex->len > ASN_MAXOIDLEN) + report("resulting OID too long"); + } + + /* + * Get the next assignment entry for the transaction. + */ + if ((tp = malloc(sizeof(*tp))) == NULL) + report("%m"); + + tp->value = *value; + tp->node_name = node->name; + + /* + * Build the OID + */ + tp->value.var = node->oid; + for (i = 0; i < vindex->len; i++) + tp->value.var.subs[tp->value.var.len++] = vindex->subs[i]; + + /* + * Puzzle together the variables for the call and call the + * set routine. The set routine may make our node pointer + * invalid (if we happend to call the module loader) so + * get a copy of the node name beforehands. + */ + snprintf(nodename, sizeof(nodename), "%s", node->name); + snmp_ctx->scratch = &tp->scratch; + snmp_ctx->var_index = 0; + err = (*node->op)(snmp_ctx, &tp->value, node->oid.len, node->index, + SNMP_OP_SET); + if (err != 0) { + free(tp); + report("assignment to %s.%s returns %d", nodename, + asn_oid2str(vindex), err); + } + + TAILQ_INSERT_TAIL(&assigns, tp, link); +} + + +/* + * Parse the section statement + */ +static void +parse_section(const struct lmodule *mod) +{ + if (token != TOK_STR) + report("expecting section name"); + + if (strcmp(strval, "snmpd") == 0) { + if (mod != NULL) + /* loading a module - ignore common stuff */ + ignore = 1; + else + /* global configuration - don't ignore */ + ignore = 0; + } else { + if (mod == NULL) { + /* global configuration - ignore module stuff */ + ignore = 1; + } else { + /* loading module - check if it's our section */ + ignore = (strcmp(strval, mod->section) != 0); + } + } + gettoken(); +} + +/* + * Convert a hostname to four u_chars + */ +static void +gethost(const char *host, u_char *ip) +{ + struct addrinfo hints, *res; + int error; + struct sockaddr_in *sain; + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_INET; + hints.ai_socktype = SOCK_DGRAM; + hints.ai_protocol = IPPROTO_UDP; + hints.ai_flags = AI_PASSIVE; + error = getaddrinfo(host, NULL, &hints, &res); + if (error != 0) + report("%s: %s", host, gai_strerror(error)); + if (res == NULL) + report("%s: unknown hostname", host); + + sain = (struct sockaddr_in *)(void *)res->ai_addr; + sain->sin_addr.s_addr = ntohl(sain->sin_addr.s_addr); + ip[0] = sain->sin_addr.s_addr >> 24; + ip[1] = sain->sin_addr.s_addr >> 16; + ip[2] = sain->sin_addr.s_addr >> 8; + ip[3] = sain->sin_addr.s_addr >> 0; + + freeaddrinfo(res); +} + +/* + * Parse the left hand side of a config line. + */ +static const struct snmp_node * +parse_oid(const char *varname, struct asn_oid *oid) +{ + struct snmp_node *node; + u_int i; + u_char ip[4]; + struct asn_oid str_oid; + + for (node = tree; node < &tree[tree_size]; node++) + if (strcmp(varname, node->name) == 0) + break; + if (node == &tree[tree_size]) + node = NULL; + + oid->len = 0; + while (token == '.') { + if (gettoken() == TOK_NUM) { + if (numval > ASN_MAXID) + report("subid too large %#jx", + (uintmax_t)numval); + if (oid->len == ASN_MAXOIDLEN) + report("index too long"); + if (gettoken() != ':') + oid->subs[oid->len++] = numval; + else { + str_oid.len = 0; + str_oid.subs[str_oid.len++] = numval; + while (gettoken() == TOK_NUM) { + str_oid.subs[str_oid.len++] = numval; + if (gettoken() != ':') + break; + } + oid->subs[oid->len++] = str_oid.len; + asn_append_oid(oid, &str_oid); + } + + } else if (token == TOK_STR) { + if (strvallen + oid->len + 1 > ASN_MAXOIDLEN) + report("oid too long"); + oid->subs[oid->len++] = strvallen; + for (i = 0; i < strvallen; i++) + oid->subs[oid->len++] = strval[i]; + gettoken(); + + } else if (token == TOK_HOST) { + gethost(strval, ip); + if (oid->len + 4 > ASN_MAXOIDLEN) + report("index too long"); + for (i = 0; i < 4; i++) + oid->subs[oid->len++] = ip[i]; + gettoken(); + } else + report("bad token in index"); + } + + return (node); +} + +/* + * Parse the value for an assignment. + */ +static void +parse_syntax_null(struct snmp_value *value __unused) +{ + if (token != TOK_EOL) + report("bad NULL syntax"); +} + +static void +parse_syntax_integer(struct snmp_value *value) +{ + if (token != TOK_NUM) + report("bad INTEGER syntax"); + if (numval > 0x7fffffff) + report("INTEGER too large %ju", (uintmax_t)numval); + + value->v.integer = numval; + gettoken(); +} + +static void +parse_syntax_counter64(struct snmp_value *value) +{ + if (token != TOK_NUM) + report("bad COUNTER64 syntax"); + + value->v.counter64 = numval; + gettoken(); +} + +static void +parse_syntax_octetstring(struct snmp_value *value) +{ + u_long alloc; + u_char *noct; + + if (token == TOK_STR) { + value->v.octetstring.len = strvallen; + value->v.octetstring.octets = malloc(strvallen); + (void)memcpy(value->v.octetstring.octets, strval, strvallen); + gettoken(); + return; + } + + /* XX:XX:XX syntax */ + value->v.octetstring.octets = NULL; + value->v.octetstring.len = 0; + + if (token != TOK_NUM) + /* empty string is allowed */ + return; + + if (ERRPUSH()) { + free(value->v.octetstring.octets); + ERRNEXT(); + } + + alloc = 0; + for (;;) { + if (token != TOK_NUM) + report("bad OCTETSTRING syntax"); + if (numval > 0xff) + report("byte value too large"); + if (alloc == value->v.octetstring.len) { + alloc += 100; + noct = realloc(value->v.octetstring.octets, alloc); + if (noct == NULL) + report("%m"); + value->v.octetstring.octets = noct; + } + value->v.octetstring.octets[value->v.octetstring.len++] + = numval; + if (gettoken() != ':') + break; + gettoken(); + } + ERRPOP(); +} + +static void +parse_syntax_oid(struct snmp_value *value) +{ + value->v.oid.len = 0; + + if (token != TOK_NUM) + return; + + for (;;) { + if (token != TOK_NUM) + report("bad OID syntax"); + if (numval > ASN_MAXID) + report("subid too large"); + if (value->v.oid.len == ASN_MAXOIDLEN) + report("OID too long"); + value->v.oid.subs[value->v.oid.len++] = numval; + if (gettoken() != '.') + break; + gettoken(); + } +} + +static void +parse_syntax_ipaddress(struct snmp_value *value) +{ + int i; + u_char ip[4]; + + if (token == TOK_NUM) { + /* numerical address */ + i = 0; + for (;;) { + if (numval >= 256) + report("ip address part too large"); + value->v.ipaddress[i++] = numval; + if (i == 4) + break; + if (gettoken() != '.') + report("expecting '.' in ip address"); + } + gettoken(); + + } else if (token == TOK_HOST) { + /* host name */ + gethost(strval, ip); + for (i = 0; i < 4; i++) + value->v.ipaddress[i] = ip[i]; + gettoken(); + + } else + report("bad ip address syntax"); +} + +static void +parse_syntax_uint32(struct snmp_value *value) +{ + + if (token != TOK_NUM) + report("bad number syntax"); + if (numval > 0xffffffff) + report("number too large"); + value->v.uint32 = numval; + gettoken(); +} + +/* + * Parse an assignement line + */ +static void +parse_assign(const char *varname) +{ + struct snmp_value value; + struct asn_oid vindex; + const struct snmp_node *node; + + node = parse_oid(varname, &vindex); + if (token != '=') + report("'=' expected, got '%c'", token); + gettoken(); + + if (ignore) { + /* skip rest of line */ + while (token != TOK_EOL && token != TOK_EOF) + gettoken(); + return; + } + if (node == NULL) + report("unknown variable"); + + switch (value.syntax = node->syntax) { + + case SNMP_SYNTAX_NULL: + parse_syntax_null(&value); + break; + + case SNMP_SYNTAX_INTEGER: + parse_syntax_integer(&value); + break; + + case SNMP_SYNTAX_COUNTER64: + parse_syntax_counter64(&value); + break; + + case SNMP_SYNTAX_OCTETSTRING: + parse_syntax_octetstring(&value); + break; + + case SNMP_SYNTAX_OID: + parse_syntax_oid(&value); + break; + + case SNMP_SYNTAX_IPADDRESS: + parse_syntax_ipaddress(&value); + break; + + case SNMP_SYNTAX_COUNTER: + case SNMP_SYNTAX_GAUGE: + case SNMP_SYNTAX_TIMETICKS: + parse_syntax_uint32(&value); + break; + + case SNMP_SYNTAX_NOSUCHOBJECT: + case SNMP_SYNTAX_NOSUCHINSTANCE: + case SNMP_SYNTAX_ENDOFMIBVIEW: + abort(); + } + + if (ERRPUSH()) { + snmp_value_free(&value); + ERRNEXT(); + } + + handle_assignment(node, &vindex, &value); + + ERRPOP(); +} + +/* + * Handle macro definition line + * We have already seen the := and the input now stands at the character + * after the =. Skip whitespace and then call the input routine directly to + * eat up characters. + */ +static void +parse_define(const char *varname) +{ + char *volatile string; + char *new; + volatile size_t alloc, length; + int c; + struct macro *m; + int t = token; + + alloc = 100; + length = 0; + if ((string = malloc(alloc)) == NULL) + report("%m"); + + if (ERRPUSH()) { + free(string); + ERRNEXT(); + } + + while ((c = input_getc_plain()) != EOF) { + if (c == '\n' || !isspace(c)) + break; + } + + while (c != EOF && c != '#' && c != '\n') { + if (alloc == length) { + alloc *= 2; + if ((new = realloc(string, alloc)) == NULL) + report("%m"); + string = new; + } + string[length++] = c; + c = input_getc_plain(); + } + if (c == '#') { + while ((c = input_getc_plain()) != EOF && c != '\n') + ; + } + if (c == EOF) + report("EOF in macro definition"); + + LIST_FOREACH(m, ¯os, link) + if (strcmp(m->name, varname) == 0) + break; + + if (m == NULL) { + if ((m = malloc(sizeof(*m))) == NULL) + report("%m"); + if ((m->name = malloc(strlen(varname) + 1)) == NULL) { + free(m); + report("%m"); + } + strcpy(m->name, varname); + m->perm = 0; + LIST_INSERT_HEAD(¯os, m, link); + + m->value = string; + m->length = length; + } else { + if (t == TOK_ASSIGN) { + free(m->value); + m->value = string; + m->length = length; + } else + free(string); + } + + token = TOK_EOL; + + ERRPOP(); +} + +/* + * Free all macros + */ +static void +macro_free_all(void) +{ + static struct macro *m, *m1; + + m = LIST_FIRST(¯os); + while (m != NULL) { + m1 = LIST_NEXT(m, link); + if (!m->perm) { + free(m->name); + free(m->value); + LIST_REMOVE(m, link); + free(m); + } + m = m1; + } +} + +/* + * Parse an include directive and switch to the new file + */ +static void +parse_include(void) +{ + int sysdir = 0; + char fname[_POSIX2_LINE_MAX]; + + if (gettoken() == '<') { + sysdir = 1; + if (gettoken() != TOK_STR) + report("expecting filename after in .include"); + } else if (token != TOK_STR) + report("expecting filename after in .include"); + + strcpy(fname, strval); + if (sysdir && gettoken() != '>') + report("expecting '>'"); + gettoken(); + if (input_open_file(fname, sysdir) == -1) + report("%s: %m", fname); +} + +/* + * Parse the configuration file + */ +static void +parse_file(const struct lmodule *mod) +{ + char varname[_POSIX2_LINE_MAX]; + + while (gettoken() != TOK_EOF) { + if (token == TOK_EOL) + /* empty line */ + continue; + if (token == '%') { + gettoken(); + parse_section(mod); + } else if (token == '.') { + if (gettoken() != TOK_STR) + report("keyword expected after '.'"); + if (strcmp(strval, "include") == 0) + parse_include(); + else + report("unknown keyword '%s'", strval); + } else if (token == TOK_STR) { + strcpy(varname, strval); + if (gettoken() == TOK_ASSIGN || token == TOK_QASSIGN) + parse_define(varname); + else + parse_assign(varname); + } + if (token != TOK_EOL) + report("eol expected"); + } +} + +/* + * Do rollback on errors + */ +static void +do_rollback(void) +{ + struct assign *tp; + struct snmp_node *node; + + while ((tp = TAILQ_LAST(&assigns, assigns)) != NULL) { + TAILQ_REMOVE(&assigns, tp, link); + for (node = tree; node < &tree[tree_size]; node++) + if (node->name == tp->node_name) { + snmp_ctx->scratch = &tp->scratch; + (void)(*node->op)(snmp_ctx, &tp->value, + node->oid.len, node->index, + SNMP_OP_ROLLBACK); + break; + } + if (node == &tree[tree_size]) + syslog(LOG_ERR, "failed to find node for " + "rollback"); + snmp_value_free(&tp->value); + free(tp); + } +} + +/* + * Do commit + */ +static void +do_commit(void) +{ + struct assign *tp; + struct snmp_node *node; + + while ((tp = TAILQ_FIRST(&assigns)) != NULL) { + TAILQ_REMOVE(&assigns, tp, link); + for (node = tree; node < &tree[tree_size]; node++) + if (node->name == tp->node_name) { + snmp_ctx->scratch = &tp->scratch; + (void)(*node->op)(snmp_ctx, &tp->value, + node->oid.len, node->index, SNMP_OP_COMMIT); + break; + } + if (node == &tree[tree_size]) + syslog(LOG_ERR, "failed to find node for commit"); + snmp_value_free(&tp->value); + free(tp); + } +} + +/* + * Read the configuration file. Handle the entire file as one transaction. + * + * If lodmod is NULL, the sections for 'snmpd' and all loaded modules are + * executed. If it is not NULL, only the sections for that module are handled. + */ +int +read_config(const char *fname, struct lmodule *lodmod) +{ + int err; + char objbuf[ASN_OIDSTRLEN]; + char idxbuf[ASN_OIDSTRLEN]; + + ignore = 0; + + input_push = 0; + + if (ERRPUSH()) + return (-1); + if (input_open_file(fname, 0) == -1) { + syslog(LOG_ERR, "%s: %m", fname); + return (-1); + } + ERRPOP(); + community = COMM_INITIALIZE; + + if ((snmp_ctx = snmp_init_context()) == NULL) { + input_close_all(); + syslog(LOG_ERR, "%m"); + return (-1); + } + + if (ERRPUSH()) { + do_rollback(); + input_close_all(); + macro_free_all(); + free(snmp_ctx); + return (-1); + } + parse_file(lodmod); + ERRPOP(); + + if ((err = snmp_dep_commit(snmp_ctx)) != SNMP_ERR_NOERROR) { + syslog(LOG_ERR, "init dep failed: %u %s %s", err, + asn_oid2str_r(&snmp_ctx->dep->obj, objbuf), + asn_oid2str_r(&snmp_ctx->dep->idx, idxbuf)); + snmp_dep_rollback(snmp_ctx); + do_rollback(); + input_close_all(); + macro_free_all(); + free(snmp_ctx); + return (-1); + } + + do_commit(); + snmp_dep_finish(snmp_ctx); + + macro_free_all(); + + free(snmp_ctx); + + return (0); +} + +/* + * Define a permanent macro + */ +int +define_macro(const char *name, const char *value) +{ + struct macro *m; + + if ((m = malloc(sizeof(*m))) == NULL) + return (-1); + if ((m->name = malloc(strlen(name) + 1)) == NULL) { + free(m); + return (-1); + } + strcpy(m->name, name); + if ((m->value = malloc(strlen(value) + 1)) == NULL) { + free(m->name); + free(m); + return (-1); + } + strcpy(m->value, value); + m->length = strlen(value); + m->perm = 1; + LIST_INSERT_HEAD(¯os, m, link); + return (0); +} Property changes on: vendor/1.14/snmpd/config.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmpd/export.c =================================================================== --- vendor/1.14/snmpd/export.c (nonexistent) +++ vendor/1.14/snmpd/export.c (revision 359491) @@ -0,0 +1,404 @@ +/* + * Copyright (c) 2001-2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmpd/export.c,v 1.8 2006/02/14 09:04:20 brandt_h Exp $ + * + * Support functions for modules. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "snmpmod.h" +#include "snmpd.h" +#include "tree.h" + +/* + * Support functions + */ + +/* + * This is user for SET of string variables. If 'req' is not -1 then + * the arguments is checked to be of that length. The old value is saved + * in scratch->ptr1 and the new value is allocated and copied. + * If there is an old values it must have been allocated by malloc. + */ +int +string_save(struct snmp_value *value, struct snmp_context *ctx, + ssize_t req_size, u_char **valp) +{ + if (req_size != -1 && value->v.octetstring.len != (u_long)req_size) + return (SNMP_ERR_BADVALUE); + + ctx->scratch->ptr1 = *valp; + + if ((*valp = malloc(value->v.octetstring.len + 1)) == NULL) { + *valp = ctx->scratch->ptr1; + return (SNMP_ERR_RES_UNAVAIL); + } + + memcpy(*valp, value->v.octetstring.octets, value->v.octetstring.len); + (*valp)[value->v.octetstring.len] = '\0'; + + return (0); +} + +/* + * Commit a string. This is easy - free the old value. + */ +void +string_commit(struct snmp_context *ctx) +{ + free(ctx->scratch->ptr1); +} + +/* + * Rollback a string - free new value and copy back old one. + */ +void +string_rollback(struct snmp_context *ctx, u_char **valp) +{ + free(*valp); + *valp = ctx->scratch->ptr1; +} + +/* + * ROLLBACK or COMMIT fails because instance has disappeared. Free string. + */ +void +string_free(struct snmp_context *ctx) +{ + free(ctx->scratch->ptr1); +} + +/* + * Get a string value for a response packet + */ +int +string_get(struct snmp_value *value, const u_char *ptr, ssize_t len) +{ + if (ptr == NULL) { + value->v.octetstring.len = 0; + value->v.octetstring.octets = NULL; + return (SNMP_ERR_NOERROR); + } + if (len == -1) + len = strlen(ptr); + if ((value->v.octetstring.octets = malloc((size_t)len)) == NULL) { + value->v.octetstring.len = 0; + return (SNMP_ERR_RES_UNAVAIL); + } + value->v.octetstring.len = (u_long)len; + memcpy(value->v.octetstring.octets, ptr, (size_t)len); + return (SNMP_ERR_NOERROR); +} + +/* + * Get a string value for a response packet but cut it if it is too long. + */ +int +string_get_max(struct snmp_value *value, const u_char *ptr, ssize_t len, + size_t maxlen) +{ + + if (ptr == NULL) { + value->v.octetstring.len = 0; + value->v.octetstring.octets = NULL; + return (SNMP_ERR_NOERROR); + } + if (len == -1) + len = strlen(ptr); + if ((size_t)len > maxlen) + len = maxlen; + if ((value->v.octetstring.octets = malloc((size_t)len)) == NULL) { + value->v.octetstring.len = 0; + return (SNMP_ERR_RES_UNAVAIL); + } + value->v.octetstring.len = (u_long)len; + memcpy(value->v.octetstring.octets, ptr, (size_t)len); + return (SNMP_ERR_NOERROR); +} + +/* + * Support for IPADDRESS + * + * Save the old IP address in scratch->int1 and set the new one. + */ +int +ip_save(struct snmp_value *value, struct snmp_context *ctx, u_char *valp) +{ + ctx->scratch->int1 = (valp[0] << 24) | (valp[1] << 16) | (valp[2] << 8) + | valp[3]; + + valp[0] = value->v.ipaddress[0]; + valp[1] = value->v.ipaddress[1]; + valp[2] = value->v.ipaddress[2]; + valp[3] = value->v.ipaddress[3]; + + return (0); +} + +/* + * Rollback the address by copying back the old one + */ +void +ip_rollback(struct snmp_context *ctx, u_char *valp) +{ + valp[0] = ctx->scratch->int1 >> 24; + valp[1] = ctx->scratch->int1 >> 16; + valp[2] = ctx->scratch->int1 >> 8; + valp[3] = ctx->scratch->int1; +} + +/* + * Nothing to do for commit + */ +void +ip_commit(struct snmp_context *ctx __unused) +{ +} + +/* + * Retrieve an IP address + */ +int +ip_get(struct snmp_value *value, u_char *valp) +{ + value->v.ipaddress[0] = valp[0]; + value->v.ipaddress[1] = valp[1]; + value->v.ipaddress[2] = valp[2]; + value->v.ipaddress[3] = valp[3]; + + return (SNMP_ERR_NOERROR); +} + +/* + * Object ID support + * + * Save the old value in a fresh allocated oid pointed to by scratch->ptr1. + */ +int +oid_save(struct snmp_value *value, struct snmp_context *ctx, + struct asn_oid *oid) +{ + if ((ctx->scratch->ptr1 = malloc(sizeof(struct asn_oid))) == NULL) + return (SNMP_ERR_RES_UNAVAIL); + *(struct asn_oid *)ctx->scratch->ptr1 = *oid; + *oid = value->v.oid; + + return (0); +} + +void +oid_rollback(struct snmp_context *ctx, struct asn_oid *oid) +{ + *oid = *(struct asn_oid *)ctx->scratch->ptr1; + free(ctx->scratch->ptr1); +} + +void +oid_commit(struct snmp_context *ctx) +{ + free(ctx->scratch->ptr1); +} + +int +oid_get(struct snmp_value *value, const struct asn_oid *oid) +{ + value->v.oid = *oid; + return (SNMP_ERR_NOERROR); +} + +/* + * Decode an index + */ +int +index_decode(const struct asn_oid *oid, u_int sub, u_int code, ...) +{ + va_list ap; + u_int index_count; + void *octs[10]; + u_int nocts; + u_int idx; + + va_start(ap, code); + index_count = SNMP_INDEX_COUNT(code); + nocts = 0; + + for (idx = 0; idx < index_count; idx++) { + switch (SNMP_INDEX(code, idx)) { + + case SNMP_SYNTAX_NULL: + break; + + case SNMP_SYNTAX_INTEGER: + if (sub == oid->len) + goto err; + *va_arg(ap, int32_t *) = oid->subs[sub++]; + break; + + case SNMP_SYNTAX_COUNTER64: + if (sub == oid->len) + goto err; + *va_arg(ap, u_int64_t *) = oid->subs[sub++]; + break; + + case SNMP_SYNTAX_OCTETSTRING: + { + u_char **cval; + size_t *sval; + u_int i; + + /* only variable size supported */ + if (sub == oid->len) + goto err; + cval = va_arg(ap, u_char **); + sval = va_arg(ap, size_t *); + *sval = oid->subs[sub++]; + if (sub + *sval > oid->len) + goto err; + if ((*cval = malloc(*sval)) == NULL) { + syslog(LOG_ERR, "%s: %m", __func__); + goto err; + } + octs[nocts++] = *cval; + for (i = 0; i < *sval; i++) { + if (oid->subs[sub] > 0xff) + goto err; + (*cval)[i] = oid->subs[sub++]; + } + break; + } + + case SNMP_SYNTAX_OID: + { + struct asn_oid *aval; + u_int i; + + if (sub == oid->len) + goto err; + aval = va_arg(ap, struct asn_oid *); + aval->len = oid->subs[sub++]; + if (aval->len > ASN_MAXOIDLEN) + goto err; + for (i = 0; i < aval->len; i++) + aval->subs[i] = oid->subs[sub++]; + break; + } + + case SNMP_SYNTAX_IPADDRESS: + { + u_int8_t *pval; + u_int i; + + if (sub + 4 > oid->len) + goto err; + pval = va_arg(ap, u_int8_t *); + for (i = 0; i < 4; i++) { + if (oid->subs[sub] > 0xff) + goto err; + pval[i] = oid->subs[sub++]; + } + break; + } + + case SNMP_SYNTAX_COUNTER: + case SNMP_SYNTAX_GAUGE: + case SNMP_SYNTAX_TIMETICKS: + if (sub == oid->len) + goto err; + if (oid->subs[sub] > 0xffffffff) + goto err; + *va_arg(ap, u_int32_t *) = oid->subs[sub++]; + break; + } + } + + va_end(ap); + return (0); + + err: + va_end(ap); + while(nocts > 0) + free(octs[--nocts]); + return (-1); +} + +/* + * Compare the index part of an OID and an index. + */ +int +index_compare_off(const struct asn_oid *oid, u_int sub, + const struct asn_oid *idx, u_int off) +{ + u_int i; + + for (i = off; i < idx->len && i < oid->len - sub; i++) { + if (oid->subs[sub + i] < idx->subs[i]) + return (-1); + if (oid->subs[sub + i] > idx->subs[i]) + return (+1); + } + if (oid->len - sub < idx->len) + return (-1); + if (oid->len - sub > idx->len) + return (+1); + + return (0); +} + +int +index_compare(const struct asn_oid *oid, u_int sub, const struct asn_oid *idx) +{ + return (index_compare_off(oid, sub, idx, 0)); +} + +/* + * Append an index to an oid + */ +void +index_append_off(struct asn_oid *var, u_int sub, const struct asn_oid *idx, + u_int off) +{ + u_int i; + + var->len = sub + idx->len; + for (i = off; i < idx->len; i++) + var->subs[sub + i] = idx->subs[i]; +} +void +index_append(struct asn_oid *var, u_int sub, const struct asn_oid *idx) +{ + index_append_off(var, sub, idx, 0); +} + Property changes on: vendor/1.14/snmpd/export.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmpd/snmpd.sh =================================================================== --- vendor/1.14/snmpd/snmpd.sh (nonexistent) +++ vendor/1.14/snmpd/snmpd.sh (revision 359491) @@ -0,0 +1,85 @@ +#!/bin/sh +# +# Copyright (c) 2001-2003 +# Fraunhofer Institute for Open Communication Systems (FhG Fokus). +# All rights reserved. +# +# Author: Harti Brandt +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $Begemot: bsnmp/snmpd/snmpd.sh,v 1.3 2004/08/06 08:47:13 brandt Exp $ +# +# SNMPd startup script +# +SNMPD=/usr/local/bin/bsnmpd +PID=/var/run/snmpd.pid +CONF=/etc/snmpd.conf + +case "$1" in + +start) + if [ -r ${PID} ] ; then + if kill -0 `cat ${PID}` ; then + echo "snmpd already running -- pid `cat ${PID}`" >/dev/stderr + exit 1 + fi + rm -f ${PID} + fi + if ${SNMPD} -c ${CONF} -p ${PID} ; then + echo "snmpd started" + fi + ;; + +stop) + if [ -r ${PID} ] ; then + if kill -0 `cat ${PID}` ; then + if kill -15 `cat ${PID}` ; then + echo "snmpd stopped" + exit 0 + fi + echo "cannot kill snmpd" >/dev/stderr + exit 1 + fi + echo "stale pid file -- removing" >/dev/stderr + rm -f ${PID} + exit 1 + fi + echo "snmpd not running" >/dev/stderr + ;; + +status) + if [ ! -r ${PID} ] ; then + echo "snmpd not running" + elif kill -0 `cat ${PID}` ; then + echo "snmpd pid `cat ${PID}`" + else + echo "stale pid file -- pid `cat ${PID}`" + fi + ;; + +*) + echo "usage: `basename $0` {start|stop|status}" + exit 1 +esac + +exit 0 Property changes on: vendor/1.14/snmpd/snmpd.sh ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:executable ## -0,0 +1 ## +* \ No newline at end of property Index: vendor/1.14/snmpd/snmpmod.3 =================================================================== --- vendor/1.14/snmpd/snmpmod.3 (nonexistent) +++ vendor/1.14/snmpd/snmpmod.3 (revision 359491) @@ -0,0 +1,1184 @@ +.\" +.\" Copyright (c) 2004-2005 +.\" Hartmut Brandt. +.\" All rights reserved. +.\" Copyright (c) 2001-2003 +.\" Fraunhofer Institute for Open Communication Systems (FhG Fokus). +.\" All rights reserved. +.\" +.\" Author: Harti Brandt +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $Begemot: bsnmp/snmpd/snmpmod.3,v 1.14 2005/10/04 13:30:35 brandt_h Exp $ +.\" +.Dd December 19, 2010 +.Dt SNMPMOD 3 +.Os +.Sh NAME +.Nm INSERT_OBJECT_OID_LINK_INDEX , +.Nm INSERT_OBJECT_INT_LINK_INDEX , +.Nm FIND_OBJECT_OID_LINK_INDEX , +.Nm NEXT_OBJECT_OID_LINK_INDEX , +.Nm FIND_OBJECT_INT_LINK_INDEX , +.Nm NEXT_OBJECT_INT_LINK_INDEX , +.Nm INSERT_OBJECT_OID_LINK , +.Nm INSERT_OBJECT_INT_LINK , +.Nm FIND_OBJECT_OID_LINK , +.Nm NEXT_OBJECT_OID_LINK , +.Nm FIND_OBJECT_INT_LINK , +.Nm NEXT_OBJECT_INT_LINK , +.Nm INSERT_OBJECT_OID , +.Nm INSERT_OBJECT_INT , +.Nm FIND_OBJECT_OID , +.Nm FIND_OBJECT_INT , +.Nm NEXT_OBJECT_OID , +.Nm NEXT_OBJECT_INT , +.Nm this_tick , +.Nm start_tick , +.Nm get_ticks , +.Nm systemg , +.Nm comm_define , +.Nm community , +.Nm oid_zeroDotZero , +.Nm oid_usmUnknownEngineIDs , +.Nm oid_usmNotInTimeWindows , +.Nm reqid_allocate , +.Nm reqid_next , +.Nm reqid_base , +.Nm reqid_istype , +.Nm reqid_type , +.Nm timer_start , +.Nm timer_start_repeat , +.Nm timer_stop , +.Nm fd_select , +.Nm fd_deselect , +.Nm fd_suspend , +.Nm fd_resume , +.Nm or_register , +.Nm or_unregister , +.Nm buf_alloc , +.Nm buf_size , +.Nm snmp_input_start , +.Nm snmp_input_finish , +.Nm snmp_output , +.Nm snmp_send_port , +.Nm snmp_send_trap , +.Nm snmp_pdu_auth_access +.Nm string_save , +.Nm string_commit , +.Nm string_rollback , +.Nm string_get , +.Nm string_get_max , +.Nm string_free , +.Nm ip_save , +.Nm ip_rollback , +.Nm ip_commit , +.Nm ip_get , +.Nm oid_save , +.Nm oid_rollback , +.Nm oid_commit , +.Nm oid_get , +.Nm index_decode , +.Nm index_compare , +.Nm index_compare_off , +.Nm index_append , +.Nm index_append_off , +.Nm snmpd_usmstats , +.Nm bsnmpd_get_usm_stats , +.Nm bsnmpd_reset_usm_stats , +.Nm usm_first_user , +.Nm usm_next_user , +.Nm usm_find_user , +.Nm usm_new_user , +.Nm usm_delete_user , +.Nm usm_flush_users , +.Nm usm_user , +.Nm snmpd_target_stat , +.Nm bsnmpd_get_target_stats , +.Nm target_first_address , +.Nm target_next_address , +.Nm target_new_address , +.Nm target_activate_address , +.Nm target_delete_address , +.Nm target_first_param , +.Nm target_next_param , +.Nm target_new_param , +.Nm target_delete_param , +.Nm target_first_notify , +.Nm target_next_notify , +.Nm target_new_notify , +.Nm target_delete_notify , +.Nm target_flush_all , +.Nm target_address , +.Nm target_param , +.Nm target_notify +.Nd "SNMP daemon loadable module interface" +.Sh LIBRARY +Begemot SNMP library +.Pq libbsnmp, -lbsnmp +.Sh SYNOPSIS +.In bsnmp/snmpmod.h +.Fn INSERT_OBJECT_OID_LINK_INDEX "PTR" "LIST" "LINK" "INDEX" +.Fn INSERT_OBJECT_INT_LINK_INDEX "PTR" "LIST" "LINK" "INDEX" +.Fn FIND_OBJECT_OID_LINK_INDEX "LIST" "OID" "SUB" "LINK" "INDEX" +.Fn FIND_OBJECT_INT_LINK_INDEX "LIST" "OID" "SUB" "LINK" "INDEX" +.Fn NEXT_OBJECT_OID_LINK_INDEX "LIST" "OID" "SUB" "LINK" "INDEX" +.Fn NEXT_OBJECT_INT_LINK_INDEX "LIST" "OID" "SUB" "LINK" "INDEX" +.Fn INSERT_OBJECT_OID_LINK "PTR" "LIST" "LINK" +.Fn INSERT_OBJECT_INT_LINK "PTR" "LIST" "LINK" +.Fn FIND_OBJECT_OID_LINK "LIST" "OID" "SUB" "LINK" +.Fn FIND_OBJECT_INT_LINK "LIST" "OID" "SUB" "LINK" +.Fn NEXT_OBJECT_OID_LINK "LIST" "OID" "SUB" "LINK" +.Fn NEXT_OBJECT_INT_LINK "LIST" "OID" "SUB" "LINK" +.Fn INSERT_OBJECT_OID "PTR" "LIST" +.Fn INSERT_OBJECT_INT "PTR" "LIST" +.Fn FIND_OBJECT_OID "LIST" "OID" "SUB" +.Fn FIND_OBJECT_INT "LIST" "OID" "SUB" +.Fn NEXT_OBJECT_OID "LIST" "OID" "SUB" +.Fn NEXT_OBJECT_INT "LIST" "OID" "SUB" +.Vt extern uint64_t this_tick ; +.Vt extern uint64_t start_tick ; +.Ft uint64_t +.Fn get_ticks "void" +.Vt extern struct systemg systemg ; +.Ft u_int +.Fn comm_define "u_int priv" "const char *descr" "struct lmodule *mod" "const char *str" +.Ft const char * +.Fn comm_string "u_int comm" +.Vt extern u_int community ; +.Vt extern const struct asn_oid oid_zeroDotZero ; +.Ft u_int +.Fn reqid_allocate "int size" "struct lmodule *mod" +.Ft int32_t +.Fn reqid_next "u_int type" +.Ft int32_t +.Fn reqid_base "u_int type" +.Ft int +.Fn reqid_istype "int32_t reqid" "u_int type" +.Ft u_int +.Fn reqid_type "int32_t reqid" +.Ft void * +.Fn timer_start "u_int ticks" "void (*func)(void *)" "void *uarg" "struct lmodule *mod" +.Ft void * +.Fn timer_start_repeat "u_int ticks" "u_int repeat_ticks" "void (*func)(void *)" "void *uarg" "struct lmodule *mod" +.Ft void +.Fn timer_stop "void *timer_id" +.Ft void * +.Fn fd_select "int fd" "void (*func)(int, void *)" "void *uarg" "struct lmodule *mod" +.Ft void +.Fn fd_deselect "void *fd_id" +.Ft void +.Fn fd_suspend "void *fd_id" +.Ft int +.Fn fd_resume "void *fd_id" +.Ft u_int +.Fn or_register "const struct asn_oid *oid" "const char *descr" "struct lmodule *mod" +.Ft void +.Fn or_unregister "u_int or_id" +.Ft void * +.Fn buf_alloc "int tx" +.Ft size_t +.Fn buf_size "int tx" +.Ft enum snmpd_input_err +.Fo snmp_input_start +.Fa "const u_char *buf" "size_t len" "const char *source" +.Fa "struct snmp_pdu *pdu" "int32_t *ip" "size_t *pdulen" +.Fc +.Ft enum snmpd_input_err +.Fo snmp_input_finish +.Fa "struct snmp_pdu *pdu" "const u_char *rcvbuf" +.Fa "size_t rcvlen" "u_char *sndbuf" "size_t *sndlen" "const char *source" +.Fa "enum snmpd_input_err ierr" "int32_t ip" "void *data" +.Fc +.Ft void +.Fo snmp_output +.Fa "struct snmp_pdu *pdu" "u_char *sndbuf" "size_t *sndlen" +.Fa "const char *dest" +.Fc +.Ft void +.Fo snmp_send_port +.Fa "void *trans" "const struct asn_oid *port" +.Fa "struct snmp_pdu *pdu" "const struct sockaddr *addr" "socklen_t addrlen" +.Fc +.Ft void +.Fn snmp_send_trap "const struct asn_oid *oid" "..." +.Ft enum snmp_code +.Fn snmp_pdu_auth_access "struct snmp_pdu *pdu" "int32_t *ip" +.Ft int +.Fn string_save "struct snmp_value *val" "struct snmp_context *ctx" "ssize_t req_size" "u_char **strp" +.Ft void +.Fn string_commit "struct snmp_context *ctx" +.Ft void +.Fn string_rollback "struct snmp_context *ctx" "u_char **strp" +.Ft int +.Fn string_get "struct snmp_value *val" "const u_char *str" "ssize_t len" +.Ft int +.Fn string_get_max "struct snmp_value *val" "const u_char *str" "ssize_t len" "size_t maxlen" +.Ft void +.Fn string_free "struct snmp_context *ctx" +.Ft int +.Fn ip_save "struct snmp_value *val" "struct snmp_context *ctx" "u_char *ipa" +.Ft void +.Fn ip_rollback "struct snmp_context *ctx" "u_char *ipa" +.Ft void +.Fn ip_commit "struct snmp_context *ctx" +.Ft int +.Fn ip_get "struct snmp_value *val" "u_char *ipa" +.Ft int +.Fn oid_save "struct snmp_value *val" "struct snmp_context *ctx" "struct asn_oid *oid" +.Ft void +.Fn oid_rollback "struct snmp_context *ctx" "struct asn_oid *oid" +.Ft void +.Fn oid_commit "struct snmp_context *ctx" +.Ft int +.Fn oid_get "struct snmp_value *val" "const struct asn_oid *oid" +.Ft int +.Fn index_decode "const struct asn_oid *oid" "u_int sub" "u_int code" "..." +.Ft int +.Fn index_compare "const struct asn_oid *oid1" "u_int sub" "const struct asn_oid *oid2" +.Ft int +.Fn index_compare_off "const struct asn_oid *oid1" "u_int sub" "const struct asn_oid *oid2" "u_int off" +.Ft void +.Fn index_append "struct asn_oid *dst" "u_int sub" "const struct asn_oid *src" +.Ft void +.Fn index_append_off "struct asn_oid *dst" "u_int sub" "const struct asn_oid *src" "u_int off" +.Vt extern struct snmpd_usmstat snmpd_usmstats ; +.Ft struct snmpd_usmstat * +.Fn bsnmpd_get_usm_stats "void" +.Ft void +.Fn bsnmpd_reset_usm_stats "void" +.Ft struct usm_user * +.Fn usm_first_user "void" +.Ft struct usm_user * +.Fn usm_next_user "struct usm_user *uuser" +.Ft struct usm_user * +.Fn usm_find_user "uint8_t *engine" "uint32_t elen" "char *uname" +.Ft struct usm_user * +.Fn usm_new_user "uint8_t *engine" "uint32_t elen" "char *uname" +.Ft void +.Fn usm_delete_user "struct usm_user *" +.Ft void +.Fn usm_flush_users "void" +.Vt extern struct usm_user *usm_user; +.Ft struct snmpd_target_stats * +.Fn bsnmpd_get_target_stats "void" +.Ft struct target_address * +.Fn target_first_address "void" +.Ft struct target_address * +.Fn target_next_address "struct target_address *" +.Ft struct target_address * +.Fn target_new_address "char *" +.Ft int +.Fn target_activate_address "struct target_address *" +.Ft int +.Fn target_delete_address "struct target_address *" +.Ft struct target_param * +.Fn target_first_param "void" +.Ft struct target_param * +.Fn target_next_param "struct target_param *" +.Ft struct target_param * +.Fn target_new_param "char *" +.Ft int +.Fn target_delete_param "struct target_param *" +.Ft struct target_notify * +.Fn target_first_notify "void" +.Ft struct target_notify * +.Fn target_next_notify "struct target_notify *" +.Ft struct target_notify * +.Fn target_new_notify "char *" +.Ft int +.Fn target_delete_notify "struct target_notify *" +.Ft void +.Fn target_flush_all "void" +.Vt extern const struct asn_oid oid_usmUnknownEngineIDs; +.Vt extern const struct asn_oid oid_usmNotInTimeWindows; +.Sh DESCRIPTION +The +.Xr bsnmpd 1 +SNMP daemon implements a minimal MIB which consists of the system group, part +of the SNMP MIB, a private configuration MIB, a trap destination table, a +UDP port table, a community table, a module table, a statistics group and +a debugging group. +All other MIBs are support through loadable modules. +This allows +.Xr bsnmpd 1 +to use for task, that are not the classical SNMP task. +.Ss MODULE LOADING AND UNLOADING +Modules are loaded by writing to the module table. +This table is indexed by a string, that identifies the module to the daemon. +This identifier is used +to select the correct configuration section from the configuration files and +to identify resources allocated to this module. +A row in the module table is +created by writing a string of non-zero length to the +.Va begemotSnmpdModulePath +column. +This string must be the complete path to the file containing the module. +A module can be unloaded by writing a zero length string to the path column +of an existing row. +.Pp +Modules may depend on each other an hence must be loaded in the correct order. +The dependencies are listed in the corresponding manual pages. +.Pp +Upon loading a module the SNMP daemon expects the module file to a export +a global symbol +.Va config . +This symbol should be a variable of type +.Vt struct snmp_module : +.Bd -literal -offset indent +typedef enum snmpd_proxy_err (*proxy_err_f)(struct snmp_pdu *, void *, + const struct asn_oid *, const struct sockaddr *, socklen_t, + enum snmpd_input_err, int32_t); + + +struct snmp_module { + const char *comment; + int (*init)(struct lmodule *, int argc, char *argv[]); + int (*fini)(void); + void (*idle)(void); + void (*dump)(void); + void (*config)(void); + void (*start)(void); + proxy_err_f proxy; + const struct snmp_node *tree; + u_int tree_size; + void (*loading)(const struct lmodule *, int); +}; +.Ed +.Pp +This structure must be statically initialized and its fields have the +following functions: +.Bl -tag -width ".It Va tree_size" +.It Va comment +This is a string that will be visible in the module table. +It should give some hint about the function of this module. +.It Va init +This function is called upon loading the module. +The module pointer should +be stored by the module because it is needed in other calls and the +argument vector will contain the arguments to this module from the daemons +command line. +This function should return 0 if everything is ok or an UNIX error code (see +.Xr errno 3 ) . +Once the function returns 0, the +.Va fini +function is called when the module is unloaded. +.It Va fini +The module is unloaded. +This gives the module a chance to free resources that +are not automatically freed. +Be sure to free all memory, because daemons tend to run very long. +This function pointer may be +.Li NULL +if it is not needed. +.It Va idle +If this function pointer is not +.Li NULL , +the function pointed to by it is called whenever the daemon is going +to wait for an event. +Try to avoid using this feature. +.It Va dump +Whenever the daemon receives a +.Li SIGUSR1 +it dumps it internal state via +.Xr syslog 3 . +If the +.Va dump +field is not +.Li NULL +it is called by the daemon to dump the state of the module. +.It Va config +Whenever the daemon receives a +.Li SIGHUP +signal it re-reads its configuration file. +If the +.Va config +field is not +.Li NULL +it is called after reading the configuration file to give the module a chance +to adapt to the new configuration. +.It Va start +If not +.Li NULL +this function is called after successful loading and initializing the module +to start its actual operation. +.It Va proxy +If the daemon receives a PDU and that PDU has a community string whose +community was registered by this module and +.Va proxy +is not +.Li NULL +than this function is called to handle the PDU. +.It Va tree +This is a pointer to the node array for the MIB tree implemented by this module. +.It Va tree_size +This is the number of nodes in +.Va tree . +.It Va loading +If this pointer is not +.Li NULL +it is called whenever another module was loaded or unloaded. +It gets a +pointer to that module and a flag that is 0 for unloading and 1 for loading. +.El +.Pp +When everything is ok, the daemon merges the module's MIB tree into its current +global tree, calls the modules +.Fn init +function. +If this function returns an error, the modules MIB tree is removed from +the global one and the module is unloaded. +If initialization is successful, the modules +.Fn start +function is called. +After it returns the +.Fn loaded +functions of all modules (including the loaded one) are called. +.Pp +When the module is unloaded, its MIB tree is removed from the global one, +the communities, request id ranges, running timers and selected file +descriptors are released, the +.Fn fini +function is called, the module file is unloaded and the +.Fn loaded +functions of all other modules are called. +.Ss IMPLEMENTING TABLES +There are a number of macros designed to help implementing SNMP tables. +A problem while implementing a table is the support for the GETNEXT operator. +The GETNEXT operation has to find out whether, given an arbitrary OID, the +lessest table row, that has an OID higher than the given OID. +The easiest way +to do this is to keep the table as an ordered list of structures each one +of which contains an OID that is the index of the table row. +This allows easy removal, insertion and search. +.Pp +The helper macros assume, that the table is organized as a TAILQ (see +.Xr queue 3 +and each structure contains a +.Vt struct asn_oid +that is used as index. +For simple tables with only a integer or unsigned index, an alternate form +of the macros is available, that presume the existence of an integer or +unsigned field as index field. +.Pp +The macros have name of the form +.Bd -literal -offset indent +{INSERT,FIND,NEXT}_OBJECT_{OID,INT}[_LINK[_INDEX]] +.Ed +.Pp +The +.Fn INSERT_* +macros are used in the SET operation to insert a new table row into the table. +The +.Fn FIND_* +macros are used in the GET operation to find a specific row in the table. +The +.Fn NEXT_* +macros are used in the GETNEXT operation to find the next row in the table. +The last two macros return a pointer to the row structure if a row is found, +.Li NULL +otherwise. +The macros +.Fn *_OBJECT_OID_* +assume the existence of a +.Vt struct asn_oid +that is used as index, the macros +.Fn *_OBJECT_INT_* +assume the existence of an unsigned integer field that is used as index. +.Pp +The macros +.Fn *_INDEX +allow the explicit naming of the index field in the parameter +.Fa INDEX , +whereas the other macros assume that this field is named +.Va index . +The macros +.Fn *_LINK_* +allow the explicit naming of the link field of the tail queues, the others +assume that the link field is named +.Va link . +Explicitly naming the link field may be necessary if the same structures +are held in two or more different tables. +.Pp +The arguments to the macros are as follows: +.Bl -tag -width "INDEX" +.It Fa PTR +A pointer to the new structure to be inserted into the table. +.It Fa LIST +A pointer to the tail queue head. +.It Fa LINK +The name of the link field in the row structure. +.It Fa INDEX +The name of the index field in the row structure. +.It Fa OID +Must point to the +.Va var +field of the +.Fa value +argument to the node operation callback. +This is the OID to search for. +.It Fa SUB +This is the index of the start of the table index in the OID pointed to +by +.Fa OID . +This is usually the same as the +.Fa sub +argument to the node operation callback. +.El +.Ss DAEMON TIMESTAMPS +The variable +.Va this_tick +contains the tick (there are 100 SNMP ticks in a second) when +the current PDU processing was started. +The variable +.Va start_tick +contains the tick when the daemon was started. +The function +.Fn get_ticks +returns the current tick. +The number of ticks since the daemon was started +is +.Bd -literal -offset indent +get_ticks() - start_tick +.Ed +.Ss THE SYSTEM GROUP +The scalar fields of the system group are held in the global variable +.Va systemg : +.Bd -literal -offset indent +struct systemg { + u_char *descr; + struct asn_oid object_id; + u_char *contact; + u_char *name; + u_char *location; + uint32_t services; + uint32_t or_last_change; +}; +.Ed +.Ss COMMUNITIES +The SNMP daemon implements a community table. +On recipte of a request message +the community string in that message is compared to each of the community +strings in that table, if a match is found, the global variable +.Va community +is set to the community identifier for that community. +Community identifiers are unsigned integers. +For the three standard communities there are three constants defined: +.Bd -literal -offset indent +#define COMM_INITIALIZE 0 +#define COMM_READ 1 +#define COMM_WRITE 2 +.Ed +.Pp +.Va community +is set to +.Li COMM_INITIALIZE +while the assignments in the configuration file are processed. +To +.Li COMM_READ +or +.Li COMM_WRITE +when the community strings for the read-write or read-only community are found +in the incoming PDU. +.Pp +Modules can define additional communities. +This may be necessary to provide +transport proxying (a PDU received on one communication link is proxied to +another link) or to implement non-UDP access points to SNMP. +A new community is defined with the function +.Fn comm_define . +It takes the following parameters: +.Bl -tag -width ".It Fa descr" +.It Fa priv +This is an integer identifying the community to the module. +Each module has its own namespace with regard to this parameter. +The community table is indexed with the module name and this identifier. +.It Fa descr +This is a string providing a human readable description of the community. +It is visible in the community table. +.It Fa mod +This is the module defining the community. +.It Fa str +This is the initial community string. +.El +.Pp +The function returns a globally unique community identifier. +If a SNMPv1 or SNMPv2 PDU is +received who's community string matches, this identifier is set into the global +.Va community . +.Pp +The function +.Fn comm_string +returns the current community string for the given community. +.Pp +All communities defined by a module are automatically released when the module +is unloaded. +.Ss THE USER-BASED SECURITY GROUP +The scalar statistics of the USM group are held in the global variable +.Va snmpd_usmstats : +.Bd -literal -offset indent +struct snmpd_usmstat { + uint32_t unsupported_seclevels; + uint32_t not_in_time_windows; + uint32_t unknown_users; + uint32_t unknown_engine_ids; + uint32_t wrong_digests; + uint32_t decrypt_errors; +}; +.Ed +.Fn bsnmpd_get_usm_stats +returns a pointer to the global structure containing the statistics. +.Fn bsnmpd_reset_usm_stats +clears the statistics of the USM group. +.Pp +A global list of configured USM users is maintained by the daemon. +.Bd -literal -offset indent +struct usm_user { + struct snmp_user suser; + uint8_t user_engine_id[SNMP_ENGINE_ID_SIZ]; + uint32_t user_engine_len; + char user_public[SNMP_ADM_STR32_SIZ]; + uint32_t user_public_len; + int32_t status; + int32_t type; + SLIST_ENTRY(usm_user) up; +}; +.Ed +This structure represents an USM user. The daemon only responds to SNMPv3 PDUs +with user credentials matching an USM user entry in its global list. +If a SNMPv3 PDU is received, whose security model is USM, the global +.Va usm_user +is set to point at the user entry that matches the credentials contained in +the PDU. +However, the daemon does not create or remove USM users, it gives an interface +to external loadable module(s) to manage the list. +.Fn usm_new_user +adds an user entry in the list, and +.Fn usm_delete_user +deletes an existing entry from the list. +.Fn usm_flush_users +is used to remove all configured USM users. +.Fn usm_first_user +will return the first user in the list, or +.Li NULL +if the list is empty. +.Fn usm_next_user +will return the next user of a given entry if one exists, or +.Li NULL . +The list is sorted according to the USM user name and Engine ID. +.Fn usm_find_user +returns the USM user entry matching the given +.Fa engine +and +.Fa uname +or +.Li NULL +if an user with the specified name and engine id is not present in the list. +.Ss THE MANAGEMENT TARGET GROUP +The Management Target group holds target address information used when sending +SNMPv3 notifications. +.Pp +The scalar statistics of the Management Target group are held in the global +variable +.Va snmpd_target_stats : +.Bd -literal -offset indent +struct snmpd_target_stats { + uint32_t unavail_contexts; + uint32_t unknown_contexts; +}; +.Ed +.Fn bsnmpd_get_target_stats +returns a pointer to the global structure containing the statistics. +.Pp +Three global lists of configured management target addresses, parameters and +notifications respectively are maintained by the daemon. +.Bd -literal -offset indent +struct target_address { + char name[SNMP_ADM_STR32_SIZ]; + uint8_t address[SNMP_UDP_ADDR_SIZ]; + int32_t timeout; + int32_t retry; + char taglist[SNMP_TAG_SIZ]; + char paramname[SNMP_ADM_STR32_SIZ]; + int32_t type; + int32_t socket; + int32_t status; + SLIST_ENTRY(target_address) ta; +}; +.Ed +This structure represents a SNMPv3 Management Target address. Each time a SNMP +TRAP is send the daemon will send the Trap to all active Management Target +addresses in its global list. +.Bd -literal -offset indent +struct target_param { + char name[SNMP_ADM_STR32_SIZ]; + int32_t mpmodel; + int32_t sec_model; + char secname[SNMP_ADM_STR32_SIZ]; + enum snmp_usm_level sec_level; + int32_t type; + int32_t status; + SLIST_ENTRY(target_param) tp; +}; +.Ed +This structure represents the information used to generate SNMP messages to the +associated SNMPv3 Management Target addresses. +.Bd -literal -offset indent +struct target_notify { + char name[SNMP_ADM_STR32_SIZ]; + char taglist[SNMP_TAG_SIZ]; + int32_t notify_type; + int32_t type; + int32_t status; + SLIST_ENTRY(target_notify) tn; +}; +.Ed +This structure represents Notification Tag entries - SNMP notifications are sent +to the Target address for each entry in the Management Target Address list that +has a tag matching the specified tag in this structure. +.Pp +The daemon does not create or remove entries in the Management Target group +lists, it gives an interface to external loadable module(s) to manage the lists. +.Fn target_new_address +adds a target address entry, and +.Fn target_delete_address +deletes an existing entry from the target address list. +.Fn target_activate_address +creates a socket associated with the target address entry so that SNMP +notifications may actually be send to that target address. +.Fn target_first_address +will return a pointer to the first target address entry in the list, while +.Fn target_next_address +will return a pointer to the next target address of a given entry if one exists. +.Fn target_new_param +adds a target parameters' entry, and +.Fn target_delete_param +deletes an existing entry from the target parameters list. +.Fn target_first_param +will return a pointer to the first target parameters' entry in the list, while +.Fn target_next_param +will return a pointer to the next target parameters of a given entry if one +exists. +.Fn target_new_notify +adds a notification target entry, and +.Fn target_delete_notify +deletes an existing entry from the notification target list. +.Fn target_first_notify +will return a pointer to the first notification target entry in the list, while +.Fn target_next_notify +will return a pointer to the next notification target of a given entry if one +exists. +.Fn target_flush_all +is used to remove all configured data from the three global Management Target +Group lists. +.Ss WELL KNOWN OIDS +The global variable +.Va oid_zeroDotZero +contains the OID 0.0. +The global variables +.Va oid_usmUnknownEngineIDs +.Va oid_usmNotInTimeWindows +contains the OIDs 1.3.6.1.6.3.15.1.1.4.0 and 1.3.6.1.6.3.15.1.1.2.0 used +in the SNMPv3 USM Engine Discovery. +.Ss REQUEST ID RANGES +For modules that implement SNMP client functions besides SNMP agent functions +it may be necessary to identify SNMP requests by their identifier to allow +easier routing of responses to the correct sub-system. +Request id ranges +provide a way to acquire globally non-overlapping sub-ranges of the entire +31-bit id range. +.Pp +A request id range is allocated with +.Fn reqid_allocate . +The arguments are: the size of the range and the module allocating the range. +For example, the call +.Bd -literal -offset indent +id = reqid_allocate(1000, module); +.Ed +.Pp +allocates a range of 1000 request ids. +The function returns the request +id range identifier or 0 if there is not enough identifier space. +The function +.Fn reqid_base +returns the lowest request id in the given range. +.Pp +Request id are allocated starting at the lowest one linear throughout the range. +If the client application may have a lot of outstanding request the range +must be large enough so that an id is not reused until it is really expired. +.Fn reqid_next +returns the sequentially next id in the range. +.Pp +The function +.Fn reqid_istype +checks whether the request id +.Fa reqid +is within the range identified by +.Fa type . +The function +.Fn reqid_type +returns the range identifier for the given +.Fa reqid +or 0 if the request id is in none of the ranges. +.Ss TIMERS +The SNMP daemon supports an arbitrary number of timers with SNMP tick granularity. +The function +.Fn timer_start +arranges for the callback +.Fa func +to be called with the argument +.Fa uarg +after +.Fa ticks +SNMP ticks have expired. +.Fa mod +is the module that starts the timer. +These timers are one-shot, they are not restarted. +Repeatable timers are started with +.Fn timer_start_repeat +which takes an additional argument +.Fa repeat_ticks . +The argument +.Fa ticks +gives the number of ticks until the first execution of the callback, while +.Fa repeat_ticks +is the number of ticks between invocations of the callback. +Note, that currently the number of initial ticks silently may be set identical +to the number of ticks between callback invocations. +The function returns a timer identifier that can be used to stop the timer via +.Fn timer_stop . +If a module is unloaded all timers started by the module that have not expired +yet are stopped. +.Ss FILE DESCRIPTOR SUPPORT +A module may need to get input from socket file descriptors without blocking +the daemon (for example to implement alternative SNMP transports). +.Pp +The function +.Fn fd_select +causes the callback function +.Fa func +to be called with the file descriptor +.Fa fd +and the user argument +.Fa uarg +whenever the file descriptor +.Fa fd +can be read or has a close condition. +If the file descriptor is not in +non-blocking mode, it is set to non-blocking mode. +If the callback is not needed anymore, +.Fn fd_deselect +may be called with the value returned from +.Fn fd_select . +All file descriptors selected by a module are automatically deselected when +the module is unloaded. +.Pp +To temporarily suspend the file descriptor registration +.Fn fd_suspend +can be called. +This also causes the file descriptor to be switched back to +blocking mode if it was blocking prior the call to +.Fn fd_select . +This is necessary to do synchronous input on a selected socket. +The effect of +.Fn fd_suspend +can be undone with +.Fn fd_resume . +.Ss OBJECT RESOURCES +The system group contains an object resource table. +A module may create an entry in this table by calling +.Fn or_register +with the +.Fa oid +to be registered, a textual description in +.Fa str +and a pointer to the module +.Fa mod . +The registration can be removed with +.Fn or_unregister . +All registrations of a module are automatically removed if the module is +unloaded. +.Ss TRANSMIT AND RECEIVE BUFFERS +A buffer is allocated via +.Fn buf_alloc . +The argument must be 1 for transmit and 0 for receive buffers. +The function may return +.Li NULL +if there is no memory available. +The current buffersize can be obtained with +.Fn buf_size . +.Sh PROCESSING PDUS +For modules that need to do their own PDU processing (for example for proxying) +the following functions are available: +.Pp +Function +.Fn snmp_input_start +decodes the PDU, searches the community, and sets the global +.Va this_tick . +It returns one of the following error codes: +.Bl -tag -width ".It Er SNMPD_INPUT_VALBADLEN" +.It Er SNMPD_INPUT_OK +Everything ok, continue with processing. +.It Er SNMPD_INPUT_FAILED +The PDU could not be decoded, has a wrong version or an unknown +community string. +.It Er SNMPD_INPUT_VALBADLEN +A SET PDU had a value field in a binding with a wrong length field in an +ASN.1 header. +.It Er SNMPD_INPUT_VALRANGE +A SET PDU had a value field in a binding with a value that is out of range +for the given ASN.1 type. +.It Er SNMPD_INPUT_VALBADENC +A SET PDU had a value field in a binding with wrong ASN.1 encoding. +.It Er SNMPD_INPUT_TRUNC +The buffer appears to contain a valid begin of a PDU, but is too short. +For streaming transports this means that the caller must save what he +already has and trying to obtain more input and reissue this input to +the function. +For datagram transports this means that part of the +datagram was lost and the input should be ignored. +.El +.Pp +The function +.Fn snmp_input_finish +does the other half of processing: if +.Fn snmp_input_start +did not return OK, tries to construct an error response. +If the start was OK, it calls the correct function from +.Xr bsnmpagent 3 +to execute the request and depending on the outcome constructs a response or +error response PDU or ignores the request PDU. +It returns either +.Er SNMPD_INPUT_OK +or +.Er SNMPD_INPUT_FAILED . +In the first case a response PDU was constructed and should be sent. +.Pp +The function +.Fn snmp_output +takes a PDU and encodes it. +.Pp +The function +.Fn snmp_send_port +takes a PDU, encodes it and sends it through the given port (identified by +the transport and the index in the port table) to the given address. +.Pp +The function +.Fn snmp_send_trap +sends a trap to all trap destinations. +The arguments are the +.Fa oid +identifying the trap and a NULL-terminated list of +.Vt struct snmp_value +pointers that are to be inserted into the trap binding list. +.Fn snmp_pdu_auth_access +verifies whether access to the object IDs contained in the +.Fa pdu + should be granted or denied, according to the configured View-Based Access +rules. +.Fa ip +contains the index of the first varbinding to which access was denied, or 0 if +access to all varbindings in the PDU is granted. +.Ss SIMPLE ACTION SUPPORT +For simple scalar variables that need no dependencies a number of support +functions is available to handle the set, commit, rollback and get. +.Pp +The following functions are used for OCTET STRING scalars, either NUL terminated +or not: +.Bl -tag -width "XXXXXXXXX" +.It Fn string_save +should be called for SNMP_OP_SET. +.Fa value +and +.Fa ctx +are the resp\&.\& arguments to the node callback. +.Fa valp +is a pointer to the pointer that holds the current value and +.Fa req_size +should be -1 if any size of the string is acceptable or a number larger or +equal zero if the string must have a specific size. +The function saves +the old value in the scratch area (note, that any initial value must have +been allocated by +.Xr malloc 3 ) , +allocates a new string, copies over the new value, NUL-terminates it and +sets the new current value. +.It Fn string_commit +simply frees the saved old value in the scratch area. +.It Fn string_rollback +frees the new value, and puts back the old one. +.It Fn string_get +is used for GET or GETNEXT. +The function +.It Fn string_get_max +can be used instead of +.Fn string_get +to ensure that the returned string has a certain maximum length. +If +.Fa len +is -1, the length is computed via +.Xr strlen 3 +from the current string value. +If the current value is NULL, +a OCTET STRING of zero length is returned. +.It Fn string_free +must be called if either rollback or commit fails to free the saved old value. +.El +.Pp +The following functions are used to process scalars of type IP-address: +.Bl -tag -width "XXXXXXXXX" +.It Fn ip_save +Saves the current value in the scratch area and sets the new value from +.Fa valp . +.It Fn ip_commit +Does nothing. +.It Fn ip_rollback +Restores the old IP address from the scratch area. +.It Fn ip_get +Retrieves the IP current address. +.El +.Pp +The following functions handle OID-typed variables: +.Bl -tag -width "XXXXXXXXX" +.It Fn oid_save +Saves the current value in the scratch area by allocating a +.Vt struct asn_oid +with +.Xr malloc 3 +and sets the new value from +.Fa oid . +.It Fn oid_commit +Frees the old value in the scratch area. +.It Fn oid_rollback +Restores the old OID from the scratch area and frees the old OID. +.It Fn oid_get +Retrieves the OID +.El +.Ss TABLE INDEX HANDLING +The following functions help in handling table indexes: +.Bl -tag -width "XXXXXXXXX" +.It Fn index_decode +Decodes the index part of the OID. +The parameter +.Fa oid +must be a pointer to the +.Va var +field of the +.Fa value +argument of the node callback. +The +.Fa sub +argument must be the index of the start of the index in the OID (this is +the +.Fa sub +argument to the node callback). +.Fa code +is the index expression (parameter +.Fa idx +to the node callback). +These parameters are followed by parameters depending on the syntax of the index +elements as follows: +.Bl -tag -width ".It Li OCTET STRING" +.It Li INTEGER +.Vt int32_t * +expected as argument. +.It Li COUNTER64 +.Vt uint64_t * +expected as argument. +Note, that this syntax is illegal for indexes. +.It Li OCTET STRING +A +.Vt u_char ** +and a +.Vt size_t * +expected as arguments. +A buffer is allocated to hold the decoded string. +.It Li OID +A +.Vt struct asn_oid * +is expected as argument. +.It Li IP ADDRESS +A +.Vt u_int8_t * +expected as argument that points to a buffer of at least four byte. +.It Li COUNTER, GAUGE, TIMETICKS +A +.Vt u_int32_t +expected. +.It Li NULL +No argument expected. +.El +.It Fn index_compare +compares the current variable with an OID. +.Fa oid1 +and +.Fa sub +come from the node callback arguments +.Fa value->var +and +.Fa sub +resp. +.Fa oid2 +is the OID to compare to. +The function returns -1, 0, +1 when the +variable is lesser, equal, higher to the given OID. +.Fa oid2 +must contain only the index part of the table column. +.It Fn index_compare_off +is equivalent to +.Fn index_compare +except that it takes an additional parameter +.Fa off +that causes it to ignore the first +.Fa off +components of both indexes. +.It Fn index_append +appends OID +.Fa src +beginning at position +.Fa sub +to +.Fa dst . +.It Fn index_append_off +appends OID +.Fa src +beginning at position +.Fa off +to +.Fa dst +beginning at position +.Fa sub ++ +.Fa off . +.El +.Sh SEE ALSO +.Xr gensnmptree 1 , +.Xr bsnmpd 1 , +.Xr bsnmpagent 3 , +.Xr bsnmpclient 3 , +.Xr bsnmplib 3 +.Sh STANDARDS +This implementation conforms to the applicable IETF RFCs and ITU-T +recommendations. +.Sh AUTHORS +.An Hartmut Brandt Aq harti@FreeBSD.org Property changes on: vendor/1.14/snmpd/snmpmod.3 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmpd/trans_lsock.h =================================================================== --- vendor/1.14/snmpd/trans_lsock.h (nonexistent) +++ vendor/1.14/snmpd/trans_lsock.h (revision 359491) @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmpd/trans_lsock.h,v 1.3 2004/08/06 08:47:15 brandt Exp $ + * + * Local domain socket transport + */ + +enum locp { + LOCP_DGRAM_UNPRIV = 1, + LOCP_DGRAM_PRIV = 2, + LOCP_STREAM_UNPRIV = 3, + LOCP_STREAM_PRIV = 4, +}; +struct lsock_peer { + LIST_ENTRY(lsock_peer) link; + struct port_input input; + struct sockaddr_un peer; + struct lsock_port *port; /* parent port */ +}; + +struct lsock_port { + struct tport tport; /* must begin with this */ + + char *name; /* unix path name */ + enum locp type; /* type of port */ + + int str_sock; /* stream socket */ + void *str_id; /* select handle */ + + LIST_HEAD(, lsock_peer) peers; +}; + +extern const struct transport_def lsock_trans; Property changes on: vendor/1.14/snmpd/trans_lsock.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/snmpd/trans_udp.h =================================================================== --- vendor/1.14/snmpd/trans_udp.h (nonexistent) +++ vendor/1.14/snmpd/trans_udp.h (revision 359491) @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2003 + * Fraunhofer Institute for Open Communication Systems (FhG Fokus). + * All rights reserved. + * + * Author: Harti Brandt + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $Begemot: bsnmp/snmpd/trans_udp.h,v 1.3 2004/08/06 08:47:16 brandt Exp $ + * + * UDP transport + */ +struct udp_port { + struct tport tport; /* must begin with this */ + + uint8_t addr[4]; /* host byteorder */ + uint16_t port; /* host byteorder */ + + struct port_input input; /* common input stuff */ + + struct sockaddr_in ret; /* the return address */ + + bool recvdstaddr; /* IP_RECVDSTADDR is on */ + struct in_addr dstaddr; /* address the request was sent to */ +}; + +/* argument for open call */ +struct udp_open { + uint8_t addr[4]; /* host byteorder */ + uint16_t port; /* host byteorder */ +}; + +extern const struct transport_def udp_trans; Property changes on: vendor/1.14/snmpd/trans_udp.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Index: vendor/1.14/tests/asn1.cc =================================================================== --- vendor/1.14/tests/asn1.cc (nonexistent) +++ vendor/1.14/tests/asn1.cc (revision 359491) @@ -0,0 +1,1041 @@ +/* + * Copyright (c) 2020 + * Hartmut Brandt + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * :se ts=4 + */ + +#include "constbuf.h" + +extern "C" { +#include "asn1.h" +} + +#include "catch.hpp" + +#include +#include +#include +#include +#include +#include + +using namespace test::literals; + +template +static std::enable_if_t, asn_buf> +mk_asn_buf(const T &b) +{ + asn_buf abuf; + + abuf.asn_cptr = b.data(); + abuf.asn_len = b.size(); + + return abuf; +} + +static asn_buf +mk_asn_buf(asn_len_t len) +{ + asn_buf abuf; + + abuf.asn_ptr = new u_char[len]; + abuf.asn_len = len; + + return abuf; +} + +static std::string g_errstr; + +static void +save_g_errstr(const struct asn_buf *b, const char *fmt, ...) +{ + va_list ap; + + char sbuf[20000]; + va_start(ap, fmt); + vsprintf(sbuf, fmt, ap); + va_end(ap); + + if (b != NULL) { + strcat(sbuf, " at"); + for (u_int i = 0; b->asn_len > i; i++) + sprintf(sbuf + strlen(sbuf), " %02x", b->asn_cptr[i]); + } + strcat(sbuf, "\n"); + + g_errstr = sbuf; +} + +/** + * Encapsulate an ASN.1 parse buffer and the parse header fields. + * Constructing parses the header. + */ +struct Asn_value +{ + /** parse buffer */ + struct asn_buf buf; + + /** error from header parsing */ + asn_err err; + + /** ASN.1 tag byte */ + uint8_t type; + + /** value length */ + asn_len_t alen; + + /** + * Construct a parse buffer and parse the header. + * + * \tparam Tbuf input buffer type + * + * \param ibuf input buffer + */ + template + explicit + Asn_value(const Tbuf &ibuf) + : buf {mk_asn_buf(ibuf)}, err {asn_get_header(&buf, &type, &alen)} + { + } +}; + +/** + * Parse the ASN.1 header and check the error code. If the error is not + * ASN_ERR_OK then check the error string. + * + * \tparam Tbuf input buffer type + * + * \param buf input buffer + * \param err expected error code (default ASN_ERR_OK) + * \param errstr expected error string (default empty) + * + * \return the parse buffer + */ +template +static auto +check_header(const Tbuf &buf, asn_err err = ASN_ERR_OK, + std::string_view errstr = {}) +{ + g_errstr.clear(); + auto r = Asn_value(buf); + REQUIRE(r.err == err); + if (r.err != ASN_ERR_OK) + REQUIRE(g_errstr == errstr); + else + REQUIRE(g_errstr == ""); + return r; +} + +/** + * Parse the ASN.1 header and expect it not to fail. The check the tag. + * + * \tparam Tbuf input buffer type + * + * \param buf input buffer + * \param tag expected type tag + * + * \return the parse buffer + */ +template +static auto +check_header(const Tbuf &buf, uint8_t type) +{ + auto r = check_header(buf); + REQUIRE(r.type == type); + return r; +} + +/** + * Parse the ASN.1 header and expect it not to fail. The check the tag and + * the length. + * + * \tparam Tbuf input buffer type + * + * \param buf input buffer + * \param tag expected type tag + * \param alen expected value length + * + * \return the parse buffer + */ +template +static auto +check_header(const Tbuf &buf, uint8_t type, asn_len_t alen) +{ + auto r = check_header(buf); + REQUIRE(r.type == type); + REQUIRE(r.alen == alen); + return r; +} + +template +static void +check_buf(const asn_buf &s, const Tbuf &exp, bool print = false) +{ + if (print) { + for (auto c : exp) + std::printf(":%02x", c); + std::printf("\n"); + + for (size_t i = 0; i < size(exp); i++) + std::printf(":%02x", s.asn_ptr[i]); + std::printf("\n"); + } + REQUIRE(std::equal(begin(exp), end(exp), s.asn_ptr)); +} + +TEST_CASE("ASN.1 header parsing", "[asn1][parse]") +{ + asn_error = save_g_errstr; + + SECTION("empty buffer") { + check_header(std::vector{}, ASN_ERR_EOBUF, + "no identifier for header at\n"); + } + SECTION("tag too large") { + check_header("x1f:06:01:7f"_cbuf, ASN_ERR_FAILED, + "tags > 0x1e not supported (0x1f) at 1f 06 01 7f\n"); + } + SECTION("no length field") { + check_header("x46"_cbuf, ASN_ERR_EOBUF, "no length field at\n"); + } + SECTION("indefinite length") { + check_header("x46:80:02:04:06"_cbuf, ASN_ERR_FAILED, + "indefinite length not supported at 02 04 06\n"); + } + SECTION("long length") { + check_header("x46:83:00:00:02:7f:12"_cbuf, ASN_ERR_FAILED, + "long length too long (3) at 00 00 02 7f 12\n"); + } + SECTION("truncated length field") { + check_header("x46:82:00"_cbuf, ASN_ERR_EOBUF, + "long length truncated at 00\n"); + } + SECTION("correct long length") { + check_header("x04:81:00"_cbuf, ASN_TYPE_OCTETSTRING, 0); +#ifndef BOGUS_CVE_2019_5610_FIX + check_header("x04:81:04:00"_cbuf, ASN_TYPE_OCTETSTRING, 4); + check_header("x04:81:ff:00"_cbuf, ASN_TYPE_OCTETSTRING, 255); +#endif + check_header("x04:82:00:00"_cbuf, ASN_TYPE_OCTETSTRING, 0); +#ifndef BOGUS_CVE_2019_5610_FIX + check_header("x04:82:00:80"_cbuf, ASN_TYPE_OCTETSTRING, 128); + check_header("x04:82:01:80"_cbuf, ASN_TYPE_OCTETSTRING, 384); + check_header("x04:82:ff:ff"_cbuf, ASN_TYPE_OCTETSTRING, 65535); +#endif + } + SECTION("short length") { + check_header("x04:00:00"_cbuf, ASN_TYPE_OCTETSTRING, 0); + check_header("x04:01:00"_cbuf, ASN_TYPE_OCTETSTRING, 1); +#ifndef BOGUS_CVE_2019_5610_FIX + check_header("x04:40:00"_cbuf, ASN_TYPE_OCTETSTRING, 64); + check_header("x04:7f:00"_cbuf, ASN_TYPE_OCTETSTRING, 127); +#endif + } +} + +TEST_CASE("ASN.1 header building", "[asn1][build]") +{ + asn_error = save_g_errstr; + + const auto conv_err = [] (asn_len_t alen, asn_len_t vlen, uint8_t type, + asn_err err, std::string_view errstr) { + auto b = mk_asn_buf(alen); + g_errstr.clear(); + REQUIRE(asn_put_header(&b, type, vlen) == err); + REQUIRE(g_errstr == errstr); + }; + + const auto conv = [] (asn_len_t alen, asn_len_t vlen, uint8_t type, + const auto &cbuf) { + auto b = mk_asn_buf(alen); + auto t = b; + REQUIRE(asn_put_header(&b, type, vlen) == ASN_ERR_OK); + REQUIRE(b.asn_len == (size_t)0); + check_buf(t, cbuf); + }; + + SECTION("no space for tag") { + conv_err(0, 0, ASN_TYPE_OCTETSTRING, ASN_ERR_EOBUF, ""); + } + SECTION("no space for length") { + conv_err(1, 0, ASN_TYPE_OCTETSTRING, ASN_ERR_EOBUF, ""); + conv_err(2, 128, ASN_TYPE_OCTETSTRING, ASN_ERR_EOBUF, ""); + } + SECTION("bad tag") { + conv_err(2, 0, 0x1f, ASN_ERR_FAILED, + "types > 0x1e not supported (0x1f)\n"); + conv_err(2, 0, 0xff, ASN_ERR_FAILED, + "types > 0x1e not supported (0x1f)\n"); + } + SECTION("ok") { + conv(2, 0, ASN_TYPE_OCTETSTRING, "x04:00"_cbuf); + } +} + +TEST_CASE("Counter64 parsing", "[asn1][parse]") +{ + asn_error = save_g_errstr; + + /** + * Sucessfully parse a COUNTER64 value. + * + * \param buf buffer to parse + * \param xval expected value + */ + const auto conv = [] (const auto &buf, uint64_t xval) { + auto r = check_header(buf, ASN_APP_COUNTER64 | ASN_CLASS_APPLICATION); + + uint64_t val; + REQUIRE(asn_get_counter64_raw(&r.buf, r.alen, &val) == ASN_ERR_OK); + REQUIRE(val == xval); + }; + + /** + * Parse COUNTER64 with error. + * + * \param buf buffer to parse + * \param err expected error from value parser + * \param errstr expected error string + */ + const auto conv_err = [] (const auto &buf, asn_err err, + std::string_view errstr) { + auto r = check_header(buf, ASN_APP_COUNTER64 | ASN_CLASS_APPLICATION); + + g_errstr.clear(); + uint64_t val; + REQUIRE(asn_get_counter64_raw(&r.buf, r.alen, &val) == err); + REQUIRE(g_errstr == errstr); + }; + + SECTION("correct encoding") { + + conv("x46:01:00"_cbuf, 0x0ULL); + conv("x46:01:01"_cbuf, 0x1ULL); + conv("x46:01:7f"_cbuf, 0x7fULL); + + conv("x46:02:00:80"_cbuf, 0x80ULL); + conv("x46:02:00:ff"_cbuf, 0xffULL); + conv("x46:02:7f:ff"_cbuf, 0x7fffULL); + + conv("x46:03:00:80:00"_cbuf, 0x8000ULL); + conv("x46:03:00:ff:ff"_cbuf, 0xffffULL); + conv("x46:03:7f:ff:ff"_cbuf, 0x7fffffULL); + + conv("x46:04:00:80:00:00"_cbuf, 0x800000ULL); + conv("x46:04:00:ff:ff:ff"_cbuf, 0xffffffULL); + conv("x46:04:7f:ff:ff:ff"_cbuf, 0x7fffffffULL); + + conv("x46:05:00:80:00:00:00"_cbuf, 0x80000000ULL); + conv("x46:05:00:ff:ff:ff:ff"_cbuf, 0xffffffffULL); + conv("x46:05:7f:ff:ff:ff:ff"_cbuf, 0x7fffffffffULL); + + conv("x46:06:00:80:00:00:00:00"_cbuf, 0x8000000000ULL); + conv("x46:06:00:ff:ff:ff:ff:ff"_cbuf, 0xffffffffffULL); + conv("x46:06:7f:ff:ff:ff:ff:ff"_cbuf, 0x7fffffffffffULL); + + conv("x46:07:00:80:00:00:00:00:00"_cbuf, 0x800000000000ULL); + conv("x46:07:00:ff:ff:ff:ff:ff:ff"_cbuf, 0xffffffffffffULL); + conv("x46:07:7f:ff:ff:ff:ff:ff:ff"_cbuf, 0x7fffffffffffffULL); + + conv("x46:08:00:80:00:00:00:00:00:00"_cbuf, 0x80000000000000ULL); + conv("x46:08:00:ff:ff:ff:ff:ff:ff:ff"_cbuf, 0xffffffffffffffULL); + conv("x46:08:7f:ff:ff:ff:ff:ff:ff:ff"_cbuf, 0x7fffffffffffffffULL); + + conv("x46:09:00:80:00:00:00:00:00:00:00"_cbuf, 0x8000000000000000ULL); + conv("x46:09:00:ff:ff:ff:ff:ff:ff:ff:ff"_cbuf, 0xffffffffffffffffULL); + } + + SECTION("zero length") { + conv_err("x46:00"_cbuf, ASN_ERR_BADLEN, + "zero-length integer at\n"); + } + + SECTION("non minimal encoding") { + conv_err("x46:02:00:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 00\n"); + conv_err("x46:02:00:7f"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 7f\n"); + conv_err("x46:03:00:00:80"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 00 80\n"); + conv_err("x46:04:00:00:80:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 00 80 00\n"); + conv_err("x46:0a:00:00:00:00:00:00:00:00:00:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 00 00 00 00 00 00 00 00 00\n"); + conv_err("x46:0a:00:01:00:00:00:00:00:00:00:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 01 00 00 00 00 00 00 00 00\n"); + } + + SECTION("out of range") { + conv_err("x46:09:01:00:00:00:00:00:00:00:00"_cbuf, ASN_ERR_RANGE, + "unsigned too large or negative at 01 00 00 00 00 00 00 00 00\n"); + conv_err("x46:0a:01:00:00:00:00:00:00:00:00:00"_cbuf, ASN_ERR_RANGE, + "unsigned too large or negative at 01 00 00 00 00 00 00 00 00 00\n"); + conv_err("x46:01:80"_cbuf, ASN_ERR_RANGE, + "unsigned too large or negative at 80\n"); + conv_err("x46:02:80:00"_cbuf, ASN_ERR_RANGE, + "unsigned too large or negative at 80 00\n"); + conv_err("x46:03:80:00:00"_cbuf, ASN_ERR_RANGE, + "unsigned too large or negative at 80 00 00\n"); + } + +#ifndef BOGUS_CVE_2019_5610_FIX + SECTION("truncated value") { + conv_err("x46:02:00"_cbuf, ASN_ERR_EOBUF, + "truncated integer at 00\n"); + conv_err("x46:09:00:80:00:00:00"_cbuf, ASN_ERR_EOBUF, + "truncated integer at 00 80 00 00 00\n"); + conv_err("x46:09:00:ff:ff:ff:ff:ff:ff:ff"_cbuf, ASN_ERR_EOBUF, + "truncated integer at 00 ff ff ff ff ff ff ff\n"); + } +#endif +} + +TEST_CASE("Counter64 building", "[asn1][build]") +{ + asn_error = save_g_errstr; + + const auto conv = [] (asn_len_t alen, uint64_t val, const auto &buf) { + auto b = mk_asn_buf(alen); + auto s = b; + REQUIRE(asn_put_counter64(&b, val) == ASN_ERR_OK); + REQUIRE(b.asn_len == (size_t)0); + check_buf(s, buf); + }; + + const auto conv_err = [] (asn_len_t alen, uint64_t val, asn_err err, + std::string_view errstr) { + auto b = mk_asn_buf(alen); + g_errstr.clear(); + REQUIRE(asn_put_counter64(&b, val) == err); + REQUIRE(g_errstr == errstr); + }; + + conv(3, 0x0, "x46:01:00"_cbuf); + conv(3, 0x1, "x46:01:01"_cbuf); + conv(3, 0x7f, "x46:01:7f"_cbuf); + + conv(4, 0x80, "x46:02:00:80"_cbuf); + conv(4, 0xff, "x46:02:00:ff"_cbuf); + conv(4, 0x7fff, "x46:02:7f:ff"_cbuf); + + conv(5, 0x8000, "x46:03:00:80:00"_cbuf); + conv(5, 0xffff, "x46:03:00:ff:ff"_cbuf); + conv(5, 0x7fffff, "x46:03:7f:ff:ff"_cbuf); + + conv(6, 0x800000, "x46:04:00:80:00:00"_cbuf); + conv(6, 0xffffff, "x46:04:00:ff:ff:ff"_cbuf); + conv(6, 0x7fffffff, "x46:04:7f:ff:ff:ff"_cbuf); + + conv(7, 0x80000000, "x46:05:00:80:00:00:00"_cbuf); + conv(7, 0xffffffff, "x46:05:00:ff:ff:ff:ff"_cbuf); + conv(7, 0x7fffffffff, "x46:05:7f:ff:ff:ff:ff"_cbuf); + + conv(8, 0x8000000000, "x46:06:00:80:00:00:00:00"_cbuf); + conv(8, 0xffffffffff, "x46:06:00:ff:ff:ff:ff:ff"_cbuf); + conv(8, 0x7fffffffffff, "x46:06:7f:ff:ff:ff:ff:ff"_cbuf); + + conv(9, 0x800000000000, "x46:07:00:80:00:00:00:00:00"_cbuf); + conv(9, 0xffffffffffff, "x46:07:00:ff:ff:ff:ff:ff:ff"_cbuf); + conv(9, 0x7fffffffffffff, "x46:07:7f:ff:ff:ff:ff:ff:ff"_cbuf); + + conv(10, 0x80000000000000, "x46:08:00:80:00:00:00:00:00:00"_cbuf); + conv(10, 0xffffffffffffff, "x46:08:00:ff:ff:ff:ff:ff:ff:ff"_cbuf); + conv(10, 0x7fffffffffffffff, "x46:08:7f:ff:ff:ff:ff:ff:ff:ff"_cbuf); + + conv(11, 0x8000000000000000, "x46:09:00:80:00:00:00:00:00:00:00"_cbuf); + conv(11, 0xffffffffffffffff, "x46:09:00:ff:ff:ff:ff:ff:ff:ff:ff"_cbuf); + + SECTION("empty buffer") { + conv_err(0, 0, ASN_ERR_EOBUF, ""); + } + SECTION("buffer too short for length field") { + conv_err(1, 0, ASN_ERR_EOBUF, ""); + } + SECTION("buffer too short") { + conv_err(2, 0, ASN_ERR_EOBUF, ""); + conv_err(3, 0x80, ASN_ERR_EOBUF, ""); + conv_err(4, 0x8000, ASN_ERR_EOBUF, ""); + conv_err(5, 0x800000, ASN_ERR_EOBUF, ""); + conv_err(6, 0x80000000, ASN_ERR_EOBUF, ""); + conv_err(7, 0x8000000000, ASN_ERR_EOBUF, ""); + conv_err(8, 0x800000000000, ASN_ERR_EOBUF, ""); + conv_err(9, 0x80000000000000, ASN_ERR_EOBUF, ""); + conv_err(10, 0x8000000000000000, ASN_ERR_EOBUF, ""); + } +} + +TEST_CASE("Unsigned32 parsing", "[asn1][parse]") +{ + asn_error = save_g_errstr; + + /** + * Sucessfully parse a COUNTER value. + * + * \param buf buffer to parse + * \param xval expected value + */ + const auto conv = [] (const auto &buf, uint32_t xval) { + auto r = check_header(buf, ASN_APP_COUNTER | ASN_CLASS_APPLICATION); + + uint32_t val; + REQUIRE(asn_get_uint32_raw(&r.buf, r.alen, &val) == ASN_ERR_OK); + REQUIRE(val == xval); + }; + + /** + * Parse COUNTER with error. + * + * \param buf buffer to parse + * \param err expected error from value parser + * \param errstr expected error string + */ + const auto conv_err = [] (const auto &buf, asn_err err, + std::string_view errstr) { + auto r = check_header(buf, ASN_APP_COUNTER | ASN_CLASS_APPLICATION); + + g_errstr.clear(); + uint32_t val; + REQUIRE(asn_get_uint32_raw(&r.buf, r.alen, &val) == err); + REQUIRE(g_errstr == errstr); + }; + + SECTION("correct encoding") { + conv("x41:01:00"_cbuf, 0x0U); + conv("x41:01:01"_cbuf, 0x1U); + conv("x41:01:7f"_cbuf, 0x7fU); + + conv("x41:02:00:80"_cbuf, 0x80U); + conv("x41:02:00:ff"_cbuf, 0xffU); + conv("x41:02:7f:ff"_cbuf, 0x7fffU); + + conv("x41:03:00:80:00"_cbuf, 0x8000U); + conv("x41:03:00:ff:ff"_cbuf, 0xffffU); + conv("x41:03:7f:ff:ff"_cbuf, 0x7fffffU); + + conv("x41:04:00:80:00:00"_cbuf, 0x800000U); + conv("x41:04:00:ff:ff:ff"_cbuf, 0xffffffU); + conv("x41:04:7f:ff:ff:ff"_cbuf, 0x7fffffffU); + + conv("x41:05:00:80:00:00:00"_cbuf, 0x80000000U); + conv("x41:05:00:ff:ff:ff:ff"_cbuf, 0xffffffffU); + } + SECTION("zero length") { + + conv_err("x41:00"_cbuf, ASN_ERR_BADLEN, + "zero-length integer at\n"); + } + + SECTION("non minimal encoding") { + conv_err("x41:02:00:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 00\n"); + conv_err("x41:02:00:7f"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 7f\n"); + conv_err("x41:03:00:00:80"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 00 80\n"); + conv_err("x41:04:00:00:80:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 00 80 00\n"); + conv_err("x41:06:00:00:00:00:00:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 00 00 00 00 00\n"); + conv_err("x41:06:00:01:00:00:00:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal unsigned at 00 01 00 00 00 00\n"); + } + + SECTION("out of range") { + conv_err("x41:05:01:00:00:00:00"_cbuf, + ASN_ERR_RANGE, "uint32 too large 4294967296 at\n"); + conv_err("x41:06:01:00:00:00:00:00"_cbuf, + ASN_ERR_RANGE, "uint32 too large 1099511627776 at\n"); + conv_err("x41:01:80"_cbuf, + ASN_ERR_RANGE, "unsigned too large or negative at 80\n"); + conv_err("x41:02:80:00"_cbuf, + ASN_ERR_RANGE, "unsigned too large or negative at 80 00\n"); + conv_err("x41:03:80:00:00"_cbuf, + ASN_ERR_RANGE, "unsigned too large or negative at 80 00 00\n"); + } + +#ifndef BOGUS_CVE_2019_5610_FIX + SECTION("truncated value") { + conv_err("x41:01"_cbuf, ASN_ERR_EOBUF, + "truncated integer at\n"); + conv_err("x41:02:01"_cbuf, ASN_ERR_EOBUF, + "truncated integer at 01\n"); + conv_err("x41:05:00:80:"_cbuf, ASN_ERR_EOBUF, + "truncated integer at 00 80\n"); + conv_err("x41:05:00:ff:ff:ff"_cbuf, ASN_ERR_EOBUF, + "truncated integer at 00 ff ff ff\n"); + } +#endif +} + +TEST_CASE("Unsigned32 building", "[asn1][build]") +{ + asn_error = save_g_errstr; + + const auto conv = [] (asn_len_t alen, uint32_t val, const auto &buf) { + auto b = mk_asn_buf(alen); + auto s = b; + REQUIRE(asn_put_uint32(&b, ASN_APP_COUNTER, val) == ASN_ERR_OK); + REQUIRE(b.asn_len == (size_t)0); + check_buf(s, buf); + }; + + const auto conv_err = [] (asn_len_t alen, uint32_t val, asn_err err, + std::string_view errstr) { + auto b = mk_asn_buf(alen); + g_errstr.clear(); + REQUIRE(asn_put_uint32(&b, ASN_APP_COUNTER, val) == err); + REQUIRE(g_errstr == errstr); + }; + + conv(3, 0x0, "x41:01:00"_cbuf); + conv(3, 0x1, "x41:01:01"_cbuf); + conv(3, 0x7f, "x41:01:7f"_cbuf); + + conv(4, 0x80, "x41:02:00:80"_cbuf); + conv(4, 0xff, "x41:02:00:ff"_cbuf); + conv(4, 0x7fff, "x41:02:7f:ff"_cbuf); + + conv(5, 0x8000, "x41:03:00:80:00"_cbuf); + conv(5, 0xffff, "x41:03:00:ff:ff"_cbuf); + conv(5, 0x7fffff, "x41:03:7f:ff:ff"_cbuf); + + conv(6, 0x800000, "x41:04:00:80:00:00"_cbuf); + conv(6, 0xffffff, "x41:04:00:ff:ff:ff"_cbuf); + conv(6, 0x7fffffff, "x41:04:7f:ff:ff:ff"_cbuf); + + conv(7, 0x80000000, "x41:05:00:80:00:00:00"_cbuf); + conv(7, 0xffffffff, "x41:05:00:ff:ff:ff:ff"_cbuf); + + SECTION("empty buffer") { + conv_err(0, 0, ASN_ERR_EOBUF, ""); + } + SECTION("buffer too short for length field") { + conv_err(1, 0, ASN_ERR_EOBUF, ""); + } + SECTION("buffer too short") { + conv_err(2, 0, ASN_ERR_EOBUF, ""); + conv_err(3, 0x80, ASN_ERR_EOBUF, ""); + conv_err(4, 0x8000, ASN_ERR_EOBUF, ""); + conv_err(5, 0x800000, ASN_ERR_EOBUF, ""); + conv_err(6, 0x80000000, ASN_ERR_EOBUF, ""); + } +} + +TEST_CASE("Integer parsing", "[asn1][parse]") +{ + asn_error = save_g_errstr; + + /** + * Sucessfully parse a INTEGER value. + * + * \param buf buffer to parse + * \param xval expected value + */ + const auto conv = [] (const auto &buf, int32_t xval) { + auto r = check_header(buf, ASN_TYPE_INTEGER); + + int32_t val; + REQUIRE(asn_get_integer_raw(&r.buf, r.alen, &val) == ASN_ERR_OK); + REQUIRE(val == xval); + }; + + /** + * Parse INTEGER with error. + * + * \param buf buffer to parse + * \param err expected error from value parser + * \param errstr expected error string + */ + const auto conv_err = [] (const auto &buf, asn_err err, + std::string_view errstr) { + auto r = check_header(buf, ASN_TYPE_INTEGER); + + g_errstr.clear(); + int32_t val; + REQUIRE(asn_get_integer_raw(&r.buf, r.alen, &val) == err); + REQUIRE(g_errstr == errstr); + }; + + SECTION("correct encoding") { + conv("x02:01:00"_cbuf, 0x0); + conv("x02:01:01"_cbuf, 0x1); + conv("x02:01:7f"_cbuf, 0x7f); + conv("x02:01:ff"_cbuf, -0x1); + conv("x02:01:80"_cbuf, -0x80); + + conv("x02:02:00:80"_cbuf, 0x80); + conv("x02:02:00:ff"_cbuf, 0xff); + conv("x02:02:7f:ff"_cbuf, 0x7fff); + conv("x02:02:ff:7f"_cbuf, -0x81); + conv("x02:02:ff:01"_cbuf, -0xff); + conv("x02:02:ff:00"_cbuf, -0x100); + conv("x02:02:80:00"_cbuf, -0x8000); + + conv("x02:03:00:80:00"_cbuf, 0x8000); + conv("x02:03:00:ff:ff"_cbuf, 0xffff); + conv("x02:03:7f:ff:ff"_cbuf, 0x7fffff); + conv("x02:03:ff:7f:ff"_cbuf, -0x8001); + conv("x02:03:ff:00:01"_cbuf, -0xffff); + conv("x02:03:ff:00:00"_cbuf, -0x10000); + conv("x02:03:80:00:00"_cbuf, -0x800000); + + conv("x02:04:00:80:00:00"_cbuf, 0x800000); + conv("x02:04:00:ff:ff:ff"_cbuf, 0xffffff); + conv("x02:04:7f:ff:ff:ff"_cbuf, 0x7fffffff); + conv("x02:04:ff:7f:ff:ff"_cbuf, -0x800001); + conv("x02:04:ff:00:00:01"_cbuf, -0xffffff); + conv("x02:04:ff:00:00:00"_cbuf, -0x1000000); + conv("x02:04:80:00:00:00"_cbuf, -0x80000000); + } + + SECTION("zero length") { + conv_err("x02:00"_cbuf, ASN_ERR_BADLEN, + "zero-length integer at\n"); + } + SECTION("too long") { + conv_err("x02:05:01:02:03:04:05"_cbuf, ASN_ERR_BADLEN, + "integer too long at\n"); + } + + SECTION("non minimal encoding") { + conv_err("x02:02:00:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at 00 00\n"); + conv_err("x02:02:00:7f"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at 00 7f\n"); + conv_err("x02:03:00:00:80"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at 00 00 80\n"); + conv_err("x02:04:00:00:80:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at 00 00 80 00\n"); + conv_err("x02:06:00:00:00:00:00:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at 00 00 00 00 00 00\n"); + conv_err("x02:06:00:01:00:00:00:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at 00 01 00 00 00 00\n"); + conv_err("x02:02:ff:80"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at ff 80\n"); + conv_err("x02:02:ff:ff"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at ff ff\n"); + conv_err("x02:03:ff:80:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at ff 80 00\n"); + conv_err("x02:03:ff:ff:ff"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at ff ff ff\n"); + conv_err("x02:04:ff:80:00:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at ff 80 00 00\n"); + conv_err("x02:04:ff:ff:ff:ff"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at ff ff ff ff\n"); + conv_err("x02:06:ff:80:00:00:00:00"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at ff 80 00 00 00 00\n"); + conv_err("x02:06:ff:ff:ff:ff:ff:ff"_cbuf, ASN_ERR_BADLEN, + "non-minimal integer at ff ff ff ff ff ff\n"); + } + +#ifndef BOGUS_CVE_2019_5610_FIX + SECTION("truncated value") { + conv_err("x02:01"_cbuf, ASN_ERR_EOBUF, + "truncated integer at\n"); + conv_err("x02:02:ff"_cbuf, ASN_ERR_EOBUF, + "truncated integer at ff\n"); + conv_err("x02:05:ff:00:03:01"_cbuf, ASN_ERR_EOBUF, + "truncated integer at ff 00 03 01\n"); + conv_err("x02:04:7f:ff:"_cbuf, ASN_ERR_EOBUF, + "truncated integer at 7f ff\n"); + conv_err("x02:04:80:00:00"_cbuf, ASN_ERR_EOBUF, + "truncated integer at 80 00 00\n"); + } +#endif +} + +TEST_CASE("Integer32 building", "[asn1][build]") +{ + asn_error = save_g_errstr; + + const auto conv = [] (asn_len_t alen, int32_t val, const auto &buf) { + auto b = mk_asn_buf(alen); + auto s = b; + REQUIRE(asn_put_integer(&b, val) == ASN_ERR_OK); + REQUIRE(b.asn_len == (size_t)0); + check_buf(s, buf); + }; + + const auto conv_err = [] (asn_len_t alen, int32_t val, asn_err err, + std::string_view errstr) { + auto b = mk_asn_buf(alen); + g_errstr.clear(); + REQUIRE(asn_put_integer(&b, val) == err); + REQUIRE(g_errstr == errstr); + }; + + conv(3, 0x0, "x02:01:00"_cbuf); + conv(3, 0x1, "x02:01:01"_cbuf); + conv(3, 0x7f, "x02:01:7f"_cbuf); + conv(3, -0x1, "x02:01:ff"_cbuf); + conv(3, -0x80, "x02:01:80"_cbuf); + + conv(4, 0x80, "x02:02:00:80"_cbuf); + conv(4, 0xff, "x02:02:00:ff"_cbuf); + conv(4, 0x7fff, "x02:02:7f:ff"_cbuf); + conv(4, -0x81, "x02:02:ff:7f"_cbuf); + conv(4, -0xff, "x02:02:ff:01"_cbuf); + conv(4, -0x100, "x02:02:ff:00"_cbuf); + conv(4, -0x8000, "x02:02:80:00"_cbuf); + + conv(5, 0x8000, "x02:03:00:80:00"_cbuf); + conv(5, 0xffff, "x02:03:00:ff:ff"_cbuf); + conv(5, 0x7fffff, "x02:03:7f:ff:ff"_cbuf); + conv(5, -0x8001, "x02:03:ff:7f:ff"_cbuf); + conv(5, -0xffff, "x02:03:ff:00:01"_cbuf); + conv(5, -0x10000, "x02:03:ff:00:00"_cbuf); + conv(5, -0x800000, "x02:03:80:00:00"_cbuf); + + conv(6, 0x800000, "x02:04:00:80:00:00"_cbuf); + conv(6, 0xffffff, "x02:04:00:ff:ff:ff"_cbuf); + conv(6, 0x7fffffff, "x02:04:7f:ff:ff:ff"_cbuf); + conv(6, -0x800001, "x02:04:ff:7f:ff:ff"_cbuf); + conv(6, -0xffffff, "x02:04:ff:00:00:01"_cbuf); + conv(6, -0x1000000, "x02:04:ff:00:00:00"_cbuf); + conv(6, -0x80000000, "x02:04:80:00:00:00"_cbuf); + + SECTION("empty buffer") { + conv_err(0, 0, ASN_ERR_EOBUF, ""); + } + SECTION("buffer too short for length field") { + conv_err(1, 0, ASN_ERR_EOBUF, ""); + } + SECTION("buffer too short") { + conv_err(2, 0, ASN_ERR_EOBUF, ""); + conv_err(3, 0xff, ASN_ERR_EOBUF, ""); + conv_err(4, 0xffff, ASN_ERR_EOBUF, ""); + conv_err(5, 0xffffff, ASN_ERR_EOBUF, ""); + conv_err(5, 0x7fffffff, ASN_ERR_EOBUF, ""); + conv_err(2, -0x80, ASN_ERR_EOBUF, ""); + conv_err(3, -0x8000, ASN_ERR_EOBUF, ""); + conv_err(4, -0x800000, ASN_ERR_EOBUF, ""); + conv_err(5, -0x80000000, ASN_ERR_EOBUF, ""); + } +} + +TEST_CASE("Oid parsing", "[asn1][parse]") +{ + asn_error = save_g_errstr; + + /** + * Sucessfully parse a INTEGER value. + * + * \param buf buffer to parse + * \param xval expected value + */ + const auto conv = [] (const auto &buf, const asn_oid &xval) { + auto r = check_header(buf, ASN_TYPE_OBJID); + + struct asn_oid val; + REQUIRE(asn_get_objid_raw(&r.buf, r.alen, &val) == ASN_ERR_OK); + REQUIRE(asn_compare_oid(&val, &xval) == 0); + }; + + /** + * Parse INTEGER with error. + * + * \param buf buffer to parse + * \param err expected error from value parser + * \param errstr expected error string + */ + const auto conv_err = [] (const auto &buf, asn_err err, + std::string_view errstr) { + auto r = check_header(buf, ASN_TYPE_OBJID); + + g_errstr.clear(); + struct asn_oid val; + REQUIRE(asn_get_objid_raw(&r.buf, r.alen, &val) == err); + REQUIRE(g_errstr == errstr); + }; + + conv("x06:01:00"_cbuf, asn_oid {2, {0, 0}}); + conv("x06:01:28"_cbuf, asn_oid {2, {1, 0}}); + conv("x06:01:50"_cbuf, asn_oid {2, {2, 0}}); + + conv("x06:01:27"_cbuf, asn_oid {2, {0, 39}}); + conv("x06:01:4f"_cbuf, asn_oid {2, {1, 39}}); + conv("x06:01:7f"_cbuf, asn_oid {2, {2, 47}}); + + conv("x06:02:81:00"_cbuf, asn_oid {2, {2, 48}}); + conv("x06:02:ff:7f"_cbuf, asn_oid {2, {2, 16303}}); + conv("x06:03:ff:ff:7f"_cbuf, asn_oid {2, {2, 2097071}}); + conv("x06:04:ff:ff:ff:7f"_cbuf, asn_oid {2, {2, 268435375}}); + conv("x06:05:8f:ff:ff:ff:7f"_cbuf, asn_oid {2, {2, 4294967215}}); + + /* maximum OID */ + conv("x06:82:02:7b:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f"_cbuf, asn_oid {128, { + 2, 4294967215, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + }}); + + SECTION("truncated OID") { +#ifndef BOGUS_CVE_2019_5610_FIX + conv_err("x06:02:01"_cbuf, ASN_ERR_EOBUF, + "truncated OBJID at 01\n"); +#endif + conv_err("x06:01:8f"_cbuf, ASN_ERR_EOBUF, + "unterminated subid at\n"); + conv_err("x06:04:07:7f:82:8e"_cbuf, ASN_ERR_EOBUF, + "unterminated subid at\n"); + } + SECTION("short OID") { + conv_err("x06:00"_cbuf, ASN_ERR_BADLEN, + "short OBJID at\n"); + } + SECTION("too long") { + conv_err("x06:81:80:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c:7c"_cbuf, ASN_ERR_BADLEN, "OID too long (128) at 7c\n"); + } + SECTION("subid too large") { + conv_err("x06:06:20:90:82:83:84:75"_cbuf, ASN_ERR_RANGE, + "OID subid too larger at 75\n"); + } +} + +TEST_CASE("Objid building", "[asn1][build]") +{ + asn_error = save_g_errstr; + + const auto conv = [] (asn_len_t alen, const asn_oid &val, const auto &buf) { + auto b = mk_asn_buf(alen); + auto s = b; + REQUIRE(asn_put_objid(&b, &val) == ASN_ERR_OK); + REQUIRE(b.asn_len == (size_t)0); + check_buf(s, buf); + }; + + const auto conv_err = [] (asn_len_t alen, const asn_oid &val, asn_err err, + std::string_view errstr) { + auto b = mk_asn_buf(alen); + g_errstr.clear(); + REQUIRE(asn_put_objid(&b, &val) == err); + REQUIRE(g_errstr == errstr); + }; + + conv(3, asn_oid {2, {0, 0}}, "x06:01:00"_cbuf); + conv(3, asn_oid {2, {1, 0}}, "x06:01:28"_cbuf); + conv(3, asn_oid {2, {2, 0}}, "x06:01:50"_cbuf); + + conv(3, asn_oid {2, {0, 39}}, "x06:01:27"_cbuf); + conv(3, asn_oid {2, {1, 39}}, "x06:01:4f"_cbuf); + conv(3, asn_oid {2, {2, 47}}, "x06:01:7f"_cbuf); + + conv(4, asn_oid {2, {2, 48}}, "x06:02:81:00"_cbuf); + conv(4, asn_oid {2, {2, 16303}}, "x06:02:ff:7f"_cbuf); + conv(5, asn_oid {2, {2, 2097071}}, "x06:03:ff:ff:7f"_cbuf); + conv(6, asn_oid {2, {2, 268435375}}, "x06:04:ff:ff:ff:7f"_cbuf); + conv(7, asn_oid {2, {2, 4294967215}}, "x06:05:8f:ff:ff:ff:7f"_cbuf); + + SECTION("sub-id too large") { + conv_err(3, asn_oid {2, {3, 0}}, ASN_ERR_RANGE, + "oid out of range (3,0)\n"); + conv_err(3, asn_oid {2, {0, 40}}, ASN_ERR_RANGE, + "oid out of range (0,40)\n"); + conv_err(3, asn_oid {2, {1, 40}}, ASN_ERR_RANGE, + "oid out of range (1,40)\n"); + conv_err(3, asn_oid {2, {2, 4294967216}}, ASN_ERR_RANGE, + "oid out of range (2,4294967216)\n"); + } + SECTION("oid too long") { + conv_err(200, asn_oid {129, {}}, ASN_ERR_RANGE, + "oid too long 129\n"); + } + SECTION("oid too short") { + conv_err(3, asn_oid {0, {}}, ASN_ERR_RANGE, + "short oid\n"); + conv_err(3, asn_oid {1, {0}}, ASN_ERR_RANGE, + "short oid\n"); + conv_err(3, asn_oid {1, {3}}, ASN_ERR_RANGE, + "oid[0] too large (3)\n"); + } + + /* maximum OID */ + conv(5 * (128 - 1) + 4, asn_oid {128, { + 2, 4294967215, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + 4294967295, 4294967295, 4294967295, 4294967295, + }}, "x06:82:02:7b:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f:8f:ff:ff:ff:7f"_cbuf); +} + +/* loop tests */ Property changes on: vendor/1.14/tests/asn1.cc ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: vendor/1.14/tests/catch.hpp =================================================================== --- vendor/1.14/tests/catch.hpp (nonexistent) +++ vendor/1.14/tests/catch.hpp (revision 359491) @@ -0,0 +1,17597 @@ +/* + * Catch v2.11.0 + * Generated: 2019-11-15 15:01:56.628356 + * ---------------------------------------------------------- + * This file has been merged from multiple headers. Please don't edit it directly + * Copyright (c) 2019 Two Blue Cubes Ltd. All rights reserved. + * + * Distributed under the Boost Software License, Version 1.0. (See accompanying + * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + */ +#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED +// start catch.hpp + + +#define CATCH_VERSION_MAJOR 2 +#define CATCH_VERSION_MINOR 11 +#define CATCH_VERSION_PATCH 0 + +#ifdef __clang__ +# pragma clang system_header +#elif defined __GNUC__ +# pragma GCC system_header +#endif + +// start catch_suppress_warnings.h + +#ifdef __clang__ +# ifdef __ICC // icpc defines the __clang__ macro +# pragma warning(push) +# pragma warning(disable: 161 1682) +# else // __ICC +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wpadded" +# pragma clang diagnostic ignored "-Wswitch-enum" +# pragma clang diagnostic ignored "-Wcovered-switch-default" +# endif +#elif defined __GNUC__ + // Because REQUIREs trigger GCC's -Wparentheses, and because still + // supported version of g++ have only buggy support for _Pragmas, + // Wparentheses have to be suppressed globally. +# pragma GCC diagnostic ignored "-Wparentheses" // See #674 for details + +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wunused-variable" +# pragma GCC diagnostic ignored "-Wpadded" +#endif +// end catch_suppress_warnings.h +#if defined(CATCH_CONFIG_MAIN) || defined(CATCH_CONFIG_RUNNER) +# define CATCH_IMPL +# define CATCH_CONFIG_ALL_PARTS +#endif + +// In the impl file, we want to have access to all parts of the headers +// Can also be used to sanely support PCHs +#if defined(CATCH_CONFIG_ALL_PARTS) +# define CATCH_CONFIG_EXTERNAL_INTERFACES +# if defined(CATCH_CONFIG_DISABLE_MATCHERS) +# undef CATCH_CONFIG_DISABLE_MATCHERS +# endif +# if !defined(CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER) +# define CATCH_CONFIG_ENABLE_CHRONO_STRINGMAKER +# endif +#endif + +#if !defined(CATCH_CONFIG_IMPL_ONLY) +// start catch_platform.h + +#ifdef __APPLE__ +# include +# if TARGET_OS_OSX == 1 +# define CATCH_PLATFORM_MAC +# elif TARGET_OS_IPHONE == 1 +# define CATCH_PLATFORM_IPHONE +# endif + +#elif defined(linux) || defined(__linux) || defined(__linux__) +# define CATCH_PLATFORM_LINUX + +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) +# define CATCH_PLATFORM_WINDOWS +#endif + +// end catch_platform.h + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// start catch_user_interfaces.h + +namespace Catch { + unsigned int rngSeed(); +} + +// end catch_user_interfaces.h +// start catch_tag_alias_autoregistrar.h + +// start catch_common.h + +// start catch_compiler_capabilities.h + +// Detect a number of compiler features - by compiler +// The following features are defined: +// +// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? +// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? +// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? +// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +#ifdef __cplusplus + +# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) +# define CATCH_CPP14_OR_GREATER +# endif + +# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +# define CATCH_CPP17_OR_GREATER +# endif + +#endif + +#if defined(CATCH_CPP17_OR_GREATER) +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +// We have to avoid both ICC and Clang, because they try to mask themselves +// as gcc, and we want only GCC in this block +#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) +#endif + +#if defined(__clang__) + +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) + +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") + +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) + +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Assume that non-Windows platforms support posix signals by default +#if !defined(CATCH_PLATFORM_WINDOWS) + #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS +#endif + +//////////////////////////////////////////////////////////////////////////////// +// We know some environments not to support full POSIX signals +#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) + #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +#endif + +#ifdef __OS400__ +# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +# define CATCH_CONFIG_COLOUR_NONE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Android somehow still does not support std::to_string +#if defined(__ANDROID__) +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Not all Windows environments support SEH properly +#if defined(__MINGW32__) +# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH +#endif + +//////////////////////////////////////////////////////////////////////////////// +// PS4 +#if defined(__ORBIS__) +# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Cygwin +#ifdef __CYGWIN__ + +// Required for some versions of Cygwin to declare gettimeofday +// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin +# define _BSD_SOURCE +// some versions of cygwin (most) do not support std::to_string. Use the libstd check. +// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 +# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ + && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) + +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING + +# endif +#endif // __CYGWIN__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#if defined(_MSC_VER) + +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) + +# if _MSC_VER >= 1900 // Visual Studio 2015 or newer +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +# endif + +// Universal Windows platform does not support SEH +// Or console colours (or console at all...) +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +# define CATCH_CONFIG_COLOUR_NONE +# else +# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH +# endif + +// MSVC traditional preprocessor needs some workaround for __VA_ARGS__ +// _MSVC_TRADITIONAL == 0 means new conformant preprocessor +// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor +# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) +# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +# endif +#endif // _MSC_VER + +#if defined(_REENTRANT) || defined(_MSC_VER) +// Enable async processing, as -pthread is specified or no additional linking is required +# define CATCH_INTERNAL_CONFIG_USE_ASYNC +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// +// Check if we are compiled with -fno-exceptions or equivalent +#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) +# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED +#endif + +//////////////////////////////////////////////////////////////////////////////// +// DJGPP +#ifdef __DJGPP__ +# define CATCH_INTERNAL_CONFIG_NO_WCHAR +#endif // __DJGPP__ + +//////////////////////////////////////////////////////////////////////////////// +// Embarcadero C++Build +#if defined(__BORLANDC__) + #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN +#endif + +//////////////////////////////////////////////////////////////////////////////// + +// Use of __COUNTER__ is suppressed during code analysis in +// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly +// handled by it. +// Otherwise all supported compilers support COUNTER macro, +// but user still might want to turn it off +#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) + #define CATCH_INTERNAL_CONFIG_COUNTER +#endif + +//////////////////////////////////////////////////////////////////////////////// + +// RTX is a special version of Windows that is real time. +// This means that it is detected as Windows, but does not provide +// the same set of capabilities as real Windows does. +#if defined(UNDER_RTSS) || defined(RTX64_BUILD) + #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH + #define CATCH_INTERNAL_CONFIG_NO_ASYNC + #define CATCH_CONFIG_COLOUR_NONE +#endif + +#if defined(__UCLIBC__) +#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER +#endif + +// Various stdlib support checks that require __has_include +#if defined(__has_include) + // Check if string_view is available and usable + #if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW + #endif + + // Check if optional is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if byte is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_BYTE + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if variant is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # if defined(__clang__) && (__clang_major__ < 8) + // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 + // fix should be in clang 8, workaround in libstdc++ 8.2 + # include + # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # define CATCH_CONFIG_NO_CPP17_VARIANT + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__clang__) && (__clang_major__ < 8) + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) +#endif // defined(__has_include) + +#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) +# define CATCH_CONFIG_COUNTER +#endif +#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) +# define CATCH_CONFIG_WINDOWS_SEH +#endif +// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. +#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +# define CATCH_CONFIG_POSIX_SIGNALS +#endif +// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. +#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) +# define CATCH_CONFIG_WCHAR +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) +# define CATCH_CONFIG_CPP11_TO_STRING +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) +# define CATCH_CONFIG_CPP17_OPTIONAL +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) +# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) +# define CATCH_CONFIG_CPP17_STRING_VIEW +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) +# define CATCH_CONFIG_CPP17_VARIANT +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) +# define CATCH_CONFIG_CPP17_BYTE +#endif + +#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) +# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) +# define CATCH_CONFIG_NEW_CAPTURE +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +# define CATCH_CONFIG_DISABLE_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) +# define CATCH_CONFIG_POLYFILL_ISNAN +#endif + +#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) +# define CATCH_CONFIG_USE_ASYNC +#endif + +#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) +# define CATCH_CONFIG_ANDROID_LOGWRITE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) +# define CATCH_CONFIG_GLOBAL_NEXTAFTER +#endif + +// Even if we do not think the compiler has that warning, we still have +// to provide a macro that can be used by the code. +#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION +#endif +#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS +#endif + +#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#elif defined(__clang__) && (__clang_major__ < 5) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +#define CATCH_TRY if ((true)) +#define CATCH_CATCH_ALL if ((false)) +#define CATCH_CATCH_ANON(type) if ((false)) +#else +#define CATCH_TRY try +#define CATCH_CATCH_ALL catch (...) +#define CATCH_CATCH_ANON(type) catch (type) +#endif + +#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) +#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#endif + +// end catch_compiler_capabilities.h +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#ifdef CATCH_CONFIG_COUNTER +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) +#else +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) +#endif + +#include +#include +#include + +// We need a dummy global operator<< so we can bring it into Catch namespace later +struct Catch_global_namespace_dummy {}; +std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); + +namespace Catch { + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + + class NonCopyable { + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; + + protected: + NonCopyable(); + virtual ~NonCopyable(); + }; + + struct SourceLineInfo { + + SourceLineInfo() = delete; + SourceLineInfo( char const* _file, std::size_t _line ) noexcept + : file( _file ), + line( _line ) + {} + + SourceLineInfo( SourceLineInfo const& other ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo( SourceLineInfo&& ) noexcept = default; + SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; + + bool empty() const noexcept { return file[0] == '\0'; } + bool operator == ( SourceLineInfo const& other ) const noexcept; + bool operator < ( SourceLineInfo const& other ) const noexcept; + + char const* file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // Bring in operator<< from global namespace into Catch namespace + // This is necessary because the overload of operator<< above makes + // lookup stop at namespace Catch + using ::operator<<; + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() const; + }; + template + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO \ + ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) + +// end catch_common.h +namespace Catch { + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + +// end catch_tag_alias_autoregistrar.h +// start catch_test_registry.h + +// start catch_interfaces_testcase.h + +#include + +namespace Catch { + + class TestSpec; + + struct ITestInvoker { + virtual void invoke () const = 0; + virtual ~ITestInvoker(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; + }; + + bool isThrowSafe( TestCase const& testCase, IConfig const& config ); + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + +} + +// end catch_interfaces_testcase.h +// start catch_stringref.h + +#include +#include +#include +#include + +namespace Catch { + + /// A non-owning string class (similar to the forthcoming std::string_view) + /// Note that, because a StringRef may be a substring of another string, + /// it may not be null terminated. + class StringRef { + public: + using size_type = std::size_t; + using const_iterator = const char*; + + private: + static constexpr char const* const s_empty = ""; + + char const* m_start = s_empty; + size_type m_size = 0; + + public: // construction + constexpr StringRef() noexcept = default; + + StringRef( char const* rawChars ) noexcept; + + constexpr StringRef( char const* rawChars, size_type size ) noexcept + : m_start( rawChars ), + m_size( size ) + {} + + StringRef( std::string const& stdString ) noexcept + : m_start( stdString.c_str() ), + m_size( stdString.size() ) + {} + + explicit operator std::string() const { + return std::string(m_start, m_size); + } + + public: // operators + auto operator == ( StringRef const& other ) const noexcept -> bool; + auto operator != (StringRef const& other) const noexcept -> bool { + return !(*this == other); + } + + auto operator[] ( size_type index ) const noexcept -> char { + assert(index < m_size); + return m_start[index]; + } + + public: // named queries + constexpr auto empty() const noexcept -> bool { + return m_size == 0; + } + constexpr auto size() const noexcept -> size_type { + return m_size; + } + + // Returns the current start pointer. If the StringRef is not + // null-terminated, throws std::domain_exception + auto c_str() const -> char const*; + + public: // substrings and searches + // Returns a substring of [start, start + length). + // If start + length > size(), then the substring is [start, size()). + // If start > size(), then the substring is empty. + auto substr( size_type start, size_type length ) const noexcept -> StringRef; + + // Returns the current start pointer. May not be null-terminated. + auto data() const noexcept -> char const*; + + constexpr auto isNullTerminated() const noexcept -> bool { + return m_start[m_size] == '\0'; + } + + public: // iterators + constexpr const_iterator begin() const { return m_start; } + constexpr const_iterator end() const { return m_start + m_size; } + }; + + auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; + auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; + + constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + return StringRef( rawChars, size ); + } +} // namespace Catch + +constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { + return Catch::StringRef( rawChars, size ); +} + +// end catch_stringref.h +// start catch_preprocessor.hpp + + +#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ +#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) + +#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ +// MSVC needs more evaluations +#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) +#else +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) +#endif + +#define CATCH_REC_END(...) +#define CATCH_REC_OUT + +#define CATCH_EMPTY() +#define CATCH_DEFER(id) id CATCH_EMPTY() + +#define CATCH_REC_GET_END2() 0, CATCH_REC_END +#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 +#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 +#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT +#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) +#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) + +#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) + +#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) + +// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, +// and passes userdata as the first parameter to each invocation, +// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) +#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) +#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ +#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ +#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) +#else +// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) +#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) +#endif + +#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ +#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) + +#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) +#else +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) +#endif + +#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ + CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) + +#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) +#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) +#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) +#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) +#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) +#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) +#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _4, _5, _6) +#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) +#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) +#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) +#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) + +#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N + +#define INTERNAL_CATCH_TYPE_GEN\ + template struct TypeList {};\ + template\ + constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ + template class...> struct TemplateTypeList{};\ + template class...Cs>\ + constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ + template\ + struct append;\ + template\ + struct rewrap;\ + template class, typename...>\ + struct create;\ + template class, typename>\ + struct convert;\ + \ + template \ + struct append { using type = T; };\ + template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ + struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ + template< template class L1, typename...E1, typename...Rest>\ + struct append, TypeList, Rest...> { using type = L1; };\ + \ + template< template class Container, template class List, typename...elems>\ + struct rewrap, List> { using type = TypeList>; };\ + template< template class Container, template class List, class...Elems, typename...Elements>\ + struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ + \ + template