In bsnmpd(1) add support for SNMPv3 message processing model, including message authentication, packet encryption & view-based access control (RFC 3412, 3414, 3415).
Sponsored by: The FreeBSD Foundation Reviewed by: philip@ (mostly) Approved by: philip@
This commit is contained in:
parent
055731ce60
commit
135f7de5dd
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/head/; revision=216294
@ -196,7 +196,7 @@ asn_put_temp_header(struct asn_buf *b, u_char type, u_char **ptr)
|
|||||||
return (ret);
|
return (ret);
|
||||||
}
|
}
|
||||||
enum asn_err
|
enum asn_err
|
||||||
asn_commit_header(struct asn_buf *b, u_char *ptr)
|
asn_commit_header(struct asn_buf *b, u_char *ptr, size_t *moved)
|
||||||
{
|
{
|
||||||
asn_len_t len;
|
asn_len_t len;
|
||||||
u_int lenlen, shift;
|
u_int lenlen, shift;
|
||||||
@ -215,6 +215,8 @@ asn_commit_header(struct asn_buf *b, u_char *ptr)
|
|||||||
memmove(ptr + 1 + lenlen, ptr + TEMP_LEN, len);
|
memmove(ptr + 1 + lenlen, ptr + TEMP_LEN, len);
|
||||||
b->asn_ptr -= shift;
|
b->asn_ptr -= shift;
|
||||||
b->asn_len += shift;
|
b->asn_len += shift;
|
||||||
|
if (moved != NULL)
|
||||||
|
*moved = shift;
|
||||||
}
|
}
|
||||||
return (ASN_ERR_OK);
|
return (ASN_ERR_OK);
|
||||||
}
|
}
|
||||||
@ -912,6 +914,20 @@ asn_skip(struct asn_buf *b, asn_len_t len)
|
|||||||
return (ASN_ERR_OK);
|
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.
|
* Compare two OIDs.
|
||||||
*
|
*
|
||||||
|
@ -93,7 +93,7 @@ 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_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_put_temp_header(struct asn_buf *, u_char, u_char **);
|
||||||
enum asn_err asn_commit_header(struct asn_buf *, 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_raw(struct asn_buf *, asn_len_t, int32_t *);
|
||||||
enum asn_err asn_get_integer(struct asn_buf *, int32_t *);
|
enum asn_err asn_get_integer(struct asn_buf *, int32_t *);
|
||||||
@ -129,6 +129,7 @@ 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_put_timeticks(struct asn_buf *, uint32_t);
|
||||||
|
|
||||||
enum asn_err asn_skip(struct asn_buf *, asn_len_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
|
* Utility functions for OIDs
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $Begemot: bsnmp/lib/bsnmpclient.3,v 1.12 2005/10/04 08:46:50 brandt_h Exp $
|
.\" $Begemot: bsnmp/lib/bsnmpclient.3,v 1.12 2005/10/04 08:46:50 brandt_h Exp $
|
||||||
.\"
|
.\"
|
||||||
.Dd October 4, 2005
|
.Dd September 9, 2010
|
||||||
.Dt BSNMPCLIENT 3
|
.Dt BSNMPCLIENT 3
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -52,7 +52,8 @@
|
|||||||
.Nm snmp_table_cb_f ,
|
.Nm snmp_table_cb_f ,
|
||||||
.Nm snmp_table_fetch ,
|
.Nm snmp_table_fetch ,
|
||||||
.Nm snmp_table_fetch_async ,
|
.Nm snmp_table_fetch_async ,
|
||||||
.Nm snmp_dialog
|
.Nm snmp_dialog ,
|
||||||
|
.Nm snmp_discover_engine
|
||||||
.Nd "SNMP client library"
|
.Nd "SNMP client library"
|
||||||
.Sh LIBRARY
|
.Sh LIBRARY
|
||||||
Begemot SNMP library
|
Begemot SNMP library
|
||||||
@ -102,44 +103,56 @@ Begemot SNMP library
|
|||||||
.Fn snmp_table_fetch_async "const struct snmp_table *descr" "void *list" "snmp_table_cb_f callback" "void *uarg"
|
.Fn snmp_table_fetch_async "const struct snmp_table *descr" "void *list" "snmp_table_cb_f callback" "void *uarg"
|
||||||
.Ft int
|
.Ft int
|
||||||
.Fn snmp_dialog "struct snmp_pdu *req" "struct snmp_pdu *resp"
|
.Fn snmp_dialog "struct snmp_pdu *req" "struct snmp_pdu *resp"
|
||||||
|
.Ft int
|
||||||
|
.Fn snmp_discover_engine "void"
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
The SNMP library contains routines to easily build SNMP client applications
|
The SNMP library contains routines to easily build SNMP client applications
|
||||||
that use SNMP versions 1 or 2.
|
that use SNMP versions 1, 2 or 3.
|
||||||
Most of the routines use a
|
Most of the routines use a
|
||||||
.Vt struct snmp_client :
|
.Vt struct snmp_client :
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
struct snmp_client {
|
struct snmp_client {
|
||||||
enum snmp_version version;
|
enum snmp_version version;
|
||||||
int trans; /* transport type to use */
|
int trans; /* which transport to use */
|
||||||
|
|
||||||
/* these two are read-only for the application */
|
/* these two are read-only for the application */
|
||||||
char *cport; /* port number as string */
|
char *cport; /* port number as string */
|
||||||
char *chost; /* host name or IP address as string */
|
char *chost; /* host name or IP address as string */
|
||||||
|
|
||||||
char read_community[SNMP_COMMUNITY_MAXLEN + 1];
|
char read_community[SNMP_COMMUNITY_MAXLEN + 1];
|
||||||
char write_community[SNMP_COMMUNITY_MAXLEN + 1];
|
char write_community[SNMP_COMMUNITY_MAXLEN + 1];
|
||||||
|
|
||||||
struct timeval timeout;
|
/* SNMPv3 specific fields */
|
||||||
u_int retries;
|
int32_t identifier;
|
||||||
|
int32_t security_model;
|
||||||
|
struct snmp_engine engine;
|
||||||
|
struct snmp_user user;
|
||||||
|
|
||||||
int dump_pdus;
|
/* SNMPv3 Access control - VACM*/
|
||||||
|
uint32_t clen;
|
||||||
|
uint8_t cengine[SNMP_ENGINE_ID_SIZ];
|
||||||
|
char cname[SNMP_CONTEXT_NAME_SIZ];
|
||||||
|
|
||||||
size_t txbuflen;
|
struct timeval timeout;
|
||||||
size_t rxbuflen;
|
u_int retries;
|
||||||
|
|
||||||
int fd;
|
int dump_pdus;
|
||||||
|
|
||||||
int32_t next_reqid;
|
size_t txbuflen;
|
||||||
int32_t max_reqid;
|
size_t rxbuflen;
|
||||||
int32_t min_reqid;
|
|
||||||
|
|
||||||
char error[SNMP_STRERROR_LEN];
|
int fd;
|
||||||
|
|
||||||
snmp_timeout_start_f timeout_start;
|
int32_t next_reqid;
|
||||||
snmp_timeout_stop_f timeout_stop;
|
int32_t max_reqid;
|
||||||
|
int32_t min_reqid;
|
||||||
|
|
||||||
/* private */
|
char error[SNMP_STRERROR_LEN];
|
||||||
char local_path[sizeof(SNMP_LOCAL_PATH)];
|
|
||||||
|
snmp_timeout_start_f timeout_start;
|
||||||
|
snmp_timeout_stop_f timeout_stop;
|
||||||
|
|
||||||
|
char local_path[sizeof(SNMP_LOCAL_PATH)];
|
||||||
};
|
};
|
||||||
.Ed
|
.Ed
|
||||||
.Pp
|
.Pp
|
||||||
@ -194,6 +207,23 @@ The default is
|
|||||||
The community name to be used for SET requests.
|
The community name to be used for SET requests.
|
||||||
The default is
|
The default is
|
||||||
.Sq private .
|
.Sq private .
|
||||||
|
.It Va identifier
|
||||||
|
The message indentifier 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 authorative 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
|
.It Va timeout
|
||||||
The maximum time to wait for responses to requests.
|
The maximum time to wait for responses to requests.
|
||||||
If the time elapses, the request is resent up to
|
If the time elapses, the request is resent up to
|
||||||
@ -617,6 +647,21 @@ returns -1.
|
|||||||
If a response was received 0 is returned.
|
If a response was received 0 is returned.
|
||||||
.Pp
|
.Pp
|
||||||
The function
|
The function
|
||||||
|
.Fn snmp_discover_engine
|
||||||
|
is used to discover the authorative 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 proccess 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 proccess was completed 0 is returned.
|
||||||
|
.Pp
|
||||||
|
The function
|
||||||
.Fn snmp_parse_server
|
.Fn snmp_parse_server
|
||||||
is used to parse an SNMP server specification string and fill in the
|
is used to parse an SNMP server specification string and fill in the
|
||||||
fields of a
|
fields of a
|
||||||
|
@ -1,4 +1,10 @@
|
|||||||
.\"
|
.\"
|
||||||
|
.\" 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
|
.\" Copyright (c) 2004-2005
|
||||||
.\" Hartmut Brandt.
|
.\" Hartmut Brandt.
|
||||||
.\" All rights reserved.
|
.\" All rights reserved.
|
||||||
@ -31,7 +37,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $Begemot: bsnmp/lib/bsnmplib.3,v 1.9 2005/10/04 08:46:51 brandt_h Exp $
|
.\" $Begemot: bsnmp/lib/bsnmplib.3,v 1.9 2005/10/04 08:46:51 brandt_h Exp $
|
||||||
.\"
|
.\"
|
||||||
.Dd October 4, 2005
|
.Dd September 9, 2010
|
||||||
.Dt BSNMPLIB 3
|
.Dt BSNMPLIB 3
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -39,9 +45,15 @@
|
|||||||
.Nm snmp_value_parse ,
|
.Nm snmp_value_parse ,
|
||||||
.Nm snmp_value_copy ,
|
.Nm snmp_value_copy ,
|
||||||
.Nm snmp_pdu_free ,
|
.Nm snmp_pdu_free ,
|
||||||
.Nm snmp_code snmp_pdu_decode ,
|
.Nm snmp_pdu_decode ,
|
||||||
.Nm snmp_code snmp_pdu_encode ,
|
.Nm snmp_pdu_encode ,
|
||||||
|
.Nm snmp_pdu_decode_header ,
|
||||||
|
.Nm snmp_pdu_decode_scoped ,
|
||||||
|
.Nm snmp_pdu_decode_secmode ,
|
||||||
.Nm snmp_pdu_dump ,
|
.Nm snmp_pdu_dump ,
|
||||||
|
.Nm snmp_passwd_to_keys ,
|
||||||
|
.Nm snmp_get_local_keys ,
|
||||||
|
.Nm snmp_calc_keychange ,
|
||||||
.Nm TRUTH_MK ,
|
.Nm TRUTH_MK ,
|
||||||
.Nm TRUTH_GET ,
|
.Nm TRUTH_GET ,
|
||||||
.Nm TRUTH_OK
|
.Nm TRUTH_OK
|
||||||
@ -64,8 +76,20 @@ Begemot SNMP library
|
|||||||
.Fn snmp_pdu_decode "struct asn_buf *buf" "struct snmp_pdu *pdu" "int32_t *ip"
|
.Fn snmp_pdu_decode "struct asn_buf *buf" "struct snmp_pdu *pdu" "int32_t *ip"
|
||||||
.Ft enum snmp_code
|
.Ft enum snmp_code
|
||||||
.Fn snmp_pdu_encode "struct snmp_pdu *pdu" "struct asn_buf *buf"
|
.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
|
.Ft void
|
||||||
.Fn snmp_pdu_dump "const struct snmp_pdu *pdu"
|
.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
|
.Ft int
|
||||||
.Fn TRUTH_MK "F"
|
.Fn TRUTH_MK "F"
|
||||||
.Ft int
|
.Ft int
|
||||||
@ -73,8 +97,8 @@ Begemot SNMP library
|
|||||||
.Ft int
|
.Ft int
|
||||||
.Fn TRUTH_OK "T"
|
.Fn TRUTH_OK "T"
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
The SNMP library contains routines to handle SNMP version 1 and 2 PDUs.
|
The SNMP library contains routines to handle SNMP version 1, 2 and 3 PDUs.
|
||||||
There are two basic structures used throughout the library:
|
There are several basic structures used throughout the library:
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
struct snmp_value {
|
struct snmp_value {
|
||||||
struct asn_oid var;
|
struct asn_oid var;
|
||||||
@ -134,34 +158,126 @@ is not zero,
|
|||||||
.Fa v.octetstring.octets
|
.Fa v.octetstring.octets
|
||||||
points to a string allocated by
|
points to a string allocated by
|
||||||
.Xr malloc 3 .
|
.Xr malloc 3 .
|
||||||
|
.Pp
|
||||||
.Bd -literal -offset indent
|
.Bd -literal -offset indent
|
||||||
#define SNMP_COMMUNITY_MAXLEN 128
|
#define SNMP_ENGINE_ID_SIZ 32
|
||||||
#define SNMP_MAX_BINDINGS 100
|
|
||||||
|
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.
|
||||||
|
.Pp
|
||||||
|
.Bd -literal -offset indent
|
||||||
|
#define SNMP_USM_NAME_SIZ (32 + 1)
|
||||||
|
#define SNMP_AUTH_KEY_SIZ 40
|
||||||
|
#define SNMP_PRIV_KEY_SIZ 32
|
||||||
|
|
||||||
|
struct snmp_user {
|
||||||
|
char sec_name[SNMP_USM_NAME_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.
|
||||||
|
.Pp
|
||||||
|
.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_SECMODEL_USM 3
|
||||||
|
|
||||||
struct snmp_pdu {
|
struct snmp_pdu {
|
||||||
char community[SNMP_COMMUNITY_MAXLEN + 1];
|
char community[SNMP_COMMUNITY_MAXLEN + 1];
|
||||||
enum snmp_version version;
|
enum snmp_version version;
|
||||||
u_int type;
|
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 */
|
/* trap only */
|
||||||
struct asn_oid enterprise;
|
struct asn_oid enterprise;
|
||||||
u_char agent_addr[4];
|
u_char agent_addr[4];
|
||||||
int32_t generic_trap;
|
int32_t generic_trap;
|
||||||
int32_t specific_trap;
|
int32_t specific_trap;
|
||||||
u_int32_t time_stamp;
|
uint32_t time_stamp;
|
||||||
|
|
||||||
/* others */
|
/* others */
|
||||||
int32_t request_id;
|
int32_t request_id;
|
||||||
int32_t error_status;
|
int32_t error_status;
|
||||||
int32_t error_index;
|
int32_t error_index;
|
||||||
|
|
||||||
/* fixes for encoding */
|
/* fixes for encoding */
|
||||||
u_char *outer_ptr;
|
size_t outer_len;
|
||||||
u_char *pdu_ptr;
|
size_t scoped_len;
|
||||||
u_char *vars_ptr;
|
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;
|
struct snmp_value bindings[SNMP_MAX_BINDINGS];
|
||||||
|
u_int nbindings;
|
||||||
};
|
};
|
||||||
.Ed
|
.Ed
|
||||||
This structure contains a decoded SNMP PDU.
|
This structure contains a decoded SNMP PDU.
|
||||||
@ -172,11 +288,15 @@ enum snmp_version {
|
|||||||
SNMP_Verr = 0,
|
SNMP_Verr = 0,
|
||||||
SNMP_V1 = 1,
|
SNMP_V1 = 1,
|
||||||
SNMP_V2c,
|
SNMP_V2c,
|
||||||
|
SNMP_V3
|
||||||
};
|
};
|
||||||
.Ed
|
.Ed
|
||||||
and
|
and
|
||||||
.Fa type
|
.Fa type
|
||||||
is the type of the PDU.
|
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).
|
||||||
.Pp
|
.Pp
|
||||||
The function
|
The function
|
||||||
.Fn snmp_value_free
|
.Fn snmp_value_free
|
||||||
@ -223,15 +343,60 @@ The function
|
|||||||
.Fn snmp_pdu_encode
|
.Fn snmp_pdu_encode
|
||||||
encodes the PDU
|
encodes the PDU
|
||||||
.Fa pdu
|
.Fa pdu
|
||||||
into the an octetstring in buffer
|
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 .
|
.Fa buf .
|
||||||
.Pp
|
.Pp
|
||||||
The function
|
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 successfull, a plain text scoped PDU is stored in the buffer.
|
||||||
|
.Pp
|
||||||
|
The function
|
||||||
.Fn snmp_pdu_dump
|
.Fn snmp_pdu_dump
|
||||||
dumps the PDU in a human readable form by calling
|
dumps the PDU in a human readable form by calling
|
||||||
.Fn snmp_printf .
|
.Fn snmp_printf .
|
||||||
.Pp
|
.Pp
|
||||||
The function
|
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
|
.Fn TRUTH_MK
|
||||||
takes a C truth value (zero or non-zero) and makes an SNMP truth value (2 or 1).
|
takes a C truth value (zero or non-zero) and makes an SNMP truth value (2 or 1).
|
||||||
The function
|
The function
|
||||||
@ -281,6 +446,13 @@ A variable binding value was out of the allowed range.
|
|||||||
The PDU is of an unsupported version.
|
The PDU is of an unsupported version.
|
||||||
.It Bq Er SNMP_CODE_BADENQ
|
.It Bq Er SNMP_CODE_BADENQ
|
||||||
There was an ASN.1 value with an unsupported tag.
|
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 occured while trying to decrypt the PDU.
|
||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
.Fn snmp_pdu_encode
|
.Fn snmp_pdu_encode
|
||||||
@ -297,8 +469,21 @@ Encoding failed.
|
|||||||
.Xr bsnmpagent 3 ,
|
.Xr bsnmpagent 3 ,
|
||||||
.Xr bsnmpclient 3 ,
|
.Xr bsnmpclient 3 ,
|
||||||
.Xr bsnmplib 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
|
.Sh STANDARDS
|
||||||
This implementation conforms to the applicable IETF RFCs and ITU-T
|
This implementation conforms to the applicable IETF RFCs and ITU-T
|
||||||
recommendations.
|
recommendations.
|
||||||
.Sh AUTHORS
|
.Sh AUTHORS
|
||||||
|
The Begemot SNMP library was originally written by
|
||||||
.An Hartmut Brandt Aq harti@FreeBSD.org
|
.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.
|
||||||
|
@ -5,6 +5,12 @@
|
|||||||
*
|
*
|
||||||
* Author: Harti Brandt <harti@freebsd.org>
|
* Author: Harti Brandt <harti@freebsd.org>
|
||||||
*
|
*
|
||||||
|
* 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
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
* are met:
|
* are met:
|
||||||
@ -271,112 +277,144 @@ parse_pdus(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
|
|||||||
return (err);
|
return (err);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Parse the outer SEQUENCE value. ASN_ERR_TAG means 'bad version'.
|
static enum asn_err
|
||||||
*/
|
parse_secparams(struct asn_buf *b, struct snmp_pdu *pdu)
|
||||||
enum asn_err
|
|
||||||
snmp_parse_message_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp)
|
|
||||||
{
|
{
|
||||||
int32_t version;
|
asn_len_t octs_len;
|
||||||
u_char type;
|
u_char buf[256]; /* XXX: calc max possible size here */
|
||||||
u_int comm_len;
|
struct asn_buf tb;
|
||||||
|
|
||||||
if (asn_get_integer(b, &version) != ASN_ERR_OK) {
|
memset(buf, 0, 256);
|
||||||
snmp_error("cannot decode version");
|
tb.asn_ptr = buf;
|
||||||
|
tb.asn_len = 256;
|
||||||
|
|
||||||
|
if (asn_get_octetstring(b, buf, &tb.asn_len) != ASN_ERR_OK) {
|
||||||
|
snmp_error("cannot parse usm header");
|
||||||
return (ASN_ERR_FAILED);
|
return (ASN_ERR_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (version == 0) {
|
if (asn_get_sequence(&tb, &octs_len) != ASN_ERR_OK) {
|
||||||
pdu->version = SNMP_V1;
|
snmp_error("cannot decode usm header");
|
||||||
} else if (version == 1) {
|
|
||||||
pdu->version = SNMP_V2c;
|
|
||||||
} else {
|
|
||||||
pdu->version = SNMP_Verr;
|
|
||||||
snmp_error("unsupported SNMP version");
|
|
||||||
return (ASN_ERR_TAG);
|
|
||||||
}
|
|
||||||
|
|
||||||
comm_len = SNMP_COMMUNITY_MAXLEN;
|
|
||||||
if (asn_get_octetstring(b, (u_char *)pdu->community,
|
|
||||||
&comm_len) != ASN_ERR_OK) {
|
|
||||||
snmp_error("cannot decode community");
|
|
||||||
return (ASN_ERR_FAILED);
|
|
||||||
}
|
|
||||||
pdu->community[comm_len] = '\0';
|
|
||||||
|
|
||||||
if (asn_get_header(b, &type, lenp) != ASN_ERR_OK) {
|
|
||||||
snmp_error("cannot get pdu header");
|
|
||||||
return (ASN_ERR_FAILED);
|
|
||||||
}
|
|
||||||
if ((type & ~ASN_TYPE_MASK) !=
|
|
||||||
(ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) {
|
|
||||||
snmp_error("bad pdu header tag");
|
|
||||||
return (ASN_ERR_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 (ASN_ERR_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 (ASN_ERR_FAILED);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
snmp_error("bad pdu type %u", pdu->type);
|
|
||||||
return (ASN_ERR_FAILED);
|
return (ASN_ERR_FAILED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
octs_len = SNMP_ENGINE_ID_SIZ;
|
||||||
if (*lenp > b->asn_len) {
|
if (asn_get_octetstring(&tb, (u_char *)&pdu->engine.engine_id,
|
||||||
snmp_error("pdu length too long");
|
&octs_len) != ASN_ERR_OK) {
|
||||||
|
snmp_error("cannot decode msg engine id");
|
||||||
return (ASN_ERR_FAILED);
|
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);
|
return (ASN_ERR_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
static enum asn_err
|
static enum snmp_code
|
||||||
parse_message(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
|
pdu_encode_secparams(struct asn_buf *b, struct snmp_pdu *pdu)
|
||||||
{
|
{
|
||||||
enum asn_err err;
|
u_char buf[256], *sptr;
|
||||||
asn_len_t len, trailer;
|
struct asn_buf tb;
|
||||||
|
size_t auth_off, moved = 0;
|
||||||
|
|
||||||
err = snmp_parse_message_hdr(b, pdu, &len);
|
auth_off = 0;
|
||||||
if (ASN_ERR_STOPPED(err))
|
memset(buf, 0, 256);
|
||||||
return (err);
|
tb.asn_ptr = buf;
|
||||||
|
tb.asn_len = 256;
|
||||||
|
|
||||||
trailer = b->asn_len - len;
|
if (asn_put_temp_header(&tb, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
|
||||||
b->asn_len = len;
|
&sptr) != ASN_ERR_OK)
|
||||||
|
return (SNMP_CODE_FAILED);
|
||||||
|
|
||||||
err = parse_pdus(b, pdu, ip);
|
if (asn_put_octetstring(&tb, (u_char *)pdu->engine.engine_id,
|
||||||
if (ASN_ERR_STOPPED(err))
|
pdu->engine.engine_len) != ASN_ERR_OK)
|
||||||
return (ASN_ERR_FAILED);
|
return (SNMP_CODE_FAILED);
|
||||||
|
|
||||||
if (b->asn_len != 0)
|
if (asn_put_integer(&tb, pdu->engine.engine_boots) != ASN_ERR_OK)
|
||||||
snmp_error("ignoring trailing junk after pdu");
|
return (SNMP_CODE_FAILED);
|
||||||
|
|
||||||
b->asn_len = trailer;
|
if (asn_put_integer(&tb, pdu->engine.engine_time) != ASN_ERR_OK)
|
||||||
|
return (SNMP_CODE_FAILED);
|
||||||
|
|
||||||
return (err);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -388,9 +426,45 @@ parse_message(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
|
|||||||
enum snmp_code
|
enum snmp_code
|
||||||
snmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
|
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;
|
asn_len_t len;
|
||||||
|
|
||||||
memset(pdu, 0, sizeof(*pdu));
|
pdu->outer_ptr = b->asn_ptr;
|
||||||
|
pdu->outer_len = b->asn_len;
|
||||||
|
|
||||||
if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
|
if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
|
||||||
snmp_error("cannot decode pdu header");
|
snmp_error("cannot decode pdu header");
|
||||||
@ -405,32 +479,192 @@ snmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
|
|||||||
b->asn_len = len;
|
b->asn_len = len;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (parse_message(b, pdu, ip)) {
|
if (asn_get_integer(b, &version) != ASN_ERR_OK) {
|
||||||
|
snmp_error("cannot decode version");
|
||||||
case ASN_ERR_OK:
|
|
||||||
return (SNMP_CODE_OK);
|
|
||||||
|
|
||||||
case ASN_ERR_FAILED:
|
|
||||||
case ASN_ERR_EOBUF:
|
|
||||||
snmp_pdu_free(pdu);
|
|
||||||
return (SNMP_CODE_FAILED);
|
return (SNMP_CODE_FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
case ASN_ERR_BADLEN:
|
if (version == 0)
|
||||||
return (SNMP_CODE_BADLEN);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
case ASN_ERR_RANGE:
|
if (pdu->version == SNMP_V3) {
|
||||||
return (SNMP_CODE_OORANGE);
|
if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
|
||||||
|
snmp_error("cannot decode pdu global data header");
|
||||||
|
return (SNMP_CODE_FAILED);
|
||||||
|
}
|
||||||
|
|
||||||
case ASN_ERR_TAG:
|
if (asn_get_integer(b, &pdu->identifier) != ASN_ERR_OK) {
|
||||||
if (pdu->version == SNMP_Verr)
|
snmp_error("cannot decode msg indetifier");
|
||||||
return (SNMP_CODE_BADVERS);
|
return (SNMP_CODE_FAILED);
|
||||||
else
|
}
|
||||||
return (SNMP_CODE_BADENC);
|
|
||||||
|
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);
|
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(b, 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(b, pdu)) != SNMP_CODE_OK)
|
||||||
|
return (SNMP_CODE_FAILED);
|
||||||
|
|
||||||
|
return (code);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Check whether what we have is the complete PDU by snooping at the
|
* Check whether what we have is the complete PDU by snooping at the
|
||||||
* enclosing structure header. This returns:
|
* enclosing structure header. This returns:
|
||||||
@ -500,6 +734,7 @@ enum snmp_code
|
|||||||
snmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu)
|
snmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu)
|
||||||
{
|
{
|
||||||
enum asn_err err;
|
enum asn_err err;
|
||||||
|
u_char *v3_hdr_ptr;
|
||||||
|
|
||||||
if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
|
if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
|
||||||
&pdu->outer_ptr) != ASN_ERR_OK)
|
&pdu->outer_ptr) != ASN_ERR_OK)
|
||||||
@ -509,14 +744,62 @@ snmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu)
|
|||||||
err = asn_put_integer(b, 0);
|
err = asn_put_integer(b, 0);
|
||||||
else if (pdu->version == SNMP_V2c)
|
else if (pdu->version == SNMP_V2c)
|
||||||
err = asn_put_integer(b, 1);
|
err = asn_put_integer(b, 1);
|
||||||
|
else if (pdu->version == SNMP_V3)
|
||||||
|
err = asn_put_integer(b, 3);
|
||||||
else
|
else
|
||||||
return (SNMP_CODE_BADVERS);
|
return (SNMP_CODE_BADVERS);
|
||||||
if (err != ASN_ERR_OK)
|
if (err != ASN_ERR_OK)
|
||||||
return (SNMP_CODE_FAILED);
|
return (SNMP_CODE_FAILED);
|
||||||
|
|
||||||
if (asn_put_octetstring(b, (u_char *)pdu->community,
|
if (pdu->version == SNMP_V3) {
|
||||||
strlen(pdu->community)) != ASN_ERR_OK)
|
if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
|
||||||
return (SNMP_CODE_FAILED);
|
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_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 |
|
if (asn_put_temp_header(b, (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT |
|
||||||
pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK)
|
pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK)
|
||||||
@ -550,13 +833,66 @@ snmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu)
|
|||||||
return (SNMP_CODE_OK);
|
return (SNMP_CODE_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum snmp_code
|
static enum asn_err
|
||||||
snmp_fix_encoding(struct asn_buf *b, const struct snmp_pdu *pdu)
|
snmp_pdu_fix_padd(struct asn_buf *b, struct snmp_pdu *pdu)
|
||||||
{
|
{
|
||||||
if (asn_commit_header(b, pdu->vars_ptr) != ASN_ERR_OK ||
|
asn_len_t padlen;
|
||||||
asn_commit_header(b, pdu->pdu_ptr) != ASN_ERR_OK ||
|
|
||||||
asn_commit_header(b, pdu->outer_ptr) != ASN_ERR_OK)
|
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);
|
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 ((code = 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(b, 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(b, 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);
|
return (SNMP_CODE_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -639,7 +975,7 @@ snmp_binding_encode(struct asn_buf *b, const struct snmp_value *binding)
|
|||||||
return (err);
|
return (err);
|
||||||
}
|
}
|
||||||
|
|
||||||
err = asn_commit_header(b, ptr);
|
err = asn_commit_header(b, ptr, NULL);
|
||||||
if (err != ASN_ERR_OK) {
|
if (err != ASN_ERR_OK) {
|
||||||
*b = save;
|
*b = save;
|
||||||
return (err);
|
return (err);
|
||||||
@ -775,6 +1111,8 @@ snmp_pdu_dump(const struct snmp_pdu *pdu)
|
|||||||
vers = "SNMPv1";
|
vers = "SNMPv1";
|
||||||
else if (pdu->version == SNMP_V2c)
|
else if (pdu->version == SNMP_V2c)
|
||||||
vers = "SNMPv2c";
|
vers = "SNMPv2c";
|
||||||
|
else if (pdu->version == SNMP_V3)
|
||||||
|
vers = "SNMPv3";
|
||||||
else
|
else
|
||||||
vers = "v?";
|
vers = "v?";
|
||||||
|
|
||||||
@ -837,6 +1175,39 @@ snmp_value_copy(struct snmp_value *to, const struct snmp_value *from)
|
|||||||
return (0);
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
snmp_pdu_init_secparams(struct snmp_pdu *pdu, struct snmp_engine *eng,
|
||||||
|
struct snmp_user *user)
|
||||||
|
{
|
||||||
|
int32_t rval;
|
||||||
|
|
||||||
|
memcpy(&pdu->engine, eng, sizeof(pdu->engine));
|
||||||
|
memcpy(&pdu->user, user, sizeof(pdu->user));
|
||||||
|
|
||||||
|
if (user->auth_proto != SNMP_AUTH_NOAUTH)
|
||||||
|
pdu->flags |= SNMP_MSG_AUTH_FLAG;
|
||||||
|
|
||||||
|
switch (user->priv_proto) {
|
||||||
|
case SNMP_PRIV_DES:
|
||||||
|
memcpy(pdu->msg_salt, &eng->engine_boots,
|
||||||
|
sizeof(eng->engine_boots));
|
||||||
|
rval = random();
|
||||||
|
memcpy(pdu->msg_salt + sizeof(eng->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
|
void
|
||||||
snmp_pdu_free(struct snmp_pdu *pdu)
|
snmp_pdu_free(struct snmp_pdu *pdu)
|
||||||
{
|
{
|
||||||
|
@ -5,6 +5,13 @@
|
|||||||
*
|
*
|
||||||
* Author: Harti Brandt <harti@freebsd.org>
|
* Author: Harti Brandt <harti@freebsd.org>
|
||||||
*
|
*
|
||||||
|
* 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
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
* are met:
|
* are met:
|
||||||
@ -35,8 +42,11 @@
|
|||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#define SNMP_COMMUNITY_MAXLEN 128
|
#define SNMP_COMMUNITY_MAXLEN 128
|
||||||
#define SNMP_MAX_BINDINGS 100
|
#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 {
|
enum snmp_syntax {
|
||||||
SNMP_SYNTAX_NULL = 0,
|
SNMP_SYNTAX_NULL = 0,
|
||||||
@ -75,33 +85,110 @@ struct snmp_value {
|
|||||||
enum snmp_version {
|
enum snmp_version {
|
||||||
SNMP_Verr = 0,
|
SNMP_Verr = 0,
|
||||||
SNMP_V1 = 1,
|
SNMP_V1 = 1,
|
||||||
SNMP_V2c,
|
SNMP_V2c = 2,
|
||||||
|
SNMP_V3,
|
||||||
|
};
|
||||||
|
|
||||||
|
#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 {
|
struct snmp_pdu {
|
||||||
char community[SNMP_COMMUNITY_MAXLEN + 1];
|
char community[SNMP_COMMUNITY_MAXLEN + 1];
|
||||||
enum snmp_version version;
|
enum snmp_version version;
|
||||||
u_int type;
|
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 */
|
/* trap only */
|
||||||
struct asn_oid enterprise;
|
struct asn_oid enterprise;
|
||||||
u_char agent_addr[4];
|
u_char agent_addr[4];
|
||||||
int32_t generic_trap;
|
int32_t generic_trap;
|
||||||
int32_t specific_trap;
|
int32_t specific_trap;
|
||||||
uint32_t time_stamp;
|
uint32_t time_stamp;
|
||||||
|
|
||||||
/* others */
|
/* others */
|
||||||
int32_t request_id;
|
int32_t request_id;
|
||||||
int32_t error_status;
|
int32_t error_status;
|
||||||
int32_t error_index;
|
int32_t error_index;
|
||||||
|
|
||||||
/* fixes for encoding */
|
/* fixes for encoding */
|
||||||
u_char *outer_ptr;
|
size_t outer_len;
|
||||||
u_char *pdu_ptr;
|
size_t scoped_len;
|
||||||
u_char *vars_ptr;
|
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;
|
struct snmp_value bindings[SNMP_MAX_BINDINGS];
|
||||||
|
u_int nbindings;
|
||||||
};
|
};
|
||||||
#define snmp_v1_pdu snmp_pdu
|
#define snmp_v1_pdu snmp_pdu
|
||||||
|
|
||||||
@ -150,20 +237,38 @@ enum snmp_code {
|
|||||||
SNMP_CODE_BADLEN,
|
SNMP_CODE_BADLEN,
|
||||||
SNMP_CODE_BADENC,
|
SNMP_CODE_BADENC,
|
||||||
SNMP_CODE_OORANGE,
|
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 *);
|
void snmp_value_free(struct snmp_value *);
|
||||||
int snmp_value_parse(const char *, enum snmp_syntax, union snmp_values *);
|
int snmp_value_parse(const char *, enum snmp_syntax, union snmp_values *);
|
||||||
int snmp_value_copy(struct snmp_value *, const struct snmp_value *);
|
int snmp_value_copy(struct snmp_value *, const struct snmp_value *);
|
||||||
|
|
||||||
void snmp_pdu_free(struct snmp_pdu *);
|
void snmp_pdu_free(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(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *);
|
||||||
enum snmp_code snmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b);
|
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 *);
|
int snmp_pdu_snoop(const struct asn_buf *);
|
||||||
|
|
||||||
void snmp_pdu_dump(const struct snmp_pdu *pdu);
|
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_error)(const char *, ...);
|
||||||
extern void (*snmp_printf)(const char *, ...);
|
extern void (*snmp_printf)(const char *, ...);
|
||||||
|
|
||||||
|
@ -165,6 +165,29 @@ find_subnode(const struct snmp_value *value)
|
|||||||
return (NULL);
|
return (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
snmp_pdu_create_response(struct snmp_pdu *pdu, struct snmp_pdu *resp)
|
||||||
|
{
|
||||||
|
memset(resp, 0, sizeof(*resp));
|
||||||
|
strcpy(resp->community, pdu->community);
|
||||||
|
resp->version = pdu->version;
|
||||||
|
resp->type = SNMP_PDU_RESPONSE;
|
||||||
|
resp->request_id = pdu->request_id;
|
||||||
|
resp->version = pdu->version;
|
||||||
|
|
||||||
|
if (resp->version != SNMP_V3)
|
||||||
|
return;
|
||||||
|
|
||||||
|
snmp_pdu_init_secparams(resp, &pdu->engine, &pdu->user);
|
||||||
|
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'.
|
* 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
|
* Build the response PDU on the fly. If the return code is SNMP_RET_ERR
|
||||||
@ -184,12 +207,7 @@ snmp_get(struct snmp_pdu *pdu, struct asn_buf *resp_b,
|
|||||||
memset(&context, 0, sizeof(context));
|
memset(&context, 0, sizeof(context));
|
||||||
context.ctx.data = data;
|
context.ctx.data = data;
|
||||||
|
|
||||||
memset(resp, 0, sizeof(*resp));
|
snmp_pdu_create_response(pdu, resp);
|
||||||
strcpy(resp->community, pdu->community);
|
|
||||||
resp->version = pdu->version;
|
|
||||||
resp->type = SNMP_PDU_RESPONSE;
|
|
||||||
resp->request_id = pdu->request_id;
|
|
||||||
resp->version = pdu->version;
|
|
||||||
|
|
||||||
if (snmp_pdu_encode_header(resp_b, resp) != SNMP_CODE_OK)
|
if (snmp_pdu_encode_header(resp_b, resp) != SNMP_CODE_OK)
|
||||||
/* cannot even encode header - very bad */
|
/* cannot even encode header - very bad */
|
||||||
@ -384,11 +402,7 @@ snmp_getnext(struct snmp_pdu *pdu, struct asn_buf *resp_b,
|
|||||||
memset(&context, 0, sizeof(context));
|
memset(&context, 0, sizeof(context));
|
||||||
context.ctx.data = data;
|
context.ctx.data = data;
|
||||||
|
|
||||||
memset(resp, 0, sizeof(*resp));
|
snmp_pdu_create_response(pdu, resp);
|
||||||
strcpy(resp->community, pdu->community);
|
|
||||||
resp->type = SNMP_PDU_RESPONSE;
|
|
||||||
resp->request_id = pdu->request_id;
|
|
||||||
resp->version = pdu->version;
|
|
||||||
|
|
||||||
if (snmp_pdu_encode_header(resp_b, resp))
|
if (snmp_pdu_encode_header(resp_b, resp))
|
||||||
return (SNMP_RET_IGN);
|
return (SNMP_RET_IGN);
|
||||||
@ -440,12 +454,7 @@ snmp_getbulk(struct snmp_pdu *pdu, struct asn_buf *resp_b,
|
|||||||
memset(&context, 0, sizeof(context));
|
memset(&context, 0, sizeof(context));
|
||||||
context.ctx.data = data;
|
context.ctx.data = data;
|
||||||
|
|
||||||
memset(resp, 0, sizeof(*resp));
|
snmp_pdu_create_response(pdu, resp);
|
||||||
strcpy(resp->community, pdu->community);
|
|
||||||
resp->version = pdu->version;
|
|
||||||
resp->type = SNMP_PDU_RESPONSE;
|
|
||||||
resp->request_id = pdu->request_id;
|
|
||||||
resp->version = pdu->version;
|
|
||||||
|
|
||||||
if (snmp_pdu_encode_header(resp_b, resp) != SNMP_CODE_OK)
|
if (snmp_pdu_encode_header(resp_b, resp) != SNMP_CODE_OK)
|
||||||
/* cannot even encode header - very bad */
|
/* cannot even encode header - very bad */
|
||||||
@ -652,11 +661,7 @@ snmp_set(struct snmp_pdu *pdu, struct asn_buf *resp_b,
|
|||||||
TAILQ_INIT(&context.dlist);
|
TAILQ_INIT(&context.dlist);
|
||||||
context.ctx.data = data;
|
context.ctx.data = data;
|
||||||
|
|
||||||
memset(resp, 0, sizeof(*resp));
|
snmp_pdu_create_response(pdu, resp);
|
||||||
strcpy(resp->community, pdu->community);
|
|
||||||
resp->type = SNMP_PDU_RESPONSE;
|
|
||||||
resp->request_id = pdu->request_id;
|
|
||||||
resp->version = pdu->version;
|
|
||||||
|
|
||||||
if (snmp_pdu_encode_header(resp_b, resp))
|
if (snmp_pdu_encode_header(resp_b, resp))
|
||||||
return (SNMP_RET_IGN);
|
return (SNMP_RET_IGN);
|
||||||
@ -951,16 +956,9 @@ snmp_make_errresp(const struct snmp_pdu *pdu, struct asn_buf *pdu_b,
|
|||||||
enum snmp_code code;
|
enum snmp_code code;
|
||||||
|
|
||||||
memset(&resp, 0, sizeof(resp));
|
memset(&resp, 0, sizeof(resp));
|
||||||
|
if ((code = snmp_pdu_decode_header(pdu_b, &resp)) != SNMP_CODE_OK)
|
||||||
/* Message sequence */
|
|
||||||
if (asn_get_sequence(pdu_b, &len) != ASN_ERR_OK)
|
|
||||||
return (SNMP_RET_IGN);
|
|
||||||
if (pdu_b->asn_len < len)
|
|
||||||
return (SNMP_RET_IGN);
|
return (SNMP_RET_IGN);
|
||||||
|
|
||||||
err = snmp_parse_message_hdr(pdu_b, &resp, &len);
|
|
||||||
if (ASN_ERR_STOPPED(err))
|
|
||||||
return (SNMP_RET_IGN);
|
|
||||||
if (pdu_b->asn_len < len)
|
if (pdu_b->asn_len < len)
|
||||||
return (SNMP_RET_IGN);
|
return (SNMP_RET_IGN);
|
||||||
pdu_b->asn_len = len;
|
pdu_b->asn_len = len;
|
||||||
|
@ -852,6 +852,9 @@ snmp_client_init(struct snmp_client *c)
|
|||||||
|
|
||||||
strcpy(c->read_community, "public");
|
strcpy(c->read_community, "public");
|
||||||
strcpy(c->write_community, "private");
|
strcpy(c->write_community, "private");
|
||||||
|
|
||||||
|
c->security_model = SNMP_SECMODEL_USM;
|
||||||
|
strcpy(c->cname, "");
|
||||||
|
|
||||||
c->timeout.tv_sec = 3;
|
c->timeout.tv_sec = 3;
|
||||||
c->timeout.tv_usec = 0;
|
c->timeout.tv_usec = 0;
|
||||||
@ -864,6 +867,8 @@ snmp_client_init(struct snmp_client *c)
|
|||||||
c->max_reqid = INT32_MAX;
|
c->max_reqid = INT32_MAX;
|
||||||
c->min_reqid = 0;
|
c->min_reqid = 0;
|
||||||
c->next_reqid = 0;
|
c->next_reqid = 0;
|
||||||
|
|
||||||
|
c->engine.max_msg_size = 1500; /* XXX */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1132,7 +1137,8 @@ snmp_close(void)
|
|||||||
void
|
void
|
||||||
snmp_pdu_create(struct snmp_pdu *pdu, u_int op)
|
snmp_pdu_create(struct snmp_pdu *pdu, u_int op)
|
||||||
{
|
{
|
||||||
memset(pdu,0,sizeof(struct snmp_pdu));
|
memset(pdu, 0, sizeof(struct snmp_pdu));
|
||||||
|
|
||||||
if (op == SNMP_PDU_SET)
|
if (op == SNMP_PDU_SET)
|
||||||
strlcpy(pdu->community, snmp_client.write_community,
|
strlcpy(pdu->community, snmp_client.write_community,
|
||||||
sizeof(pdu->community));
|
sizeof(pdu->community));
|
||||||
@ -1145,6 +1151,33 @@ snmp_pdu_create(struct snmp_pdu *pdu, u_int op)
|
|||||||
pdu->error_status = 0;
|
pdu->error_status = 0;
|
||||||
pdu->error_index = 0;
|
pdu->error_index = 0;
|
||||||
pdu->nbindings = 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)
|
||||||
|
snmp_pdu_init_secparams(pdu, &snmp_client.engine,
|
||||||
|
&snmp_client.user);
|
||||||
|
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 */
|
/* add pairs of (struct asn_oid, enum snmp_syntax) to an existing pdu */
|
||||||
@ -1406,15 +1439,24 @@ snmp_receive_packet(struct snmp_pdu *pdu, struct timeval *tv)
|
|||||||
abuf.asn_ptr = buf;
|
abuf.asn_ptr = buf;
|
||||||
abuf.asn_len = ret;
|
abuf.asn_len = ret;
|
||||||
|
|
||||||
|
memset(pdu, 0, sizeof(*pdu));
|
||||||
|
if (snmp_client.security_model == SNMP_SECMODEL_USM)
|
||||||
|
snmp_pdu_init_secparams(pdu, &snmp_client.engine,
|
||||||
|
&snmp_client.user);
|
||||||
|
|
||||||
if (SNMP_CODE_OK != (ret = snmp_pdu_decode(&abuf, pdu, &ip))) {
|
if (SNMP_CODE_OK != (ret = snmp_pdu_decode(&abuf, pdu, &ip))) {
|
||||||
seterr(&snmp_client, "snmp_decode_pdu: failed %d", ret);
|
seterr(&snmp_client, "snmp_decode_pdu: failed %d", ret);
|
||||||
free(buf);
|
free(buf);
|
||||||
return (-1);
|
return (-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
if (snmp_client.dump_pdus)
|
if (snmp_client.dump_pdus)
|
||||||
snmp_pdu_dump(pdu);
|
snmp_pdu_dump(pdu);
|
||||||
|
|
||||||
|
snmp_client.engine.engine_time = pdu->engine.engine_time;
|
||||||
|
snmp_client.engine.engine_boots = pdu->engine.engine_boots;
|
||||||
|
|
||||||
return (+1);
|
return (+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1684,6 +1726,93 @@ snmp_dialog(struct snmp_v1_pdu *req, struct snmp_v1_pdu *resp)
|
|||||||
return (-1);
|
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_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;
|
||||||
|
|
||||||
|
return (0);
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
snmp_client_set_host(struct snmp_client *cl, const char *h)
|
snmp_client_set_host(struct snmp_client *cl, const char *h)
|
||||||
{
|
{
|
||||||
|
@ -69,36 +69,47 @@ typedef void (*snmp_timeout_stop_f)(void *timeout_id);
|
|||||||
* Client context.
|
* Client context.
|
||||||
*/
|
*/
|
||||||
struct snmp_client {
|
struct snmp_client {
|
||||||
enum snmp_version version;
|
enum snmp_version version;
|
||||||
int trans; /* which transport to use */
|
int trans; /* which transport to use */
|
||||||
|
|
||||||
/* these two are read-only for the application */
|
/* these two are read-only for the application */
|
||||||
char *cport; /* port number as string */
|
char *cport; /* port number as string */
|
||||||
char *chost; /* host name or IP address as string */
|
char *chost; /* host name or IP address as string */
|
||||||
|
|
||||||
char read_community[SNMP_COMMUNITY_MAXLEN + 1];
|
char read_community[SNMP_COMMUNITY_MAXLEN + 1];
|
||||||
char write_community[SNMP_COMMUNITY_MAXLEN + 1];
|
char write_community[SNMP_COMMUNITY_MAXLEN + 1];
|
||||||
|
|
||||||
struct timeval timeout;
|
/* SNMPv3 specific fields */
|
||||||
u_int retries;
|
int32_t identifier;
|
||||||
|
int32_t security_model;
|
||||||
|
struct snmp_engine engine;
|
||||||
|
struct snmp_user user;
|
||||||
|
|
||||||
int dump_pdus;
|
/* SNMPv3 Access control - VACM*/
|
||||||
|
uint32_t clen;
|
||||||
|
uint8_t cengine[SNMP_ENGINE_ID_SIZ];
|
||||||
|
char cname[SNMP_CONTEXT_NAME_SIZ];
|
||||||
|
|
||||||
size_t txbuflen;
|
struct timeval timeout;
|
||||||
size_t rxbuflen;
|
u_int retries;
|
||||||
|
|
||||||
int fd;
|
int dump_pdus;
|
||||||
|
|
||||||
int32_t next_reqid;
|
size_t txbuflen;
|
||||||
int32_t max_reqid;
|
size_t rxbuflen;
|
||||||
int32_t min_reqid;
|
|
||||||
|
|
||||||
char error[SNMP_STRERROR_LEN];
|
int fd;
|
||||||
|
|
||||||
snmp_timeout_start_f timeout_start;
|
int32_t next_reqid;
|
||||||
snmp_timeout_stop_f timeout_stop;
|
int32_t max_reqid;
|
||||||
|
int32_t min_reqid;
|
||||||
|
|
||||||
char local_path[sizeof(SNMP_LOCAL_PATH)];
|
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 */
|
/* the global context */
|
||||||
@ -181,6 +192,9 @@ int snmp_table_fetch_async(const struct snmp_table *, void *,
|
|||||||
/* send a request and wait for the response */
|
/* send a request and wait for the response */
|
||||||
int snmp_dialog(struct snmp_pdu *_req, struct snmp_pdu *_resp);
|
int snmp_dialog(struct snmp_pdu *_req, struct snmp_pdu *_resp);
|
||||||
|
|
||||||
|
/* discover an authorative snmpEngineId */
|
||||||
|
int snmp_discover_engine(char *);
|
||||||
|
|
||||||
/* parse a server specification */
|
/* parse a server specification */
|
||||||
int snmp_parse_server(struct snmp_client *, const char *);
|
int snmp_parse_server(struct snmp_client *, const char *);
|
||||||
|
|
||||||
|
@ -34,12 +34,18 @@
|
|||||||
|
|
||||||
enum asn_err snmp_binding_encode(struct asn_buf *, const struct snmp_value *);
|
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_pdu_encode_header(struct asn_buf *, struct snmp_pdu *);
|
||||||
enum snmp_code snmp_fix_encoding(struct asn_buf *, const struct snmp_pdu *);
|
enum snmp_code snmp_fix_encoding(struct asn_buf *, struct snmp_pdu *);
|
||||||
enum asn_err snmp_parse_message_hdr(struct asn_buf *b, struct snmp_pdu *pdu,
|
|
||||||
asn_len_t *lenp);
|
|
||||||
enum asn_err snmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu,
|
enum asn_err snmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu,
|
||||||
asn_len_t *lenp);
|
asn_len_t *lenp);
|
||||||
|
|
||||||
|
void snmp_pdu_init_secparams(struct snmp_pdu *, struct snmp_engine *,
|
||||||
|
struct snmp_user *);
|
||||||
|
|
||||||
|
enum snmp_code snmp_pdu_calc_digest(struct asn_buf *, const struct snmp_pdu *,
|
||||||
|
uint8_t *);
|
||||||
|
enum snmp_code snmp_pdu_encrypt(struct asn_buf *, const struct snmp_pdu *);
|
||||||
|
enum snmp_code snmp_pdu_decrypt(struct asn_buf *, const struct snmp_pdu *);
|
||||||
|
|
||||||
#define DEFAULT_HOST "localhost"
|
#define DEFAULT_HOST "localhost"
|
||||||
#define DEFAULT_PORT "snmp"
|
#define DEFAULT_PORT "snmp"
|
||||||
#define DEFAULT_LOCAL "/var/run/snmp.sock"
|
#define DEFAULT_LOCAL "/var/run/snmp.sock"
|
||||||
|
132
contrib/bsnmp/snmp_usm/snmp_usm.3
Executable file
132
contrib/bsnmp/snmp_usm/snmp_usm.3
Executable file
@ -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$
|
||||||
|
.\"
|
||||||
|
.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 successfull.
|
||||||
|
.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 exsiting 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
|
614
contrib/bsnmp/snmp_usm/usm_snmp.c
Executable file
614
contrib/bsnmp/snmp_usm/usm_snmp.c
Executable file
@ -0,0 +1,614 @@
|
|||||||
|
/*-
|
||||||
|
* 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$
|
||||||
|
*/
|
||||||
|
#include <sys/queue.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
|
||||||
|
#include "asn1.h"
|
||||||
|
#include "snmp.h"
|
||||||
|
#include "snmpmod.h"
|
||||||
|
|
||||||
|
#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);
|
||||||
|
|
||||||
|
if (community != COMM_INITIALIZE &&
|
||||||
|
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,
|
||||||
|
SNMP_PRIV_KEY_SIZ);
|
||||||
|
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,
|
||||||
|
SNMP_ADM_STR32_SIZ);
|
||||||
|
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,
|
||||||
|
SNMP_AUTH_KEY_SIZ);
|
||||||
|
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,
|
||||||
|
SNMP_AUTH_KEY_SIZ);
|
||||||
|
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,
|
||||||
|
SNMP_ADM_STR32_SIZ);
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char usm_comment[] = \
|
||||||
|
"This module implements SNMP User-based Security Model defined in RFC 3414.";
|
||||||
|
|
||||||
|
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,
|
||||||
|
};
|
109
contrib/bsnmp/snmp_usm/usm_tree.def
Executable file
109
contrib/bsnmp/snmp_usm/usm_tree.def
Executable file
@ -0,0 +1,109 @@
|
|||||||
|
#-
|
||||||
|
# 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 StorageType ENUM (
|
||||||
|
1 other
|
||||||
|
2 volatile
|
||||||
|
3 nonVolatile
|
||||||
|
4 permanent
|
||||||
|
5 readOnly
|
||||||
|
)
|
||||||
|
|
||||||
|
typedef RowStatus ENUM (
|
||||||
|
1 active
|
||||||
|
2 notInService
|
||||||
|
3 notReady
|
||||||
|
4 createAndGo
|
||||||
|
5 createAndWait
|
||||||
|
6 destroy
|
||||||
|
)
|
||||||
|
|
||||||
|
(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
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
94
contrib/bsnmp/snmp_vacm/snmp_vacm.3
Executable file
94
contrib/bsnmp/snmp_vacm/snmp_vacm.3
Executable file
@ -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$
|
||||||
|
.\"
|
||||||
|
.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 forbiden.
|
||||||
|
.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
|
1026
contrib/bsnmp/snmp_vacm/vacm_snmp.c
Executable file
1026
contrib/bsnmp/snmp_vacm/vacm_snmp.c
Executable file
File diff suppressed because it is too large
Load Diff
104
contrib/bsnmp/snmp_vacm/vacm_tree.def
Executable file
104
contrib/bsnmp/snmp_vacm/vacm_tree.def
Executable file
@ -0,0 +1,104 @@
|
|||||||
|
#-
|
||||||
|
# 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 StorageType ENUM (
|
||||||
|
1 other
|
||||||
|
2 volatile
|
||||||
|
3 nonVolatile
|
||||||
|
4 permanent
|
||||||
|
5 readOnly
|
||||||
|
)
|
||||||
|
|
||||||
|
typedef RowStatus ENUM (
|
||||||
|
1 active
|
||||||
|
2 notInService
|
||||||
|
3 notReady
|
||||||
|
4 createAndGo
|
||||||
|
5 createAndWait
|
||||||
|
6 destroy
|
||||||
|
)
|
||||||
|
|
||||||
|
(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
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
@ -139,7 +139,8 @@ begemotSnmpdVersionEnable OBJECT-TYPE
|
|||||||
bits are defined:
|
bits are defined:
|
||||||
|
|
||||||
0x00000001 - SNMPv1
|
0x00000001 - SNMPv1
|
||||||
0x00000002 - SNMPv2c"
|
0x00000002 - SNMPv2c
|
||||||
|
0x00000004 - SNMPv3"
|
||||||
DEFVAL { 3 }
|
DEFVAL { 3 }
|
||||||
::= { begemotSnmpdConfig 5 }
|
::= { begemotSnmpdConfig 5 }
|
||||||
|
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
* Variable access for SNMPd
|
* Variable access for SNMPd
|
||||||
*/
|
*/
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
@ -42,6 +43,7 @@
|
|||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
|
#include <errno.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
|
||||||
#include "snmpmod.h"
|
#include "snmpmod.h"
|
||||||
@ -162,7 +164,83 @@ init_actvals(void)
|
|||||||
return (0);
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
/*************************************************************
|
/*************************************************************
|
||||||
*
|
*
|
||||||
@ -979,6 +1057,103 @@ op_snmp_set(struct snmp_context *ctx __unused, struct snmp_value *value,
|
|||||||
abort();
|
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:
|
||||||
|
snmpd_engine.engine_time = (get_ticks() - start_tick) / 100ULL;
|
||||||
|
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
|
* Transport table
|
||||||
*/
|
*/
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $Begemot: bsnmp/snmpd/bsnmpd.1,v 1.12 2006/02/27 09:50:03 brandt_h Exp $
|
.\" $Begemot: bsnmp/snmpd/bsnmpd.1,v 1.12 2006/02/27 09:50:03 brandt_h Exp $
|
||||||
.\"
|
.\"
|
||||||
.Dd October 23, 2010
|
.Dd September 9, 2010
|
||||||
.Dt BSNMPD 1
|
.Dt BSNMPD 1
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -42,6 +42,7 @@
|
|||||||
.Op Fl dh
|
.Op Fl dh
|
||||||
.Op Fl c Ar file
|
.Op Fl c Ar file
|
||||||
.Op Fl D Ar options
|
.Op Fl D Ar options
|
||||||
|
.Op Fl e Ar file
|
||||||
.Op Fl I Ar paths
|
.Op Fl I Ar paths
|
||||||
.Op Fl l Ar prefix
|
.Op Fl l Ar prefix
|
||||||
.Op Fl m Ar variable Ns Op = Ns Ar value
|
.Op Fl m Ar variable Ns Op = Ns Ar value
|
||||||
@ -68,9 +69,11 @@ Use
|
|||||||
.Ar file
|
.Ar file
|
||||||
as configuration file instead of the standard one.
|
as configuration file instead of the standard one.
|
||||||
.It Fl D Ar options
|
.It Fl D Ar options
|
||||||
Debugging options are specified as a comma separated string.
|
Debugging options are specified with a
|
||||||
|
.Fl o
|
||||||
|
flag followed by a comma separated string of options.
|
||||||
The following options are available.
|
The following options are available.
|
||||||
.Bl -tag -width "trace=level"
|
.Bl -tag -width ".It Cm trace Ns Cm = Ns Cm level"
|
||||||
.It Cm dump
|
.It Cm dump
|
||||||
Dump all sent and received PDUs to the terminal.
|
Dump all sent and received PDUs to the terminal.
|
||||||
.It Cm events
|
.It Cm events
|
||||||
@ -80,8 +83,11 @@ to 10.
|
|||||||
.It Cm trace Ns Cm = Ns Cm level
|
.It Cm trace Ns Cm = Ns Cm level
|
||||||
Set the snmp library trace flag to the specified
|
Set the snmp library trace flag to the specified
|
||||||
value.
|
value.
|
||||||
The value can be specified in the usual C-syntax for numbers.
|
|
||||||
.El
|
.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
|
.It Fl I Ar paths
|
||||||
Specify a colon separated list of directories to search for configuration
|
Specify a colon separated list of directories to search for configuration
|
||||||
include files.
|
include files.
|
||||||
@ -246,6 +252,8 @@ Default configuration file, where the default
|
|||||||
.Aq prefix
|
.Aq prefix
|
||||||
is
|
is
|
||||||
.Dq snmpd .
|
.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
|
.It Pa /var/run/ Ns Ao Ar prefix Ac Ns \&.pid
|
||||||
Default pid file.
|
Default pid file.
|
||||||
.It Pa /etc:/usr/etc/:/usr/local/etc
|
.It Pa /etc:/usr/etc/:/usr/local/etc
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
* Parse configuration file.
|
* Parse configuration file.
|
||||||
*/
|
*/
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -810,6 +811,7 @@ parse_oid(const char *varname, struct asn_oid *oid)
|
|||||||
struct snmp_node *node;
|
struct snmp_node *node;
|
||||||
u_int i;
|
u_int i;
|
||||||
u_char ip[4];
|
u_char ip[4];
|
||||||
|
struct asn_oid str_oid;
|
||||||
|
|
||||||
for (node = tree; node < &tree[tree_size]; node++)
|
for (node = tree; node < &tree[tree_size]; node++)
|
||||||
if (strcmp(varname, node->name) == 0)
|
if (strcmp(varname, node->name) == 0)
|
||||||
@ -824,7 +826,19 @@ parse_oid(const char *varname, struct asn_oid *oid)
|
|||||||
report("subid too large %#"QUADXFMT, numval);
|
report("subid too large %#"QUADXFMT, numval);
|
||||||
if (oid->len == ASN_MAXOIDLEN)
|
if (oid->len == ASN_MAXOIDLEN)
|
||||||
report("index too long");
|
report("index too long");
|
||||||
oid->subs[oid->len++] = numval;
|
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) {
|
} else if (token == TOK_STR) {
|
||||||
if (strvallen + oid->len + 1 > ASN_MAXOIDLEN)
|
if (strvallen + oid->len + 1 > ASN_MAXOIDLEN)
|
||||||
@ -832,6 +846,7 @@ parse_oid(const char *varname, struct asn_oid *oid)
|
|||||||
oid->subs[oid->len++] = strvallen;
|
oid->subs[oid->len++] = strvallen;
|
||||||
for (i = 0; i < strvallen; i++)
|
for (i = 0; i < strvallen; i++)
|
||||||
oid->subs[oid->len++] = strval[i];
|
oid->subs[oid->len++] = strval[i];
|
||||||
|
gettoken();
|
||||||
|
|
||||||
} else if (token == TOK_HOST) {
|
} else if (token == TOK_HOST) {
|
||||||
gethost(strval, ip);
|
gethost(strval, ip);
|
||||||
@ -839,10 +854,9 @@ parse_oid(const char *varname, struct asn_oid *oid)
|
|||||||
report("index too long");
|
report("index too long");
|
||||||
for (i = 0; i < 4; i++)
|
for (i = 0; i < 4; i++)
|
||||||
oid->subs[oid->len++] = ip[i];
|
oid->subs[oid->len++] = ip[i];
|
||||||
|
gettoken();
|
||||||
} else
|
} else
|
||||||
report("bad token in index");
|
report("bad token in index");
|
||||||
gettoken();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (node);
|
return (node);
|
||||||
@ -1006,7 +1020,7 @@ parse_assign(const char *varname)
|
|||||||
|
|
||||||
node = parse_oid(varname, &vindex);
|
node = parse_oid(varname, &vindex);
|
||||||
if (token != '=')
|
if (token != '=')
|
||||||
report("'=' expected");
|
report("'=' expected, got '%c'", token);
|
||||||
gettoken();
|
gettoken();
|
||||||
|
|
||||||
if (ignore) {
|
if (ignore) {
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
* Support functions for modules.
|
* Support functions for modules.
|
||||||
*/
|
*/
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -30,7 +30,7 @@
|
|||||||
*
|
*
|
||||||
* Private SNMPd data and functions.
|
* Private SNMPd data and functions.
|
||||||
*/
|
*/
|
||||||
#include <sys/queue.h>
|
|
||||||
#ifdef USE_LIBBEGEMOT
|
#ifdef USE_LIBBEGEMOT
|
||||||
#include <rpoll.h>
|
#include <rpoll.h>
|
||||||
#else
|
#else
|
||||||
@ -247,7 +247,8 @@ extern struct snmpd snmpd;
|
|||||||
|
|
||||||
#define VERS_ENABLE_V1 0x00000001
|
#define VERS_ENABLE_V1 0x00000001
|
||||||
#define VERS_ENABLE_V2C 0x00000002
|
#define VERS_ENABLE_V2C 0x00000002
|
||||||
#define VERS_ENABLE_ALL 0x00000003
|
#define VERS_ENABLE_V3 0x00000004
|
||||||
|
#define VERS_ENABLE_ALL (VERS_ENABLE_V1 | VERS_ENABLE_V2C | VERS_ENABLE_V3)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The debug group
|
* The debug group
|
||||||
@ -279,6 +280,11 @@ struct snmpd_stats {
|
|||||||
};
|
};
|
||||||
extern struct snmpd_stats snmpd_stats;
|
extern struct snmpd_stats snmpd_stats;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* SNMPd Engine
|
||||||
|
*/
|
||||||
|
extern struct snmp_engine snmpd_engine;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* OR Table
|
* OR Table
|
||||||
*/
|
*/
|
||||||
@ -322,6 +328,11 @@ extern const char *syspath;
|
|||||||
extern int32_t snmp_serial_no;
|
extern int32_t snmp_serial_no;
|
||||||
|
|
||||||
int init_actvals(void);
|
int init_actvals(void);
|
||||||
|
|
||||||
|
extern char engine_file[];
|
||||||
|
int init_snmpd_engine(void);
|
||||||
|
int set_snmpd_engine(void);
|
||||||
|
|
||||||
int read_config(const char *, struct lmodule *);
|
int read_config(const char *, struct lmodule *);
|
||||||
int define_macro(const char *name, const char *value);
|
int define_macro(const char *name, const char *value);
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
.\"
|
.\"
|
||||||
.\" $Begemot: bsnmp/snmpd/snmpmod.3,v 1.14 2005/10/04 13:30:35 brandt_h Exp $
|
.\" $Begemot: bsnmp/snmpd/snmpmod.3,v 1.14 2005/10/04 13:30:35 brandt_h Exp $
|
||||||
.\"
|
.\"
|
||||||
.Dd February 27, 2006
|
.Dd September 9, 2010
|
||||||
.Dt SNMPMOD 3
|
.Dt SNMPMOD 3
|
||||||
.Os
|
.Os
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -60,6 +60,8 @@
|
|||||||
.Nm comm_define ,
|
.Nm comm_define ,
|
||||||
.Nm community ,
|
.Nm community ,
|
||||||
.Nm oid_zeroDotZero ,
|
.Nm oid_zeroDotZero ,
|
||||||
|
.Nm oid_usmUnknownEngineIDs ,
|
||||||
|
.Nm oid_usmNotInTimeWindows ,
|
||||||
.Nm reqid_allocate ,
|
.Nm reqid_allocate ,
|
||||||
.Nm reqid_next ,
|
.Nm reqid_next ,
|
||||||
.Nm reqid_base ,
|
.Nm reqid_base ,
|
||||||
@ -99,7 +101,16 @@
|
|||||||
.Nm index_compare ,
|
.Nm index_compare ,
|
||||||
.Nm index_compare_off ,
|
.Nm index_compare_off ,
|
||||||
.Nm index_append ,
|
.Nm index_append ,
|
||||||
.Nm index_append_off
|
.Nm index_append_off,
|
||||||
|
.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
|
||||||
.Nd "SNMP daemon loadable module interface"
|
.Nd "SNMP daemon loadable module interface"
|
||||||
.Sh LIBRARY
|
.Sh LIBRARY
|
||||||
Begemot SNMP library
|
Begemot SNMP library
|
||||||
@ -228,6 +239,25 @@ Begemot SNMP library
|
|||||||
.Fn index_append "struct asn_oid *dst" "u_int sub" "const struct asn_oid *src"
|
.Fn index_append "struct asn_oid *dst" "u_int sub" "const struct asn_oid *src"
|
||||||
.Ft void
|
.Ft void
|
||||||
.Fn index_append_off "struct asn_oid *dst" "u_int sub" "const struct asn_oid *src" "u_int off"
|
.Fn index_append_off "struct asn_oid *dst" "u_int sub" "const struct asn_oid *src" "u_int off"
|
||||||
|
.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;
|
||||||
|
.Vt extern const struct asn_oid oid_usmUnknownEngineIDs;
|
||||||
|
.Vt extern const struct asn_oid oid_usmNotInTimeWindows;
|
||||||
.Sh DESCRIPTION
|
.Sh DESCRIPTION
|
||||||
The
|
The
|
||||||
.Xr bsnmpd 1
|
.Xr bsnmpd 1
|
||||||
@ -539,7 +569,7 @@ This is the initial community string.
|
|||||||
.El
|
.El
|
||||||
.Pp
|
.Pp
|
||||||
The function returns a globally unique community identifier.
|
The function returns a globally unique community identifier.
|
||||||
If a PDU is
|
If a SNMPv1 or SNMPv2 PDU is
|
||||||
received who's community string matches, this identifier is set into the global
|
received who's community string matches, this identifier is set into the global
|
||||||
.Va community .
|
.Va community .
|
||||||
.Pp
|
.Pp
|
||||||
@ -549,10 +579,76 @@ returns the current community string for the given community.
|
|||||||
.Pp
|
.Pp
|
||||||
All communities defined by a module are automatically released when the module
|
All communities defined by a module are automatically released when the module
|
||||||
is unloaded.
|
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_USM_NAME_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 WELL KNOWN OIDS
|
.Ss WELL KNOWN OIDS
|
||||||
The global variable
|
The global variable
|
||||||
.Va oid_zeroDotZero
|
.Va oid_zeroDotZero
|
||||||
contains the OID 0.0.
|
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
|
.Ss REQUEST ID RANGES
|
||||||
For modules that implement SNMP client functions besides SNMP agent functions
|
For modules that implement SNMP client functions besides SNMP agent functions
|
||||||
it may be necessary to identify SNMP requests by their identifier to allow
|
it may be necessary to identify SNMP requests by their identifier to allow
|
||||||
|
@ -332,11 +332,137 @@ const char * comm_string(u_int);
|
|||||||
/* community for current packet */
|
/* community for current packet */
|
||||||
extern u_int community;
|
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);
|
||||||
|
|
||||||
|
/*
|
||||||
* Well known OIDs
|
* Well known OIDs
|
||||||
*/
|
*/
|
||||||
extern const struct asn_oid oid_zeroDotZero;
|
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.
|
* Request ID ranges.
|
||||||
*
|
*
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
* Local domain socket transport
|
* Local domain socket transport
|
||||||
*/
|
*/
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
* UDP transport
|
* UDP transport
|
||||||
*/
|
*/
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
* TrapSinkTable
|
* TrapSinkTable
|
||||||
*/
|
*/
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
#include <sys/queue.h>
|
||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#include <sys/un.h>
|
#include <sys/un.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
@ -196,5 +196,15 @@
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
(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)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
#
|
#
|
||||||
# Author: Harti Brandt <harti@freebsd.org>
|
# Author: Harti Brandt <harti@freebsd.org>
|
||||||
|
|
||||||
|
.include <bsd.own.mk>
|
||||||
|
|
||||||
CONTRIB= ${.CURDIR}/../../../contrib/bsnmp/lib
|
CONTRIB= ${.CURDIR}/../../../contrib/bsnmp/lib
|
||||||
.PATH: ${CONTRIB}
|
.PATH: ${CONTRIB}
|
||||||
|
|
||||||
@ -11,8 +13,13 @@ SHLIBDIR?= /lib
|
|||||||
CFLAGS+= -I${CONTRIB} -DHAVE_ERR_H -DHAVE_GETADDRINFO -DHAVE_STRLCPY
|
CFLAGS+= -I${CONTRIB} -DHAVE_ERR_H -DHAVE_GETADDRINFO -DHAVE_STRLCPY
|
||||||
CFLAGS+= -DHAVE_STDINT_H -DHAVE_INTTYPES_H -DQUADFMT='"llu"' -DQUADXFMT='"llx"'
|
CFLAGS+= -DHAVE_STDINT_H -DHAVE_INTTYPES_H -DQUADFMT='"llu"' -DQUADXFMT='"llx"'
|
||||||
|
|
||||||
SRCS= asn1.c snmp.c snmpagent.c snmpclient.c support.c
|
.if ${MK_OPENSSL} != "no"
|
||||||
INCS= asn1.h snmp.h snmpagent.h snmpclient.h
|
CFLAGS+= -DHAVE_LIBCRYPTO
|
||||||
|
LDADD+= -lcrypto
|
||||||
|
.endif
|
||||||
|
|
||||||
|
SRCS= asn1.c snmp.c snmpagent.c snmpclient.c snmpcrypto.c support.c
|
||||||
|
INCS= asn1.h snmp.h snmpagent.h snmpclient.h
|
||||||
MAN= asn1.3 bsnmplib.3 bsnmpclient.3 bsnmpagent.3
|
MAN= asn1.3 bsnmplib.3 bsnmpclient.3 bsnmpagent.3
|
||||||
|
|
||||||
.include <bsd.lib.mk>
|
.include <bsd.lib.mk>
|
||||||
|
@ -2,6 +2,8 @@
|
|||||||
#
|
#
|
||||||
# Author: Harti Brandt <harti@freebsd.org>
|
# Author: Harti Brandt <harti@freebsd.org>
|
||||||
|
|
||||||
|
.include <bsd.own.mk>
|
||||||
|
|
||||||
CONTRIB=${.CURDIR}/../../../contrib/bsnmp
|
CONTRIB=${.CURDIR}/../../../contrib/bsnmp
|
||||||
.PATH: ${CONTRIB}/snmpd
|
.PATH: ${CONTRIB}/snmpd
|
||||||
|
|
||||||
@ -11,7 +13,7 @@ SRCS+= oid.h tree.c tree.h
|
|||||||
XSYM= snmpMIB begemotSnmpdModuleTable begemotSnmpd begemotTrapSinkTable \
|
XSYM= snmpMIB begemotSnmpdModuleTable begemotSnmpd begemotTrapSinkTable \
|
||||||
sysUpTime snmpTrapOID coldStart authenticationFailure \
|
sysUpTime snmpTrapOID coldStart authenticationFailure \
|
||||||
begemotSnmpdTransUdp begemotSnmpdTransLsock begemotSnmpdLocalPortTable \
|
begemotSnmpdTransUdp begemotSnmpdTransLsock begemotSnmpdLocalPortTable \
|
||||||
freeBSDVersion
|
freeBSD freeBSDVersion
|
||||||
CLEANFILES= oid.h tree.c tree.h
|
CLEANFILES= oid.h tree.c tree.h
|
||||||
MAN= bsnmpd.1 snmpmod.3
|
MAN= bsnmpd.1 snmpmod.3
|
||||||
NO_WERROR=
|
NO_WERROR=
|
||||||
@ -31,6 +33,10 @@ LDADD= -lbegemot -lbsnmp -lwrap
|
|||||||
|
|
||||||
LDFLAGS= -export-dynamic
|
LDFLAGS= -export-dynamic
|
||||||
|
|
||||||
|
.if ${MK_OPENSSL} != "no"
|
||||||
|
CFLAGS+= -DHAVE_LIBCRYPTO
|
||||||
|
.endif
|
||||||
|
|
||||||
oid.h: tree.def Makefile
|
oid.h: tree.def Makefile
|
||||||
gensnmptree -e ${XSYM} < ${.ALLSRC:M*.def} > ${.TARGET}
|
gensnmptree -e ${XSYM} < ${.ALLSRC:M*.def} > ${.TARGET}
|
||||||
|
|
||||||
|
@ -13,6 +13,8 @@ SUBDIR= ${_snmp_atm} \
|
|||||||
snmp_hostres \
|
snmp_hostres \
|
||||||
snmp_mibII \
|
snmp_mibII \
|
||||||
snmp_pf \
|
snmp_pf \
|
||||||
|
snmp_usm \
|
||||||
|
snmp_vacm \
|
||||||
snmp_wlan
|
snmp_wlan
|
||||||
|
|
||||||
.if ${MK_NETGRAPH_SUPPORT} != "no"
|
.if ${MK_NETGRAPH_SUPPORT} != "no"
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
* $FreeBSD$
|
* $FreeBSD$
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <sys/queue.h>
|
||||||
#include <bsnmp/snmpmod.h>
|
#include <bsnmp/snmpmod.h>
|
||||||
|
|
||||||
#include <net/pfvar.h>
|
#include <net/pfvar.h>
|
||||||
|
22
usr.sbin/bsnmpd/modules/snmp_usm/Makefile
Executable file
22
usr.sbin/bsnmpd/modules/snmp_usm/Makefile
Executable file
@ -0,0 +1,22 @@
|
|||||||
|
# $FreeBSD$
|
||||||
|
#
|
||||||
|
# Author: Shteryana Shopova <syrinx@freebsd.org>
|
||||||
|
|
||||||
|
CONTRIB= ${.CURDIR}/../../../../contrib/bsnmp
|
||||||
|
.PATH: ${CONTRIB}/snmp_usm
|
||||||
|
|
||||||
|
MOD= usm
|
||||||
|
SRCS= usm_snmp.c
|
||||||
|
XSYM= snmpUsmMIB usmNoAuthProtocol usmHMACMD5AuthProtocol \
|
||||||
|
usmHMACSHAAuthProtocol usmNoPrivProtocol usmDESPrivProtocol \
|
||||||
|
usmAesCfb128Protocol usmUserSecurityName
|
||||||
|
|
||||||
|
MAN= snmp_usm.3
|
||||||
|
|
||||||
|
CFLAGS+= -I${CONTRIB}/lib -I${CONTRIB}/snmpd -DSNMPTREE_TYPES
|
||||||
|
CFLAGS+= -DHAVE_ERR_H -DHAVE_GETADDRINFO -DHAVE_STRLCPY -DHAVE_SYS_TREE_H
|
||||||
|
|
||||||
|
DEFS= ${MOD}_tree.def
|
||||||
|
BMIBS=
|
||||||
|
|
||||||
|
.include <bsd.snmpmod.mk>
|
20
usr.sbin/bsnmpd/modules/snmp_vacm/Makefile
Executable file
20
usr.sbin/bsnmpd/modules/snmp_vacm/Makefile
Executable file
@ -0,0 +1,20 @@
|
|||||||
|
# $FreeBSD$
|
||||||
|
#
|
||||||
|
# Author: Shteryana Shopova <syrinx@freebsd.org>
|
||||||
|
|
||||||
|
CONTRIB= ${.CURDIR}/../../../../contrib/bsnmp
|
||||||
|
.PATH: ${CONTRIB}/snmp_vacm
|
||||||
|
|
||||||
|
MOD= vacm
|
||||||
|
SRCS= vacm_snmp.c
|
||||||
|
XSYM= snmpVacmMIB
|
||||||
|
|
||||||
|
MAN= snmp_vacm.3
|
||||||
|
|
||||||
|
CFLAGS+= -I${CONTRIB}/lib -I${CONTRIB}/snmpd -DSNMPTREE_TYPES
|
||||||
|
CFLAGS+= -DHAVE_ERR_H -DHAVE_GETADDRINFO -DHAVE_STRLCPY -DHAVE_SYS_TREE_H
|
||||||
|
|
||||||
|
DEFS= ${MOD}_tree.def
|
||||||
|
BMIBS=
|
||||||
|
|
||||||
|
.include <bsd.snmpmod.mk>
|
Loading…
Reference in New Issue
Block a user