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