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