svn commit: r216294 - in head: contrib/bsnmp/lib
contrib/bsnmp/snmp_usm contrib/bsnmp/snmp_vacm
contrib/bsnmp/snmpd lib/libbsnmp/libbsnmp
usr.sbin/bsnmpd/bsnmpd usr.sbin/bsnmpd/modules usr.sbin/bsn...
Shteryana Shopova
syrinx at FreeBSD.org
Wed Dec 8 13:51:39 UTC 2010
Author: syrinx
Date: Wed Dec 8 13:51:38 2010
New Revision: 216294
URL: http://svn.freebsd.org/changeset/base/216294
Log:
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@
Added:
head/contrib/bsnmp/snmp_usm/
head/contrib/bsnmp/snmp_usm/snmp_usm.3 (contents, props changed)
head/contrib/bsnmp/snmp_usm/usm_snmp.c (contents, props changed)
head/contrib/bsnmp/snmp_usm/usm_tree.def (contents, props changed)
head/contrib/bsnmp/snmp_vacm/
head/contrib/bsnmp/snmp_vacm/snmp_vacm.3 (contents, props changed)
head/contrib/bsnmp/snmp_vacm/vacm_snmp.c (contents, props changed)
head/contrib/bsnmp/snmp_vacm/vacm_tree.def (contents, props changed)
head/usr.sbin/bsnmpd/modules/snmp_usm/
head/usr.sbin/bsnmpd/modules/snmp_usm/Makefile (contents, props changed)
head/usr.sbin/bsnmpd/modules/snmp_vacm/
head/usr.sbin/bsnmpd/modules/snmp_vacm/Makefile (contents, props changed)
Modified:
head/contrib/bsnmp/lib/asn1.c
head/contrib/bsnmp/lib/asn1.h
head/contrib/bsnmp/lib/bsnmpclient.3
head/contrib/bsnmp/lib/bsnmplib.3
head/contrib/bsnmp/lib/snmp.c
head/contrib/bsnmp/lib/snmp.h
head/contrib/bsnmp/lib/snmpagent.c
head/contrib/bsnmp/lib/snmpclient.c
head/contrib/bsnmp/lib/snmpclient.h
head/contrib/bsnmp/lib/snmppriv.h
head/contrib/bsnmp/snmpd/BEGEMOT-SNMPD.txt
head/contrib/bsnmp/snmpd/action.c
head/contrib/bsnmp/snmpd/bsnmpd.1
head/contrib/bsnmp/snmpd/config.c
head/contrib/bsnmp/snmpd/export.c
head/contrib/bsnmp/snmpd/main.c
head/contrib/bsnmp/snmpd/snmpd.h
head/contrib/bsnmp/snmpd/snmpmod.3
head/contrib/bsnmp/snmpd/snmpmod.h
head/contrib/bsnmp/snmpd/trans_lsock.c
head/contrib/bsnmp/snmpd/trans_udp.c
head/contrib/bsnmp/snmpd/trap.c
head/contrib/bsnmp/snmpd/tree.def
head/lib/libbsnmp/libbsnmp/Makefile
head/usr.sbin/bsnmpd/bsnmpd/Makefile
head/usr.sbin/bsnmpd/modules/Makefile
head/usr.sbin/bsnmpd/modules/snmp_pf/pf_snmp.c
Modified: head/contrib/bsnmp/lib/asn1.c
==============================================================================
--- head/contrib/bsnmp/lib/asn1.c Wed Dec 8 13:51:25 2010 (r216293)
+++ head/contrib/bsnmp/lib/asn1.c Wed Dec 8 13:51:38 2010 (r216294)
@@ -196,7 +196,7 @@ asn_put_temp_header(struct asn_buf *b, u
return (ret);
}
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;
u_int lenlen, shift;
@@ -215,6 +215,8 @@ asn_commit_header(struct asn_buf *b, u_c
memmove(ptr + 1 + lenlen, ptr + TEMP_LEN, len);
b->asn_ptr -= shift;
b->asn_len += shift;
+ if (moved != NULL)
+ *moved = shift;
}
return (ASN_ERR_OK);
}
@@ -913,6 +915,20 @@ asn_skip(struct asn_buf *b, asn_len_t le
}
/*
+ * Add a padding
+ */
+enum asn_err
+asn_pad(struct asn_buf *b, asn_len_t len)
+{
+ if (b->asn_len < len)
+ return (ASN_ERR_EOBUF);
+ b->asn_ptr += len;
+ b->asn_len -= len;
+
+ return (ASN_ERR_OK);
+}
+
+/*
* Compare two OIDs.
*
* o1 < o2 : -1
Modified: head/contrib/bsnmp/lib/asn1.h
==============================================================================
--- head/contrib/bsnmp/lib/asn1.h Wed Dec 8 13:51:25 2010 (r216293)
+++ head/contrib/bsnmp/lib/asn1.h Wed Dec 8 13:51:38 2010 (r216294)
@@ -93,7 +93,7 @@ enum asn_err asn_get_header(struct asn_b
enum asn_err asn_put_header(struct asn_buf *, u_char, asn_len_t);
enum asn_err asn_put_temp_header(struct asn_buf *, u_char, u_char **);
-enum asn_err asn_commit_header(struct asn_buf *, u_char *);
+enum asn_err asn_commit_header(struct asn_buf *, u_char *, size_t *);
enum asn_err asn_get_integer_raw(struct asn_buf *, asn_len_t, int32_t *);
enum asn_err asn_get_integer(struct asn_buf *, int32_t *);
@@ -129,6 +129,7 @@ enum asn_err asn_get_timeticks(struct as
enum asn_err asn_put_timeticks(struct asn_buf *, uint32_t);
enum asn_err asn_skip(struct asn_buf *, asn_len_t);
+enum asn_err asn_pad(struct asn_buf *, asn_len_t);
/*
* Utility functions for OIDs
Modified: head/contrib/bsnmp/lib/bsnmpclient.3
==============================================================================
--- head/contrib/bsnmp/lib/bsnmpclient.3 Wed Dec 8 13:51:25 2010 (r216293)
+++ head/contrib/bsnmp/lib/bsnmpclient.3 Wed Dec 8 13:51:38 2010 (r216294)
@@ -31,7 +31,7 @@
.\"
.\" $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
.Os
.Sh NAME
@@ -52,7 +52,8 @@
.Nm snmp_table_cb_f ,
.Nm snmp_table_fetch ,
.Nm snmp_table_fetch_async ,
-.Nm snmp_dialog
+.Nm snmp_dialog ,
+.Nm snmp_discover_engine
.Nd "SNMP client library"
.Sh 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"
.Ft int
.Fn snmp_dialog "struct snmp_pdu *req" "struct snmp_pdu *resp"
+.Ft int
+.Fn snmp_discover_engine "void"
.Sh DESCRIPTION
The SNMP library contains routines to easily build SNMP client applications
-that use SNMP versions 1 or 2.
+that use SNMP versions 1, 2 or 3.
Most of the routines use a
.Vt struct snmp_client :
.Bd -literal -offset indent
struct snmp_client {
- enum snmp_version version;
- int trans; /* transport type to use */
+ enum snmp_version version;
+ int trans; /* which transport to use */
/* these two are read-only for the application */
- char *cport; /* port number as string */
- char *chost; /* host name or IP address as string */
+ char *cport; /* port number as string */
+ char *chost; /* host name or IP address as string */
+
+ char read_community[SNMP_COMMUNITY_MAXLEN + 1];
+ char write_community[SNMP_COMMUNITY_MAXLEN + 1];
+
+ /* SNMPv3 specific fields */
+ int32_t identifier;
+ int32_t security_model;
+ struct snmp_engine engine;
+ struct snmp_user user;
- char read_community[SNMP_COMMUNITY_MAXLEN + 1];
- char write_community[SNMP_COMMUNITY_MAXLEN + 1];
+ /* SNMPv3 Access control - VACM*/
+ uint32_t clen;
+ uint8_t cengine[SNMP_ENGINE_ID_SIZ];
+ char cname[SNMP_CONTEXT_NAME_SIZ];
- struct timeval timeout;
- u_int retries;
+ struct timeval timeout;
+ u_int retries;
- int dump_pdus;
+ int dump_pdus;
- size_t txbuflen;
- size_t rxbuflen;
+ size_t txbuflen;
+ size_t rxbuflen;
- int fd;
+ int fd;
- int32_t next_reqid;
- int32_t max_reqid;
- int32_t min_reqid;
+ int32_t next_reqid;
+ int32_t max_reqid;
+ int32_t min_reqid;
- char error[SNMP_STRERROR_LEN];
+ char error[SNMP_STRERROR_LEN];
- snmp_timeout_start_f timeout_start;
- snmp_timeout_stop_f timeout_stop;
+ snmp_timeout_start_f timeout_start;
+ snmp_timeout_stop_f timeout_stop;
- /* private */
- char local_path[sizeof(SNMP_LOCAL_PATH)];
+ char local_path[sizeof(SNMP_LOCAL_PATH)];
};
.Ed
.Pp
@@ -194,6 +207,23 @@ The default is
The community name to be used for SET requests.
The default is
.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
The maximum time to wait for responses to requests.
If the time elapses, the request is resent up to
@@ -617,6 +647,21 @@ returns -1.
If a response was received 0 is returned.
.Pp
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
is used to parse an SNMP server specification string and fill in the
fields of a
Modified: head/contrib/bsnmp/lib/bsnmplib.3
==============================================================================
--- head/contrib/bsnmp/lib/bsnmplib.3 Wed Dec 8 13:51:25 2010 (r216293)
+++ head/contrib/bsnmp/lib/bsnmplib.3 Wed Dec 8 13:51:38 2010 (r216294)
@@ -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
.\" Hartmut Brandt.
.\" All rights reserved.
@@ -31,7 +37,7 @@
.\"
.\" $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
.Os
.Sh NAME
@@ -39,9 +45,15 @@
.Nm snmp_value_parse ,
.Nm snmp_value_copy ,
.Nm snmp_pdu_free ,
-.Nm snmp_code snmp_pdu_decode ,
-.Nm snmp_code snmp_pdu_encode ,
+.Nm snmp_pdu_decode ,
+.Nm snmp_pdu_encode ,
+.Nm snmp_pdu_decode_header ,
+.Nm snmp_pdu_decode_scoped ,
+.Nm snmp_pdu_decode_secmode ,
.Nm snmp_pdu_dump ,
+.Nm snmp_passwd_to_keys ,
+.Nm snmp_get_local_keys ,
+.Nm snmp_calc_keychange ,
.Nm TRUTH_MK ,
.Nm TRUTH_GET ,
.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"
.Ft enum snmp_code
.Fn snmp_pdu_encode "struct snmp_pdu *pdu" "struct asn_buf *buf"
+.Ft enum snmp_code
+.Fn snmp_pdu_decode_header "struct snmp_pdu *pdu" "struct asn_buf *buf"
+.Ft enum snmp_code
+.Fn snmp_pdu_decode_scoped "struct asn_buf *buf" "struct snmp_pdu *pdu" "int32_t *ip"
+.Ft enum snmp_code
+.Fn snmp_pdu_decode_secmode "struct asn_buf *buf" "struct snmp_pdu *pdu"
.Ft void
.Fn snmp_pdu_dump "const struct snmp_pdu *pdu"
+.Ft enum snmp_code
+.Fn snmp_passwd_to_keys "struct snmp_user *user" "char *passwd"
+.Ft enum snmp_code
+.Fn snmp_get_local_keys "struct snmp_user *user" "uint8_t *eid" "uint32_t elen"
+.Ft enum snmp_code
+.Fn snmp_calc_keychange "struct snmp_user *user" "uint8_t *keychange"
.Ft int
.Fn TRUTH_MK "F"
.Ft int
@@ -73,8 +97,8 @@ Begemot SNMP library
.Ft int
.Fn TRUTH_OK "T"
.Sh DESCRIPTION
-The SNMP library contains routines to handle SNMP version 1 and 2 PDUs.
-There are two basic structures used throughout the library:
+The SNMP library contains routines to handle SNMP version 1, 2 and 3 PDUs.
+There are several basic structures used throughout the library:
.Bd -literal -offset indent
struct snmp_value {
struct asn_oid var;
@@ -134,34 +158,126 @@ is not zero,
.Fa v.octetstring.octets
points to a string allocated by
.Xr malloc 3 .
+.Pp
+.Bd -literal -offset indent
+#define SNMP_ENGINE_ID_SIZ 32
+
+struct snmp_engine {
+ uint8_t engine_id[SNMP_ENGINE_ID_SIZ];
+ uint32_t engine_len;
+ int32_t engine_boots;
+ int32_t engine_time;
+ int32_t max_msg_size;
+};
+.Ed
+.Pp
+This structure represents an SNMP engine as specified by the SNMP Management
+Architecture described in RFC 3411.
+.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_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 {
- char community[SNMP_COMMUNITY_MAXLEN + 1];
- enum snmp_version version;
- u_int type;
+ char community[SNMP_COMMUNITY_MAXLEN + 1];
+ enum snmp_version version;
+ u_int type;
+
+ /* SNMPv3 PDU header fields */
+ int32_t identifier;
+ uint8_t flags;
+ int32_t security_model;
+ struct snmp_engine engine;
+
+ /* Associated USM user parameters */
+ struct snmp_user user;
+ uint8_t msg_digest[SNMP_USM_AUTH_SIZE];
+ uint8_t msg_salt[SNMP_USM_PRIV_SIZE];
+
+ /* View-based Access Model */
+ uint32_t context_engine_len;
+ uint8_t context_engine[SNMP_ENGINE_ID_SIZ];
+ char context_name[SNMP_CONTEXT_NAME_SIZ];
/* trap only */
- struct asn_oid enterprise;
- u_char agent_addr[4];
- int32_t generic_trap;
- int32_t specific_trap;
- u_int32_t time_stamp;
+ struct asn_oid enterprise;
+ u_char agent_addr[4];
+ int32_t generic_trap;
+ int32_t specific_trap;
+ uint32_t time_stamp;
/* others */
- int32_t request_id;
- int32_t error_status;
- int32_t error_index;
+ int32_t request_id;
+ int32_t error_status;
+ int32_t error_index;
/* fixes for encoding */
- u_char *outer_ptr;
- u_char *pdu_ptr;
- u_char *vars_ptr;
+ size_t outer_len;
+ size_t scoped_len;
+ u_char *outer_ptr;
+ u_char *digest_ptr;
+ u_char *encrypted_ptr;
+ u_char *scoped_ptr;
+ u_char *pdu_ptr;
+ u_char *vars_ptr;
+
- struct snmp_value bindings[SNMP_MAX_BINDINGS];
- u_int nbindings;
+ struct snmp_value bindings[SNMP_MAX_BINDINGS];
+ u_int nbindings;
};
.Ed
This structure contains a decoded SNMP PDU.
@@ -172,11 +288,15 @@ enum snmp_version {
SNMP_Verr = 0,
SNMP_V1 = 1,
SNMP_V2c,
+ SNMP_V3
};
.Ed
and
.Fa type
is the type of the PDU.
+.Fa security_model
+is the security model used for SNMPv3 PDUs. The only supported
+value currently is 3 (User-based Security Model).
.Pp
The function
.Fn snmp_value_free
@@ -223,15 +343,60 @@ The function
.Fn snmp_pdu_encode
encodes the 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 .
+.Pp
+The function
+.Fn snmp_pdu_decode_header
+decodes the header of the PDU pointed to by
+.Fa buf .
+The uncoded PDU contents remain in the buffer.
+.Pp
+The function
+.Fn snmp_pdu_decode_scoped
+decodes the scoped PDU pointed to by
.Fa buf .
.Pp
The function
+.Fn snmp_pdu_decode_secmode
+verifies the authentication parameter contained in the PDU (if present) and
+if the PDU is encrypted, decrypts the PDU contents pointed to by
+.Fa buf .
+If successfull, a plain text scoped PDU is stored in the buffer.
+.Pp
+The function
.Fn snmp_pdu_dump
dumps the PDU in a human readable form by calling
.Fn snmp_printf .
.Pp
The function
+.Fn snmp_passwd_to_keys
+calculates a binary private authentication key corresponding to a plain text human
+readable password string. The calculated key is placed in the
+.Fa auth_key
+field of the
+.Fa user .
+.Pp
+The function
+.Fn snmp_get_local_keys
+calculates a localazied authentication and privacy keys for a specified SNMPv3
+engine. The calculateds keys are placed in the
+.Fa auth_key
+and
+.Fa priv_key
+fields of the
+.Fa user .
+.Pp
+The function
+.Fn snmp_calc_keychange
+calculates a binary key change octet string based on the contents of an old and
+a new binary localized key. The rezult is placed in the buffer pointer to by
+.Fa keychange
+and may be used by an SNMPv3 user who wishes to change his/her password
+or localized key.
+.Pp
+The function
.Fn TRUTH_MK
takes a C truth value (zero or non-zero) and makes an SNMP truth value (2 or 1).
The function
@@ -281,6 +446,13 @@ A variable binding value was out of the
The PDU is of an unsupported version.
.It Bq Er SNMP_CODE_BADENQ
There was an ASN.1 value with an unsupported tag.
+.It Bq Er SNMP_CODE_BADSECLEVEL
+The requested securityLevel contained in the PDU is not supported.
+.It Bq Er SNMP_CODE_BADDIGEST
+The PDU authentication parameter received in the PDU did not match the
+calculated message digest.
+.It Bq Er SNMP_CODE_EDECRYPT
+Error occured while trying to decrypt the PDU.
.El
.Pp
.Fn snmp_pdu_encode
@@ -297,8 +469,21 @@ Encoding failed.
.Xr bsnmpagent 3 ,
.Xr bsnmpclient 3 ,
.Xr bsnmplib 3
+.Sh CAVEAT
+The SNMPv3 message digests, encryption and decryption, and key routines use
+the cryptographic functions from
+.Xr crypto 3 .
+The library may optionally be built without references to the
+.Xr crypto 3
+library. In such case only plain text SNMPv3 PDUs without message digests
+may be proccessed correctly.
.Sh STANDARDS
This implementation conforms to the applicable IETF RFCs and ITU-T
recommendations.
.Sh AUTHORS
+The Begemot SNMP library was originally written by
.An Hartmut Brandt Aq harti at FreeBSD.org
+.Pp
+.An Shteryana Shopova Aq syrinx at FreeBSD.org
+added support for the SNMPv3 message proccessing and User-Based
+Security model message authentication and privacy.
Modified: head/contrib/bsnmp/lib/snmp.c
==============================================================================
--- head/contrib/bsnmp/lib/snmp.c Wed Dec 8 13:51:25 2010 (r216293)
+++ head/contrib/bsnmp/lib/snmp.c Wed Dec 8 13:51:38 2010 (r216294)
@@ -5,6 +5,12 @@
*
* Author: Harti Brandt <harti at 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
* modification, are permitted provided that the following conditions
* are met:
@@ -271,47 +277,310 @@ parse_pdus(struct asn_buf *b, struct snm
return (err);
}
+
+static enum asn_err
+parse_secparams(struct asn_buf *b, struct snmp_pdu *pdu)
+{
+ asn_len_t octs_len;
+ u_char buf[256]; /* XXX: calc max possible size here */
+ struct asn_buf tb;
+
+ memset(buf, 0, 256);
+ tb.asn_ptr = buf;
+ tb.asn_len = 256;
+
+ if (asn_get_octetstring(b, buf, &tb.asn_len) != ASN_ERR_OK) {
+ snmp_error("cannot parse usm header");
+ return (ASN_ERR_FAILED);
+ }
+
+ if (asn_get_sequence(&tb, &octs_len) != ASN_ERR_OK) {
+ snmp_error("cannot decode usm header");
+ return (ASN_ERR_FAILED);
+ }
+
+ octs_len = SNMP_ENGINE_ID_SIZ;
+ if (asn_get_octetstring(&tb, (u_char *)&pdu->engine.engine_id,
+ &octs_len) != ASN_ERR_OK) {
+ snmp_error("cannot decode msg engine id");
+ return (ASN_ERR_FAILED);
+ }
+ pdu->engine.engine_len = octs_len;
+
+ if (asn_get_integer(&tb, &pdu->engine.engine_boots) != ASN_ERR_OK) {
+ snmp_error("cannot decode msg engine boots");
+ return (ASN_ERR_FAILED);
+ }
+
+ if (asn_get_integer(&tb, &pdu->engine.engine_time) != ASN_ERR_OK) {
+ snmp_error("cannot decode msg engine time");
+ return (ASN_ERR_FAILED);
+ }
+
+ octs_len = SNMP_ADM_STR32_SIZ - 1;
+ if (asn_get_octetstring(&tb, (u_char *)&pdu->user.sec_name, &octs_len)
+ != ASN_ERR_OK) {
+ snmp_error("cannot decode msg user name");
+ return (ASN_ERR_FAILED);
+ }
+ pdu->user.sec_name[octs_len] = '\0';
+
+ octs_len = sizeof(pdu->msg_digest);
+ if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_digest, &octs_len) !=
+ ASN_ERR_OK || ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0 &&
+ octs_len != sizeof(pdu->msg_digest))) {
+ snmp_error("cannot decode msg authentication param");
+ return (ASN_ERR_FAILED);
+ }
+
+ octs_len = sizeof(pdu->msg_salt);
+ if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_salt, &octs_len) !=
+ ASN_ERR_OK ||((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 &&
+ octs_len != sizeof(pdu->msg_salt))) {
+ snmp_error("cannot decode msg authentication param");
+ return (ASN_ERR_FAILED);
+ }
+
+ if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) {
+ pdu->digest_ptr = b->asn_ptr - SNMP_USM_AUTH_SIZE;
+ pdu->digest_ptr -= octs_len + ASN_MAXLENLEN;
+ }
+
+ return (ASN_ERR_OK);
+}
+
+static enum snmp_code
+pdu_encode_secparams(struct asn_buf *b, struct snmp_pdu *pdu)
+{
+ u_char buf[256], *sptr;
+ struct asn_buf tb;
+ size_t auth_off, moved = 0;
+
+ auth_off = 0;
+ memset(buf, 0, 256);
+ tb.asn_ptr = buf;
+ tb.asn_len = 256;
+
+ if (asn_put_temp_header(&tb, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
+ &sptr) != ASN_ERR_OK)
+ return (SNMP_CODE_FAILED);
+
+ if (asn_put_octetstring(&tb, (u_char *)pdu->engine.engine_id,
+ pdu->engine.engine_len) != ASN_ERR_OK)
+ return (SNMP_CODE_FAILED);
+
+ if (asn_put_integer(&tb, pdu->engine.engine_boots) != ASN_ERR_OK)
+ return (SNMP_CODE_FAILED);
+
+ if (asn_put_integer(&tb, pdu->engine.engine_time) != ASN_ERR_OK)
+ return (SNMP_CODE_FAILED);
+
+ if (asn_put_octetstring(&tb, (u_char *)pdu->user.sec_name,
+ strlen(pdu->user.sec_name)) != ASN_ERR_OK)
+ return (SNMP_CODE_FAILED);
+
+ if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) {
+ auth_off = sizeof(buf) - tb.asn_len + ASN_MAXLENLEN;
+ if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest,
+ sizeof(pdu->msg_digest)) != ASN_ERR_OK)
+ return (SNMP_CODE_FAILED);
+ } else {
+ if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest, 0)
+ != ASN_ERR_OK)
+ return (SNMP_CODE_FAILED);
+ }
+
+ if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0) {
+ if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt,
+ sizeof(pdu->msg_salt)) != ASN_ERR_OK)
+ return (SNMP_CODE_FAILED);
+ } else {
+ if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt, 0)
+ != ASN_ERR_OK)
+ return (SNMP_CODE_FAILED);
+ }
+
+ if (asn_commit_header(&tb, sptr, &moved) != ASN_ERR_OK)
+ return (SNMP_CODE_FAILED);
+
+ if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0)
+ pdu->digest_ptr = b->asn_ptr + auth_off - moved;
+
+ if (asn_put_octetstring(b, buf, sizeof(buf) - tb.asn_len) != ASN_ERR_OK)
+ return (SNMP_CODE_FAILED);
+ pdu->digest_ptr += ASN_MAXLENLEN;
+
+ if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && asn_put_temp_header(b,
+ ASN_TYPE_OCTETSTRING, &pdu->encrypted_ptr) != ASN_ERR_OK)
+ return (SNMP_CODE_FAILED);
+
+ return (SNMP_CODE_OK);
+}
+
/*
- * Parse the outer SEQUENCE value. ASN_ERR_TAG means 'bad version'.
+ * Decode the PDU except for the variable bindings itself.
+ * If decoding fails because of a bad binding, but the rest can be
+ * decoded, ip points to the index of the failed variable (errors
+ * OORANGE, BADLEN or BADVERS).
*/
-enum asn_err
-snmp_parse_message_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp)
+enum snmp_code
+snmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
+{
+ enum snmp_code code;
+
+ if ((code = snmp_pdu_decode_header(b, pdu)) != SNMP_CODE_OK)
+ return (code);
+
+ if (pdu->version == SNMP_V3) {
+ if (pdu->security_model != SNMP_SECMODEL_USM)
+ return (SNMP_CODE_FAILED);
+ if ((code = snmp_pdu_decode_secmode(b, pdu)) != SNMP_CODE_OK)
+ return (code);
+ }
+
+ code = snmp_pdu_decode_scoped(b, pdu, ip);
+
+ switch (code) {
+ case SNMP_CODE_FAILED:
+ snmp_pdu_free(pdu);
+ break;
+
+ case SNMP_CODE_BADENC:
+ if (pdu->version == SNMP_Verr)
+ return (SNMP_CODE_BADVERS);
+
+ default:
+ break;
+ }
+
+ return (code);
+}
+
+enum snmp_code
+snmp_pdu_decode_header(struct asn_buf *b, struct snmp_pdu *pdu)
{
int32_t version;
- u_char type;
- u_int comm_len;
+ u_int octs_len;
+ asn_len_t len;
+
+ pdu->outer_ptr = b->asn_ptr;
+ pdu->outer_len = b->asn_len;
+
+ if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
+ snmp_error("cannot decode pdu header");
+ return (SNMP_CODE_FAILED);
+ }
+ if (b->asn_len < len) {
+ snmp_error("outer sequence value too short");
+ return (SNMP_CODE_FAILED);
+ }
+ if (b->asn_len != len) {
+ snmp_error("ignoring trailing junk in message");
+ b->asn_len = len;
+ }
if (asn_get_integer(b, &version) != ASN_ERR_OK) {
snmp_error("cannot decode version");
- return (ASN_ERR_FAILED);
+ return (SNMP_CODE_FAILED);
}
- if (version == 0) {
+ if (version == 0)
pdu->version = SNMP_V1;
- } else if (version == 1) {
+ else if (version == 1)
pdu->version = SNMP_V2c;
- } else {
+ else if (version == 3)
+ pdu->version = SNMP_V3;
+ else {
pdu->version = SNMP_Verr;
snmp_error("unsupported SNMP version");
- return (ASN_ERR_TAG);
+ return (SNMP_CODE_BADENC);
}
- 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);
+ if (pdu->version == SNMP_V3) {
+ if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
+ snmp_error("cannot decode pdu global data header");
+ return (SNMP_CODE_FAILED);
+ }
+
+ if (asn_get_integer(b, &pdu->identifier) != ASN_ERR_OK) {
+ snmp_error("cannot decode msg indetifier");
+ return (SNMP_CODE_FAILED);
+ }
+
+ if (asn_get_integer(b, &pdu->engine.max_msg_size)
+ != ASN_ERR_OK) {
+ snmp_error("cannot decode msg size");
+ return (SNMP_CODE_FAILED);
+ }
+
+ octs_len = 1;
+ if (asn_get_octetstring(b, (u_char *)&pdu->flags,
+ &octs_len) != ASN_ERR_OK) {
+ snmp_error("cannot decode msg flags");
+ return (SNMP_CODE_FAILED);
+ }
+
+ if (asn_get_integer(b, &pdu->security_model) != ASN_ERR_OK) {
+ snmp_error("cannot decode msg size");
+ return (SNMP_CODE_FAILED);
+ }
+
+ if (pdu->security_model != SNMP_SECMODEL_USM)
+ return (SNMP_CODE_FAILED);
+
+ if (parse_secparams(b, pdu) != ASN_ERR_OK)
+ return (SNMP_CODE_FAILED);
+ } else {
+ octs_len = SNMP_COMMUNITY_MAXLEN;
+ if (asn_get_octetstring(b, (u_char *)pdu->community,
+ &octs_len) != ASN_ERR_OK) {
+ snmp_error("cannot decode community");
+ return (SNMP_CODE_FAILED);
+ }
+ pdu->community[octs_len] = '\0';
+ }
+
+ return (SNMP_CODE_OK);
+}
+
+enum snmp_code
+snmp_pdu_decode_scoped(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
+{
+ u_char type;
+ asn_len_t len, trailer;
+ enum asn_err err;
+
+ if (pdu->version == SNMP_V3) {
+ if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
+ snmp_error("cannot decode scoped pdu header");
+ return (SNMP_CODE_FAILED);
+ }
+
+ len = SNMP_ENGINE_ID_SIZ;
+ if (asn_get_octetstring(b, (u_char *)&pdu->context_engine,
+ &len) != ASN_ERR_OK) {
+ snmp_error("cannot decode msg context engine");
+ return (SNMP_CODE_FAILED);
+ }
+ pdu->context_engine_len = len;
+
+ len = SNMP_CONTEXT_NAME_SIZ;
+ if (asn_get_octetstring(b, (u_char *)&pdu->context_name,
+ &len) != ASN_ERR_OK) {
+ snmp_error("cannot decode msg context name");
+ return (SNMP_CODE_FAILED);
+ }
+ pdu->context_name[len] = '\0';
}
- pdu->community[comm_len] = '\0';
- if (asn_get_header(b, &type, lenp) != ASN_ERR_OK) {
+ if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
snmp_error("cannot get pdu header");
- return (ASN_ERR_FAILED);
+ return (SNMP_CODE_FAILED);
}
if ((type & ~ASN_TYPE_MASK) !=
(ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) {
snmp_error("bad pdu header tag");
- return (ASN_ERR_FAILED);
+ return (SNMP_CODE_FAILED);
}
pdu->type = type & ASN_TYPE_MASK;
@@ -326,7 +595,7 @@ snmp_parse_message_hdr(struct asn_buf *b
case SNMP_PDU_TRAP:
if (pdu->version != SNMP_V1) {
snmp_error("bad pdu type %u", pdu->type);
- return (ASN_ERR_FAILED);
+ return (SNMP_CODE_FAILED);
}
break;
@@ -336,99 +605,64 @@ snmp_parse_message_hdr(struct asn_buf *b
case SNMP_PDU_REPORT:
if (pdu->version == SNMP_V1) {
snmp_error("bad pdu type %u", pdu->type);
- return (ASN_ERR_FAILED);
+ return (SNMP_CODE_FAILED);
}
break;
default:
snmp_error("bad pdu type %u", pdu->type);
- return (ASN_ERR_FAILED);
- }
-
-
- if (*lenp > b->asn_len) {
- snmp_error("pdu length too long");
- return (ASN_ERR_FAILED);
+ return (SNMP_CODE_FAILED);
}
- return (ASN_ERR_OK);
-}
-
-static enum asn_err
-parse_message(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
-{
- enum asn_err err;
- asn_len_t len, trailer;
-
- err = snmp_parse_message_hdr(b, pdu, &len);
- if (ASN_ERR_STOPPED(err))
- return (err);
-
trailer = b->asn_len - len;
b->asn_len = len;
err = parse_pdus(b, pdu, ip);
if (ASN_ERR_STOPPED(err))
- return (ASN_ERR_FAILED);
+ return (SNMP_CODE_FAILED);
if (b->asn_len != 0)
snmp_error("ignoring trailing junk after pdu");
b->asn_len = trailer;
- return (err);
+ return (SNMP_CODE_OK);
}
-/*
- * Decode the PDU except for the variable bindings itself.
- * If decoding fails because of a bad binding, but the rest can be
- * decoded, ip points to the index of the failed variable (errors
- * OORANGE, BADLEN or BADVERS).
- */
enum snmp_code
-snmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
+snmp_pdu_decode_secmode(struct asn_buf *b, struct snmp_pdu *pdu)
{
- asn_len_t len;
+ u_char type;
+ enum snmp_code code;
+ uint8_t digest[SNMP_USM_AUTH_SIZE];
- memset(pdu, 0, sizeof(*pdu));
+ if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH &&
+ (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0)
+ return (SNMP_CODE_BADSECLEVEL);
- if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
- snmp_error("cannot decode pdu header");
+ if ((code = snmp_pdu_calc_digest(b, pdu, digest)) !=
+ SNMP_CODE_OK)
return (SNMP_CODE_FAILED);
- }
- if (b->asn_len < len) {
- snmp_error("outer sequence value too short");
+
+ 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);
}
- if (b->asn_len != len) {
- snmp_error("ignoring trailing junk in message");
- b->asn_len = len;
- }
-
- switch (parse_message(b, pdu, ip)) {
+ pdu->scoped_ptr = b->asn_ptr;
- case ASN_ERR_OK:
- return (SNMP_CODE_OK);
+ if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV &&
+ (pdu->flags & SNMP_MSG_PRIV_FLAG) == 0)
+ return (SNMP_CODE_BADSECLEVEL);
- case ASN_ERR_FAILED:
- case ASN_ERR_EOBUF:
- snmp_pdu_free(pdu);
+ if ((code = snmp_pdu_decrypt(b, pdu)) != SNMP_CODE_OK)
return (SNMP_CODE_FAILED);
- case ASN_ERR_BADLEN:
*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***
More information about the svn-src-head
mailing list