xref: /freebsd/contrib/bsnmp/snmpd/export.c (revision b3972edb64a125a49fb34991b8e37d23e944e452)
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  */
56 int
57 string_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  */
79 void
80 string_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  */
88 void
89 string_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  */
98 void
99 string_free(struct snmp_context *ctx)
100 {
101 	free(ctx->scratch->ptr1);
102 }
103 
104 /*
105  * Get a string value for a response packet
106  */
107 int
108 string_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 	value->v.octetstring.len = (u_long)len;
118 	if ((value->v.octetstring.octets = malloc((size_t)len)) == NULL)
119 		return (SNMP_ERR_RES_UNAVAIL);
120 	memcpy(value->v.octetstring.octets, ptr, (size_t)len);
121 	return (SNMP_ERR_NOERROR);
122 }
123 
124 /*
125  * Get a string value for a response packet but cut it if it is too long.
126  */
127 int
128 string_get_max(struct snmp_value *value, const u_char *ptr, ssize_t len,
129     size_t maxlen)
130 {
131 
132 	if (ptr == NULL) {
133 		value->v.octetstring.len = 0;
134 		value->v.octetstring.octets = NULL;
135 		return (SNMP_ERR_NOERROR);
136 	}
137 	if (len == -1)
138 		len = strlen(ptr);
139 	if ((size_t)len > maxlen)
140 		len = maxlen;
141 	value->v.octetstring.len = (u_long)len;
142 	if ((value->v.octetstring.octets = malloc((size_t)len)) == NULL)
143 		return (SNMP_ERR_RES_UNAVAIL);
144 	memcpy(value->v.octetstring.octets, ptr, (size_t)len);
145 	return (SNMP_ERR_NOERROR);
146 }
147 
148 /*
149  * Support for IPADDRESS
150  *
151  * Save the old IP address in scratch->int1 and set the new one.
152  */
153 int
154 ip_save(struct snmp_value *value, struct snmp_context *ctx, u_char *valp)
155 {
156 	ctx->scratch->int1 = (valp[0] << 24) | (valp[1] << 16) | (valp[2] << 8)
157 	    | valp[3];
158 
159 	valp[0] = value->v.ipaddress[0];
160 	valp[1] = value->v.ipaddress[1];
161 	valp[2] = value->v.ipaddress[2];
162 	valp[3] = value->v.ipaddress[3];
163 
164 	return (0);
165 }
166 
167 /*
168  * Rollback the address by copying back the old one
169  */
170 void
171 ip_rollback(struct snmp_context *ctx, u_char *valp)
172 {
173 	valp[0] = ctx->scratch->int1 >> 24;
174 	valp[1] = ctx->scratch->int1 >> 16;
175 	valp[2] = ctx->scratch->int1 >> 8;
176 	valp[3] = ctx->scratch->int1;
177 }
178 
179 /*
180  * Nothing to do for commit
181  */
182 void
183 ip_commit(struct snmp_context *ctx __unused)
184 {
185 }
186 
187 /*
188  * Retrieve an IP address
189  */
190 int
191 ip_get(struct snmp_value *value, u_char *valp)
192 {
193 	value->v.ipaddress[0] = valp[0];
194 	value->v.ipaddress[1] = valp[1];
195 	value->v.ipaddress[2] = valp[2];
196 	value->v.ipaddress[3] = valp[3];
197 
198 	return (SNMP_ERR_NOERROR);
199 }
200 
201 /*
202  * Object ID support
203  *
204  * Save the old value in a fresh allocated oid pointed to by scratch->ptr1.
205  */
206 int
207 oid_save(struct snmp_value *value, struct snmp_context *ctx,
208     struct asn_oid *oid)
209 {
210 	if ((ctx->scratch->ptr1 = malloc(sizeof(struct asn_oid))) == NULL)
211 		return (SNMP_ERR_RES_UNAVAIL);
212 	*(struct asn_oid *)ctx->scratch->ptr1 = *oid;
213 	*oid = value->v.oid;
214 
215 	return (0);
216 }
217 
218 void
219 oid_rollback(struct snmp_context *ctx, struct asn_oid *oid)
220 {
221 	*oid = *(struct asn_oid *)ctx->scratch->ptr1;
222 	free(ctx->scratch->ptr1);
223 }
224 
225 void
226 oid_commit(struct snmp_context *ctx)
227 {
228 	free(ctx->scratch->ptr1);
229 }
230 
231 int
232 oid_get(struct snmp_value *value, const struct asn_oid *oid)
233 {
234 	value->v.oid = *oid;
235 	return (SNMP_ERR_NOERROR);
236 }
237 
238 /*
239  * Decode an index
240  */
241 int
242 index_decode(const struct asn_oid *oid, u_int sub, u_int code, ...)
243 {
244 	va_list ap;
245 	u_int index_count;
246 	void *octs[10];
247 	u_int nocts;
248 	u_int idx;
249 
250 	va_start(ap, code);
251 	index_count = SNMP_INDEX_COUNT(code);
252 	nocts = 0;
253 
254 	for (idx = 0; idx < index_count; idx++) {
255 		switch (SNMP_INDEX(code, idx)) {
256 
257 		  case SNMP_SYNTAX_NULL:
258 			break;
259 
260 		  case SNMP_SYNTAX_INTEGER:
261 			if (sub == oid->len)
262 				goto err;
263 			*va_arg(ap, int32_t *) = oid->subs[sub++];
264 			break;
265 
266 		  case SNMP_SYNTAX_COUNTER64:
267 			if (sub == oid->len)
268 				goto err;
269 			*va_arg(ap, u_int64_t *) = oid->subs[sub++];
270 			break;
271 
272 		  case SNMP_SYNTAX_OCTETSTRING:
273 		    {
274 			u_char **cval;
275 			size_t *sval;
276 			u_int i;
277 
278 			/* only variable size supported */
279 			if (sub == oid->len)
280 				goto err;
281 			cval = va_arg(ap, u_char **);
282 			sval = va_arg(ap, size_t *);
283 			*sval = oid->subs[sub++];
284 			if (sub + *sval > oid->len)
285 				goto err;
286 			if ((*cval = malloc(*sval)) == NULL) {
287 				syslog(LOG_ERR, "%s: %m", __func__);
288 				goto err;
289 			}
290 			octs[nocts++] = *cval;
291 			for (i = 0; i < *sval; i++) {
292 				if (oid->subs[sub] > 0xff)
293 					goto err;
294 				(*cval)[i] = oid->subs[sub++];
295 			}
296 			break;
297 		    }
298 
299 		  case SNMP_SYNTAX_OID:
300 		    {
301 			struct asn_oid *aval;
302 			u_int i;
303 
304 			if (sub == oid->len)
305 				goto err;
306 			aval = va_arg(ap, struct asn_oid *);
307 			aval->len = oid->subs[sub++];
308 			if (aval->len > ASN_MAXOIDLEN)
309 				goto err;
310 			for (i = 0; i < aval->len; i++)
311 				aval->subs[i] = oid->subs[sub++];
312 			break;
313 		    }
314 
315 		  case SNMP_SYNTAX_IPADDRESS:
316 		    {
317 			u_int8_t *pval;
318 			u_int i;
319 
320 			if (sub + 4 > oid->len)
321 				goto err;
322 			pval = va_arg(ap, u_int8_t *);
323 			for (i = 0; i < 4; i++) {
324 				if (oid->subs[sub] > 0xff)
325 					goto err;
326 				pval[i] = oid->subs[sub++];
327 			}
328 			break;
329 		    }
330 
331 		  case SNMP_SYNTAX_COUNTER:
332 		  case SNMP_SYNTAX_GAUGE:
333 		  case SNMP_SYNTAX_TIMETICKS:
334 			if (sub == oid->len)
335 				goto err;
336 			if (oid->subs[sub] > 0xffffffff)
337 				goto err;
338 			*va_arg(ap, u_int32_t *) = oid->subs[sub++];
339 			break;
340 		}
341 	}
342 
343 	va_end(ap);
344 	return (0);
345 
346   err:
347 	va_end(ap);
348 	while(nocts > 0)
349 		free(octs[--nocts]);
350 	return (-1);
351 }
352 
353 /*
354  * Compare the index part of an OID and an index.
355  */
356 int
357 index_compare_off(const struct asn_oid *oid, u_int sub,
358     const struct asn_oid *idx, u_int off)
359 {
360 	u_int i;
361 
362 	for (i = off; i < idx->len && i < oid->len - sub; i++) {
363 		if (oid->subs[sub + i] < idx->subs[i])
364 			return (-1);
365 		if (oid->subs[sub + i] > idx->subs[i])
366 			return (+1);
367 	}
368 	if (oid->len - sub < idx->len)
369 		return (-1);
370 	if (oid->len - sub > idx->len)
371 		return (+1);
372 
373 	return (0);
374 }
375 
376 int
377 index_compare(const struct asn_oid *oid, u_int sub, const struct asn_oid *idx)
378 {
379 	return (index_compare_off(oid, sub, idx, 0));
380 }
381 
382 /*
383  * Append an index to an oid
384  */
385 void
386 index_append_off(struct asn_oid *var, u_int sub, const struct asn_oid *idx,
387     u_int off)
388 {
389 	u_int i;
390 
391 	var->len = sub + idx->len;
392 	for (i = off; i < idx->len; i++)
393 		var->subs[sub + i] = idx->subs[i];
394 }
395 void
396 index_append(struct asn_oid *var, u_int sub, const struct asn_oid *idx)
397 {
398 	index_append_off(var, sub, idx, 0);
399 }
400 
401