xref: /freebsd/contrib/bsnmp/lib/snmpagent.c (revision e1d581b289848ffa97c452756dc52d45efb68a01)
1f06ca4afSHartmut Brandt /*
2f06ca4afSHartmut Brandt  * Copyright (c) 2001-2003
3f06ca4afSHartmut Brandt  *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4f06ca4afSHartmut Brandt  *	All rights reserved.
5f06ca4afSHartmut Brandt  *
6f06ca4afSHartmut Brandt  * Author: Harti Brandt <harti@freebsd.org>
7f06ca4afSHartmut Brandt  *
8896052c1SHartmut Brandt  * Redistribution and use in source and binary forms, with or without
9896052c1SHartmut Brandt  * modification, are permitted provided that the following conditions
10896052c1SHartmut Brandt  * are met:
11896052c1SHartmut Brandt  * 1. Redistributions of source code must retain the above copyright
12896052c1SHartmut Brandt  *    notice, this list of conditions and the following disclaimer.
13f06ca4afSHartmut Brandt  * 2. Redistributions in binary form must reproduce the above copyright
14f06ca4afSHartmut Brandt  *    notice, this list of conditions and the following disclaimer in the
15f06ca4afSHartmut Brandt  *    documentation and/or other materials provided with the distribution.
16f06ca4afSHartmut Brandt  *
17896052c1SHartmut Brandt  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18896052c1SHartmut Brandt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19896052c1SHartmut Brandt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20896052c1SHartmut Brandt  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21896052c1SHartmut Brandt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22896052c1SHartmut Brandt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23896052c1SHartmut Brandt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24896052c1SHartmut Brandt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25896052c1SHartmut Brandt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26896052c1SHartmut Brandt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27896052c1SHartmut Brandt  * SUCH DAMAGE.
28f06ca4afSHartmut Brandt  *
29165c5d31SHartmut Brandt  * $Begemot: bsnmp/lib/snmpagent.c,v 1.20 2005/10/04 11:21:33 brandt_h Exp $
30f06ca4afSHartmut Brandt  *
31f06ca4afSHartmut Brandt  * SNMP Agent functions
32f06ca4afSHartmut Brandt  */
33f06ca4afSHartmut Brandt #include <sys/types.h>
34f06ca4afSHartmut Brandt #include <sys/queue.h>
35f06ca4afSHartmut Brandt #include <stdio.h>
36f06ca4afSHartmut Brandt #include <stdlib.h>
37f06ca4afSHartmut Brandt #include <stddef.h>
38f06ca4afSHartmut Brandt #include <stdarg.h>
39165c5d31SHartmut Brandt #ifdef HAVE_STDINT_H
40896052c1SHartmut Brandt #include <stdint.h>
41165c5d31SHartmut Brandt #elif defined(HAVE_INTTYPES_H)
42165c5d31SHartmut Brandt #include <inttypes.h>
43165c5d31SHartmut Brandt #endif
44f06ca4afSHartmut Brandt #include <string.h>
45f06ca4afSHartmut Brandt 
46f06ca4afSHartmut Brandt #include "asn1.h"
47f06ca4afSHartmut Brandt #include "snmp.h"
48f06ca4afSHartmut Brandt #include "snmppriv.h"
49f06ca4afSHartmut Brandt #include "snmpagent.h"
50f06ca4afSHartmut Brandt 
51f06ca4afSHartmut Brandt static void snmp_debug_func(const char *fmt, ...);
52f06ca4afSHartmut Brandt 
53f06ca4afSHartmut Brandt void (*snmp_debug)(const char *fmt, ...) = snmp_debug_func;
54f06ca4afSHartmut Brandt 
55f06ca4afSHartmut Brandt struct snmp_node *tree;
56f06ca4afSHartmut Brandt u_int  tree_size;
57f06ca4afSHartmut Brandt 
58f06ca4afSHartmut Brandt /*
59f06ca4afSHartmut Brandt  * Structure to hold dependencies during SET processing
60f06ca4afSHartmut Brandt  * The last two members of this structure must be the
61f06ca4afSHartmut Brandt  * dependency visible by the user and the user data.
62f06ca4afSHartmut Brandt  */
63f06ca4afSHartmut Brandt struct depend {
64f06ca4afSHartmut Brandt 	TAILQ_ENTRY(depend) link;
65f06ca4afSHartmut Brandt 	size_t	len;		/* size of data part */
66f06ca4afSHartmut Brandt 	snmp_depop_t	func;
67f06ca4afSHartmut Brandt 	struct snmp_dependency dep;
68896052c1SHartmut Brandt #if defined(__GNUC__) && __GNUC__ < 3
69896052c1SHartmut Brandt 	u_char	data[0];
70896052c1SHartmut Brandt #else
71f06ca4afSHartmut Brandt 	u_char	data[];
72896052c1SHartmut Brandt #endif
73f06ca4afSHartmut Brandt };
74f06ca4afSHartmut Brandt TAILQ_HEAD(depend_list, depend);
75f06ca4afSHartmut Brandt 
76f06ca4afSHartmut Brandt /*
77f06ca4afSHartmut Brandt  * Set context
78f06ca4afSHartmut Brandt  */
79f06ca4afSHartmut Brandt struct context {
80f06ca4afSHartmut Brandt 	struct snmp_context	ctx;
81f06ca4afSHartmut Brandt 	struct depend_list	dlist;
82f06ca4afSHartmut Brandt 	const struct snmp_node	*node[SNMP_MAX_BINDINGS];
83f06ca4afSHartmut Brandt 	struct snmp_scratch	scratch[SNMP_MAX_BINDINGS];
84f06ca4afSHartmut Brandt 	struct depend		*depend;
85f06ca4afSHartmut Brandt };
86f06ca4afSHartmut Brandt 
87f06ca4afSHartmut Brandt #define	TR(W)	(snmp_trace & SNMP_TRACE_##W)
88f06ca4afSHartmut Brandt u_int snmp_trace = 0;
89f06ca4afSHartmut Brandt 
90f06ca4afSHartmut Brandt static char oidbuf[ASN_OIDSTRLEN];
91f06ca4afSHartmut Brandt 
92f06ca4afSHartmut Brandt /*
93f06ca4afSHartmut Brandt  * Allocate a context
94f06ca4afSHartmut Brandt  */
95f06ca4afSHartmut Brandt struct snmp_context *
snmp_init_context(void)96f06ca4afSHartmut Brandt snmp_init_context(void)
97f06ca4afSHartmut Brandt {
98f06ca4afSHartmut Brandt 	struct context *context;
99f06ca4afSHartmut Brandt 
100f06ca4afSHartmut Brandt 	if ((context = malloc(sizeof(*context))) == NULL)
101f06ca4afSHartmut Brandt 		return (NULL);
102f06ca4afSHartmut Brandt 
103f06ca4afSHartmut Brandt 	memset(context, 0, sizeof(*context));
104f06ca4afSHartmut Brandt 	TAILQ_INIT(&context->dlist);
105f06ca4afSHartmut Brandt 
106f06ca4afSHartmut Brandt 	return (&context->ctx);
107f06ca4afSHartmut Brandt }
108f06ca4afSHartmut Brandt 
109f06ca4afSHartmut Brandt /*
110f06ca4afSHartmut Brandt  * Find a variable for SET/GET and the first GETBULK pass.
111f06ca4afSHartmut Brandt  * Return the node pointer. If the search fails, set the errp to
112f06ca4afSHartmut Brandt  * the correct SNMPv2 GET exception code.
113f06ca4afSHartmut Brandt  */
114f06ca4afSHartmut Brandt static struct snmp_node *
find_node(const struct snmp_value * value,enum snmp_syntax * errp)115f06ca4afSHartmut Brandt find_node(const struct snmp_value *value, enum snmp_syntax *errp)
116f06ca4afSHartmut Brandt {
117f06ca4afSHartmut Brandt 	struct snmp_node *tp;
118f06ca4afSHartmut Brandt 
119f06ca4afSHartmut Brandt 	if (TR(FIND))
120f06ca4afSHartmut Brandt 		snmp_debug("find: searching %s",
121f06ca4afSHartmut Brandt 		    asn_oid2str_r(&value->var, oidbuf));
122f06ca4afSHartmut Brandt 
123f06ca4afSHartmut Brandt 	/*
124f06ca4afSHartmut Brandt 	 * If we have an exact match (the entry in the table is a
125f06ca4afSHartmut Brandt 	 * sub-oid from the variable) we have found what we are for.
126f06ca4afSHartmut Brandt 	 * If the table oid is higher than the variable, there is no match.
127f06ca4afSHartmut Brandt 	 */
128f06ca4afSHartmut Brandt 	for (tp = tree; tp < tree + tree_size; tp++) {
129f06ca4afSHartmut Brandt 		if (asn_is_suboid(&tp->oid, &value->var))
130f06ca4afSHartmut Brandt 			goto found;
131f06ca4afSHartmut Brandt 		if (asn_compare_oid(&tp->oid, &value->var) >= 0)
132f06ca4afSHartmut Brandt 			break;
133f06ca4afSHartmut Brandt 	}
134f06ca4afSHartmut Brandt 
135f06ca4afSHartmut Brandt 	if (TR(FIND))
136f06ca4afSHartmut Brandt 		snmp_debug("find: no match");
137f06ca4afSHartmut Brandt 	*errp = SNMP_SYNTAX_NOSUCHOBJECT;
138f06ca4afSHartmut Brandt 	return (NULL);
139f06ca4afSHartmut Brandt 
140f06ca4afSHartmut Brandt   found:
141f06ca4afSHartmut Brandt 	/* leafs must have a 0 instance identifier */
142f06ca4afSHartmut Brandt 	if (tp->type == SNMP_NODE_LEAF &&
143f06ca4afSHartmut Brandt 	    (value->var.len != tp->oid.len + 1 ||
144f06ca4afSHartmut Brandt 	     value->var.subs[tp->oid.len] != 0)) {
145f06ca4afSHartmut Brandt 		if (TR(FIND))
146f06ca4afSHartmut Brandt 			snmp_debug("find: bad leaf index");
147f06ca4afSHartmut Brandt 		*errp = SNMP_SYNTAX_NOSUCHINSTANCE;
148f06ca4afSHartmut Brandt 		return (NULL);
149f06ca4afSHartmut Brandt 	}
150f06ca4afSHartmut Brandt 	if (TR(FIND))
151f06ca4afSHartmut Brandt 		snmp_debug("find: found %s",
152f06ca4afSHartmut Brandt 		    asn_oid2str_r(&value->var, oidbuf));
153f06ca4afSHartmut Brandt 	return (tp);
154f06ca4afSHartmut Brandt }
155f06ca4afSHartmut Brandt 
156f06ca4afSHartmut Brandt static struct snmp_node *
find_subnode(const struct snmp_value * value)157f06ca4afSHartmut Brandt find_subnode(const struct snmp_value *value)
158f06ca4afSHartmut Brandt {
159f06ca4afSHartmut Brandt 	struct snmp_node *tp;
160f06ca4afSHartmut Brandt 
161f06ca4afSHartmut Brandt 	for (tp = tree; tp < tree + tree_size; tp++) {
162f06ca4afSHartmut Brandt 		if (asn_is_suboid(&value->var, &tp->oid))
163f06ca4afSHartmut Brandt 			return (tp);
164f06ca4afSHartmut Brandt 	}
165f06ca4afSHartmut Brandt 	return (NULL);
166f06ca4afSHartmut Brandt }
167f06ca4afSHartmut Brandt 
168135f7de5SShteryana Shopova static void
snmp_pdu_create_response(const struct snmp_pdu * pdu,struct snmp_pdu * resp)16906983448SShteryana Shopova snmp_pdu_create_response(const struct snmp_pdu *pdu, struct snmp_pdu *resp)
170135f7de5SShteryana Shopova {
171135f7de5SShteryana Shopova 	memset(resp, 0, sizeof(*resp));
172135f7de5SShteryana Shopova 	strcpy(resp->community, pdu->community);
173135f7de5SShteryana Shopova 	resp->version = pdu->version;
174*3b49535aSShteryana Shopova 	if (pdu->flags & SNMP_MSG_AUTODISCOVER)
175*3b49535aSShteryana Shopova 		resp->type = SNMP_PDU_REPORT; /* RFC 3414.4 */
176*3b49535aSShteryana Shopova 	else
177135f7de5SShteryana Shopova 		resp->type = SNMP_PDU_RESPONSE;
178135f7de5SShteryana Shopova 	resp->request_id = pdu->request_id;
179135f7de5SShteryana Shopova 	resp->version = pdu->version;
180135f7de5SShteryana Shopova 
181135f7de5SShteryana Shopova 	if (resp->version != SNMP_V3)
182135f7de5SShteryana Shopova 		return;
183135f7de5SShteryana Shopova 
18472cd7a52SShteryana Shopova 	memcpy(&resp->engine, &pdu->engine, sizeof(pdu->engine));
18572cd7a52SShteryana Shopova 	memcpy(&resp->user, &pdu->user, sizeof(pdu->user));
18672cd7a52SShteryana Shopova 	snmp_pdu_init_secparams(resp);
187135f7de5SShteryana Shopova 	resp->identifier = pdu->identifier;
188135f7de5SShteryana Shopova 	resp->security_model = pdu->security_model;
189135f7de5SShteryana Shopova 	resp->context_engine_len = pdu->context_engine_len;
190135f7de5SShteryana Shopova 	memcpy(resp->context_engine, pdu->context_engine,
191135f7de5SShteryana Shopova 	    resp->context_engine_len);
192135f7de5SShteryana Shopova 	strlcpy(resp->context_name, pdu->context_name,
193135f7de5SShteryana Shopova 	    sizeof(resp->context_name));
194135f7de5SShteryana Shopova }
195135f7de5SShteryana Shopova 
196f06ca4afSHartmut Brandt /*
197f06ca4afSHartmut Brandt  * Execute a GET operation. The tree is rooted at the global 'root'.
198f06ca4afSHartmut Brandt  * Build the response PDU on the fly. If the return code is SNMP_RET_ERR
199f06ca4afSHartmut Brandt  * the pdu error status and index will be set.
200f06ca4afSHartmut Brandt  */
201f06ca4afSHartmut Brandt enum snmp_ret
snmp_get(struct snmp_pdu * pdu,struct asn_buf * resp_b,struct snmp_pdu * resp,void * data)202f06ca4afSHartmut Brandt snmp_get(struct snmp_pdu *pdu, struct asn_buf *resp_b,
203f06ca4afSHartmut Brandt     struct snmp_pdu *resp, void *data)
204f06ca4afSHartmut Brandt {
205f06ca4afSHartmut Brandt 	int ret;
206f06ca4afSHartmut Brandt 	u_int i;
207f06ca4afSHartmut Brandt 	struct snmp_node *tp;
208f06ca4afSHartmut Brandt 	enum snmp_syntax except;
209f06ca4afSHartmut Brandt 	struct context context;
210f06ca4afSHartmut Brandt 	enum asn_err err;
211f06ca4afSHartmut Brandt 
212f06ca4afSHartmut Brandt 	memset(&context, 0, sizeof(context));
213f06ca4afSHartmut Brandt 	context.ctx.data = data;
214f06ca4afSHartmut Brandt 
215135f7de5SShteryana Shopova 	snmp_pdu_create_response(pdu, resp);
216f06ca4afSHartmut Brandt 
217f06ca4afSHartmut Brandt 	if (snmp_pdu_encode_header(resp_b, resp) != SNMP_CODE_OK)
218f06ca4afSHartmut Brandt 		/* cannot even encode header - very bad */
219f06ca4afSHartmut Brandt 		return (SNMP_RET_IGN);
220f06ca4afSHartmut Brandt 
221f06ca4afSHartmut Brandt 	for (i = 0; i < pdu->nbindings; i++) {
222f06ca4afSHartmut Brandt 		resp->bindings[i].var = pdu->bindings[i].var;
223f06ca4afSHartmut Brandt 		if ((tp = find_node(&pdu->bindings[i], &except)) == NULL) {
224f06ca4afSHartmut Brandt 			if (pdu->version == SNMP_V1) {
225f06ca4afSHartmut Brandt 				if (TR(GET))
226f06ca4afSHartmut Brandt 					snmp_debug("get: nosuchname");
227f06ca4afSHartmut Brandt 				pdu->error_status = SNMP_ERR_NOSUCHNAME;
228f06ca4afSHartmut Brandt 				pdu->error_index = i + 1;
229f06ca4afSHartmut Brandt 				snmp_pdu_free(resp);
230f06ca4afSHartmut Brandt 				return (SNMP_RET_ERR);
231f06ca4afSHartmut Brandt 			}
232f06ca4afSHartmut Brandt 			if (TR(GET))
233f06ca4afSHartmut Brandt 				snmp_debug("get: exception %u", except);
234f06ca4afSHartmut Brandt 			resp->bindings[i].syntax = except;
235f06ca4afSHartmut Brandt 
236f06ca4afSHartmut Brandt 		} else {
237f06ca4afSHartmut Brandt 			/* call the action to fetch the value. */
238f06ca4afSHartmut Brandt 			resp->bindings[i].syntax = tp->syntax;
239f06ca4afSHartmut Brandt 			ret = (*tp->op)(&context.ctx, &resp->bindings[i],
240f06ca4afSHartmut Brandt 			    tp->oid.len, tp->index, SNMP_OP_GET);
241f06ca4afSHartmut Brandt 			if (TR(GET))
242f06ca4afSHartmut Brandt 				snmp_debug("get: action returns %d", ret);
243f06ca4afSHartmut Brandt 
244f06ca4afSHartmut Brandt 			if (ret == SNMP_ERR_NOSUCHNAME) {
245f06ca4afSHartmut Brandt 				if (pdu->version == SNMP_V1) {
246f06ca4afSHartmut Brandt 					pdu->error_status = SNMP_ERR_NOSUCHNAME;
247f06ca4afSHartmut Brandt 					pdu->error_index = i + 1;
248f06ca4afSHartmut Brandt 					snmp_pdu_free(resp);
249f06ca4afSHartmut Brandt 					return (SNMP_RET_ERR);
250f06ca4afSHartmut Brandt 				}
251f06ca4afSHartmut Brandt 				if (TR(GET))
252f06ca4afSHartmut Brandt 					snmp_debug("get: exception noSuchInstance");
253f06ca4afSHartmut Brandt 				resp->bindings[i].syntax = SNMP_SYNTAX_NOSUCHINSTANCE;
254f06ca4afSHartmut Brandt 
255f06ca4afSHartmut Brandt 			} else if (ret != SNMP_ERR_NOERROR) {
256f06ca4afSHartmut Brandt 				pdu->error_status = SNMP_ERR_GENERR;
257f06ca4afSHartmut Brandt 				pdu->error_index = i + 1;
258f06ca4afSHartmut Brandt 				snmp_pdu_free(resp);
259f06ca4afSHartmut Brandt 				return (SNMP_RET_ERR);
260f06ca4afSHartmut Brandt 			}
261f06ca4afSHartmut Brandt 		}
262f06ca4afSHartmut Brandt 		resp->nbindings++;
263f06ca4afSHartmut Brandt 
264f06ca4afSHartmut Brandt 		err = snmp_binding_encode(resp_b, &resp->bindings[i]);
265f06ca4afSHartmut Brandt 
266f06ca4afSHartmut Brandt 		if (err == ASN_ERR_EOBUF) {
267f06ca4afSHartmut Brandt 			pdu->error_status = SNMP_ERR_TOOBIG;
268f06ca4afSHartmut Brandt 			pdu->error_index = 0;
269f06ca4afSHartmut Brandt 			snmp_pdu_free(resp);
270f06ca4afSHartmut Brandt 			return (SNMP_RET_ERR);
271f06ca4afSHartmut Brandt 		}
272f06ca4afSHartmut Brandt 		if (err != ASN_ERR_OK) {
273f06ca4afSHartmut Brandt 			if (TR(GET))
274f06ca4afSHartmut Brandt 				snmp_debug("get: binding encoding: %u", err);
275f06ca4afSHartmut Brandt 			pdu->error_status = SNMP_ERR_GENERR;
276f06ca4afSHartmut Brandt 			pdu->error_index = i + 1;
277f06ca4afSHartmut Brandt 			snmp_pdu_free(resp);
278f06ca4afSHartmut Brandt 			return (SNMP_RET_ERR);
279f06ca4afSHartmut Brandt 		}
280f06ca4afSHartmut Brandt 	}
281f06ca4afSHartmut Brandt 
282546401ceSShteryana Shopova 	if (snmp_fix_encoding(resp_b, resp) != SNMP_CODE_OK) {
283546401ceSShteryana Shopova 		snmp_debug("get: failed to encode PDU");
284546401ceSShteryana Shopova 		return (SNMP_RET_ERR);
285546401ceSShteryana Shopova 	}
286546401ceSShteryana Shopova 
287546401ceSShteryana Shopova 	return (SNMP_RET_OK);
288f06ca4afSHartmut Brandt }
289f06ca4afSHartmut Brandt 
290f06ca4afSHartmut Brandt static struct snmp_node *
next_node(const struct snmp_value * value,int * pnext)291f06ca4afSHartmut Brandt next_node(const struct snmp_value *value, int *pnext)
292f06ca4afSHartmut Brandt {
293f06ca4afSHartmut Brandt 	struct snmp_node *tp;
294f06ca4afSHartmut Brandt 
295f06ca4afSHartmut Brandt 	if (TR(FIND))
296f06ca4afSHartmut Brandt 		snmp_debug("next: searching %s",
297f06ca4afSHartmut Brandt 		    asn_oid2str_r(&value->var, oidbuf));
298f06ca4afSHartmut Brandt 
299f06ca4afSHartmut Brandt 	*pnext = 0;
300f06ca4afSHartmut Brandt 	for (tp = tree; tp < tree + tree_size; tp++) {
301f06ca4afSHartmut Brandt 		if (asn_is_suboid(&tp->oid, &value->var)) {
302f06ca4afSHartmut Brandt 			/* the tree OID is a sub-oid of the requested OID. */
303f06ca4afSHartmut Brandt 			if (tp->type == SNMP_NODE_LEAF) {
304f06ca4afSHartmut Brandt 				if (tp->oid.len == value->var.len) {
305f06ca4afSHartmut Brandt 					/* request for scalar type */
306f06ca4afSHartmut Brandt 					if (TR(FIND))
307f06ca4afSHartmut Brandt 						snmp_debug("next: found scalar %s",
308f06ca4afSHartmut Brandt 						    asn_oid2str_r(&tp->oid, oidbuf));
309f06ca4afSHartmut Brandt 					return (tp);
310f06ca4afSHartmut Brandt 				}
311f06ca4afSHartmut Brandt 				/* try next */
312f06ca4afSHartmut Brandt 			} else {
313f06ca4afSHartmut Brandt 				if (TR(FIND))
314f06ca4afSHartmut Brandt 					snmp_debug("next: found column %s",
315f06ca4afSHartmut Brandt 					    asn_oid2str_r(&tp->oid, oidbuf));
316f06ca4afSHartmut Brandt 				return (tp);
317f06ca4afSHartmut Brandt 			}
318f06ca4afSHartmut Brandt 		} else if (asn_is_suboid(&value->var, &tp->oid) ||
319f06ca4afSHartmut Brandt 		    asn_compare_oid(&tp->oid, &value->var) >= 0) {
320f06ca4afSHartmut Brandt 			if (TR(FIND))
321f06ca4afSHartmut Brandt 				snmp_debug("next: found %s",
322f06ca4afSHartmut Brandt 				    asn_oid2str_r(&tp->oid, oidbuf));
323f06ca4afSHartmut Brandt 			*pnext = 1;
324f06ca4afSHartmut Brandt 			return (tp);
325f06ca4afSHartmut Brandt 		}
326f06ca4afSHartmut Brandt 	}
327f06ca4afSHartmut Brandt 
328f06ca4afSHartmut Brandt 	if (TR(FIND))
329f06ca4afSHartmut Brandt 		snmp_debug("next: failed");
330f06ca4afSHartmut Brandt 
331f06ca4afSHartmut Brandt 	return (NULL);
332f06ca4afSHartmut Brandt }
333f06ca4afSHartmut Brandt 
334f06ca4afSHartmut Brandt static enum snmp_ret
do_getnext(struct context * context,const struct snmp_value * inb,struct snmp_value * outb,struct snmp_pdu * pdu)335f06ca4afSHartmut Brandt do_getnext(struct context *context, const struct snmp_value *inb,
336f06ca4afSHartmut Brandt     struct snmp_value *outb, struct snmp_pdu *pdu)
337f06ca4afSHartmut Brandt {
338f06ca4afSHartmut Brandt 	const struct snmp_node *tp;
339f06ca4afSHartmut Brandt 	int ret, next;
340f06ca4afSHartmut Brandt 
341f06ca4afSHartmut Brandt 	if ((tp = next_node(inb, &next)) == NULL)
342f06ca4afSHartmut Brandt 		goto eofMib;
343f06ca4afSHartmut Brandt 
344f06ca4afSHartmut Brandt 	/* retain old variable if we are doing a GETNEXT on an exact
345f06ca4afSHartmut Brandt 	 * matched leaf only */
346f06ca4afSHartmut Brandt 	if (tp->type == SNMP_NODE_LEAF || next)
347f06ca4afSHartmut Brandt 		outb->var = tp->oid;
348f06ca4afSHartmut Brandt 	else
349f06ca4afSHartmut Brandt 		outb->var = inb->var;
350f06ca4afSHartmut Brandt 
351f06ca4afSHartmut Brandt 	for (;;) {
352f06ca4afSHartmut Brandt 		outb->syntax = tp->syntax;
353f06ca4afSHartmut Brandt 		if (tp->type == SNMP_NODE_LEAF) {
354f06ca4afSHartmut Brandt 			/* make a GET operation */
355f06ca4afSHartmut Brandt 			outb->var.subs[outb->var.len++] = 0;
356f06ca4afSHartmut Brandt 			ret = (*tp->op)(&context->ctx, outb, tp->oid.len,
357f06ca4afSHartmut Brandt 			    tp->index, SNMP_OP_GET);
358f06ca4afSHartmut Brandt 		} else {
359f06ca4afSHartmut Brandt 			/* make a GETNEXT */
360f06ca4afSHartmut Brandt 			ret = (*tp->op)(&context->ctx, outb, tp->oid.len,
361f06ca4afSHartmut Brandt 			     tp->index, SNMP_OP_GETNEXT);
362f06ca4afSHartmut Brandt 		}
363f06ca4afSHartmut Brandt 		if (ret != SNMP_ERR_NOSUCHNAME) {
364f06ca4afSHartmut Brandt 			/* got something */
365f06ca4afSHartmut Brandt 			if (ret != SNMP_ERR_NOERROR && TR(GETNEXT))
366f06ca4afSHartmut Brandt 				snmp_debug("getnext: %s returns %u",
367f06ca4afSHartmut Brandt 				    asn_oid2str(&outb->var), ret);
368f06ca4afSHartmut Brandt 			break;
369f06ca4afSHartmut Brandt 		}
370f06ca4afSHartmut Brandt 
371f06ca4afSHartmut Brandt 		/* object has no data - try next */
372f06ca4afSHartmut Brandt 		if (++tp == tree + tree_size)
373f06ca4afSHartmut Brandt 			break;
37494caccb3SHartmut Brandt 
37594caccb3SHartmut Brandt 		if (TR(GETNEXT))
37694caccb3SHartmut Brandt 			snmp_debug("getnext: no data - avancing to %s",
37794caccb3SHartmut Brandt 			    asn_oid2str(&tp->oid));
37894caccb3SHartmut Brandt 
379f06ca4afSHartmut Brandt 		outb->var = tp->oid;
380f06ca4afSHartmut Brandt 	}
381f06ca4afSHartmut Brandt 
382f06ca4afSHartmut Brandt 	if (ret == SNMP_ERR_NOSUCHNAME) {
383f06ca4afSHartmut Brandt   eofMib:
384f06ca4afSHartmut Brandt 		outb->var = inb->var;
385f06ca4afSHartmut Brandt 		if (pdu->version == SNMP_V1) {
386f06ca4afSHartmut Brandt 			pdu->error_status = SNMP_ERR_NOSUCHNAME;
387f06ca4afSHartmut Brandt 			return (SNMP_RET_ERR);
388f06ca4afSHartmut Brandt 		}
389f06ca4afSHartmut Brandt 		outb->syntax = SNMP_SYNTAX_ENDOFMIBVIEW;
390f06ca4afSHartmut Brandt 
391f06ca4afSHartmut Brandt 	} else if (ret != SNMP_ERR_NOERROR) {
392f06ca4afSHartmut Brandt 		pdu->error_status = SNMP_ERR_GENERR;
393f06ca4afSHartmut Brandt 		return (SNMP_RET_ERR);
394f06ca4afSHartmut Brandt 	}
395f06ca4afSHartmut Brandt 	return (SNMP_RET_OK);
396f06ca4afSHartmut Brandt }
397f06ca4afSHartmut Brandt 
398f06ca4afSHartmut Brandt 
399f06ca4afSHartmut Brandt /*
400f06ca4afSHartmut Brandt  * Execute a GETNEXT operation. The tree is rooted at the global 'root'.
401f06ca4afSHartmut Brandt  * Build the response PDU on the fly. The return is:
402f06ca4afSHartmut Brandt  */
403f06ca4afSHartmut Brandt enum snmp_ret
snmp_getnext(struct snmp_pdu * pdu,struct asn_buf * resp_b,struct snmp_pdu * resp,void * data)404f06ca4afSHartmut Brandt snmp_getnext(struct snmp_pdu *pdu, struct asn_buf *resp_b,
405f06ca4afSHartmut Brandt     struct snmp_pdu *resp, void *data)
406f06ca4afSHartmut Brandt {
407f06ca4afSHartmut Brandt 	struct context context;
408f06ca4afSHartmut Brandt 	u_int i;
409f06ca4afSHartmut Brandt 	enum asn_err err;
410f06ca4afSHartmut Brandt 	enum snmp_ret result;
411f06ca4afSHartmut Brandt 
412f06ca4afSHartmut Brandt 	memset(&context, 0, sizeof(context));
413f06ca4afSHartmut Brandt 	context.ctx.data = data;
414f06ca4afSHartmut Brandt 
415135f7de5SShteryana Shopova 	snmp_pdu_create_response(pdu, resp);
416f06ca4afSHartmut Brandt 
417f06ca4afSHartmut Brandt 	if (snmp_pdu_encode_header(resp_b, resp))
418f06ca4afSHartmut Brandt 		return (SNMP_RET_IGN);
419f06ca4afSHartmut Brandt 
420f06ca4afSHartmut Brandt 	for (i = 0; i < pdu->nbindings; i++) {
421f06ca4afSHartmut Brandt 		result = do_getnext(&context, &pdu->bindings[i],
422f06ca4afSHartmut Brandt 		    &resp->bindings[i], pdu);
423f06ca4afSHartmut Brandt 
424f06ca4afSHartmut Brandt 		if (result != SNMP_RET_OK) {
425f06ca4afSHartmut Brandt 			pdu->error_index = i + 1;
426f06ca4afSHartmut Brandt 			snmp_pdu_free(resp);
427f06ca4afSHartmut Brandt 			return (result);
428f06ca4afSHartmut Brandt 		}
429f06ca4afSHartmut Brandt 
430f06ca4afSHartmut Brandt 		resp->nbindings++;
431f06ca4afSHartmut Brandt 
432f06ca4afSHartmut Brandt 		err = snmp_binding_encode(resp_b, &resp->bindings[i]);
433f06ca4afSHartmut Brandt 
434f06ca4afSHartmut Brandt 		if (err == ASN_ERR_EOBUF) {
435f06ca4afSHartmut Brandt 			pdu->error_status = SNMP_ERR_TOOBIG;
436f06ca4afSHartmut Brandt 			pdu->error_index = 0;
437f06ca4afSHartmut Brandt 			snmp_pdu_free(resp);
438f06ca4afSHartmut Brandt 			return (SNMP_RET_ERR);
439f06ca4afSHartmut Brandt 		}
440f06ca4afSHartmut Brandt 		if (err != ASN_ERR_OK) {
441f06ca4afSHartmut Brandt 			if (TR(GET))
442f06ca4afSHartmut Brandt 				snmp_debug("getnext: binding encoding: %u", err);
443f06ca4afSHartmut Brandt 			pdu->error_status = SNMP_ERR_GENERR;
444f06ca4afSHartmut Brandt 			pdu->error_index = i + 1;
445f06ca4afSHartmut Brandt 			snmp_pdu_free(resp);
446f06ca4afSHartmut Brandt 			return (SNMP_RET_ERR);
447f06ca4afSHartmut Brandt 		}
448f06ca4afSHartmut Brandt 	}
449546401ceSShteryana Shopova 
450546401ceSShteryana Shopova 	if (snmp_fix_encoding(resp_b, resp) != SNMP_CODE_OK) {
451546401ceSShteryana Shopova 		snmp_debug("getnext: failed to encode PDU");
452546401ceSShteryana Shopova 		return (SNMP_RET_ERR);
453546401ceSShteryana Shopova 	}
454546401ceSShteryana Shopova 
455546401ceSShteryana Shopova 	return (SNMP_RET_OK);
456f06ca4afSHartmut Brandt }
457f06ca4afSHartmut Brandt 
458f06ca4afSHartmut Brandt enum snmp_ret
snmp_getbulk(struct snmp_pdu * pdu,struct asn_buf * resp_b,struct snmp_pdu * resp,void * data)459f06ca4afSHartmut Brandt snmp_getbulk(struct snmp_pdu *pdu, struct asn_buf *resp_b,
460f06ca4afSHartmut Brandt     struct snmp_pdu *resp, void *data)
461f06ca4afSHartmut Brandt {
462f06ca4afSHartmut Brandt 	struct context context;
463f06ca4afSHartmut Brandt 	u_int i;
464f06ca4afSHartmut Brandt 	int cnt;
465f06ca4afSHartmut Brandt 	u_int non_rep;
466f06ca4afSHartmut Brandt 	int eomib;
467f06ca4afSHartmut Brandt 	enum snmp_ret result;
468f06ca4afSHartmut Brandt 	enum asn_err err;
469f06ca4afSHartmut Brandt 
470f06ca4afSHartmut Brandt 	memset(&context, 0, sizeof(context));
471f06ca4afSHartmut Brandt 	context.ctx.data = data;
472f06ca4afSHartmut Brandt 
473135f7de5SShteryana Shopova 	snmp_pdu_create_response(pdu, resp);
474f06ca4afSHartmut Brandt 
475f06ca4afSHartmut Brandt 	if (snmp_pdu_encode_header(resp_b, resp) != SNMP_CODE_OK)
476f06ca4afSHartmut Brandt 		/* cannot even encode header - very bad */
477f06ca4afSHartmut Brandt 		return (SNMP_RET_IGN);
478f06ca4afSHartmut Brandt 
479f06ca4afSHartmut Brandt 	if ((non_rep = pdu->error_status) > pdu->nbindings)
480f06ca4afSHartmut Brandt 		non_rep = pdu->nbindings;
481f06ca4afSHartmut Brandt 
482f06ca4afSHartmut Brandt 	/* non-repeaters */
483f06ca4afSHartmut Brandt 	for (i = 0; i < non_rep; i++) {
484f06ca4afSHartmut Brandt 		result = do_getnext(&context, &pdu->bindings[i],
485f06ca4afSHartmut Brandt 		    &resp->bindings[resp->nbindings], pdu);
486f06ca4afSHartmut Brandt 
487f06ca4afSHartmut Brandt 		if (result != SNMP_RET_OK) {
488f06ca4afSHartmut Brandt 			pdu->error_index = i + 1;
489f06ca4afSHartmut Brandt 			snmp_pdu_free(resp);
490f06ca4afSHartmut Brandt 			return (result);
491f06ca4afSHartmut Brandt 		}
492f06ca4afSHartmut Brandt 
493f06ca4afSHartmut Brandt 		err = snmp_binding_encode(resp_b,
494f06ca4afSHartmut Brandt 		    &resp->bindings[resp->nbindings++]);
495f06ca4afSHartmut Brandt 
496f06ca4afSHartmut Brandt 		if (err == ASN_ERR_EOBUF)
497f06ca4afSHartmut Brandt 			goto done;
498f06ca4afSHartmut Brandt 
499f06ca4afSHartmut Brandt 		if (err != ASN_ERR_OK) {
500f06ca4afSHartmut Brandt 			if (TR(GET))
501f06ca4afSHartmut Brandt 				snmp_debug("getnext: binding encoding: %u", err);
502f06ca4afSHartmut Brandt 			pdu->error_status = SNMP_ERR_GENERR;
503f06ca4afSHartmut Brandt 			pdu->error_index = i + 1;
504f06ca4afSHartmut Brandt 			snmp_pdu_free(resp);
505f06ca4afSHartmut Brandt 			return (SNMP_RET_ERR);
506f06ca4afSHartmut Brandt 		}
507f06ca4afSHartmut Brandt 	}
508f06ca4afSHartmut Brandt 
509f06ca4afSHartmut Brandt 	if (non_rep == pdu->nbindings)
510f06ca4afSHartmut Brandt 		goto done;
511f06ca4afSHartmut Brandt 
512f06ca4afSHartmut Brandt 	/* repeates */
513f06ca4afSHartmut Brandt 	for (cnt = 0; cnt < pdu->error_index; cnt++) {
514f06ca4afSHartmut Brandt 		eomib = 1;
515f06ca4afSHartmut Brandt 		for (i = non_rep; i < pdu->nbindings; i++) {
516ecd241b6SXin LI 
517ecd241b6SXin LI 			if (resp->nbindings == SNMP_MAX_BINDINGS)
518ecd241b6SXin LI 				/* PDU is full */
519ecd241b6SXin LI 				goto done;
520ecd241b6SXin LI 
521f06ca4afSHartmut Brandt 			if (cnt == 0)
522f06ca4afSHartmut Brandt 				result = do_getnext(&context, &pdu->bindings[i],
523f06ca4afSHartmut Brandt 				    &resp->bindings[resp->nbindings], pdu);
524f06ca4afSHartmut Brandt 			else
525f06ca4afSHartmut Brandt 				result = do_getnext(&context,
526f06ca4afSHartmut Brandt 				    &resp->bindings[resp->nbindings -
527f06ca4afSHartmut Brandt 				    (pdu->nbindings - non_rep)],
528f06ca4afSHartmut Brandt 				    &resp->bindings[resp->nbindings], pdu);
529f06ca4afSHartmut Brandt 
530f06ca4afSHartmut Brandt 			if (result != SNMP_RET_OK) {
531f06ca4afSHartmut Brandt 				pdu->error_index = i + 1;
532f06ca4afSHartmut Brandt 				snmp_pdu_free(resp);
533f06ca4afSHartmut Brandt 				return (result);
534f06ca4afSHartmut Brandt 			}
535f06ca4afSHartmut Brandt 			if (resp->bindings[resp->nbindings].syntax !=
536f06ca4afSHartmut Brandt 			    SNMP_SYNTAX_ENDOFMIBVIEW)
537f06ca4afSHartmut Brandt 				eomib = 0;
538f06ca4afSHartmut Brandt 
539f06ca4afSHartmut Brandt 			err = snmp_binding_encode(resp_b,
540f06ca4afSHartmut Brandt 			    &resp->bindings[resp->nbindings++]);
541f06ca4afSHartmut Brandt 
542f06ca4afSHartmut Brandt 			if (err == ASN_ERR_EOBUF)
543f06ca4afSHartmut Brandt 				goto done;
544f06ca4afSHartmut Brandt 
545f06ca4afSHartmut Brandt 			if (err != ASN_ERR_OK) {
546f06ca4afSHartmut Brandt 				if (TR(GET))
547f06ca4afSHartmut Brandt 					snmp_debug("getnext: binding encoding: %u", err);
548f06ca4afSHartmut Brandt 				pdu->error_status = SNMP_ERR_GENERR;
549f06ca4afSHartmut Brandt 				pdu->error_index = i + 1;
550f06ca4afSHartmut Brandt 				snmp_pdu_free(resp);
551f06ca4afSHartmut Brandt 				return (SNMP_RET_ERR);
552f06ca4afSHartmut Brandt 			}
553f06ca4afSHartmut Brandt 		}
554f06ca4afSHartmut Brandt 		if (eomib)
555f06ca4afSHartmut Brandt 			break;
556f06ca4afSHartmut Brandt 	}
557f06ca4afSHartmut Brandt 
558f06ca4afSHartmut Brandt   done:
559546401ceSShteryana Shopova 	if (snmp_fix_encoding(resp_b, resp) != SNMP_CODE_OK) {
560546401ceSShteryana Shopova 		snmp_debug("getnext: failed to encode PDU");
561546401ceSShteryana Shopova 		return (SNMP_RET_ERR);
562546401ceSShteryana Shopova 	}
563546401ceSShteryana Shopova 
564546401ceSShteryana Shopova 	return (SNMP_RET_OK);
565f06ca4afSHartmut Brandt }
566f06ca4afSHartmut Brandt 
567f06ca4afSHartmut Brandt /*
568f06ca4afSHartmut Brandt  * Rollback a SET operation. Failed index is 'i'.
569f06ca4afSHartmut Brandt  */
570f06ca4afSHartmut Brandt static void
rollback(struct context * context,struct snmp_pdu * pdu,u_int i)571f06ca4afSHartmut Brandt rollback(struct context *context, struct snmp_pdu *pdu, u_int i)
572f06ca4afSHartmut Brandt {
573f06ca4afSHartmut Brandt 	struct snmp_value *b;
574f06ca4afSHartmut Brandt 	const struct snmp_node *np;
575f06ca4afSHartmut Brandt 	int ret;
576f06ca4afSHartmut Brandt 
577f06ca4afSHartmut Brandt 	while (i-- > 0) {
578f06ca4afSHartmut Brandt 		b = &pdu->bindings[i];
579f06ca4afSHartmut Brandt 		np = context->node[i];
580f06ca4afSHartmut Brandt 
581f06ca4afSHartmut Brandt 		context->ctx.scratch = &context->scratch[i];
582f06ca4afSHartmut Brandt 
583f06ca4afSHartmut Brandt 		ret = (*np->op)(&context->ctx, b, np->oid.len, np->index,
584f06ca4afSHartmut Brandt 		    SNMP_OP_ROLLBACK);
585f06ca4afSHartmut Brandt 
586f06ca4afSHartmut Brandt 		if (ret != SNMP_ERR_NOERROR) {
587f06ca4afSHartmut Brandt 			snmp_error("set: rollback failed (%d) on variable %s "
588f06ca4afSHartmut Brandt 			    "index %u", ret, asn_oid2str(&b->var), i);
589f06ca4afSHartmut Brandt 			if (pdu->version != SNMP_V1) {
590f06ca4afSHartmut Brandt 				pdu->error_status = SNMP_ERR_UNDO_FAILED;
591f06ca4afSHartmut Brandt 				pdu->error_index = 0;
592f06ca4afSHartmut Brandt 			}
593f06ca4afSHartmut Brandt 		}
594f06ca4afSHartmut Brandt 	}
595f06ca4afSHartmut Brandt }
596f06ca4afSHartmut Brandt 
597f06ca4afSHartmut Brandt /*
598f06ca4afSHartmut Brandt  * Commit dependencies.
599f06ca4afSHartmut Brandt  */
600f06ca4afSHartmut Brandt int
snmp_dep_commit(struct snmp_context * ctx)601f06ca4afSHartmut Brandt snmp_dep_commit(struct snmp_context *ctx)
602f06ca4afSHartmut Brandt {
603f06ca4afSHartmut Brandt 	struct context *context = (struct context *)ctx;
604f06ca4afSHartmut Brandt 	int ret;
605f06ca4afSHartmut Brandt 
606f06ca4afSHartmut Brandt 	TAILQ_FOREACH(context->depend, &context->dlist, link) {
607f06ca4afSHartmut Brandt 		ctx->dep = &context->depend->dep;
608f06ca4afSHartmut Brandt 
609f06ca4afSHartmut Brandt 		if (TR(SET))
610f06ca4afSHartmut Brandt 			snmp_debug("set: dependency commit %s",
611f06ca4afSHartmut Brandt 			    asn_oid2str(&ctx->dep->obj));
612f06ca4afSHartmut Brandt 
613f06ca4afSHartmut Brandt 		ret = context->depend->func(ctx, ctx->dep, SNMP_DEPOP_COMMIT);
614f06ca4afSHartmut Brandt 
615f06ca4afSHartmut Brandt 		if (ret != SNMP_ERR_NOERROR) {
616f06ca4afSHartmut Brandt 			if (TR(SET))
617f06ca4afSHartmut Brandt 				snmp_debug("set: dependency failed %d", ret);
618f06ca4afSHartmut Brandt 			return (ret);
619f06ca4afSHartmut Brandt 		}
620f06ca4afSHartmut Brandt 	}
621f06ca4afSHartmut Brandt 	return (SNMP_ERR_NOERROR);
622f06ca4afSHartmut Brandt }
623f06ca4afSHartmut Brandt 
624f06ca4afSHartmut Brandt /*
625f06ca4afSHartmut Brandt  * Rollback dependencies
626f06ca4afSHartmut Brandt  */
627f06ca4afSHartmut Brandt int
snmp_dep_rollback(struct snmp_context * ctx)628f06ca4afSHartmut Brandt snmp_dep_rollback(struct snmp_context *ctx)
629f06ca4afSHartmut Brandt {
630f06ca4afSHartmut Brandt 	struct context *context = (struct context *)ctx;
631f06ca4afSHartmut Brandt 	int ret, ret1;
632f06ca4afSHartmut Brandt 	char objbuf[ASN_OIDSTRLEN];
633f06ca4afSHartmut Brandt 	char idxbuf[ASN_OIDSTRLEN];
634f06ca4afSHartmut Brandt 
635f06ca4afSHartmut Brandt 	ret1 = SNMP_ERR_NOERROR;
636f06ca4afSHartmut Brandt 	while ((context->depend =
637f06ca4afSHartmut Brandt 	    TAILQ_PREV(context->depend, depend_list, link)) != NULL) {
638f06ca4afSHartmut Brandt 		ctx->dep = &context->depend->dep;
639f06ca4afSHartmut Brandt 
640f06ca4afSHartmut Brandt 		if (TR(SET))
641f06ca4afSHartmut Brandt 			snmp_debug("set: dependency rollback %s",
642f06ca4afSHartmut Brandt 			    asn_oid2str(&ctx->dep->obj));
643f06ca4afSHartmut Brandt 
644f06ca4afSHartmut Brandt 		ret = context->depend->func(ctx, ctx->dep, SNMP_DEPOP_ROLLBACK);
645f06ca4afSHartmut Brandt 
646f06ca4afSHartmut Brandt 		if (ret != SNMP_ERR_NOERROR) {
647f06ca4afSHartmut Brandt 			snmp_debug("set: dep rollback returns %u: %s %s", ret,
648f06ca4afSHartmut Brandt 			    asn_oid2str_r(&ctx->dep->obj, objbuf),
649f06ca4afSHartmut Brandt 			    asn_oid2str_r(&ctx->dep->idx, idxbuf));
650f06ca4afSHartmut Brandt 			if (ret1 == SNMP_ERR_NOERROR)
651f06ca4afSHartmut Brandt 				ret1 = ret;
652f06ca4afSHartmut Brandt 		}
653f06ca4afSHartmut Brandt 	}
654f06ca4afSHartmut Brandt 	return (ret1);
655f06ca4afSHartmut Brandt }
656f06ca4afSHartmut Brandt 
6578eecd77aSHartmut Brandt void
snmp_dep_finish(struct snmp_context * ctx)6588eecd77aSHartmut Brandt snmp_dep_finish(struct snmp_context *ctx)
6598eecd77aSHartmut Brandt {
6608eecd77aSHartmut Brandt 	struct context *context = (struct context *)ctx;
6618eecd77aSHartmut Brandt 	struct depend *d;
6628eecd77aSHartmut Brandt 
6638eecd77aSHartmut Brandt 	while ((d = TAILQ_FIRST(&context->dlist)) != NULL) {
6648eecd77aSHartmut Brandt 		ctx->dep = &d->dep;
6658eecd77aSHartmut Brandt 		(void)d->func(ctx, ctx->dep, SNMP_DEPOP_FINISH);
6668eecd77aSHartmut Brandt 		TAILQ_REMOVE(&context->dlist, d, link);
6678eecd77aSHartmut Brandt 		free(d);
6688eecd77aSHartmut Brandt 	}
6698eecd77aSHartmut Brandt }
6708eecd77aSHartmut Brandt 
671f06ca4afSHartmut Brandt /*
672f06ca4afSHartmut Brandt  * Do a SET operation.
673f06ca4afSHartmut Brandt  */
674f06ca4afSHartmut Brandt enum snmp_ret
snmp_set(struct snmp_pdu * pdu,struct asn_buf * resp_b,struct snmp_pdu * resp,void * data)675f06ca4afSHartmut Brandt snmp_set(struct snmp_pdu *pdu, struct asn_buf *resp_b,
676f06ca4afSHartmut Brandt     struct snmp_pdu *resp, void *data)
677f06ca4afSHartmut Brandt {
678f06ca4afSHartmut Brandt 	int ret;
679f06ca4afSHartmut Brandt 	u_int i;
680f06ca4afSHartmut Brandt 	enum asn_err asnerr;
681f06ca4afSHartmut Brandt 	struct context context;
682f06ca4afSHartmut Brandt 	const struct snmp_node *np;
683f06ca4afSHartmut Brandt 	struct snmp_value *b;
684f06ca4afSHartmut Brandt 	enum snmp_syntax except;
685f06ca4afSHartmut Brandt 
686f06ca4afSHartmut Brandt 	memset(&context, 0, sizeof(context));
687f06ca4afSHartmut Brandt 	TAILQ_INIT(&context.dlist);
688f06ca4afSHartmut Brandt 	context.ctx.data = data;
689f06ca4afSHartmut Brandt 
690135f7de5SShteryana Shopova 	snmp_pdu_create_response(pdu, resp);
691f06ca4afSHartmut Brandt 
692f06ca4afSHartmut Brandt 	if (snmp_pdu_encode_header(resp_b, resp))
693f06ca4afSHartmut Brandt 		return (SNMP_RET_IGN);
694f06ca4afSHartmut Brandt 
695f06ca4afSHartmut Brandt 	/*
696f06ca4afSHartmut Brandt 	 * 1. Find all nodes, check that they are writeable and
697f06ca4afSHartmut Brandt 	 *    that the syntax is ok, copy over the binding to the response.
698f06ca4afSHartmut Brandt 	 */
699f06ca4afSHartmut Brandt 	for (i = 0; i < pdu->nbindings; i++) {
700f06ca4afSHartmut Brandt 		b = &pdu->bindings[i];
701f06ca4afSHartmut Brandt 
702f06ca4afSHartmut Brandt 		if ((np = context.node[i] = find_node(b, &except)) == NULL) {
703f06ca4afSHartmut Brandt 			/* not found altogether or LEAF with wrong index */
704f06ca4afSHartmut Brandt 			if (TR(SET))
705f06ca4afSHartmut Brandt 				snmp_debug("set: node not found %s",
706f06ca4afSHartmut Brandt 				    asn_oid2str_r(&b->var, oidbuf));
707f06ca4afSHartmut Brandt 			if (pdu->version == SNMP_V1) {
708f06ca4afSHartmut Brandt 				pdu->error_index = i + 1;
709f06ca4afSHartmut Brandt 				pdu->error_status = SNMP_ERR_NOSUCHNAME;
710f06ca4afSHartmut Brandt 			} else if ((np = find_subnode(b)) != NULL) {
711f06ca4afSHartmut Brandt 				/* 2. intermediate object */
712f06ca4afSHartmut Brandt 				pdu->error_index = i + 1;
713f06ca4afSHartmut Brandt 				pdu->error_status = SNMP_ERR_NOT_WRITEABLE;
714f06ca4afSHartmut Brandt 			} else if (except == SNMP_SYNTAX_NOSUCHOBJECT) {
715f06ca4afSHartmut Brandt 				pdu->error_index = i + 1;
716f06ca4afSHartmut Brandt 				pdu->error_status = SNMP_ERR_NO_ACCESS;
717f06ca4afSHartmut Brandt 			} else {
718f06ca4afSHartmut Brandt 				pdu->error_index = i + 1;
719f06ca4afSHartmut Brandt 				pdu->error_status = SNMP_ERR_NO_CREATION;
720f06ca4afSHartmut Brandt 			}
721f06ca4afSHartmut Brandt 			snmp_pdu_free(resp);
722f06ca4afSHartmut Brandt 			return (SNMP_RET_ERR);
723f06ca4afSHartmut Brandt 		}
724f06ca4afSHartmut Brandt 		/*
725f06ca4afSHartmut Brandt 		 * 2. write/createable?
726f06ca4afSHartmut Brandt 		 * Can check this for leafs only, because in v2 we have
727f06ca4afSHartmut Brandt 		 * to differentiate between NOT_WRITEABLE and NO_CREATION
728f06ca4afSHartmut Brandt 		 * and only the action routine for COLUMNS knows, whether
729f06ca4afSHartmut Brandt 		 * a column exists.
730f06ca4afSHartmut Brandt 		 */
731f06ca4afSHartmut Brandt 		if (np->type == SNMP_NODE_LEAF &&
732f06ca4afSHartmut Brandt 		    !(np->flags & SNMP_NODE_CANSET)) {
733f06ca4afSHartmut Brandt 			if (pdu->version == SNMP_V1) {
734f06ca4afSHartmut Brandt 				pdu->error_index = i + 1;
735f06ca4afSHartmut Brandt 				pdu->error_status = SNMP_ERR_NOSUCHNAME;
736f06ca4afSHartmut Brandt 			} else {
737f06ca4afSHartmut Brandt 				pdu->error_index = i + 1;
738f06ca4afSHartmut Brandt 				pdu->error_status = SNMP_ERR_NOT_WRITEABLE;
739f06ca4afSHartmut Brandt 			}
740f06ca4afSHartmut Brandt 			snmp_pdu_free(resp);
741f06ca4afSHartmut Brandt 			return (SNMP_RET_ERR);
742f06ca4afSHartmut Brandt 		}
743f06ca4afSHartmut Brandt 		/*
744f06ca4afSHartmut Brandt 		 * 3. Ensure the right syntax
745f06ca4afSHartmut Brandt 		 */
746f06ca4afSHartmut Brandt 		if (np->syntax != b->syntax) {
747f06ca4afSHartmut Brandt 			if (pdu->version == SNMP_V1) {
748f06ca4afSHartmut Brandt 				pdu->error_index = i + 1;
749f06ca4afSHartmut Brandt 				pdu->error_status = SNMP_ERR_BADVALUE; /* v2: wrongType */
750f06ca4afSHartmut Brandt 			} else {
751f06ca4afSHartmut Brandt 				pdu->error_index = i + 1;
752f06ca4afSHartmut Brandt 				pdu->error_status = SNMP_ERR_WRONG_TYPE;
753f06ca4afSHartmut Brandt 			}
754f06ca4afSHartmut Brandt 			snmp_pdu_free(resp);
755f06ca4afSHartmut Brandt 			return (SNMP_RET_ERR);
756f06ca4afSHartmut Brandt 		}
757f06ca4afSHartmut Brandt 		/*
758f06ca4afSHartmut Brandt 		 * 4. Copy binding
759f06ca4afSHartmut Brandt 		 */
760f06ca4afSHartmut Brandt 		if (snmp_value_copy(&resp->bindings[i], b)) {
761f06ca4afSHartmut Brandt 			pdu->error_index = i + 1;
762f06ca4afSHartmut Brandt 			pdu->error_status = SNMP_ERR_GENERR;
763f06ca4afSHartmut Brandt 			snmp_pdu_free(resp);
764f06ca4afSHartmut Brandt 			return (SNMP_RET_ERR);
765f06ca4afSHartmut Brandt 		}
766f06ca4afSHartmut Brandt 		asnerr = snmp_binding_encode(resp_b, &resp->bindings[i]);
767f06ca4afSHartmut Brandt 		if (asnerr == ASN_ERR_EOBUF) {
768f06ca4afSHartmut Brandt 			pdu->error_index = i + 1;
769f06ca4afSHartmut Brandt 			pdu->error_status = SNMP_ERR_TOOBIG;
770f06ca4afSHartmut Brandt 			snmp_pdu_free(resp);
771f06ca4afSHartmut Brandt 			return (SNMP_RET_ERR);
772f06ca4afSHartmut Brandt 		} else if (asnerr != ASN_ERR_OK) {
773f06ca4afSHartmut Brandt 			pdu->error_index = i + 1;
774f06ca4afSHartmut Brandt 			pdu->error_status = SNMP_ERR_GENERR;
775f06ca4afSHartmut Brandt 			snmp_pdu_free(resp);
776f06ca4afSHartmut Brandt 			return (SNMP_RET_ERR);
777f06ca4afSHartmut Brandt 		}
778f06ca4afSHartmut Brandt 		resp->nbindings++;
779f06ca4afSHartmut Brandt 	}
780f06ca4afSHartmut Brandt 
7818eecd77aSHartmut Brandt 	context.ctx.code = SNMP_RET_OK;
782f06ca4afSHartmut Brandt 
783f06ca4afSHartmut Brandt 	/*
784f06ca4afSHartmut Brandt 	 * 2. Call the SET method for each node. If a SET fails, rollback
785f06ca4afSHartmut Brandt 	 *    everything. Map error codes depending on the version.
786f06ca4afSHartmut Brandt 	 */
787f06ca4afSHartmut Brandt 	for (i = 0; i < pdu->nbindings; i++) {
788f06ca4afSHartmut Brandt 		b = &pdu->bindings[i];
789f06ca4afSHartmut Brandt 		np = context.node[i];
790f06ca4afSHartmut Brandt 
791f06ca4afSHartmut Brandt 		context.ctx.var_index = i + 1;
792f06ca4afSHartmut Brandt 		context.ctx.scratch = &context.scratch[i];
793f06ca4afSHartmut Brandt 
794f06ca4afSHartmut Brandt 		ret = (*np->op)(&context.ctx, b, np->oid.len, np->index,
795f06ca4afSHartmut Brandt 		    SNMP_OP_SET);
796f06ca4afSHartmut Brandt 
797f06ca4afSHartmut Brandt 		if (TR(SET))
798f06ca4afSHartmut Brandt 			snmp_debug("set: action %s returns %d", np->name, ret);
799f06ca4afSHartmut Brandt 
800f06ca4afSHartmut Brandt 		if (pdu->version == SNMP_V1) {
801f06ca4afSHartmut Brandt 			switch (ret) {
802f06ca4afSHartmut Brandt 			  case SNMP_ERR_NO_ACCESS:
803f06ca4afSHartmut Brandt 				ret = SNMP_ERR_NOSUCHNAME;
804f06ca4afSHartmut Brandt 				break;
805f06ca4afSHartmut Brandt 			  case SNMP_ERR_WRONG_TYPE:
806f06ca4afSHartmut Brandt 				/* should no happen */
807f06ca4afSHartmut Brandt 				ret = SNMP_ERR_BADVALUE;
808f06ca4afSHartmut Brandt 				break;
809f06ca4afSHartmut Brandt 			  case SNMP_ERR_WRONG_LENGTH:
810f06ca4afSHartmut Brandt 				ret = SNMP_ERR_BADVALUE;
811f06ca4afSHartmut Brandt 				break;
812f06ca4afSHartmut Brandt 			  case SNMP_ERR_WRONG_ENCODING:
813f06ca4afSHartmut Brandt 				/* should not happen */
814f06ca4afSHartmut Brandt 				ret = SNMP_ERR_BADVALUE;
815f06ca4afSHartmut Brandt 				break;
816f06ca4afSHartmut Brandt 			  case SNMP_ERR_WRONG_VALUE:
817f06ca4afSHartmut Brandt 				ret = SNMP_ERR_BADVALUE;
818f06ca4afSHartmut Brandt 				break;
819f06ca4afSHartmut Brandt 			  case SNMP_ERR_NO_CREATION:
820f06ca4afSHartmut Brandt 				ret = SNMP_ERR_NOSUCHNAME;
821f06ca4afSHartmut Brandt 				break;
822f06ca4afSHartmut Brandt 			  case SNMP_ERR_INCONS_VALUE:
823f06ca4afSHartmut Brandt 				ret = SNMP_ERR_BADVALUE;
824f06ca4afSHartmut Brandt 				break;
825f06ca4afSHartmut Brandt 			  case SNMP_ERR_RES_UNAVAIL:
826f06ca4afSHartmut Brandt 				ret = SNMP_ERR_GENERR;
827f06ca4afSHartmut Brandt 				break;
828f06ca4afSHartmut Brandt 			  case SNMP_ERR_COMMIT_FAILED:
829f06ca4afSHartmut Brandt 				ret = SNMP_ERR_GENERR;
830f06ca4afSHartmut Brandt 				break;
831f06ca4afSHartmut Brandt 			  case SNMP_ERR_UNDO_FAILED:
832f06ca4afSHartmut Brandt 				ret = SNMP_ERR_GENERR;
833f06ca4afSHartmut Brandt 				break;
834f06ca4afSHartmut Brandt 			  case SNMP_ERR_AUTH_ERR:
835f06ca4afSHartmut Brandt 				/* should not happen */
836f06ca4afSHartmut Brandt 				ret = SNMP_ERR_GENERR;
837f06ca4afSHartmut Brandt 				break;
838f06ca4afSHartmut Brandt 			  case SNMP_ERR_NOT_WRITEABLE:
839f06ca4afSHartmut Brandt 				ret = SNMP_ERR_NOSUCHNAME;
840f06ca4afSHartmut Brandt 				break;
841f06ca4afSHartmut Brandt 			  case SNMP_ERR_INCONS_NAME:
842f06ca4afSHartmut Brandt 				ret = SNMP_ERR_BADVALUE;
843f06ca4afSHartmut Brandt 				break;
844f06ca4afSHartmut Brandt 			}
845f06ca4afSHartmut Brandt 		}
846f06ca4afSHartmut Brandt 		if (ret != SNMP_ERR_NOERROR) {
847f06ca4afSHartmut Brandt 			pdu->error_index = i + 1;
848f06ca4afSHartmut Brandt 			pdu->error_status = ret;
849f06ca4afSHartmut Brandt 
850f06ca4afSHartmut Brandt 			rollback(&context, pdu, i);
851f06ca4afSHartmut Brandt 			snmp_pdu_free(resp);
852f06ca4afSHartmut Brandt 
8538eecd77aSHartmut Brandt 			context.ctx.code = SNMP_RET_ERR;
854f06ca4afSHartmut Brandt 
855f06ca4afSHartmut Brandt 			goto errout;
856f06ca4afSHartmut Brandt 		}
857f06ca4afSHartmut Brandt 	}
858f06ca4afSHartmut Brandt 
859f06ca4afSHartmut Brandt 	/*
860f06ca4afSHartmut Brandt 	 * 3. Call dependencies
861f06ca4afSHartmut Brandt 	 */
862f06ca4afSHartmut Brandt 	if (TR(SET))
863f06ca4afSHartmut Brandt 		snmp_debug("set: set operations ok");
864f06ca4afSHartmut Brandt 
865f06ca4afSHartmut Brandt 	if ((ret = snmp_dep_commit(&context.ctx)) != SNMP_ERR_NOERROR) {
866f06ca4afSHartmut Brandt 		pdu->error_status = ret;
867f06ca4afSHartmut Brandt 		pdu->error_index = context.ctx.var_index;
868f06ca4afSHartmut Brandt 
869f06ca4afSHartmut Brandt 		if ((ret = snmp_dep_rollback(&context.ctx)) != SNMP_ERR_NOERROR) {
870f06ca4afSHartmut Brandt 			if (pdu->version != SNMP_V1) {
871f06ca4afSHartmut Brandt 				pdu->error_status = SNMP_ERR_UNDO_FAILED;
872f06ca4afSHartmut Brandt 				pdu->error_index = 0;
873f06ca4afSHartmut Brandt 			}
874f06ca4afSHartmut Brandt 		}
875f06ca4afSHartmut Brandt 		rollback(&context, pdu, i);
876f06ca4afSHartmut Brandt 		snmp_pdu_free(resp);
877f06ca4afSHartmut Brandt 
8788eecd77aSHartmut Brandt 		context.ctx.code = SNMP_RET_ERR;
879f06ca4afSHartmut Brandt 
880f06ca4afSHartmut Brandt 		goto errout;
881f06ca4afSHartmut Brandt 	}
882f06ca4afSHartmut Brandt 
883f06ca4afSHartmut Brandt 	/*
884f06ca4afSHartmut Brandt 	 * 4. Commit and copy values from the original packet to the response.
885f06ca4afSHartmut Brandt 	 *    This is not the commit operation from RFC 1905 but rather an
886f06ca4afSHartmut Brandt 	 *    'FREE RESOURCES' operation. It shouldn't fail.
887f06ca4afSHartmut Brandt 	 */
888f06ca4afSHartmut Brandt 	if (TR(SET))
889f06ca4afSHartmut Brandt 		snmp_debug("set: commiting");
890f06ca4afSHartmut Brandt 
891f06ca4afSHartmut Brandt 	for (i = 0; i < pdu->nbindings; i++) {
892f06ca4afSHartmut Brandt 		b = &resp->bindings[i];
893f06ca4afSHartmut Brandt 		np = context.node[i];
894f06ca4afSHartmut Brandt 
895f06ca4afSHartmut Brandt 		context.ctx.var_index = i + 1;
896f06ca4afSHartmut Brandt 		context.ctx.scratch = &context.scratch[i];
897f06ca4afSHartmut Brandt 
898f06ca4afSHartmut Brandt 		ret = (*np->op)(&context.ctx, b, np->oid.len, np->index,
899f06ca4afSHartmut Brandt 		    SNMP_OP_COMMIT);
900f06ca4afSHartmut Brandt 
901f06ca4afSHartmut Brandt 		if (ret != SNMP_ERR_NOERROR)
902f06ca4afSHartmut Brandt 			snmp_error("set: commit failed (%d) on"
903f06ca4afSHartmut Brandt 			    " variable %s index %u", ret,
904f06ca4afSHartmut Brandt 			    asn_oid2str_r(&b->var, oidbuf), i);
905f06ca4afSHartmut Brandt 	}
906f06ca4afSHartmut Brandt 
907f06ca4afSHartmut Brandt 	if (snmp_fix_encoding(resp_b, resp) != SNMP_CODE_OK) {
908f06ca4afSHartmut Brandt 		snmp_error("set: fix_encoding failed");
909f06ca4afSHartmut Brandt 		snmp_pdu_free(resp);
9108eecd77aSHartmut Brandt 		context.ctx.code = SNMP_RET_IGN;
911f06ca4afSHartmut Brandt 	}
912f06ca4afSHartmut Brandt 
913f06ca4afSHartmut Brandt 	/*
914f06ca4afSHartmut Brandt 	 * Done
915f06ca4afSHartmut Brandt 	 */
916f06ca4afSHartmut Brandt   errout:
9178eecd77aSHartmut Brandt 	snmp_dep_finish(&context.ctx);
918f06ca4afSHartmut Brandt 
919f06ca4afSHartmut Brandt 	if (TR(SET))
9208eecd77aSHartmut Brandt 		snmp_debug("set: returning %d", context.ctx.code);
921f06ca4afSHartmut Brandt 
9228eecd77aSHartmut Brandt 	return (context.ctx.code);
923f06ca4afSHartmut Brandt }
924f06ca4afSHartmut Brandt /*
925f06ca4afSHartmut Brandt  * Lookup a dependency. If it doesn't exist, create one
926f06ca4afSHartmut Brandt  */
927f06ca4afSHartmut Brandt struct snmp_dependency *
snmp_dep_lookup(struct snmp_context * ctx,const struct asn_oid * obj,const struct asn_oid * idx,size_t len,snmp_depop_t func)928f06ca4afSHartmut Brandt snmp_dep_lookup(struct snmp_context *ctx, const struct asn_oid *obj,
929f06ca4afSHartmut Brandt     const struct asn_oid *idx, size_t len, snmp_depop_t func)
930f06ca4afSHartmut Brandt {
931f06ca4afSHartmut Brandt 	struct context *context;
932f06ca4afSHartmut Brandt 	struct depend *d;
933f06ca4afSHartmut Brandt 
934f06ca4afSHartmut Brandt 	context = (struct context *)(void *)
935f06ca4afSHartmut Brandt 	    ((char *)ctx - offsetof(struct context, ctx));
936f06ca4afSHartmut Brandt 	if (TR(DEPEND)) {
937f06ca4afSHartmut Brandt 		snmp_debug("depend: looking for %s", asn_oid2str(obj));
938f06ca4afSHartmut Brandt 		if (idx)
939f06ca4afSHartmut Brandt 			snmp_debug("depend: index is %s", asn_oid2str(idx));
940f06ca4afSHartmut Brandt 	}
941f06ca4afSHartmut Brandt 	TAILQ_FOREACH(d, &context->dlist, link)
942f06ca4afSHartmut Brandt 		if (asn_compare_oid(obj, &d->dep.obj) == 0 &&
943f06ca4afSHartmut Brandt 		    ((idx == NULL && d->dep.idx.len == 0) ||
944f06ca4afSHartmut Brandt 		     (idx != NULL && asn_compare_oid(idx, &d->dep.idx) == 0))) {
945f06ca4afSHartmut Brandt 			if(TR(DEPEND))
946f06ca4afSHartmut Brandt 				snmp_debug("depend: found");
947f06ca4afSHartmut Brandt 			return (&d->dep);
948f06ca4afSHartmut Brandt 		}
949f06ca4afSHartmut Brandt 
950f06ca4afSHartmut Brandt 	if(TR(DEPEND))
951f06ca4afSHartmut Brandt 		snmp_debug("depend: creating");
952f06ca4afSHartmut Brandt 
953f06ca4afSHartmut Brandt 	if ((d = malloc(offsetof(struct depend, dep) + len)) == NULL)
954f06ca4afSHartmut Brandt 		return (NULL);
955f06ca4afSHartmut Brandt 	memset(&d->dep, 0, len);
956f06ca4afSHartmut Brandt 
957f06ca4afSHartmut Brandt 	d->dep.obj = *obj;
958f06ca4afSHartmut Brandt 	if (idx == NULL)
959f06ca4afSHartmut Brandt 		d->dep.idx.len = 0;
960f06ca4afSHartmut Brandt 	else
961f06ca4afSHartmut Brandt 		d->dep.idx = *idx;
962f06ca4afSHartmut Brandt 	d->len = len;
963f06ca4afSHartmut Brandt 	d->func = func;
964f06ca4afSHartmut Brandt 
965f06ca4afSHartmut Brandt 	TAILQ_INSERT_TAIL(&context->dlist, d, link);
966f06ca4afSHartmut Brandt 
967f06ca4afSHartmut Brandt 	return (&d->dep);
968f06ca4afSHartmut Brandt }
969f06ca4afSHartmut Brandt 
970f06ca4afSHartmut Brandt /*
971f06ca4afSHartmut Brandt  * Make an error response from a PDU. We do this without decoding the
972f06ca4afSHartmut Brandt  * variable bindings. This means we can sent the junk back to a caller
973f06ca4afSHartmut Brandt  * that has sent us junk in the first place.
974f06ca4afSHartmut Brandt  */
975f06ca4afSHartmut Brandt enum snmp_ret
snmp_make_errresp(const struct snmp_pdu * pdu,struct asn_buf * pdu_b,struct asn_buf * resp_b)976f06ca4afSHartmut Brandt snmp_make_errresp(const struct snmp_pdu *pdu, struct asn_buf *pdu_b,
977f06ca4afSHartmut Brandt     struct asn_buf *resp_b)
978f06ca4afSHartmut Brandt {
97906983448SShteryana Shopova 	u_char type;
980f06ca4afSHartmut Brandt 	asn_len_t len;
981f06ca4afSHartmut Brandt 	struct snmp_pdu resp;
982f06ca4afSHartmut Brandt 	enum asn_err err;
983f06ca4afSHartmut Brandt 	enum snmp_code code;
984f06ca4afSHartmut Brandt 
98506983448SShteryana Shopova 	snmp_pdu_create_response(pdu, &resp);
98606983448SShteryana Shopova 
987135f7de5SShteryana Shopova 	if ((code = snmp_pdu_decode_header(pdu_b, &resp)) != SNMP_CODE_OK)
988f06ca4afSHartmut Brandt 		return (SNMP_RET_IGN);
989f06ca4afSHartmut Brandt 
99006983448SShteryana Shopova 	if (pdu->version == SNMP_V3) {
99106983448SShteryana Shopova 		if (resp.user.priv_proto != SNMP_PRIV_NOPRIV &&
99206983448SShteryana Shopova 		   (asn_get_header(pdu_b, &type, &resp.scoped_len) != ASN_ERR_OK
99306983448SShteryana Shopova 		   || type != ASN_TYPE_OCTETSTRING)) {
99406983448SShteryana Shopova 			snmp_error("cannot decode encrypted pdu");
995f06ca4afSHartmut Brandt 			return (SNMP_RET_IGN);
99606983448SShteryana Shopova 		}
99706983448SShteryana Shopova 
99806983448SShteryana Shopova 		if (asn_get_sequence(pdu_b, &len) != ASN_ERR_OK) {
99906983448SShteryana Shopova 			snmp_error("cannot decode scoped pdu header");
100006983448SShteryana Shopova 			return (SNMP_RET_IGN);
100106983448SShteryana Shopova 		}
100206983448SShteryana Shopova 
100306983448SShteryana Shopova 		len = SNMP_ENGINE_ID_SIZ;
100406983448SShteryana Shopova 		if (asn_get_octetstring(pdu_b, (u_char *)resp.context_engine,
100506983448SShteryana Shopova 		    &len) != ASN_ERR_OK) {
100606983448SShteryana Shopova 			snmp_error("cannot decode msg context engine");
100706983448SShteryana Shopova 			return (SNMP_RET_IGN);
100806983448SShteryana Shopova 		}
100906983448SShteryana Shopova 		resp.context_engine_len = len;
101006983448SShteryana Shopova 		len = SNMP_CONTEXT_NAME_SIZ;
101106983448SShteryana Shopova 		if (asn_get_octetstring(pdu_b, (u_char *)resp.context_name,
101206983448SShteryana Shopova 		    &len) != ASN_ERR_OK) {
101306983448SShteryana Shopova 			snmp_error("cannot decode msg context name");
101406983448SShteryana Shopova 			return (SNMP_RET_IGN);
101506983448SShteryana Shopova 		}
101606983448SShteryana Shopova 		resp.context_name[len] = '\0';
101706983448SShteryana Shopova 	}
101806983448SShteryana Shopova 
101906983448SShteryana Shopova 
102006983448SShteryana Shopova 	if (asn_get_header(pdu_b, &type, &len) != ASN_ERR_OK) {
102106983448SShteryana Shopova 		snmp_error("cannot get pdu header");
102206983448SShteryana Shopova 		return (SNMP_RET_IGN);
102306983448SShteryana Shopova 	}
102406983448SShteryana Shopova 
102506983448SShteryana Shopova 	if ((type & ~ASN_TYPE_MASK) !=
102606983448SShteryana Shopova 	    (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) {
102706983448SShteryana Shopova 		snmp_error("bad pdu header tag");
102806983448SShteryana Shopova 		return (SNMP_RET_IGN);
102906983448SShteryana Shopova 	}
1030f06ca4afSHartmut Brandt 
1031f06ca4afSHartmut Brandt 	err = snmp_parse_pdus_hdr(pdu_b, &resp, &len);
1032f06ca4afSHartmut Brandt 	if (ASN_ERR_STOPPED(err))
1033f06ca4afSHartmut Brandt 		return (SNMP_RET_IGN);
1034f06ca4afSHartmut Brandt 	if (pdu_b->asn_len < len)
1035f06ca4afSHartmut Brandt 		return (SNMP_RET_IGN);
1036f06ca4afSHartmut Brandt 	pdu_b->asn_len = len;
1037f06ca4afSHartmut Brandt 
1038f06ca4afSHartmut Brandt 	/* now we have the bindings left - construct new message */
1039f06ca4afSHartmut Brandt 	resp.error_status = pdu->error_status;
1040f06ca4afSHartmut Brandt 	resp.error_index = pdu->error_index;
1041f06ca4afSHartmut Brandt 	resp.type = SNMP_PDU_RESPONSE;
1042f06ca4afSHartmut Brandt 
1043f06ca4afSHartmut Brandt 	code = snmp_pdu_encode_header(resp_b, &resp);
1044f06ca4afSHartmut Brandt 	if (code != SNMP_CODE_OK)
1045f06ca4afSHartmut Brandt 		return (SNMP_RET_IGN);
1046f06ca4afSHartmut Brandt 
1047f06ca4afSHartmut Brandt 	if (pdu_b->asn_len > resp_b->asn_len)
1048f06ca4afSHartmut Brandt 		/* too short */
1049f06ca4afSHartmut Brandt 		return (SNMP_RET_IGN);
1050f06ca4afSHartmut Brandt 	(void)memcpy(resp_b->asn_ptr, pdu_b->asn_cptr, pdu_b->asn_len);
1051f06ca4afSHartmut Brandt 	resp_b->asn_len -= pdu_b->asn_len;
1052f06ca4afSHartmut Brandt 	resp_b->asn_ptr += pdu_b->asn_len;
1053f06ca4afSHartmut Brandt 
1054f06ca4afSHartmut Brandt 	code = snmp_fix_encoding(resp_b, &resp);
1055f06ca4afSHartmut Brandt 	if (code != SNMP_CODE_OK)
1056f06ca4afSHartmut Brandt 		return (SNMP_RET_IGN);
1057f06ca4afSHartmut Brandt 
1058f06ca4afSHartmut Brandt 	return (SNMP_RET_OK);
1059f06ca4afSHartmut Brandt }
1060f06ca4afSHartmut Brandt 
1061f06ca4afSHartmut Brandt static void
snmp_debug_func(const char * fmt,...)1062f06ca4afSHartmut Brandt snmp_debug_func(const char *fmt, ...)
1063f06ca4afSHartmut Brandt {
1064f06ca4afSHartmut Brandt 	va_list ap;
1065f06ca4afSHartmut Brandt 
1066f06ca4afSHartmut Brandt 	va_start(ap, fmt);
1067f06ca4afSHartmut Brandt 	vfprintf(stderr, fmt, ap);
1068f06ca4afSHartmut Brandt 	va_end(ap);
1069f06ca4afSHartmut Brandt 	fprintf(stderr, "\n");
1070f06ca4afSHartmut Brandt }
1071