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.7 2004/08/06 08:47:11 brandt 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 * Support for IPADDRESS 125 * 126 * Save the old IP address in scratch->int1 and set the new one. 127 */ 128 int 129 ip_save(struct snmp_value *value, struct snmp_context *ctx, u_char *valp) 130 { 131 ctx->scratch->int1 = (valp[0] << 24) | (valp[1] << 16) | (valp[2] << 8) 132 | valp[3]; 133 134 valp[0] = value->v.ipaddress[0]; 135 valp[1] = value->v.ipaddress[1]; 136 valp[2] = value->v.ipaddress[2]; 137 valp[3] = value->v.ipaddress[3]; 138 139 return (0); 140 } 141 142 /* 143 * Rollback the address by copying back the old one 144 */ 145 void 146 ip_rollback(struct snmp_context *ctx, u_char *valp) 147 { 148 valp[0] = ctx->scratch->int1 >> 24; 149 valp[1] = ctx->scratch->int1 >> 16; 150 valp[2] = ctx->scratch->int1 >> 8; 151 valp[3] = ctx->scratch->int1; 152 } 153 154 /* 155 * Nothing to do for commit 156 */ 157 void 158 ip_commit(struct snmp_context *ctx __unused) 159 { 160 } 161 162 /* 163 * Retrieve an IP address 164 */ 165 int 166 ip_get(struct snmp_value *value, u_char *valp) 167 { 168 value->v.ipaddress[0] = valp[0]; 169 value->v.ipaddress[1] = valp[1]; 170 value->v.ipaddress[2] = valp[2]; 171 value->v.ipaddress[3] = valp[3]; 172 return (SNMP_ERR_NOERROR); 173 } 174 175 /* 176 * Object ID support 177 * 178 * Save the old value in a fresh allocated oid pointed to by scratch->ptr1. 179 */ 180 int 181 oid_save(struct snmp_value *value, struct snmp_context *ctx, 182 struct asn_oid *oid) 183 { 184 if ((ctx->scratch->ptr1 = malloc(sizeof(struct asn_oid))) == NULL) 185 return (SNMP_ERR_RES_UNAVAIL); 186 *(struct asn_oid *)ctx->scratch->ptr1 = *oid; 187 *oid = value->v.oid; 188 189 return (0); 190 } 191 192 void 193 oid_rollback(struct snmp_context *ctx, struct asn_oid *oid) 194 { 195 *oid = *(struct asn_oid *)ctx->scratch->ptr1; 196 free(ctx->scratch->ptr1); 197 } 198 199 void 200 oid_commit(struct snmp_context *ctx) 201 { 202 free(ctx->scratch->ptr1); 203 } 204 205 int 206 oid_get(struct snmp_value *value, const struct asn_oid *oid) 207 { 208 value->v.oid = *oid; 209 return (SNMP_ERR_NOERROR); 210 } 211 212 /* 213 * Decode an index 214 */ 215 int 216 index_decode(const struct asn_oid *oid, u_int sub, u_int code, ...) 217 { 218 va_list ap; 219 u_int index_count; 220 void *octs[10]; 221 u_int nocts; 222 u_int idx; 223 224 va_start(ap, code); 225 index_count = SNMP_INDEX_COUNT(code); 226 nocts = 0; 227 228 for (idx = 0; idx < index_count; idx++) { 229 switch (SNMP_INDEX(code, idx)) { 230 231 case SNMP_SYNTAX_NULL: 232 break; 233 234 case SNMP_SYNTAX_INTEGER: 235 if (sub == oid->len) 236 goto err; 237 *va_arg(ap, int32_t *) = oid->subs[sub++]; 238 break; 239 240 case SNMP_SYNTAX_COUNTER64: 241 if (sub == oid->len) 242 goto err; 243 *va_arg(ap, u_int64_t *) = oid->subs[sub++]; 244 break; 245 246 case SNMP_SYNTAX_OCTETSTRING: 247 { 248 u_char **cval; 249 size_t *sval; 250 u_int i; 251 252 /* only variable size supported */ 253 if (sub == oid->len) 254 goto err; 255 cval = va_arg(ap, u_char **); 256 sval = va_arg(ap, size_t *); 257 *sval = oid->subs[sub++]; 258 if (sub + *sval > oid->len) 259 goto err; 260 if ((*cval = malloc(*sval)) == NULL) { 261 syslog(LOG_ERR, "%s: %m", __func__); 262 goto err; 263 } 264 octs[nocts++] = *cval; 265 for (i = 0; i < *sval; i++) { 266 if (oid->subs[sub] > 0xff) 267 goto err; 268 (*cval)[i] = oid->subs[sub++]; 269 } 270 break; 271 } 272 273 case SNMP_SYNTAX_OID: 274 { 275 struct asn_oid *aval; 276 u_int i; 277 278 if (sub == oid->len) 279 goto err; 280 aval = va_arg(ap, struct asn_oid *); 281 aval->len = oid->subs[sub++]; 282 if (aval->len > ASN_MAXOIDLEN) 283 goto err; 284 for (i = 0; i < aval->len; i++) 285 aval->subs[i] = oid->subs[sub++]; 286 break; 287 } 288 289 case SNMP_SYNTAX_IPADDRESS: 290 { 291 u_int8_t *pval; 292 u_int i; 293 294 if (sub + 4 > oid->len) 295 goto err; 296 pval = va_arg(ap, u_int8_t *); 297 for (i = 0; i < 4; i++) { 298 if (oid->subs[sub] > 0xff) 299 goto err; 300 pval[i] = oid->subs[sub++]; 301 } 302 break; 303 } 304 305 case SNMP_SYNTAX_COUNTER: 306 case SNMP_SYNTAX_GAUGE: 307 case SNMP_SYNTAX_TIMETICKS: 308 if (sub == oid->len) 309 goto err; 310 if (oid->subs[sub] > 0xffffffff) 311 goto err; 312 *va_arg(ap, u_int32_t *) = oid->subs[sub++]; 313 break; 314 } 315 } 316 317 va_end(ap); 318 return (0); 319 320 err: 321 va_end(ap); 322 while(nocts > 0) 323 free(octs[--nocts]); 324 return (-1); 325 } 326 327 /* 328 * Compare the index part of an OID and an index. 329 */ 330 int 331 index_compare_off(const struct asn_oid *oid, u_int sub, 332 const struct asn_oid *idx, u_int off) 333 { 334 u_int i; 335 336 for (i = off; i < idx->len && i < oid->len - sub; i++) { 337 if (oid->subs[sub + i] < idx->subs[i]) 338 return (-1); 339 if (oid->subs[sub + i] > idx->subs[i]) 340 return (+1); 341 } 342 if (oid->len - sub < idx->len) 343 return (-1); 344 if (oid->len - sub > idx->len) 345 return (+1); 346 347 return (0); 348 } 349 350 int 351 index_compare(const struct asn_oid *oid, u_int sub, const struct asn_oid *idx) 352 { 353 return (index_compare_off(oid, sub, idx, 0)); 354 } 355 356 /* 357 * Append an index to an oid 358 */ 359 void 360 index_append_off(struct asn_oid *var, u_int sub, const struct asn_oid *idx, 361 u_int off) 362 { 363 u_int i; 364 365 var->len = sub + idx->len; 366 for (i = off; i < idx->len; i++) 367 var->subs[sub + i] = idx->subs[i]; 368 } 369 void 370 index_append(struct asn_oid *var, u_int sub, const struct asn_oid *idx) 371 { 372 index_append_off(var, sub, idx, 0); 373 } 374 375