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