xref: /freebsd/contrib/bsnmp/snmpd/export.c (revision 9336e0699bda8a301cd2bfa37106b6ec5e32012e)
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/un.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <syslog.h>
39 #include <stdarg.h>
40 
41 #include "snmpmod.h"
42 #include "snmpd.h"
43 #include "tree.h"
44 
45 /*
46  * Support functions
47  */
48 
49 /*
50  * This is user for SET of string variables. If 'req' is not -1 then
51  * the arguments is checked to be of that length. The old value is saved
52  * in scratch->ptr1 and the new value is allocated and copied.
53  * If there is an old values it must have been allocated by malloc.
54  */
55 int
56 string_save(struct snmp_value *value, struct snmp_context *ctx,
57     ssize_t req_size, u_char **valp)
58 {
59 	if (req_size != -1 && value->v.octetstring.len != (u_long)req_size)
60 		return (SNMP_ERR_BADVALUE);
61 
62 	ctx->scratch->ptr1 = *valp;
63 
64 	if ((*valp = malloc(value->v.octetstring.len + 1)) == NULL) {
65 		*valp = ctx->scratch->ptr1;
66 		return (SNMP_ERR_RES_UNAVAIL);
67 	}
68 
69 	memcpy(*valp, value->v.octetstring.octets, value->v.octetstring.len);
70 	(*valp)[value->v.octetstring.len] = '\0';
71 
72 	return (0);
73 }
74 
75 /*
76  * Commit a string. This is easy - free the old value.
77  */
78 void
79 string_commit(struct snmp_context *ctx)
80 {
81 	free(ctx->scratch->ptr1);
82 }
83 
84 /*
85  * Rollback a string - free new value and copy back old one.
86  */
87 void
88 string_rollback(struct snmp_context *ctx, u_char **valp)
89 {
90 	free(*valp);
91 	*valp = ctx->scratch->ptr1;
92 }
93 
94 /*
95  * ROLLBACK or COMMIT fails because instance has disappeared. Free string.
96  */
97 void
98 string_free(struct snmp_context *ctx)
99 {
100 	free(ctx->scratch->ptr1);
101 }
102 
103 /*
104  * Get a string value for a response packet
105  */
106 int
107 string_get(struct snmp_value *value, const u_char *ptr, ssize_t len)
108 {
109 	if (ptr == NULL) {
110 		value->v.octetstring.len = 0;
111 		value->v.octetstring.octets = NULL;
112 		return (SNMP_ERR_NOERROR);
113 	}
114 	if (len == -1)
115 		len = strlen(ptr);
116 	value->v.octetstring.len = (u_long)len;
117 	if ((value->v.octetstring.octets = malloc((size_t)len)) == NULL)
118 		return (SNMP_ERR_RES_UNAVAIL);
119 	memcpy(value->v.octetstring.octets, ptr, (size_t)len);
120 	return (SNMP_ERR_NOERROR);
121 }
122 
123 /*
124  * Get a string value for a response packet but cut it if it is too long.
125  */
126 int
127 string_get_max(struct snmp_value *value, const u_char *ptr, ssize_t len,
128     size_t maxlen)
129 {
130 
131 	if (ptr == NULL) {
132 		value->v.octetstring.len = 0;
133 		value->v.octetstring.octets = NULL;
134 		return (SNMP_ERR_NOERROR);
135 	}
136 	if (len == -1)
137 		len = strlen(ptr);
138 	if ((size_t)len > maxlen)
139 		len = maxlen;
140 	value->v.octetstring.len = (u_long)len;
141 	if ((value->v.octetstring.octets = malloc((size_t)len)) == NULL)
142 		return (SNMP_ERR_RES_UNAVAIL);
143 	memcpy(value->v.octetstring.octets, ptr, (size_t)len);
144 	return (SNMP_ERR_NOERROR);
145 }
146 
147 /*
148  * Support for IPADDRESS
149  *
150  * Save the old IP address in scratch->int1 and set the new one.
151  */
152 int
153 ip_save(struct snmp_value *value, struct snmp_context *ctx, u_char *valp)
154 {
155 	ctx->scratch->int1 = (valp[0] << 24) | (valp[1] << 16) | (valp[2] << 8)
156 	    | valp[3];
157 
158 	valp[0] = value->v.ipaddress[0];
159 	valp[1] = value->v.ipaddress[1];
160 	valp[2] = value->v.ipaddress[2];
161 	valp[3] = value->v.ipaddress[3];
162 
163 	return (0);
164 }
165 
166 /*
167  * Rollback the address by copying back the old one
168  */
169 void
170 ip_rollback(struct snmp_context *ctx, u_char *valp)
171 {
172 	valp[0] = ctx->scratch->int1 >> 24;
173 	valp[1] = ctx->scratch->int1 >> 16;
174 	valp[2] = ctx->scratch->int1 >> 8;
175 	valp[3] = ctx->scratch->int1;
176 }
177 
178 /*
179  * Nothing to do for commit
180  */
181 void
182 ip_commit(struct snmp_context *ctx __unused)
183 {
184 }
185 
186 /*
187  * Retrieve an IP address
188  */
189 int
190 ip_get(struct snmp_value *value, u_char *valp)
191 {
192 	value->v.ipaddress[0] = valp[0];
193 	value->v.ipaddress[1] = valp[1];
194 	value->v.ipaddress[2] = valp[2];
195 	value->v.ipaddress[3] = valp[3];
196 	return (SNMP_ERR_NOERROR);
197 }
198 
199 /*
200  * Object ID support
201  *
202  * Save the old value in a fresh allocated oid pointed to by scratch->ptr1.
203  */
204 int
205 oid_save(struct snmp_value *value, struct snmp_context *ctx,
206     struct asn_oid *oid)
207 {
208 	if ((ctx->scratch->ptr1 = malloc(sizeof(struct asn_oid))) == NULL)
209 		return (SNMP_ERR_RES_UNAVAIL);
210 	*(struct asn_oid *)ctx->scratch->ptr1 = *oid;
211 	*oid = value->v.oid;
212 
213 	return (0);
214 }
215 
216 void
217 oid_rollback(struct snmp_context *ctx, struct asn_oid *oid)
218 {
219 	*oid = *(struct asn_oid *)ctx->scratch->ptr1;
220 	free(ctx->scratch->ptr1);
221 }
222 
223 void
224 oid_commit(struct snmp_context *ctx)
225 {
226 	free(ctx->scratch->ptr1);
227 }
228 
229 int
230 oid_get(struct snmp_value *value, const struct asn_oid *oid)
231 {
232 	value->v.oid = *oid;
233 	return (SNMP_ERR_NOERROR);
234 }
235 
236 /*
237  * Decode an index
238  */
239 int
240 index_decode(const struct asn_oid *oid, u_int sub, u_int code, ...)
241 {
242 	va_list ap;
243 	u_int index_count;
244 	void *octs[10];
245 	u_int nocts;
246 	u_int idx;
247 
248 	va_start(ap, code);
249 	index_count = SNMP_INDEX_COUNT(code);
250 	nocts = 0;
251 
252 	for (idx = 0; idx < index_count; idx++) {
253 		switch (SNMP_INDEX(code, idx)) {
254 
255 		  case SNMP_SYNTAX_NULL:
256 			break;
257 
258 		  case SNMP_SYNTAX_INTEGER:
259 			if (sub == oid->len)
260 				goto err;
261 			*va_arg(ap, int32_t *) = oid->subs[sub++];
262 			break;
263 
264 		  case SNMP_SYNTAX_COUNTER64:
265 			if (sub == oid->len)
266 				goto err;
267 			*va_arg(ap, u_int64_t *) = oid->subs[sub++];
268 			break;
269 
270 		  case SNMP_SYNTAX_OCTETSTRING:
271 		    {
272 			u_char **cval;
273 			size_t *sval;
274 			u_int i;
275 
276 			/* only variable size supported */
277 			if (sub == oid->len)
278 				goto err;
279 			cval = va_arg(ap, u_char **);
280 			sval = va_arg(ap, size_t *);
281 			*sval = oid->subs[sub++];
282 			if (sub + *sval > oid->len)
283 				goto err;
284 			if ((*cval = malloc(*sval)) == NULL) {
285 				syslog(LOG_ERR, "%s: %m", __func__);
286 				goto err;
287 			}
288 			octs[nocts++] = *cval;
289 			for (i = 0; i < *sval; i++) {
290 				if (oid->subs[sub] > 0xff)
291 					goto err;
292 				(*cval)[i] = oid->subs[sub++];
293 			}
294 			break;
295 		    }
296 
297 		  case SNMP_SYNTAX_OID:
298 		    {
299 			struct asn_oid *aval;
300 			u_int i;
301 
302 			if (sub == oid->len)
303 				goto err;
304 			aval = va_arg(ap, struct asn_oid *);
305 			aval->len = oid->subs[sub++];
306 			if (aval->len > ASN_MAXOIDLEN)
307 				goto err;
308 			for (i = 0; i < aval->len; i++)
309 				aval->subs[i] = oid->subs[sub++];
310 			break;
311 		    }
312 
313 		  case SNMP_SYNTAX_IPADDRESS:
314 		    {
315 			u_int8_t *pval;
316 			u_int i;
317 
318 			if (sub + 4 > oid->len)
319 				goto err;
320 			pval = va_arg(ap, u_int8_t *);
321 			for (i = 0; i < 4; i++) {
322 				if (oid->subs[sub] > 0xff)
323 					goto err;
324 				pval[i] = oid->subs[sub++];
325 			}
326 			break;
327 		    }
328 
329 		  case SNMP_SYNTAX_COUNTER:
330 		  case SNMP_SYNTAX_GAUGE:
331 		  case SNMP_SYNTAX_TIMETICKS:
332 			if (sub == oid->len)
333 				goto err;
334 			if (oid->subs[sub] > 0xffffffff)
335 				goto err;
336 			*va_arg(ap, u_int32_t *) = oid->subs[sub++];
337 			break;
338 		}
339 	}
340 
341 	va_end(ap);
342 	return (0);
343 
344   err:
345 	va_end(ap);
346 	while(nocts > 0)
347 		free(octs[--nocts]);
348 	return (-1);
349 }
350 
351 /*
352  * Compare the index part of an OID and an index.
353  */
354 int
355 index_compare_off(const struct asn_oid *oid, u_int sub,
356     const struct asn_oid *idx, u_int off)
357 {
358 	u_int i;
359 
360 	for (i = off; i < idx->len && i < oid->len - sub; i++) {
361 		if (oid->subs[sub + i] < idx->subs[i])
362 			return (-1);
363 		if (oid->subs[sub + i] > idx->subs[i])
364 			return (+1);
365 	}
366 	if (oid->len - sub < idx->len)
367 		return (-1);
368 	if (oid->len - sub > idx->len)
369 		return (+1);
370 
371 	return (0);
372 }
373 
374 int
375 index_compare(const struct asn_oid *oid, u_int sub, const struct asn_oid *idx)
376 {
377 	return (index_compare_off(oid, sub, idx, 0));
378 }
379 
380 /*
381  * Append an index to an oid
382  */
383 void
384 index_append_off(struct asn_oid *var, u_int sub, const struct asn_oid *idx,
385     u_int off)
386 {
387 	u_int i;
388 
389 	var->len = sub + idx->len;
390 	for (i = off; i < idx->len; i++)
391 		var->subs[sub + i] = idx->subs[i];
392 }
393 void
394 index_append(struct asn_oid *var, u_int sub, const struct asn_oid *idx)
395 {
396 	index_append_off(var, sub, idx, 0);
397 }
398 
399