export.c revision 311597
1/*
2 * Copyright (c) 2001-2003
3 *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4 *	All rights reserved.
5 *
6 * Author: Harti Brandt <harti@freebsd.org>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $Begemot: bsnmp/snmpd/export.c,v 1.8 2006/02/14 09:04:20 brandt_h Exp $
30 *
31 * Support functions for modules.
32 */
33#include <sys/types.h>
34#include <sys/queue.h>
35#include <sys/un.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <syslog.h>
40#include <stdarg.h>
41
42#include "snmpmod.h"
43#include "snmpd.h"
44#include "tree.h"
45
46/*
47 * Support functions
48 */
49
50/*
51 * This is user for SET of string variables. If 'req' is not -1 then
52 * the arguments is checked to be of that length. The old value is saved
53 * in scratch->ptr1 and the new value is allocated and copied.
54 * If there is an old values it must have been allocated by malloc.
55 */
56int
57string_save(struct snmp_value *value, struct snmp_context *ctx,
58    ssize_t req_size, u_char **valp)
59{
60	if (req_size != -1 && value->v.octetstring.len != (u_long)req_size)
61		return (SNMP_ERR_BADVALUE);
62
63	ctx->scratch->ptr1 = *valp;
64
65	if ((*valp = malloc(value->v.octetstring.len + 1)) == NULL) {
66		*valp = ctx->scratch->ptr1;
67		return (SNMP_ERR_RES_UNAVAIL);
68	}
69
70	memcpy(*valp, value->v.octetstring.octets, value->v.octetstring.len);
71	(*valp)[value->v.octetstring.len] = '\0';
72
73	return (0);
74}
75
76/*
77 * Commit a string. This is easy - free the old value.
78 */
79void
80string_commit(struct snmp_context *ctx)
81{
82	free(ctx->scratch->ptr1);
83}
84
85/*
86 * Rollback a string - free new value and copy back old one.
87 */
88void
89string_rollback(struct snmp_context *ctx, u_char **valp)
90{
91	free(*valp);
92	*valp = ctx->scratch->ptr1;
93}
94
95/*
96 * ROLLBACK or COMMIT fails because instance has disappeared. Free string.
97 */
98void
99string_free(struct snmp_context *ctx)
100{
101	free(ctx->scratch->ptr1);
102}
103
104/*
105 * Get a string value for a response packet
106 */
107int
108string_get(struct snmp_value *value, const u_char *ptr, ssize_t len)
109{
110	if (ptr == NULL) {
111		value->v.octetstring.len = 0;
112		value->v.octetstring.octets = NULL;
113		return (SNMP_ERR_NOERROR);
114	}
115	if (len == -1)
116		len = strlen(ptr);
117	if ((value->v.octetstring.octets = malloc((size_t)len)) == NULL) {
118		value->v.octetstring.len = 0;
119		return (SNMP_ERR_RES_UNAVAIL);
120	}
121	value->v.octetstring.len = (u_long)len;
122	memcpy(value->v.octetstring.octets, ptr, (size_t)len);
123	return (SNMP_ERR_NOERROR);
124}
125
126/*
127 * Get a string value for a response packet but cut it if it is too long.
128 */
129int
130string_get_max(struct snmp_value *value, const u_char *ptr, ssize_t len,
131    size_t maxlen)
132{
133
134	if (ptr == NULL) {
135		value->v.octetstring.len = 0;
136		value->v.octetstring.octets = NULL;
137		return (SNMP_ERR_NOERROR);
138	}
139	if (len == -1)
140		len = strlen(ptr);
141	if ((size_t)len > maxlen)
142		len = maxlen;
143	if ((value->v.octetstring.octets = malloc((size_t)len)) == NULL) {
144		value->v.octetstring.len = 0;
145		return (SNMP_ERR_RES_UNAVAIL);
146	}
147	value->v.octetstring.len = (u_long)len;
148	memcpy(value->v.octetstring.octets, ptr, (size_t)len);
149	return (SNMP_ERR_NOERROR);
150}
151
152/*
153 * Support for IPADDRESS
154 *
155 * Save the old IP address in scratch->int1 and set the new one.
156 */
157int
158ip_save(struct snmp_value *value, struct snmp_context *ctx, u_char *valp)
159{
160	ctx->scratch->int1 = (valp[0] << 24) | (valp[1] << 16) | (valp[2] << 8)
161	    | valp[3];
162
163	valp[0] = value->v.ipaddress[0];
164	valp[1] = value->v.ipaddress[1];
165	valp[2] = value->v.ipaddress[2];
166	valp[3] = value->v.ipaddress[3];
167
168	return (0);
169}
170
171/*
172 * Rollback the address by copying back the old one
173 */
174void
175ip_rollback(struct snmp_context *ctx, u_char *valp)
176{
177	valp[0] = ctx->scratch->int1 >> 24;
178	valp[1] = ctx->scratch->int1 >> 16;
179	valp[2] = ctx->scratch->int1 >> 8;
180	valp[3] = ctx->scratch->int1;
181}
182
183/*
184 * Nothing to do for commit
185 */
186void
187ip_commit(struct snmp_context *ctx __unused)
188{
189}
190
191/*
192 * Retrieve an IP address
193 */
194int
195ip_get(struct snmp_value *value, u_char *valp)
196{
197	value->v.ipaddress[0] = valp[0];
198	value->v.ipaddress[1] = valp[1];
199	value->v.ipaddress[2] = valp[2];
200	value->v.ipaddress[3] = valp[3];
201
202	return (SNMP_ERR_NOERROR);
203}
204
205/*
206 * Object ID support
207 *
208 * Save the old value in a fresh allocated oid pointed to by scratch->ptr1.
209 */
210int
211oid_save(struct snmp_value *value, struct snmp_context *ctx,
212    struct asn_oid *oid)
213{
214	if ((ctx->scratch->ptr1 = malloc(sizeof(struct asn_oid))) == NULL)
215		return (SNMP_ERR_RES_UNAVAIL);
216	*(struct asn_oid *)ctx->scratch->ptr1 = *oid;
217	*oid = value->v.oid;
218
219	return (0);
220}
221
222void
223oid_rollback(struct snmp_context *ctx, struct asn_oid *oid)
224{
225	*oid = *(struct asn_oid *)ctx->scratch->ptr1;
226	free(ctx->scratch->ptr1);
227}
228
229void
230oid_commit(struct snmp_context *ctx)
231{
232	free(ctx->scratch->ptr1);
233}
234
235int
236oid_get(struct snmp_value *value, const struct asn_oid *oid)
237{
238	value->v.oid = *oid;
239	return (SNMP_ERR_NOERROR);
240}
241
242/*
243 * Decode an index
244 */
245int
246index_decode(const struct asn_oid *oid, u_int sub, u_int code, ...)
247{
248	va_list ap;
249	u_int index_count;
250	void *octs[10];
251	u_int nocts;
252	u_int idx;
253
254	va_start(ap, code);
255	index_count = SNMP_INDEX_COUNT(code);
256	nocts = 0;
257
258	for (idx = 0; idx < index_count; idx++) {
259		switch (SNMP_INDEX(code, idx)) {
260
261		  case SNMP_SYNTAX_NULL:
262			break;
263
264		  case SNMP_SYNTAX_INTEGER:
265			if (sub == oid->len)
266				goto err;
267			*va_arg(ap, int32_t *) = oid->subs[sub++];
268			break;
269
270		  case SNMP_SYNTAX_COUNTER64:
271			if (sub == oid->len)
272				goto err;
273			*va_arg(ap, u_int64_t *) = oid->subs[sub++];
274			break;
275
276		  case SNMP_SYNTAX_OCTETSTRING:
277		    {
278			u_char **cval;
279			size_t *sval;
280			u_int i;
281
282			/* only variable size supported */
283			if (sub == oid->len)
284				goto err;
285			cval = va_arg(ap, u_char **);
286			sval = va_arg(ap, size_t *);
287			*sval = oid->subs[sub++];
288			if (sub + *sval > oid->len)
289				goto err;
290			if ((*cval = malloc(*sval)) == NULL) {
291				syslog(LOG_ERR, "%s: %m", __func__);
292				goto err;
293			}
294			octs[nocts++] = *cval;
295			for (i = 0; i < *sval; i++) {
296				if (oid->subs[sub] > 0xff)
297					goto err;
298				(*cval)[i] = oid->subs[sub++];
299			}
300			break;
301		    }
302
303		  case SNMP_SYNTAX_OID:
304		    {
305			struct asn_oid *aval;
306			u_int i;
307
308			if (sub == oid->len)
309				goto err;
310			aval = va_arg(ap, struct asn_oid *);
311			aval->len = oid->subs[sub++];
312			if (aval->len > ASN_MAXOIDLEN)
313				goto err;
314			for (i = 0; i < aval->len; i++)
315				aval->subs[i] = oid->subs[sub++];
316			break;
317		    }
318
319		  case SNMP_SYNTAX_IPADDRESS:
320		    {
321			u_int8_t *pval;
322			u_int i;
323
324			if (sub + 4 > oid->len)
325				goto err;
326			pval = va_arg(ap, u_int8_t *);
327			for (i = 0; i < 4; i++) {
328				if (oid->subs[sub] > 0xff)
329					goto err;
330				pval[i] = oid->subs[sub++];
331			}
332			break;
333		    }
334
335		  case SNMP_SYNTAX_COUNTER:
336		  case SNMP_SYNTAX_GAUGE:
337		  case SNMP_SYNTAX_TIMETICKS:
338			if (sub == oid->len)
339				goto err;
340			if (oid->subs[sub] > 0xffffffff)
341				goto err;
342			*va_arg(ap, u_int32_t *) = oid->subs[sub++];
343			break;
344		}
345	}
346
347	va_end(ap);
348	return (0);
349
350  err:
351	va_end(ap);
352	while(nocts > 0)
353		free(octs[--nocts]);
354	return (-1);
355}
356
357/*
358 * Compare the index part of an OID and an index.
359 */
360int
361index_compare_off(const struct asn_oid *oid, u_int sub,
362    const struct asn_oid *idx, u_int off)
363{
364	u_int i;
365
366	for (i = off; i < idx->len && i < oid->len - sub; i++) {
367		if (oid->subs[sub + i] < idx->subs[i])
368			return (-1);
369		if (oid->subs[sub + i] > idx->subs[i])
370			return (+1);
371	}
372	if (oid->len - sub < idx->len)
373		return (-1);
374	if (oid->len - sub > idx->len)
375		return (+1);
376
377	return (0);
378}
379
380int
381index_compare(const struct asn_oid *oid, u_int sub, const struct asn_oid *idx)
382{
383	return (index_compare_off(oid, sub, idx, 0));
384}
385
386/*
387 * Append an index to an oid
388 */
389void
390index_append_off(struct asn_oid *var, u_int sub, const struct asn_oid *idx,
391    u_int off)
392{
393	u_int i;
394
395	var->len = sub + idx->len;
396	for (i = off; i < idx->len; i++)
397		var->subs[sub + i] = idx->subs[i];
398}
399void
400index_append(struct asn_oid *var, u_int sub, const struct asn_oid *idx)
401{
402	index_append_off(var, sub, idx, 0);
403}
404
405