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 of this software and documentation and use in source and 9 * binary forms, with or without modification, are permitted provided that 10 * the following conditions are met: 11 * 12 * 1. Redistributions of source code or documentation must retain the above 13 * copyright notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS 22 * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 23 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 24 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 25 * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 28 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 31 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 * 33 * $Begemot: bsnmp/snmpd/export.c,v 1.6 2003/12/03 10:08:47 hbb Exp $ 34 * 35 * Support functions for modules. 36 */ 37 #include <sys/types.h> 38 #include <sys/un.h> 39 #include <stdio.h> 40 #include <stdlib.h> 41 #include <string.h> 42 #include <syslog.h> 43 #include <stdarg.h> 44 45 #include "snmpmod.h" 46 #include "snmpd.h" 47 #include "tree.h" 48 49 /* 50 * Support functions 51 */ 52 53 /* 54 * This is user for SET of string variables. If 'req' is not -1 then 55 * the arguments is checked to be of that length. The old value is saved 56 * in scratch->ptr1 and the new value is allocated and copied. 57 * If there is an old values it must have been allocated by malloc. 58 */ 59 int 60 string_save(struct snmp_value *value, struct snmp_context *ctx, 61 ssize_t req_size, u_char **valp) 62 { 63 if (req_size != -1 && value->v.octetstring.len != (u_long)req_size) 64 return (SNMP_ERR_BADVALUE); 65 66 ctx->scratch->ptr1 = *valp; 67 68 if ((*valp = malloc(value->v.octetstring.len + 1)) == NULL) { 69 *valp = ctx->scratch->ptr1; 70 return (SNMP_ERR_RES_UNAVAIL); 71 } 72 73 memcpy(*valp, value->v.octetstring.octets, value->v.octetstring.len); 74 (*valp)[value->v.octetstring.len] = '\0'; 75 76 return (0); 77 } 78 79 /* 80 * Commit a string. This is easy - free the old value. 81 */ 82 void 83 string_commit(struct snmp_context *ctx) 84 { 85 free(ctx->scratch->ptr1); 86 } 87 88 /* 89 * Rollback a string - free new value and copy back old one. 90 */ 91 void 92 string_rollback(struct snmp_context *ctx, u_char **valp) 93 { 94 free(*valp); 95 *valp = ctx->scratch->ptr1; 96 } 97 98 /* 99 * ROLLBACK or COMMIT fails because instance has disappeared. Free string. 100 */ 101 void 102 string_free(struct snmp_context *ctx) 103 { 104 free(ctx->scratch->ptr1); 105 } 106 107 /* 108 * Get a string value for a response packet 109 */ 110 int 111 string_get(struct snmp_value *value, const u_char *ptr, ssize_t len) 112 { 113 if (ptr == NULL) { 114 value->v.octetstring.len = 0; 115 value->v.octetstring.octets = NULL; 116 return (SNMP_ERR_NOERROR); 117 } 118 if (len == -1) 119 len = strlen(ptr); 120 value->v.octetstring.len = (u_long)len; 121 if ((value->v.octetstring.octets = malloc((size_t)len)) == NULL) 122 return (SNMP_ERR_RES_UNAVAIL); 123 memcpy(value->v.octetstring.octets, ptr, (size_t)len); 124 return (SNMP_ERR_NOERROR); 125 } 126 127 /* 128 * Support for IPADDRESS 129 * 130 * Save the old IP address in scratch->int1 and set the new one. 131 */ 132 int 133 ip_save(struct snmp_value *value, struct snmp_context *ctx, u_char *valp) 134 { 135 ctx->scratch->int1 = (valp[0] << 24) | (valp[1] << 16) | (valp[2] << 8) 136 | valp[3]; 137 138 valp[0] = value->v.ipaddress[0]; 139 valp[1] = value->v.ipaddress[1]; 140 valp[2] = value->v.ipaddress[2]; 141 valp[3] = value->v.ipaddress[3]; 142 143 return (0); 144 } 145 146 /* 147 * Rollback the address by copying back the old one 148 */ 149 void 150 ip_rollback(struct snmp_context *ctx, u_char *valp) 151 { 152 valp[0] = ctx->scratch->int1 >> 24; 153 valp[1] = ctx->scratch->int1 >> 16; 154 valp[2] = ctx->scratch->int1 >> 8; 155 valp[3] = ctx->scratch->int1; 156 } 157 158 /* 159 * Nothing to do for commit 160 */ 161 void 162 ip_commit(struct snmp_context *ctx __unused) 163 { 164 } 165 166 /* 167 * Retrieve an IP address 168 */ 169 int 170 ip_get(struct snmp_value *value, u_char *valp) 171 { 172 value->v.ipaddress[0] = valp[0]; 173 value->v.ipaddress[1] = valp[1]; 174 value->v.ipaddress[2] = valp[2]; 175 value->v.ipaddress[3] = valp[3]; 176 return (SNMP_ERR_NOERROR); 177 } 178 179 /* 180 * Object ID support 181 * 182 * Save the old value in a fresh allocated oid pointed to by scratch->ptr1. 183 */ 184 int 185 oid_save(struct snmp_value *value, struct snmp_context *ctx, 186 struct asn_oid *oid) 187 { 188 if ((ctx->scratch->ptr1 = malloc(sizeof(struct asn_oid))) == NULL) 189 return (SNMP_ERR_RES_UNAVAIL); 190 *(struct asn_oid *)ctx->scratch->ptr1 = *oid; 191 *oid = value->v.oid; 192 193 return (0); 194 } 195 196 void 197 oid_rollback(struct snmp_context *ctx, struct asn_oid *oid) 198 { 199 *oid = *(struct asn_oid *)ctx->scratch->ptr1; 200 free(ctx->scratch->ptr1); 201 } 202 203 void 204 oid_commit(struct snmp_context *ctx) 205 { 206 free(ctx->scratch->ptr1); 207 } 208 209 int 210 oid_get(struct snmp_value *value, const struct asn_oid *oid) 211 { 212 value->v.oid = *oid; 213 return (SNMP_ERR_NOERROR); 214 } 215 216 /* 217 * Decode an index 218 */ 219 int 220 index_decode(const struct asn_oid *oid, u_int sub, u_int code, ...) 221 { 222 va_list ap; 223 u_int index_count; 224 void *octs[10]; 225 u_int nocts; 226 u_int idx; 227 228 va_start(ap, code); 229 index_count = SNMP_INDEX_COUNT(code); 230 nocts = 0; 231 232 for (idx = 0; idx < index_count; idx++) { 233 switch (SNMP_INDEX(code, idx)) { 234 235 case SNMP_SYNTAX_NULL: 236 break; 237 238 case SNMP_SYNTAX_INTEGER: 239 if (sub == oid->len) 240 goto err; 241 *va_arg(ap, int32_t *) = oid->subs[sub++]; 242 break; 243 244 case SNMP_SYNTAX_COUNTER64: 245 if (sub == oid->len) 246 goto err; 247 *va_arg(ap, u_int64_t *) = oid->subs[sub++]; 248 break; 249 250 case SNMP_SYNTAX_OCTETSTRING: 251 { 252 u_char **cval; 253 size_t *sval; 254 u_int i; 255 256 /* only variable size supported */ 257 if (sub == oid->len) 258 goto err; 259 cval = va_arg(ap, u_char **); 260 sval = va_arg(ap, size_t *); 261 *sval = oid->subs[sub++]; 262 if (sub + *sval > oid->len) 263 goto err; 264 if ((*cval = malloc(*sval)) == NULL) { 265 syslog(LOG_ERR, "%s: %m", __func__); 266 goto err; 267 } 268 octs[nocts++] = *cval; 269 for (i = 0; i < *sval; i++) { 270 if (oid->subs[sub] > 0xff) 271 goto err; 272 (*cval)[i] = oid->subs[sub++]; 273 } 274 break; 275 } 276 277 case SNMP_SYNTAX_OID: 278 { 279 struct asn_oid *aval; 280 u_int i; 281 282 if (sub == oid->len) 283 goto err; 284 aval = va_arg(ap, struct asn_oid *); 285 aval->len = oid->subs[sub++]; 286 if (aval->len > ASN_MAXOIDLEN) 287 goto err; 288 for (i = 0; i < aval->len; i++) 289 aval->subs[i] = oid->subs[sub++]; 290 break; 291 } 292 293 case SNMP_SYNTAX_IPADDRESS: 294 { 295 u_int8_t *pval; 296 u_int i; 297 298 if (sub + 4 > oid->len) 299 goto err; 300 pval = va_arg(ap, u_int8_t *); 301 for (i = 0; i < 4; i++) { 302 if (oid->subs[sub] > 0xff) 303 goto err; 304 pval[i] = oid->subs[sub++]; 305 } 306 break; 307 } 308 309 case SNMP_SYNTAX_COUNTER: 310 case SNMP_SYNTAX_GAUGE: 311 case SNMP_SYNTAX_TIMETICKS: 312 if (sub == oid->len) 313 goto err; 314 if (oid->subs[sub] > 0xffffffff) 315 goto err; 316 *va_arg(ap, u_int32_t *) = oid->subs[sub++]; 317 break; 318 } 319 } 320 321 va_end(ap); 322 return (0); 323 324 err: 325 va_end(ap); 326 while(nocts > 0) 327 free(octs[--nocts]); 328 return (-1); 329 } 330 331 /* 332 * Compare the index part of an OID and an index. 333 */ 334 int 335 index_compare_off(const struct asn_oid *oid, u_int sub, 336 const struct asn_oid *idx, u_int off) 337 { 338 u_int i; 339 340 for (i = off; i < idx->len && i < oid->len - sub; i++) { 341 if (oid->subs[sub + i] < idx->subs[i]) 342 return (-1); 343 if (oid->subs[sub + i] > idx->subs[i]) 344 return (+1); 345 } 346 if (oid->len - sub < idx->len) 347 return (-1); 348 if (oid->len - sub > idx->len) 349 return (+1); 350 351 return (0); 352 } 353 354 int 355 index_compare(const struct asn_oid *oid, u_int sub, const struct asn_oid *idx) 356 { 357 return (index_compare_off(oid, sub, idx, 0)); 358 } 359 360 /* 361 * Append an index to an oid 362 */ 363 void 364 index_append_off(struct asn_oid *var, u_int sub, const struct asn_oid *idx, 365 u_int off) 366 { 367 u_int i; 368 369 var->len = sub + idx->len; 370 for (i = off; i < idx->len; i++) 371 var->subs[sub + i] = idx->subs[i]; 372 } 373 void 374 index_append(struct asn_oid *var, u_int sub, const struct asn_oid *idx) 375 { 376 index_append_off(var, sub, idx, 0); 377 } 378 379