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/un.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <syslog.h> 39 #include <stdarg.h> 40 41 #include "snmpmod.h" 42 #include "snmpd.h" 43 #include "tree.h" 44 45 /* 46 * Support functions 47 */ 48 49 /* 50 * This is user for SET of string variables. If 'req' is not -1 then 51 * the arguments is checked to be of that length. The old value is saved 52 * in scratch->ptr1 and the new value is allocated and copied. 53 * If there is an old values it must have been allocated by malloc. 54 */ 55 int 56 string_save(struct snmp_value *value, struct snmp_context *ctx, 57 ssize_t req_size, u_char **valp) 58 { 59 if (req_size != -1 && value->v.octetstring.len != (u_long)req_size) 60 return (SNMP_ERR_BADVALUE); 61 62 ctx->scratch->ptr1 = *valp; 63 64 if ((*valp = malloc(value->v.octetstring.len + 1)) == NULL) { 65 *valp = ctx->scratch->ptr1; 66 return (SNMP_ERR_RES_UNAVAIL); 67 } 68 69 memcpy(*valp, value->v.octetstring.octets, value->v.octetstring.len); 70 (*valp)[value->v.octetstring.len] = '\0'; 71 72 return (0); 73 } 74 75 /* 76 * Commit a string. This is easy - free the old value. 77 */ 78 void 79 string_commit(struct snmp_context *ctx) 80 { 81 free(ctx->scratch->ptr1); 82 } 83 84 /* 85 * Rollback a string - free new value and copy back old one. 86 */ 87 void 88 string_rollback(struct snmp_context *ctx, u_char **valp) 89 { 90 free(*valp); 91 *valp = ctx->scratch->ptr1; 92 } 93 94 /* 95 * ROLLBACK or COMMIT fails because instance has disappeared. Free string. 96 */ 97 void 98 string_free(struct snmp_context *ctx) 99 { 100 free(ctx->scratch->ptr1); 101 } 102 103 /* 104 * Get a string value for a response packet 105 */ 106 int 107 string_get(struct snmp_value *value, const u_char *ptr, ssize_t len) 108 { 109 if (ptr == NULL) { 110 value->v.octetstring.len = 0; 111 value->v.octetstring.octets = NULL; 112 return (SNMP_ERR_NOERROR); 113 } 114 if (len == -1) 115 len = strlen(ptr); 116 value->v.octetstring.len = (u_long)len; 117 if ((value->v.octetstring.octets = malloc((size_t)len)) == NULL) 118 return (SNMP_ERR_RES_UNAVAIL); 119 memcpy(value->v.octetstring.octets, ptr, (size_t)len); 120 return (SNMP_ERR_NOERROR); 121 } 122 123 /* 124 * Get a string value for a response packet but cut it if it is too long. 125 */ 126 int 127 string_get_max(struct snmp_value *value, const u_char *ptr, ssize_t len, 128 size_t maxlen) 129 { 130 131 if (ptr == NULL) { 132 value->v.octetstring.len = 0; 133 value->v.octetstring.octets = NULL; 134 return (SNMP_ERR_NOERROR); 135 } 136 if (len == -1) 137 len = strlen(ptr); 138 if ((size_t)len > maxlen) 139 len = maxlen; 140 value->v.octetstring.len = (u_long)len; 141 if ((value->v.octetstring.octets = malloc((size_t)len)) == NULL) 142 return (SNMP_ERR_RES_UNAVAIL); 143 memcpy(value->v.octetstring.octets, ptr, (size_t)len); 144 return (SNMP_ERR_NOERROR); 145 } 146 147 /* 148 * Support for IPADDRESS 149 * 150 * Save the old IP address in scratch->int1 and set the new one. 151 */ 152 int 153 ip_save(struct snmp_value *value, struct snmp_context *ctx, u_char *valp) 154 { 155 ctx->scratch->int1 = (valp[0] << 24) | (valp[1] << 16) | (valp[2] << 8) 156 | valp[3]; 157 158 valp[0] = value->v.ipaddress[0]; 159 valp[1] = value->v.ipaddress[1]; 160 valp[2] = value->v.ipaddress[2]; 161 valp[3] = value->v.ipaddress[3]; 162 163 return (0); 164 } 165 166 /* 167 * Rollback the address by copying back the old one 168 */ 169 void 170 ip_rollback(struct snmp_context *ctx, u_char *valp) 171 { 172 valp[0] = ctx->scratch->int1 >> 24; 173 valp[1] = ctx->scratch->int1 >> 16; 174 valp[2] = ctx->scratch->int1 >> 8; 175 valp[3] = ctx->scratch->int1; 176 } 177 178 /* 179 * Nothing to do for commit 180 */ 181 void 182 ip_commit(struct snmp_context *ctx __unused) 183 { 184 } 185 186 /* 187 * Retrieve an IP address 188 */ 189 int 190 ip_get(struct snmp_value *value, u_char *valp) 191 { 192 value->v.ipaddress[0] = valp[0]; 193 value->v.ipaddress[1] = valp[1]; 194 value->v.ipaddress[2] = valp[2]; 195 value->v.ipaddress[3] = valp[3]; 196 return (SNMP_ERR_NOERROR); 197 } 198 199 /* 200 * Object ID support 201 * 202 * Save the old value in a fresh allocated oid pointed to by scratch->ptr1. 203 */ 204 int 205 oid_save(struct snmp_value *value, struct snmp_context *ctx, 206 struct asn_oid *oid) 207 { 208 if ((ctx->scratch->ptr1 = malloc(sizeof(struct asn_oid))) == NULL) 209 return (SNMP_ERR_RES_UNAVAIL); 210 *(struct asn_oid *)ctx->scratch->ptr1 = *oid; 211 *oid = value->v.oid; 212 213 return (0); 214 } 215 216 void 217 oid_rollback(struct snmp_context *ctx, struct asn_oid *oid) 218 { 219 *oid = *(struct asn_oid *)ctx->scratch->ptr1; 220 free(ctx->scratch->ptr1); 221 } 222 223 void 224 oid_commit(struct snmp_context *ctx) 225 { 226 free(ctx->scratch->ptr1); 227 } 228 229 int 230 oid_get(struct snmp_value *value, const struct asn_oid *oid) 231 { 232 value->v.oid = *oid; 233 return (SNMP_ERR_NOERROR); 234 } 235 236 /* 237 * Decode an index 238 */ 239 int 240 index_decode(const struct asn_oid *oid, u_int sub, u_int code, ...) 241 { 242 va_list ap; 243 u_int index_count; 244 void *octs[10]; 245 u_int nocts; 246 u_int idx; 247 248 va_start(ap, code); 249 index_count = SNMP_INDEX_COUNT(code); 250 nocts = 0; 251 252 for (idx = 0; idx < index_count; idx++) { 253 switch (SNMP_INDEX(code, idx)) { 254 255 case SNMP_SYNTAX_NULL: 256 break; 257 258 case SNMP_SYNTAX_INTEGER: 259 if (sub == oid->len) 260 goto err; 261 *va_arg(ap, int32_t *) = oid->subs[sub++]; 262 break; 263 264 case SNMP_SYNTAX_COUNTER64: 265 if (sub == oid->len) 266 goto err; 267 *va_arg(ap, u_int64_t *) = oid->subs[sub++]; 268 break; 269 270 case SNMP_SYNTAX_OCTETSTRING: 271 { 272 u_char **cval; 273 size_t *sval; 274 u_int i; 275 276 /* only variable size supported */ 277 if (sub == oid->len) 278 goto err; 279 cval = va_arg(ap, u_char **); 280 sval = va_arg(ap, size_t *); 281 *sval = oid->subs[sub++]; 282 if (sub + *sval > oid->len) 283 goto err; 284 if ((*cval = malloc(*sval)) == NULL) { 285 syslog(LOG_ERR, "%s: %m", __func__); 286 goto err; 287 } 288 octs[nocts++] = *cval; 289 for (i = 0; i < *sval; i++) { 290 if (oid->subs[sub] > 0xff) 291 goto err; 292 (*cval)[i] = oid->subs[sub++]; 293 } 294 break; 295 } 296 297 case SNMP_SYNTAX_OID: 298 { 299 struct asn_oid *aval; 300 u_int i; 301 302 if (sub == oid->len) 303 goto err; 304 aval = va_arg(ap, struct asn_oid *); 305 aval->len = oid->subs[sub++]; 306 if (aval->len > ASN_MAXOIDLEN) 307 goto err; 308 for (i = 0; i < aval->len; i++) 309 aval->subs[i] = oid->subs[sub++]; 310 break; 311 } 312 313 case SNMP_SYNTAX_IPADDRESS: 314 { 315 u_int8_t *pval; 316 u_int i; 317 318 if (sub + 4 > oid->len) 319 goto err; 320 pval = va_arg(ap, u_int8_t *); 321 for (i = 0; i < 4; i++) { 322 if (oid->subs[sub] > 0xff) 323 goto err; 324 pval[i] = oid->subs[sub++]; 325 } 326 break; 327 } 328 329 case SNMP_SYNTAX_COUNTER: 330 case SNMP_SYNTAX_GAUGE: 331 case SNMP_SYNTAX_TIMETICKS: 332 if (sub == oid->len) 333 goto err; 334 if (oid->subs[sub] > 0xffffffff) 335 goto err; 336 *va_arg(ap, u_int32_t *) = oid->subs[sub++]; 337 break; 338 } 339 } 340 341 va_end(ap); 342 return (0); 343 344 err: 345 va_end(ap); 346 while(nocts > 0) 347 free(octs[--nocts]); 348 return (-1); 349 } 350 351 /* 352 * Compare the index part of an OID and an index. 353 */ 354 int 355 index_compare_off(const struct asn_oid *oid, u_int sub, 356 const struct asn_oid *idx, u_int off) 357 { 358 u_int i; 359 360 for (i = off; i < idx->len && i < oid->len - sub; i++) { 361 if (oid->subs[sub + i] < idx->subs[i]) 362 return (-1); 363 if (oid->subs[sub + i] > idx->subs[i]) 364 return (+1); 365 } 366 if (oid->len - sub < idx->len) 367 return (-1); 368 if (oid->len - sub > idx->len) 369 return (+1); 370 371 return (0); 372 } 373 374 int 375 index_compare(const struct asn_oid *oid, u_int sub, const struct asn_oid *idx) 376 { 377 return (index_compare_off(oid, sub, idx, 0)); 378 } 379 380 /* 381 * Append an index to an oid 382 */ 383 void 384 index_append_off(struct asn_oid *var, u_int sub, const struct asn_oid *idx, 385 u_int off) 386 { 387 u_int i; 388 389 var->len = sub + idx->len; 390 for (i = off; i < idx->len; i++) 391 var->subs[sub + i] = idx->subs[i]; 392 } 393 void 394 index_append(struct asn_oid *var, u_int sub, const struct asn_oid *idx) 395 { 396 index_append_off(var, sub, idx, 0); 397 } 398 399