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
string_save(struct snmp_value * value,struct snmp_context * ctx,ssize_t req_size,u_char ** valp)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
string_commit(struct snmp_context * ctx)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
string_rollback(struct snmp_context * ctx,u_char ** valp)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
string_free(struct snmp_context * ctx)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
string_get(struct snmp_value * value,const u_char * ptr,ssize_t len)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 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 */
129 int
string_get_max(struct snmp_value * value,const u_char * ptr,ssize_t len,size_t maxlen)130 string_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 */
157 int
ip_save(struct snmp_value * value,struct snmp_context * ctx,u_char * valp)158 ip_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 */
174 void
ip_rollback(struct snmp_context * ctx,u_char * valp)175 ip_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 */
186 void
ip_commit(struct snmp_context * ctx __unused)187 ip_commit(struct snmp_context *ctx __unused)
188 {
189 }
190
191 /*
192 * Retrieve an IP address
193 */
194 int
ip_get(struct snmp_value * value,u_char * valp)195 ip_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 */
210 int
oid_save(struct snmp_value * value,struct snmp_context * ctx,struct asn_oid * oid)211 oid_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
222 void
oid_rollback(struct snmp_context * ctx,struct asn_oid * oid)223 oid_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
229 void
oid_commit(struct snmp_context * ctx)230 oid_commit(struct snmp_context *ctx)
231 {
232 free(ctx->scratch->ptr1);
233 }
234
235 int
oid_get(struct snmp_value * value,const struct asn_oid * oid)236 oid_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 */
245 int
index_decode(const struct asn_oid * oid,u_int sub,u_int code,...)246 index_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 */
360 int
index_compare_off(const struct asn_oid * oid,u_int sub,const struct asn_oid * idx,u_int off)361 index_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
380 int
index_compare(const struct asn_oid * oid,u_int sub,const struct asn_oid * idx)381 index_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 */
389 void
index_append_off(struct asn_oid * var,u_int sub,const struct asn_oid * idx,u_int off)390 index_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 }
399 void
index_append(struct asn_oid * var,u_int sub,const struct asn_oid * idx)400 index_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