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