1 /* 2 * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org> 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 #include <sys/socket.h> 17 18 #include <arpa/inet.h> 19 20 #include <ctype.h> 21 #include <endian.h> 22 #include <errno.h> 23 #include <inttypes.h> 24 #include <stdlib.h> 25 #include <stdint.h> 26 #include <stdio.h> 27 #include <string.h> 28 #include <strings.h> 29 #include <unistd.h> 30 31 #include "agentx.h" 32 33 #define AGENTX_PDU_HEADER 20 34 35 static int agentx_pdu_need(struct agentx *, size_t); 36 static int agentx_pdu_header(struct agentx *, 37 enum agentx_pdu_type, uint8_t, uint32_t, uint32_t, uint32_t, 38 struct agentx_ostring *); 39 static uint32_t agentx_packetid(struct agentx *); 40 static uint32_t agentx_pdu_queue(struct agentx *); 41 static int agentx_pdu_add_uint16(struct agentx *, uint16_t); 42 static int agentx_pdu_add_uint32(struct agentx *, uint32_t); 43 static int agentx_pdu_add_uint64(struct agentx *, uint64_t); 44 static int agentx_pdu_add_oid(struct agentx *, struct agentx_oid *, int); 45 static int agentx_pdu_add_str(struct agentx *, struct agentx_ostring *); 46 static int agentx_pdu_add_varbindlist( struct agentx *, struct agentx_varbind *, 47 size_t); 48 static uint16_t agentx_pdutoh16(struct agentx_pdu_header *, uint8_t *); 49 static uint32_t agentx_pdutoh32(struct agentx_pdu_header *, uint8_t *); 50 static uint64_t agentx_pdutoh64(struct agentx_pdu_header *, uint8_t *); 51 static ssize_t agentx_pdutooid(struct agentx_pdu_header *, struct agentx_oid *, 52 uint8_t *, size_t); 53 static ssize_t agentx_pdutoostring(struct agentx_pdu_header *, 54 struct agentx_ostring *, uint8_t *, size_t); 55 static ssize_t agentx_pdutovarbind(struct agentx_pdu_header *, 56 struct agentx_varbind *, uint8_t *, size_t); 57 58 struct agentx * 59 agentx_new(int fd) 60 { 61 struct agentx *ax; 62 63 if (fd == -1) { 64 errno = EINVAL; 65 return NULL; 66 } 67 68 if ((ax = calloc(1, sizeof(*ax))) == NULL) 69 return NULL; 70 ax->ax_fd = fd; 71 if ((ax->ax_rbuf = malloc(512)) == NULL) 72 goto fail; 73 ax->ax_rbsize = 512; 74 ax->ax_byteorder = AGENTX_BYTE_ORDER_NATIVE; 75 76 return ax; 77 78 fail: 79 free(ax); 80 return NULL; 81 } 82 83 void 84 agentx_free(struct agentx *ax) 85 { 86 if (ax == NULL) 87 return; 88 close(ax->ax_fd); 89 free(ax->ax_rbuf); 90 free(ax->ax_wbuf); 91 free(ax->ax_packetids); 92 free(ax); 93 } 94 95 struct agentx_pdu * 96 agentx_recv(struct agentx *ax) 97 { 98 struct agentx_pdu *pdu; 99 struct agentx_pdu_header header; 100 struct agentx_pdu_response *response; 101 struct agentx_varbind *varbind; 102 struct agentx_pdu_searchrangelist *srl; 103 struct agentx_pdu_varbindlist *vbl; 104 struct agentx_searchrange *sr; 105 size_t rbsize, packetidx = 0, i, rawlen; 106 ssize_t nread; 107 uint8_t *u8; 108 uint8_t *rbuf; 109 int found; 110 111 /* Only read a single packet at a time to make sure libevent triggers */ 112 if (ax->ax_rblen < AGENTX_PDU_HEADER) { 113 if ((nread = read(ax->ax_fd, ax->ax_rbuf + ax->ax_rblen, 114 AGENTX_PDU_HEADER - ax->ax_rblen)) == 0) { 115 errno = ECONNRESET; 116 return NULL; 117 } 118 if (nread == -1) 119 return NULL; 120 ax->ax_rblen += nread; 121 if (ax->ax_rblen < AGENTX_PDU_HEADER) { 122 errno = EAGAIN; 123 return NULL; 124 } 125 } 126 u8 = ax->ax_rbuf; 127 header.aph_version = *u8++; 128 header.aph_type = *u8++; 129 header.aph_flags = *u8++; 130 u8++; 131 header.aph_sessionid = agentx_pdutoh32(&header, u8); 132 u8 += 4; 133 header.aph_transactionid = agentx_pdutoh32(&header, u8); 134 u8 += 4; 135 header.aph_packetid = agentx_pdutoh32(&header, u8); 136 u8 += 4; 137 header.aph_plength = agentx_pdutoh32(&header, u8); 138 139 if (header.aph_version != 1) { 140 errno = EPROTO; 141 return NULL; 142 } 143 if (ax->ax_rblen < AGENTX_PDU_HEADER + header.aph_plength) { 144 if (AGENTX_PDU_HEADER + header.aph_plength > ax->ax_rbsize) { 145 rbsize = (((AGENTX_PDU_HEADER + header.aph_plength) 146 / 512) + 1) * 512; 147 if ((rbuf = recallocarray(ax->ax_rbuf, ax->ax_rbsize, 148 rbsize, sizeof(*rbuf))) == NULL) 149 return NULL; 150 ax->ax_rbsize = rbsize; 151 ax->ax_rbuf = rbuf; 152 } 153 nread = read(ax->ax_fd, ax->ax_rbuf + ax->ax_rblen, 154 header.aph_plength - (ax->ax_rblen - AGENTX_PDU_HEADER)); 155 if (nread == 0) 156 errno = ECONNRESET; 157 if (nread <= 0) 158 return NULL; 159 ax->ax_rblen += nread; 160 if (ax->ax_rblen < AGENTX_PDU_HEADER + header.aph_plength) { 161 errno = EAGAIN; 162 return NULL; 163 } 164 } 165 166 if ((pdu = calloc(1, sizeof(*pdu))) == NULL) 167 return NULL; 168 169 memcpy(&(pdu->ap_header), &header, sizeof(header)); 170 171 #if defined(AGENTX_DEBUG) && defined(AGENTX_DEBUG_VERBOSE) 172 { 173 char chars[4]; 174 int print = 1; 175 176 fprintf(stderr, "received packet:\n"); 177 for (i = 0; i < pdu->ap_header.aph_plength + AGENTX_PDU_HEADER; 178 i++) { 179 fprintf(stderr, "%02hhx ", ax->ax_rbuf[i]); 180 chars[i % 4] = ax->ax_rbuf[i]; 181 if (!isprint(ax->ax_rbuf[i])) 182 print = 0; 183 if (i % 4 == 3) { 184 if (print) 185 fprintf(stderr, "%.4s", chars); 186 fprintf(stderr, "\n"); 187 print = 1; 188 } 189 } 190 } 191 #endif 192 193 u8 = (ax->ax_rbuf) + AGENTX_PDU_HEADER; 194 rawlen = pdu->ap_header.aph_plength; 195 if (pdu->ap_header.aph_flags & AGENTX_PDU_FLAG_NON_DEFAULT_CONTEXT) { 196 nread = agentx_pdutoostring(&header, &(pdu->ap_context), u8, 197 rawlen); 198 if (nread == -1) 199 goto fail; 200 rawlen -= nread; 201 u8 += nread; 202 } 203 204 switch (pdu->ap_header.aph_type) { 205 case AGENTX_PDU_TYPE_GETBULK: 206 if (rawlen < 4) { 207 errno = EPROTO; 208 goto fail; 209 } 210 pdu->ap_payload.ap_getbulk.ap_nonrep = 211 agentx_pdutoh16(&header, u8); 212 u8 += 2; 213 pdu->ap_payload.ap_getbulk.ap_maxrep = 214 agentx_pdutoh16(&header, u8); 215 u8 += 2; 216 srl = &(pdu->ap_payload.ap_getbulk.ap_srl); 217 rawlen -= 4; 218 /* FALLTHROUGH */ 219 case AGENTX_PDU_TYPE_GET: 220 case AGENTX_PDU_TYPE_GETNEXT: 221 if (pdu->ap_header.aph_type != AGENTX_PDU_TYPE_GETBULK) 222 srl = &(pdu->ap_payload.ap_srl); 223 while (rawlen > 0 ) { 224 srl->ap_nsr++; 225 sr = reallocarray(srl->ap_sr, srl->ap_nsr, sizeof(*sr)); 226 if (sr == NULL) 227 goto fail; 228 srl->ap_sr = sr; 229 sr += (srl->ap_nsr - 1); 230 if ((nread = agentx_pdutooid(&header, &(sr->asr_start), 231 u8, rawlen)) == -1) 232 goto fail; 233 rawlen -= nread; 234 u8 += nread; 235 if ((nread = agentx_pdutooid(&header, &(sr->asr_stop), 236 u8, rawlen)) == -1) 237 goto fail; 238 rawlen -= nread; 239 u8 += nread; 240 } 241 break; 242 case AGENTX_PDU_TYPE_TESTSET: 243 vbl = &(pdu->ap_payload.ap_vbl); 244 while (rawlen > 0) { 245 varbind = recallocarray(vbl->ap_varbind, 246 vbl->ap_nvarbind, vbl->ap_nvarbind + 1, 247 sizeof(*(vbl->ap_varbind))); 248 if (varbind == NULL) 249 goto fail; 250 vbl->ap_varbind = varbind; 251 nread = agentx_pdutovarbind(&header, 252 &(vbl->ap_varbind[vbl->ap_nvarbind]), u8, rawlen); 253 if (nread == -1) 254 goto fail; 255 vbl->ap_nvarbind++; 256 u8 += nread; 257 rawlen -= nread; 258 } 259 break; 260 case AGENTX_PDU_TYPE_COMMITSET: 261 case AGENTX_PDU_TYPE_UNDOSET: 262 case AGENTX_PDU_TYPE_CLEANUPSET: 263 if (rawlen != 0) { 264 errno = EPROTO; 265 goto fail; 266 } 267 break; 268 case AGENTX_PDU_TYPE_RESPONSE: 269 if (ax->ax_packetids != NULL) { 270 found = 0; 271 for (i = 0; ax->ax_packetids[i] != 0; i++) { 272 if (ax->ax_packetids[i] == 273 pdu->ap_header.aph_packetid) { 274 packetidx = i; 275 found = 1; 276 } 277 } 278 if (found) { 279 ax->ax_packetids[packetidx] = 280 ax->ax_packetids[i - 1]; 281 ax->ax_packetids[i - 1] = 0; 282 } else { 283 errno = EPROTO; 284 goto fail; 285 } 286 } 287 if (rawlen < 8) { 288 errno = EPROTO; 289 goto fail; 290 } 291 response = &(pdu->ap_payload.ap_response); 292 response->ap_uptime = agentx_pdutoh32(&header, u8); 293 u8 += 4; 294 response->ap_error = agentx_pdutoh16(&header, u8); 295 u8 += 2; 296 response->ap_index = agentx_pdutoh16(&header, u8); 297 u8 += 2; 298 rawlen -= 8; 299 while (rawlen > 0) { 300 varbind = recallocarray(response->ap_varbindlist, 301 response->ap_nvarbind, response->ap_nvarbind + 1, 302 sizeof(*(response->ap_varbindlist))); 303 if (varbind == NULL) 304 goto fail; 305 response->ap_varbindlist = varbind; 306 nread = agentx_pdutovarbind(&header, 307 &(response->ap_varbindlist[response->ap_nvarbind]), 308 u8, rawlen); 309 if (nread == -1) 310 goto fail; 311 response->ap_nvarbind++; 312 u8 += nread; 313 rawlen -= nread; 314 } 315 break; 316 default: 317 pdu->ap_payload.ap_raw = malloc(pdu->ap_header.aph_plength); 318 if (pdu->ap_payload.ap_raw == NULL) 319 goto fail; 320 memcpy(pdu->ap_payload.ap_raw, ax->ax_rbuf + AGENTX_PDU_HEADER, 321 pdu->ap_header.aph_plength); 322 break; 323 } 324 325 ax->ax_rblen = 0; 326 327 return pdu; 328 fail: 329 agentx_pdu_free(pdu); 330 return NULL; 331 } 332 333 static int 334 agentx_pdu_need(struct agentx *ax, size_t need) 335 { 336 uint8_t *wbuf; 337 size_t wbsize; 338 339 if (ax->ax_wbtlen >= ax->ax_wbsize) { 340 wbsize = ((ax->ax_wbtlen / 512) + 1) * 512; 341 wbuf = recallocarray(ax->ax_wbuf, ax->ax_wbsize, wbsize, 1); 342 if (wbuf == NULL) { 343 ax->ax_wbtlen = ax->ax_wblen; 344 return -1; 345 } 346 ax->ax_wbsize = wbsize; 347 ax->ax_wbuf = wbuf; 348 } 349 350 return 0; 351 } 352 353 ssize_t 354 agentx_send(struct agentx *ax) 355 { 356 ssize_t nwrite; 357 358 if (ax->ax_wblen != ax->ax_wbtlen) { 359 errno = EALREADY; 360 return -1; 361 } 362 363 if (ax->ax_wblen == 0) 364 return 0; 365 366 #if defined(AGENTX_DEBUG) && defined(AGENTX_DEBUG_VERBOSE) 367 { 368 size_t i; 369 char chars[4]; 370 int print = 1; 371 372 fprintf(stderr, "sending packet:\n"); 373 for (i = 0; i < ax->ax_wblen; i++) { 374 fprintf(stderr, "%02hhx ", ax->ax_wbuf[i]); 375 chars[i % 4] = ax->ax_wbuf[i]; 376 if (!isprint(ax->ax_wbuf[i])) 377 print = 0; 378 if (i % 4 == 3) { 379 if (print) 380 fprintf(stderr, "%.4s", chars); 381 fprintf(stderr, "\n"); 382 print = 1; 383 } 384 } 385 } 386 #endif 387 388 if ((nwrite = send(ax->ax_fd, ax->ax_wbuf, ax->ax_wblen, 389 MSG_NOSIGNAL | MSG_DONTWAIT)) == -1) 390 return -1; 391 392 memmove(ax->ax_wbuf, ax->ax_wbuf + nwrite, ax->ax_wblen - nwrite); 393 ax->ax_wblen -= nwrite; 394 ax->ax_wbtlen = ax->ax_wblen; 395 396 return ax->ax_wblen; 397 } 398 399 uint32_t 400 agentx_open(struct agentx *ax, uint8_t timeout, struct agentx_oid *oid, 401 struct agentx_ostring *descr) 402 { 403 if (agentx_pdu_header(ax, AGENTX_PDU_TYPE_OPEN, 0, 0, 0, 0, 404 NULL) == -1) 405 return 0; 406 agentx_pdu_need(ax, 4); 407 ax->ax_wbuf[ax->ax_wbtlen++] = timeout; 408 memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, 3); 409 ax->ax_wbtlen += 3; 410 if (agentx_pdu_add_oid(ax, oid, 0) == -1) 411 return 0; 412 if (agentx_pdu_add_str(ax, descr) == -1) 413 return 0; 414 415 return agentx_pdu_queue(ax); 416 } 417 418 uint32_t 419 agentx_close(struct agentx *ax, uint32_t sessionid, 420 enum agentx_close_reason reason) 421 { 422 if (agentx_pdu_header(ax, AGENTX_PDU_TYPE_CLOSE, 0, sessionid, 0, 0, 423 NULL) == -1) 424 return 0; 425 426 if (agentx_pdu_need(ax, 4) == -1) 427 return 0; 428 ax->ax_wbuf[ax->ax_wbtlen++] = (uint8_t)reason; 429 memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, 3); 430 ax->ax_wbtlen += 3; 431 432 return agentx_pdu_queue(ax); 433 } 434 435 uint32_t 436 agentx_indexallocate(struct agentx *ax, uint8_t flags, uint32_t sessionid, 437 struct agentx_ostring *context, struct agentx_varbind *vblist, size_t nvb) 438 { 439 if (flags & ~(AGENTX_PDU_FLAG_NEW_INDEX | AGENTX_PDU_FLAG_ANY_INDEX)) { 440 errno = EINVAL; 441 return 0; 442 } 443 444 if (agentx_pdu_header(ax, AGENTX_PDU_TYPE_INDEXALLOCATE, flags, 445 sessionid, 0, 0, context) == -1) 446 return 0; 447 448 if (agentx_pdu_add_varbindlist(ax, vblist, nvb) == -1) 449 return 0; 450 451 return agentx_pdu_queue(ax); 452 } 453 454 uint32_t 455 agentx_indexdeallocate(struct agentx *ax, uint32_t sessionid, 456 struct agentx_ostring *context, struct agentx_varbind *vblist, size_t nvb) 457 { 458 if (agentx_pdu_header(ax, AGENTX_PDU_TYPE_INDEXDEALLOCATE, 0, 459 sessionid, 0, 0, context) == -1) 460 return 0; 461 462 if (agentx_pdu_add_varbindlist(ax, vblist, nvb) == -1) 463 return 0; 464 465 return agentx_pdu_queue(ax); 466 } 467 468 uint32_t 469 agentx_addagentcaps(struct agentx *ax, uint32_t sessionid, 470 struct agentx_ostring *context, struct agentx_oid *id, 471 struct agentx_ostring *descr) 472 { 473 if (agentx_pdu_header(ax, AGENTX_PDU_TYPE_ADDAGENTCAPS, 0, 474 sessionid, 0, 0, context) == -1) 475 return 0; 476 if (agentx_pdu_add_oid(ax, id, 0) == -1) 477 return 0; 478 if (agentx_pdu_add_str(ax, descr) == -1) 479 return 0; 480 481 return agentx_pdu_queue(ax); 482 } 483 484 uint32_t 485 agentx_removeagentcaps(struct agentx *ax, uint32_t sessionid, 486 struct agentx_ostring *context, struct agentx_oid *id) 487 { 488 if (agentx_pdu_header(ax, AGENTX_PDU_TYPE_REMOVEAGENTCAPS, 0, 489 sessionid, 0, 0, context) == -1) 490 return 0; 491 if (agentx_pdu_add_oid(ax, id, 0) == -1) 492 return 0; 493 494 return agentx_pdu_queue(ax); 495 496 } 497 498 uint32_t 499 agentx_register(struct agentx *ax, uint8_t flags, uint32_t sessionid, 500 struct agentx_ostring *context, uint8_t timeout, uint8_t priority, 501 uint8_t range_subid, struct agentx_oid *subtree, uint32_t upperbound) 502 { 503 if (flags & ~(AGENTX_PDU_FLAG_INSTANCE_REGISTRATION)) { 504 errno = EINVAL; 505 return 0; 506 } 507 508 if (agentx_pdu_header(ax, AGENTX_PDU_TYPE_REGISTER, flags, 509 sessionid, 0, 0, context) == -1) 510 return 0; 511 512 if (agentx_pdu_need(ax, 4) == -1) 513 return 0; 514 ax->ax_wbuf[ax->ax_wbtlen++] = timeout; 515 ax->ax_wbuf[ax->ax_wbtlen++] = priority; 516 ax->ax_wbuf[ax->ax_wbtlen++] = range_subid; 517 ax->ax_wbuf[ax->ax_wbtlen++] = 0; 518 if (agentx_pdu_add_oid(ax, subtree, 0) == -1) 519 return 0; 520 if (range_subid != 0) { 521 if (agentx_pdu_add_uint32(ax, upperbound) == -1) 522 return 0; 523 } 524 525 return agentx_pdu_queue(ax); 526 } 527 528 uint32_t 529 agentx_unregister(struct agentx *ax, uint32_t sessionid, 530 struct agentx_ostring *context, uint8_t priority, uint8_t range_subid, 531 struct agentx_oid *subtree, uint32_t upperbound) 532 { 533 if (agentx_pdu_header(ax, AGENTX_PDU_TYPE_UNREGISTER, 0, 534 sessionid, 0, 0, context) == -1) 535 return 0; 536 537 if (agentx_pdu_need(ax, 4) == -1) 538 return 0; 539 ax->ax_wbuf[ax->ax_wbtlen++] = 0; 540 ax->ax_wbuf[ax->ax_wbtlen++] = priority; 541 ax->ax_wbuf[ax->ax_wbtlen++] = range_subid; 542 ax->ax_wbuf[ax->ax_wbtlen++] = 0; 543 if (agentx_pdu_add_oid(ax, subtree, 0) == -1) 544 return 0; 545 if (range_subid != 0) { 546 if (agentx_pdu_add_uint32(ax, upperbound) == -1) 547 return 0; 548 } 549 550 return agentx_pdu_queue(ax); 551 } 552 553 int 554 agentx_response(struct agentx *ax, uint32_t sessionid, uint32_t transactionid, 555 uint32_t packetid, struct agentx_ostring *context, uint32_t sysuptime, 556 uint16_t error, uint16_t index, struct agentx_varbind *vblist, size_t nvb) 557 { 558 if (agentx_pdu_header(ax, AGENTX_PDU_TYPE_RESPONSE, 0, sessionid, 559 transactionid, packetid, context) == -1) 560 return -1; 561 562 if (agentx_pdu_add_uint32(ax, sysuptime) == -1 || 563 agentx_pdu_add_uint16(ax, error) == -1 || 564 agentx_pdu_add_uint16(ax, index) == -1) 565 return -1; 566 567 if (agentx_pdu_add_varbindlist(ax, vblist, nvb) == -1) 568 return -1; 569 if (agentx_pdu_queue(ax) == 0) 570 return -1; 571 return 0; 572 } 573 574 void 575 agentx_pdu_free(struct agentx_pdu *pdu) 576 { 577 size_t i; 578 struct agentx_pdu_response *response; 579 580 if (pdu->ap_header.aph_flags & AGENTX_PDU_FLAG_NON_DEFAULT_CONTEXT) 581 free(pdu->ap_context.aos_string); 582 583 switch (pdu->ap_header.aph_type) { 584 case AGENTX_PDU_TYPE_GET: 585 case AGENTX_PDU_TYPE_GETNEXT: 586 case AGENTX_PDU_TYPE_GETBULK: 587 free(pdu->ap_payload.ap_srl.ap_sr); 588 break; 589 case AGENTX_PDU_TYPE_RESPONSE: 590 response = &(pdu->ap_payload.ap_response); 591 for (i = 0; i < response->ap_nvarbind; i++) 592 agentx_varbind_free(&(response->ap_varbindlist[i])); 593 free(response->ap_varbindlist); 594 break; 595 default: 596 free(pdu->ap_payload.ap_raw); 597 break; 598 } 599 free(pdu); 600 } 601 602 void 603 agentx_varbind_free(struct agentx_varbind *varbind) 604 { 605 switch (varbind->avb_type) { 606 case AGENTX_DATA_TYPE_OCTETSTRING: 607 case AGENTX_DATA_TYPE_IPADDRESS: 608 case AGENTX_DATA_TYPE_OPAQUE: 609 free(varbind->avb_data.avb_ostring.aos_string); 610 break; 611 default: 612 break; 613 } 614 } 615 616 const char * 617 agentx_error2string(enum agentx_pdu_error error) 618 { 619 static char buffer[64]; 620 switch (error) { 621 case AGENTX_PDU_ERROR_NOERROR: 622 return "No error"; 623 case AGENTX_PDU_ERROR_GENERR: 624 return "Generic error"; 625 case AGENTX_PDU_ERROR_NOACCESS: 626 return "No access"; 627 case AGENTX_PDU_ERROR_WRONGTYPE: 628 return "Wrong type"; 629 case AGENTX_PDU_ERROR_WRONGLENGTH: 630 return "Wrong length"; 631 case AGENTX_PDU_ERROR_WRONGENCODING: 632 return "Wrong encoding"; 633 case AGENTX_PDU_ERROR_WRONGVALUE: 634 return "Wrong value"; 635 case AGENTX_PDU_ERROR_NOCREATION: 636 return "No creation"; 637 case AGENTX_PDU_ERROR_INCONSISTENTVALUE: 638 return "Inconsistent value"; 639 case AGENTX_PDU_ERROR_RESOURCEUNAVAILABLE: 640 return "Resource unavailable"; 641 case AGENTX_PDU_ERROR_COMMITFAILED: 642 return "Commit failed"; 643 case AGENTX_PDU_ERROR_UNDOFAILED: 644 return "Undo failed"; 645 case AGENTX_PDU_ERROR_NOTWRITABLE: 646 return "Not writable"; 647 case AGENTX_PDU_ERROR_INCONSISTENTNAME: 648 return "Inconsistent name"; 649 case AGENTX_PDU_ERROR_OPENFAILED: 650 return "Open Failed"; 651 case AGENTX_PDU_ERROR_NOTOPEN: 652 return "Not open"; 653 case AGENTX_PDU_ERROR_INDEXWRONGTYPE: 654 return "Index wrong type"; 655 case AGENTX_PDU_ERROR_INDEXALREADYALLOCATED: 656 return "Index already allocated"; 657 case AGENTX_PDU_ERROR_INDEXNONEAVAILABLE: 658 return "Index none available"; 659 case AGENTX_PDU_ERROR_INDEXNOTALLOCATED: 660 return "Index not allocated"; 661 case AGENTX_PDU_ERROR_UNSUPPORTEDCONETXT: 662 return "Unsupported context"; 663 case AGENTX_PDU_ERROR_DUPLICATEREGISTRATION: 664 return "Duplicate registration"; 665 case AGENTX_PDU_ERROR_UNKNOWNREGISTRATION: 666 return "Unkown registration"; 667 case AGENTX_PDU_ERROR_UNKNOWNAGENTCAPS: 668 return "Unknown agent capabilities"; 669 case AGENTX_PDU_ERROR_PARSEERROR: 670 return "Parse error"; 671 case AGENTX_PDU_ERROR_REQUESTDENIED: 672 return "Request denied"; 673 case AGENTX_PDU_ERROR_PROCESSINGERROR: 674 return "Processing error"; 675 } 676 snprintf(buffer, sizeof(buffer), "Unknown error: %d", error); 677 return buffer; 678 } 679 680 const char * 681 agentx_pdutype2string(enum agentx_pdu_type type) 682 { 683 static char buffer[64]; 684 switch(type) { 685 case AGENTX_PDU_TYPE_OPEN: 686 return "agentx-Open-PDU"; 687 case AGENTX_PDU_TYPE_CLOSE: 688 return "agentx-Close-PDU"; 689 case AGENTX_PDU_TYPE_REGISTER: 690 return "agentx-Register-PDU"; 691 case AGENTX_PDU_TYPE_UNREGISTER: 692 return "agentx-Unregister-PDU"; 693 case AGENTX_PDU_TYPE_GET: 694 return "agentx-Get-PDU"; 695 case AGENTX_PDU_TYPE_GETNEXT: 696 return "agentx-GetNext-PDU"; 697 case AGENTX_PDU_TYPE_GETBULK: 698 return "agentx-GetBulk-PDU"; 699 case AGENTX_PDU_TYPE_TESTSET: 700 return "agentx-TestSet-PDU"; 701 case AGENTX_PDU_TYPE_COMMITSET: 702 return "agentx-CommitSet-PDU"; 703 case AGENTX_PDU_TYPE_UNDOSET: 704 return "agentx-UndoSet-PDU"; 705 case AGENTX_PDU_TYPE_CLEANUPSET: 706 return "agentx-CleanupSet-PDU"; 707 case AGENTX_PDU_TYPE_NOTIFY: 708 return "agentx-Notify-PDU"; 709 case AGENTX_PDU_TYPE_PING: 710 return "agentx-Ping-PDU"; 711 case AGENTX_PDU_TYPE_INDEXALLOCATE: 712 return "agentx-IndexAllocate-PDU"; 713 case AGENTX_PDU_TYPE_INDEXDEALLOCATE: 714 return "agentx-IndexDeallocate-PDU"; 715 case AGENTX_PDU_TYPE_ADDAGENTCAPS: 716 return "agentx-AddAgentCaps-PDU"; 717 case AGENTX_PDU_TYPE_REMOVEAGENTCAPS: 718 return "agentx-RemoveAgentCaps-PDU"; 719 case AGENTX_PDU_TYPE_RESPONSE: 720 return "agentx-Response-PDU"; 721 } 722 snprintf(buffer, sizeof(buffer), "Unknown type: %d", type); 723 return buffer; 724 } 725 726 const char * 727 agentx_closereason2string(enum agentx_close_reason reason) 728 { 729 static char buffer[64]; 730 731 switch (reason) { 732 case AGENTX_CLOSE_OTHER: 733 return "Undefined reason"; 734 case AGENTX_CLOSEN_PARSEERROR: 735 return "Too many AgentX parse errors from peer"; 736 case AGENTX_CLOSE_PROTOCOLERROR: 737 return "Too many AgentX protocol errors from peer"; 738 case AGENTX_CLOSE_TIMEOUTS: 739 return "Too many timeouts waiting for peer"; 740 case AGENTX_CLOSE_SHUTDOWN: 741 return "shutting down"; 742 case AGENTX_CLOSE_BYMANAGER: 743 return "Manager shuts down"; 744 } 745 snprintf(buffer, sizeof(buffer), "Unknown reason: %d", reason); 746 return buffer; 747 } 748 749 const char * 750 agentx_oid2string(struct agentx_oid *oid) 751 { 752 return agentx_oidrange2string(oid, 0, 0); 753 } 754 755 const char * 756 agentx_oidrange2string(struct agentx_oid *oid, uint8_t range_subid, 757 uint32_t upperbound) 758 { 759 static char buf[1024]; 760 char *p; 761 size_t i, rest; 762 int ret; 763 764 rest = sizeof(buf); 765 p = buf; 766 for (i = 0; i < oid->aoi_idlen; i++) { 767 if (range_subid != 0 && range_subid - 1 == (uint8_t)i) 768 ret = snprintf(p, rest, ".[%u-%u]", oid->aoi_id[i], 769 upperbound); 770 else 771 ret = snprintf(p, rest, ".%u", oid->aoi_id[i]); 772 if ((size_t) ret >= rest) { 773 snprintf(buf, sizeof(buf), "Couldn't parse oid"); 774 return buf; 775 } 776 p += ret; 777 rest -= (size_t) ret; 778 } 779 return buf; 780 } 781 782 const char * 783 agentx_varbind2string(struct agentx_varbind *vb) 784 { 785 static char buf[1024]; 786 char tmpbuf[1024]; 787 size_t i, bufleft; 788 int ishex = 0; 789 char *p; 790 int ret; 791 792 switch (vb->avb_type) { 793 case AGENTX_DATA_TYPE_INTEGER: 794 snprintf(buf, sizeof(buf), "%s: (int)%u", 795 agentx_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32); 796 break; 797 case AGENTX_DATA_TYPE_OCTETSTRING: 798 for (i = 0; 799 i < vb->avb_data.avb_ostring.aos_slen && !ishex; i++) { 800 if (!isprint(vb->avb_data.avb_ostring.aos_string[i])) 801 ishex = 1; 802 } 803 if (ishex) { 804 p = tmpbuf; 805 bufleft = sizeof(tmpbuf); 806 for (i = 0; 807 i < vb->avb_data.avb_ostring.aos_slen; i++) { 808 ret = snprintf(p, bufleft, " %02hhX", 809 vb->avb_data.avb_ostring.aos_string[i]); 810 if (ret >= (int) bufleft) { 811 p = strrchr(p, ' '); 812 strlcpy(p, "...", 4); 813 break; 814 } 815 p += 3; 816 bufleft -= 3; 817 } 818 ret = snprintf(buf, sizeof(buf), "%s: (hex-string)%s", 819 agentx_oid2string(&(vb->avb_oid)), tmpbuf); 820 if (ret >= (int) sizeof(buf)) { 821 p = strrchr(buf, ' '); 822 strlcpy(p, "...", 4); 823 } 824 } else { 825 ret = snprintf(buf, sizeof(buf), "%s: (string)", 826 agentx_oid2string(&(vb->avb_oid))); 827 if (ret >= (int) sizeof(buf)) { 828 snprintf(buf, sizeof(buf), "<too large OID>: " 829 "(string)<too large string>"); 830 break; 831 } 832 p = buf + ret; 833 bufleft = (int) sizeof(buf) - ret; 834 if (snprintf(p, bufleft, "%.*s", 835 vb->avb_data.avb_ostring.aos_slen, 836 vb->avb_data.avb_ostring.aos_string) >= 837 (int) bufleft) { 838 p = buf + sizeof(buf) - 4; 839 strlcpy(p, "...", 4); 840 } 841 } 842 break; 843 case AGENTX_DATA_TYPE_NULL: 844 snprintf(buf, sizeof(buf), "%s: <null>", 845 agentx_oid2string(&(vb->avb_oid))); 846 break; 847 case AGENTX_DATA_TYPE_OID: 848 strlcpy(tmpbuf, 849 agentx_oid2string(&(vb->avb_data.avb_oid)), sizeof(tmpbuf)); 850 snprintf(buf, sizeof(buf), "%s: (oid)%s", 851 agentx_oid2string(&(vb->avb_oid)), tmpbuf); 852 break; 853 case AGENTX_DATA_TYPE_IPADDRESS: 854 if (vb->avb_data.avb_ostring.aos_slen != 4) { 855 snprintf(buf, sizeof(buf), "%s: (ipaddress)<invalid>", 856 agentx_oid2string(&(vb->avb_oid))); 857 break; 858 } 859 if (inet_ntop(PF_INET, vb->avb_data.avb_ostring.aos_string, 860 tmpbuf, sizeof(tmpbuf)) == NULL) { 861 snprintf(buf, sizeof(buf), "%s: (ipaddress)" 862 "<unparseable>: %s", 863 agentx_oid2string(&(vb->avb_oid)), 864 strerror(errno)); 865 break; 866 } 867 snprintf(buf, sizeof(buf), "%s: (ipaddress)%s", 868 agentx_oid2string(&(vb->avb_oid)), tmpbuf); 869 break; 870 case AGENTX_DATA_TYPE_COUNTER32: 871 snprintf(buf, sizeof(buf), "%s: (counter32)%u", 872 agentx_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32); 873 break; 874 case AGENTX_DATA_TYPE_GAUGE32: 875 snprintf(buf, sizeof(buf), "%s: (gauge32)%u", 876 agentx_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32); 877 break; 878 case AGENTX_DATA_TYPE_TIMETICKS: 879 snprintf(buf, sizeof(buf), "%s: (timeticks)%u", 880 agentx_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32); 881 break; 882 case AGENTX_DATA_TYPE_OPAQUE: 883 p = tmpbuf; 884 bufleft = sizeof(tmpbuf); 885 for (i = 0; 886 i < vb->avb_data.avb_ostring.aos_slen; i++) { 887 ret = snprintf(p, bufleft, " %02hhX", 888 vb->avb_data.avb_ostring.aos_string[i]); 889 if (ret >= (int) bufleft) { 890 p = strrchr(p, ' '); 891 strlcpy(p, "...", 4); 892 break; 893 } 894 p += 3; 895 bufleft -= 3; 896 } 897 ret = snprintf(buf, sizeof(buf), "%s: (opaque)%s", 898 agentx_oid2string(&(vb->avb_oid)), tmpbuf); 899 if (ret >= (int) sizeof(buf)) { 900 p = strrchr(buf, ' '); 901 strlcpy(p, "...", 4); 902 } 903 break; 904 case AGENTX_DATA_TYPE_COUNTER64: 905 snprintf(buf, sizeof(buf), "%s: (counter64)%"PRIu64, 906 agentx_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint64); 907 break; 908 case AGENTX_DATA_TYPE_NOSUCHOBJECT: 909 snprintf(buf, sizeof(buf), "%s: <noSuchObject>", 910 agentx_oid2string(&(vb->avb_oid))); 911 break; 912 case AGENTX_DATA_TYPE_NOSUCHINSTANCE: 913 snprintf(buf, sizeof(buf), "%s: <noSuchInstance>", 914 agentx_oid2string(&(vb->avb_oid))); 915 break; 916 case AGENTX_DATA_TYPE_ENDOFMIBVIEW: 917 snprintf(buf, sizeof(buf), "%s: <endOfMibView>", 918 agentx_oid2string(&(vb->avb_oid))); 919 break; 920 } 921 return buf; 922 } 923 924 int 925 agentx_oid_cmp(struct agentx_oid *o1, struct agentx_oid *o2) 926 { 927 size_t i, min; 928 929 min = o1->aoi_idlen < o2->aoi_idlen ? o1->aoi_idlen : o2->aoi_idlen; 930 for (i = 0; i < min; i++) { 931 if (o1->aoi_id[i] < o2->aoi_id[i]) 932 return -1; 933 if (o1->aoi_id[i] > o2->aoi_id[i]) 934 return 1; 935 } 936 /* o1 is parent of o2 */ 937 if (o1->aoi_idlen < o2->aoi_idlen) 938 return -2; 939 /* o1 is child of o2 */ 940 if (o1->aoi_idlen > o2->aoi_idlen) 941 return 2; 942 return 0; 943 } 944 945 int 946 agentx_oid_add(struct agentx_oid *oid, uint32_t value) 947 { 948 if (oid->aoi_idlen == AGENTX_OID_MAX_LEN) 949 return -1; 950 oid->aoi_id[oid->aoi_idlen++] = value; 951 return 0; 952 } 953 954 static uint32_t 955 agentx_pdu_queue(struct agentx *ax) 956 { 957 struct agentx_pdu_header header; 958 uint32_t packetid, plength; 959 size_t wbtlen = ax->ax_wbtlen; 960 961 header.aph_flags = ax->ax_byteorder == AGENTX_BYTE_ORDER_BE ? 962 AGENTX_PDU_FLAG_NETWORK_BYTE_ORDER : 0; 963 packetid = agentx_pdutoh32(&header, &(ax->ax_wbuf[ax->ax_wblen + 12])); 964 plength = (ax->ax_wbtlen - ax->ax_wblen) - AGENTX_PDU_HEADER; 965 ax->ax_wbtlen = ax->ax_wblen + 16; 966 (void)agentx_pdu_add_uint32(ax, plength); 967 968 ax->ax_wblen = ax->ax_wbtlen = wbtlen; 969 970 return packetid; 971 } 972 973 static int 974 agentx_pdu_header(struct agentx *ax, enum agentx_pdu_type type, uint8_t flags, 975 uint32_t sessionid, uint32_t transactionid, uint32_t packetid, 976 struct agentx_ostring *context) 977 { 978 if (ax->ax_wblen != ax->ax_wbtlen) { 979 errno = EALREADY; 980 return -1; 981 } 982 983 ax->ax_wbtlen = ax->ax_wblen; 984 if (agentx_pdu_need(ax, 4) == -1) 985 return -1; 986 ax->ax_wbuf[ax->ax_wbtlen++] = 1; 987 ax->ax_wbuf[ax->ax_wbtlen++] = (uint8_t) type; 988 if (context != NULL) 989 flags |= AGENTX_PDU_FLAG_NON_DEFAULT_CONTEXT; 990 if (ax->ax_byteorder == AGENTX_BYTE_ORDER_BE) 991 flags |= AGENTX_PDU_FLAG_NETWORK_BYTE_ORDER; 992 ax->ax_wbuf[ax->ax_wbtlen++] = flags; 993 ax->ax_wbuf[ax->ax_wbtlen++] = 0; 994 if (packetid == 0) 995 packetid = agentx_packetid(ax); 996 if (agentx_pdu_add_uint32(ax, sessionid) == -1 || 997 agentx_pdu_add_uint32(ax, transactionid) == -1 || 998 agentx_pdu_add_uint32(ax, packetid) == -1 || 999 agentx_pdu_need(ax, 4) == -1) 1000 return -1; 1001 ax->ax_wbtlen += 4; 1002 if (context != NULL) { 1003 if (agentx_pdu_add_str(ax, context) == -1) 1004 return -1; 1005 } 1006 1007 return 0; 1008 } 1009 1010 static uint32_t 1011 agentx_packetid(struct agentx *ax) 1012 { 1013 uint32_t packetid, *packetids; 1014 size_t npackets = 0, i; 1015 int found; 1016 1017 if (ax->ax_packetids != NULL) { 1018 for (npackets = 0; ax->ax_packetids[npackets] != 0; npackets++) 1019 continue; 1020 } 1021 if (ax->ax_packetidsize == 0 || npackets == ax->ax_packetidsize - 1) { 1022 packetids = recallocarray(ax->ax_packetids, ax->ax_packetidsize, 1023 ax->ax_packetidsize + 25, sizeof(*packetids)); 1024 if (packetids == NULL) 1025 return 0; 1026 ax->ax_packetidsize += 25; 1027 ax->ax_packetids = packetids; 1028 } 1029 do { 1030 found = 0; 1031 packetid = arc4random(); 1032 for (i = 0; ax->ax_packetids[i] != 0; i++) { 1033 if (ax->ax_packetids[i] == packetid) { 1034 found = 1; 1035 break; 1036 } 1037 } 1038 } while (packetid == 0 || found); 1039 ax->ax_packetids[npackets] = packetid; 1040 1041 return packetid; 1042 } 1043 1044 static int 1045 agentx_pdu_add_uint16(struct agentx *ax, uint16_t value) 1046 { 1047 if (agentx_pdu_need(ax, sizeof(value)) == -1) 1048 return -1; 1049 1050 if (ax->ax_byteorder == AGENTX_BYTE_ORDER_BE) 1051 value = htobe16(value); 1052 else 1053 value = htole16(value); 1054 memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value)); 1055 ax->ax_wbtlen += sizeof(value); 1056 return 0; 1057 } 1058 1059 static int 1060 agentx_pdu_add_uint32(struct agentx *ax, uint32_t value) 1061 { 1062 if (agentx_pdu_need(ax, sizeof(value)) == -1) 1063 return -1; 1064 1065 if (ax->ax_byteorder == AGENTX_BYTE_ORDER_BE) 1066 value = htobe32(value); 1067 else 1068 value = htole32(value); 1069 memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value)); 1070 ax->ax_wbtlen += sizeof(value); 1071 return 0; 1072 } 1073 1074 static int 1075 agentx_pdu_add_uint64(struct agentx *ax, uint64_t value) 1076 { 1077 if (agentx_pdu_need(ax, sizeof(value)) == -1) 1078 return -1; 1079 1080 if (ax->ax_byteorder == AGENTX_BYTE_ORDER_BE) 1081 value = htobe64(value); 1082 else 1083 value = htole64(value); 1084 memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value)); 1085 ax->ax_wbtlen += sizeof(value); 1086 return 0; 1087 } 1088 1089 1090 static int 1091 agentx_pdu_add_oid(struct agentx *ax, struct agentx_oid *oid, int include) 1092 { 1093 static struct agentx_oid nulloid = {0}; 1094 uint8_t prefix = 0, n_subid, i = 0; 1095 1096 n_subid = oid->aoi_idlen; 1097 1098 if (oid == NULL) 1099 oid = &nulloid; 1100 1101 if (oid->aoi_idlen > 4 && 1102 oid->aoi_id[0] == 1 && oid->aoi_id[1] == 3 && 1103 oid->aoi_id[2] == 6 && oid->aoi_id[3] == 1 && 1104 oid->aoi_id[4] <= UINT8_MAX) { 1105 prefix = oid->aoi_id[4]; 1106 i = 5; 1107 } 1108 1109 if (agentx_pdu_need(ax, 4) == -1) 1110 return -1; 1111 ax->ax_wbuf[ax->ax_wbtlen++] = n_subid - i; 1112 ax->ax_wbuf[ax->ax_wbtlen++] = prefix; 1113 ax->ax_wbuf[ax->ax_wbtlen++] = !!include; 1114 ax->ax_wbuf[ax->ax_wbtlen++] = 0; 1115 1116 for (; i < n_subid; i++) { 1117 if (agentx_pdu_add_uint32(ax, oid->aoi_id[i]) == -1) 1118 return -1; 1119 } 1120 1121 return 0; 1122 } 1123 1124 static int 1125 agentx_pdu_add_str(struct agentx *ax, struct agentx_ostring *str) 1126 { 1127 size_t length, zeroes; 1128 1129 if (agentx_pdu_add_uint32(ax, str->aos_slen) == -1) 1130 return -1; 1131 1132 if ((zeroes = (4 - (str->aos_slen % 4))) == 4) 1133 zeroes = 0; 1134 length = str->aos_slen + zeroes; 1135 if (agentx_pdu_need(ax, length) == -1) 1136 return -1; 1137 1138 memcpy(&(ax->ax_wbuf[ax->ax_wbtlen]), str->aos_string, str->aos_slen); 1139 ax->ax_wbtlen += str->aos_slen; 1140 memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, zeroes); 1141 ax->ax_wbtlen += zeroes; 1142 return 0; 1143 } 1144 1145 static int 1146 agentx_pdu_add_varbindlist(struct agentx *ax, 1147 struct agentx_varbind *vblist, size_t nvb) 1148 { 1149 size_t i; 1150 uint16_t temp; 1151 1152 for (i = 0; i < nvb; i++) { 1153 temp = (uint16_t) vblist[i].avb_type; 1154 if (agentx_pdu_add_uint16(ax, temp) == -1 || 1155 agentx_pdu_need(ax, 2)) 1156 return -1; 1157 memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, 2); 1158 ax->ax_wbtlen += 2; 1159 if (agentx_pdu_add_oid(ax, &(vblist[i].avb_oid), 0) == -1) 1160 return -1; 1161 switch (vblist[i].avb_type) { 1162 case AGENTX_DATA_TYPE_INTEGER: 1163 case AGENTX_DATA_TYPE_COUNTER32: 1164 case AGENTX_DATA_TYPE_GAUGE32: 1165 case AGENTX_DATA_TYPE_TIMETICKS: 1166 if (agentx_pdu_add_uint32(ax, 1167 vblist[i].avb_data.avb_uint32) == -1) 1168 return -1; 1169 break; 1170 case AGENTX_DATA_TYPE_COUNTER64: 1171 if (agentx_pdu_add_uint64(ax, 1172 vblist[i].avb_data.avb_uint64) == -1) 1173 return -1; 1174 break; 1175 case AGENTX_DATA_TYPE_OCTETSTRING: 1176 case AGENTX_DATA_TYPE_IPADDRESS: 1177 case AGENTX_DATA_TYPE_OPAQUE: 1178 if (agentx_pdu_add_str(ax, 1179 &(vblist[i].avb_data.avb_ostring)) == -1) 1180 return -1; 1181 break; 1182 case AGENTX_DATA_TYPE_OID: 1183 if (agentx_pdu_add_oid(ax, 1184 &(vblist[i].avb_data.avb_oid), 1) == -1) 1185 return -1; 1186 break; 1187 case AGENTX_DATA_TYPE_NULL: 1188 case AGENTX_DATA_TYPE_NOSUCHOBJECT: 1189 case AGENTX_DATA_TYPE_NOSUCHINSTANCE: 1190 case AGENTX_DATA_TYPE_ENDOFMIBVIEW: 1191 break; 1192 default: 1193 errno = EINVAL; 1194 return -1; 1195 } 1196 } 1197 return 0; 1198 } 1199 1200 static uint16_t 1201 agentx_pdutoh16(struct agentx_pdu_header *header, uint8_t *buf) 1202 { 1203 uint16_t value; 1204 1205 memcpy(&value, buf, sizeof(value)); 1206 if (header->aph_flags & AGENTX_PDU_FLAG_NETWORK_BYTE_ORDER) 1207 return be16toh(value); 1208 return le16toh(value); 1209 } 1210 1211 static uint32_t 1212 agentx_pdutoh32(struct agentx_pdu_header *header, uint8_t *buf) 1213 { 1214 uint32_t value; 1215 1216 memcpy(&value, buf, sizeof(value)); 1217 if (header->aph_flags & AGENTX_PDU_FLAG_NETWORK_BYTE_ORDER) 1218 return be32toh(value); 1219 return le32toh(value); 1220 } 1221 1222 static uint64_t 1223 agentx_pdutoh64(struct agentx_pdu_header *header, uint8_t *buf) 1224 { 1225 uint64_t value; 1226 1227 memcpy(&value, buf, sizeof(value)); 1228 if (header->aph_flags & AGENTX_PDU_FLAG_NETWORK_BYTE_ORDER) 1229 return be64toh(value); 1230 return le64toh(value); 1231 } 1232 1233 static ssize_t 1234 agentx_pdutooid(struct agentx_pdu_header *header, struct agentx_oid *oid, 1235 uint8_t *buf, size_t rawlen) 1236 { 1237 size_t i = 0; 1238 ssize_t nread; 1239 1240 if (rawlen < 4) 1241 goto fail; 1242 rawlen -= 4; 1243 nread = 4; 1244 oid->aoi_idlen = *buf++; 1245 if (rawlen < (oid->aoi_idlen * 4)) 1246 goto fail; 1247 nread += oid->aoi_idlen * 4; 1248 if (*buf != 0) { 1249 oid->aoi_id[0] = 1; 1250 oid->aoi_id[1] = 3; 1251 oid->aoi_id[2] = 6; 1252 oid->aoi_id[3] = 1; 1253 oid->aoi_id[4] = *buf; 1254 oid->aoi_idlen += 5; 1255 i = 5; 1256 } 1257 buf++; 1258 oid->aoi_include = *buf; 1259 for (buf += 2; i < oid->aoi_idlen; i++, buf += 4) 1260 oid->aoi_id[i] = agentx_pdutoh32(header, buf); 1261 1262 return nread; 1263 1264 fail: 1265 errno = EPROTO; 1266 return -1; 1267 } 1268 1269 static ssize_t 1270 agentx_pdutoostring(struct agentx_pdu_header *header, 1271 struct agentx_ostring *ostring, uint8_t *buf, size_t rawlen) 1272 { 1273 ssize_t nread; 1274 1275 if (rawlen < 4) 1276 goto fail; 1277 1278 ostring->aos_slen = agentx_pdutoh32(header, buf); 1279 rawlen -= 4; 1280 buf += 4; 1281 if (ostring->aos_slen > rawlen) 1282 goto fail; 1283 if ((ostring->aos_string = malloc(ostring->aos_slen + 1)) == NULL) 1284 return -1; 1285 memcpy(ostring->aos_string, buf, ostring->aos_slen); 1286 ostring->aos_string[ostring->aos_slen] = '\0'; 1287 1288 nread = 4 + ostring->aos_slen; 1289 if (ostring->aos_slen % 4 != 0) 1290 nread += 4 - (ostring->aos_slen % 4); 1291 1292 return nread; 1293 1294 fail: 1295 errno = EPROTO; 1296 return -1; 1297 } 1298 1299 static ssize_t 1300 agentx_pdutovarbind(struct agentx_pdu_header *header, 1301 struct agentx_varbind *varbind, uint8_t *buf, size_t rawlen) 1302 { 1303 ssize_t nread, rread = 4; 1304 1305 if (rawlen == 0) 1306 return 0; 1307 1308 if (rawlen < 8) 1309 goto fail; 1310 varbind->avb_type = agentx_pdutoh16(header, buf); 1311 1312 buf += 4; 1313 rawlen -= 4; 1314 nread = agentx_pdutooid(header, &(varbind->avb_oid), buf, rawlen); 1315 if (nread == -1) 1316 return -1; 1317 rread += nread; 1318 buf += nread; 1319 rawlen -= nread; 1320 1321 switch(varbind->avb_type) { 1322 case AGENTX_DATA_TYPE_INTEGER: 1323 case AGENTX_DATA_TYPE_COUNTER32: 1324 case AGENTX_DATA_TYPE_GAUGE32: 1325 case AGENTX_DATA_TYPE_TIMETICKS: 1326 if (rawlen < 4) 1327 goto fail; 1328 varbind->avb_data.avb_uint32 = agentx_pdutoh32(header, buf); 1329 return rread + 4; 1330 case AGENTX_DATA_TYPE_COUNTER64: 1331 if (rawlen < 8) 1332 goto fail; 1333 varbind->avb_data.avb_uint64 = agentx_pdutoh64(header, buf); 1334 return rread + 8; 1335 case AGENTX_DATA_TYPE_OCTETSTRING: 1336 case AGENTX_DATA_TYPE_IPADDRESS: 1337 case AGENTX_DATA_TYPE_OPAQUE: 1338 nread = agentx_pdutoostring(header, 1339 &(varbind->avb_data.avb_ostring), buf, rawlen); 1340 if (nread == -1) 1341 return -1; 1342 return nread + rread; 1343 case AGENTX_DATA_TYPE_OID: 1344 nread = agentx_pdutooid(header, &(varbind->avb_data.avb_oid), 1345 buf, rawlen); 1346 if (nread == -1) 1347 return -1; 1348 return nread + rread; 1349 case AGENTX_DATA_TYPE_NULL: 1350 case AGENTX_DATA_TYPE_NOSUCHOBJECT: 1351 case AGENTX_DATA_TYPE_NOSUCHINSTANCE: 1352 case AGENTX_DATA_TYPE_ENDOFMIBVIEW: 1353 return rread; 1354 } 1355 1356 fail: 1357 errno = EPROTO; 1358 return -1; 1359 } 1360