1 /* $OpenBSD: ax.c,v 1.8 2021/10/24 17:43:38 martijn 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 if (oid->aoi_idlen == 0) 768 (void)strlcpy(buf, "null", sizeof(buf)); 769 for (i = 0; i < oid->aoi_idlen; i++) { 770 if (range_subid != 0 && range_subid - 1 == (uint8_t)i) 771 ret = snprintf(p, rest, ".[%u-%u]", oid->aoi_id[i], 772 upperbound); 773 else 774 ret = snprintf(p, rest, ".%u", oid->aoi_id[i]); 775 if ((size_t) ret >= rest) { 776 snprintf(buf, sizeof(buf), "Couldn't parse oid"); 777 return buf; 778 } 779 p += ret; 780 rest -= (size_t) ret; 781 } 782 return buf; 783 } 784 785 const char * 786 ax_varbind2string(struct ax_varbind *vb) 787 { 788 static char buf[1024]; 789 char tmpbuf[1024]; 790 size_t i, bufleft; 791 int ishex = 0; 792 char *p; 793 int ret; 794 795 switch (vb->avb_type) { 796 case AX_DATA_TYPE_INTEGER: 797 snprintf(buf, sizeof(buf), "%s: (int)%d", 798 ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_int32); 799 break; 800 case AX_DATA_TYPE_OCTETSTRING: 801 for (i = 0; 802 i < vb->avb_data.avb_ostring.aos_slen && !ishex; i++) { 803 if (!isprint(vb->avb_data.avb_ostring.aos_string[i])) 804 ishex = 1; 805 } 806 if (ishex) { 807 p = tmpbuf; 808 bufleft = sizeof(tmpbuf); 809 for (i = 0; 810 i < vb->avb_data.avb_ostring.aos_slen; i++) { 811 ret = snprintf(p, bufleft, " %02hhX", 812 vb->avb_data.avb_ostring.aos_string[i]); 813 if (ret >= (int) bufleft) { 814 p = strrchr(p, ' '); 815 strlcpy(p, "...", 4); 816 break; 817 } 818 p += 3; 819 bufleft -= 3; 820 } 821 ret = snprintf(buf, sizeof(buf), "%s: (hex-string)%s", 822 ax_oid2string(&(vb->avb_oid)), tmpbuf); 823 if (ret >= (int) sizeof(buf)) { 824 p = strrchr(buf, ' '); 825 strlcpy(p, "...", 4); 826 } 827 } else { 828 ret = snprintf(buf, sizeof(buf), "%s: (string)", 829 ax_oid2string(&(vb->avb_oid))); 830 if (ret >= (int) sizeof(buf)) { 831 snprintf(buf, sizeof(buf), "<too large OID>: " 832 "(string)<too large string>"); 833 break; 834 } 835 p = buf + ret; 836 bufleft = (int) sizeof(buf) - ret; 837 if (snprintf(p, bufleft, "%.*s", 838 vb->avb_data.avb_ostring.aos_slen, 839 vb->avb_data.avb_ostring.aos_string) >= 840 (int) bufleft) { 841 p = buf + sizeof(buf) - 4; 842 strlcpy(p, "...", 4); 843 } 844 } 845 break; 846 case AX_DATA_TYPE_NULL: 847 snprintf(buf, sizeof(buf), "%s: <null>", 848 ax_oid2string(&(vb->avb_oid))); 849 break; 850 case AX_DATA_TYPE_OID: 851 strlcpy(tmpbuf, 852 ax_oid2string(&(vb->avb_data.avb_oid)), sizeof(tmpbuf)); 853 snprintf(buf, sizeof(buf), "%s: (oid)%s", 854 ax_oid2string(&(vb->avb_oid)), tmpbuf); 855 break; 856 case AX_DATA_TYPE_IPADDRESS: 857 if (vb->avb_data.avb_ostring.aos_slen != 4) { 858 snprintf(buf, sizeof(buf), "%s: (ipaddress)<invalid>", 859 ax_oid2string(&(vb->avb_oid))); 860 break; 861 } 862 if (inet_ntop(PF_INET, vb->avb_data.avb_ostring.aos_string, 863 tmpbuf, sizeof(tmpbuf)) == NULL) { 864 snprintf(buf, sizeof(buf), "%s: (ipaddress)" 865 "<unparseable>: %s", 866 ax_oid2string(&(vb->avb_oid)), 867 strerror(errno)); 868 break; 869 } 870 snprintf(buf, sizeof(buf), "%s: (ipaddress)%s", 871 ax_oid2string(&(vb->avb_oid)), tmpbuf); 872 break; 873 case AX_DATA_TYPE_COUNTER32: 874 snprintf(buf, sizeof(buf), "%s: (counter32)%u", 875 ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32); 876 break; 877 case AX_DATA_TYPE_GAUGE32: 878 snprintf(buf, sizeof(buf), "%s: (gauge32)%u", 879 ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32); 880 break; 881 case AX_DATA_TYPE_TIMETICKS: 882 snprintf(buf, sizeof(buf), "%s: (timeticks)%u", 883 ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32); 884 break; 885 case AX_DATA_TYPE_OPAQUE: 886 p = tmpbuf; 887 bufleft = sizeof(tmpbuf); 888 for (i = 0; 889 i < vb->avb_data.avb_ostring.aos_slen; i++) { 890 ret = snprintf(p, bufleft, " %02hhX", 891 vb->avb_data.avb_ostring.aos_string[i]); 892 if (ret >= (int) bufleft) { 893 p = strrchr(p, ' '); 894 strlcpy(p, "...", 4); 895 break; 896 } 897 p += 3; 898 bufleft -= 3; 899 } 900 ret = snprintf(buf, sizeof(buf), "%s: (opaque)%s", 901 ax_oid2string(&(vb->avb_oid)), tmpbuf); 902 if (ret >= (int) sizeof(buf)) { 903 p = strrchr(buf, ' '); 904 strlcpy(p, "...", 4); 905 } 906 break; 907 case AX_DATA_TYPE_COUNTER64: 908 snprintf(buf, sizeof(buf), "%s: (counter64)%"PRIu64, 909 ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint64); 910 break; 911 case AX_DATA_TYPE_NOSUCHOBJECT: 912 snprintf(buf, sizeof(buf), "%s: <noSuchObject>", 913 ax_oid2string(&(vb->avb_oid))); 914 break; 915 case AX_DATA_TYPE_NOSUCHINSTANCE: 916 snprintf(buf, sizeof(buf), "%s: <noSuchInstance>", 917 ax_oid2string(&(vb->avb_oid))); 918 break; 919 case AX_DATA_TYPE_ENDOFMIBVIEW: 920 snprintf(buf, sizeof(buf), "%s: <endOfMibView>", 921 ax_oid2string(&(vb->avb_oid))); 922 break; 923 } 924 return buf; 925 } 926 927 int 928 ax_oid_cmp(struct ax_oid *o1, struct ax_oid *o2) 929 { 930 size_t i, min; 931 932 min = o1->aoi_idlen < o2->aoi_idlen ? o1->aoi_idlen : o2->aoi_idlen; 933 for (i = 0; i < min; i++) { 934 if (o1->aoi_id[i] < o2->aoi_id[i]) 935 return -1; 936 if (o1->aoi_id[i] > o2->aoi_id[i]) 937 return 1; 938 } 939 /* o1 is parent of o2 */ 940 if (o1->aoi_idlen < o2->aoi_idlen) 941 return -2; 942 /* o1 is child of o2 */ 943 if (o1->aoi_idlen > o2->aoi_idlen) 944 return 2; 945 return 0; 946 } 947 948 int 949 ax_oid_add(struct ax_oid *oid, uint32_t value) 950 { 951 if (oid->aoi_idlen == AX_OID_MAX_LEN) 952 return -1; 953 oid->aoi_id[oid->aoi_idlen++] = value; 954 return 0; 955 } 956 957 static uint32_t 958 ax_pdu_queue(struct ax *ax) 959 { 960 struct ax_pdu_header header; 961 uint32_t packetid, plength; 962 size_t wbtlen = ax->ax_wbtlen; 963 964 header.aph_flags = ax->ax_byteorder == AX_BYTE_ORDER_BE ? 965 AX_PDU_FLAG_NETWORK_BYTE_ORDER : 0; 966 packetid = ax_pdutoh32(&header, &(ax->ax_wbuf[ax->ax_wblen + 12])); 967 plength = (ax->ax_wbtlen - ax->ax_wblen) - AX_PDU_HEADER; 968 ax->ax_wbtlen = ax->ax_wblen + 16; 969 (void)ax_pdu_add_uint32(ax, plength); 970 971 ax->ax_wblen = ax->ax_wbtlen = wbtlen; 972 973 return packetid; 974 } 975 976 static int 977 ax_pdu_header(struct ax *ax, enum ax_pdu_type type, uint8_t flags, 978 uint32_t sessionid, uint32_t transactionid, uint32_t packetid, 979 struct ax_ostring *context) 980 { 981 if (ax->ax_wblen != ax->ax_wbtlen) { 982 errno = EALREADY; 983 return -1; 984 } 985 986 if (ax_pdu_need(ax, 4) == -1) 987 return -1; 988 ax->ax_wbuf[ax->ax_wbtlen++] = 1; 989 ax->ax_wbuf[ax->ax_wbtlen++] = (uint8_t) type; 990 if (context != NULL) 991 flags |= AX_PDU_FLAG_NON_DEFAULT_CONTEXT; 992 if (ax->ax_byteorder == AX_BYTE_ORDER_BE) 993 flags |= AX_PDU_FLAG_NETWORK_BYTE_ORDER; 994 ax->ax_wbuf[ax->ax_wbtlen++] = flags; 995 ax->ax_wbuf[ax->ax_wbtlen++] = 0; 996 if (packetid == 0) 997 packetid = ax_packetid(ax); 998 if (ax_pdu_add_uint32(ax, sessionid) == -1 || 999 ax_pdu_add_uint32(ax, transactionid) == -1 || 1000 ax_pdu_add_uint32(ax, packetid) == -1 || 1001 ax_pdu_need(ax, 4) == -1) 1002 return -1; 1003 ax->ax_wbtlen += 4; 1004 if (context != NULL) { 1005 if (ax_pdu_add_str(ax, context) == -1) 1006 return -1; 1007 } 1008 1009 return 0; 1010 } 1011 1012 static uint32_t 1013 ax_packetid(struct ax *ax) 1014 { 1015 uint32_t packetid, *packetids; 1016 size_t npackets = 0, i; 1017 int found; 1018 1019 if (ax->ax_packetids != NULL) { 1020 for (npackets = 0; ax->ax_packetids[npackets] != 0; npackets++) 1021 continue; 1022 } 1023 if (ax->ax_packetidsize == 0 || npackets == ax->ax_packetidsize - 1) { 1024 packetids = recallocarray(ax->ax_packetids, ax->ax_packetidsize, 1025 ax->ax_packetidsize + 25, sizeof(*packetids)); 1026 if (packetids == NULL) 1027 return 0; 1028 ax->ax_packetidsize += 25; 1029 ax->ax_packetids = packetids; 1030 } 1031 do { 1032 found = 0; 1033 packetid = arc4random(); 1034 for (i = 0; ax->ax_packetids[i] != 0; i++) { 1035 if (ax->ax_packetids[i] == packetid) { 1036 found = 1; 1037 break; 1038 } 1039 } 1040 } while (packetid == 0 || found); 1041 ax->ax_packetids[npackets] = packetid; 1042 1043 return packetid; 1044 } 1045 1046 static int 1047 ax_pdu_add_uint16(struct ax *ax, uint16_t value) 1048 { 1049 if (ax_pdu_need(ax, sizeof(value)) == -1) 1050 return -1; 1051 1052 if (ax->ax_byteorder == AX_BYTE_ORDER_BE) 1053 value = htobe16(value); 1054 else 1055 value = htole16(value); 1056 memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value)); 1057 ax->ax_wbtlen += sizeof(value); 1058 return 0; 1059 } 1060 1061 static int 1062 ax_pdu_add_uint32(struct ax *ax, uint32_t value) 1063 { 1064 if (ax_pdu_need(ax, sizeof(value)) == -1) 1065 return -1; 1066 1067 if (ax->ax_byteorder == AX_BYTE_ORDER_BE) 1068 value = htobe32(value); 1069 else 1070 value = htole32(value); 1071 memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value)); 1072 ax->ax_wbtlen += sizeof(value); 1073 return 0; 1074 } 1075 1076 static int 1077 ax_pdu_add_uint64(struct ax *ax, uint64_t value) 1078 { 1079 if (ax_pdu_need(ax, sizeof(value)) == -1) 1080 return -1; 1081 1082 if (ax->ax_byteorder == AX_BYTE_ORDER_BE) 1083 value = htobe64(value); 1084 else 1085 value = htole64(value); 1086 memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value)); 1087 ax->ax_wbtlen += sizeof(value); 1088 return 0; 1089 } 1090 1091 1092 static int 1093 ax_pdu_add_oid(struct ax *ax, struct ax_oid *oid, int include) 1094 { 1095 static struct ax_oid nulloid = {0}; 1096 uint8_t prefix = 0, n_subid, i = 0; 1097 1098 n_subid = oid->aoi_idlen; 1099 1100 if (oid == NULL) 1101 oid = &nulloid; 1102 1103 if (oid->aoi_idlen > 4 && 1104 oid->aoi_id[0] == 1 && oid->aoi_id[1] == 3 && 1105 oid->aoi_id[2] == 6 && oid->aoi_id[3] == 1 && 1106 oid->aoi_id[4] <= UINT8_MAX) { 1107 prefix = oid->aoi_id[4]; 1108 i = 5; 1109 } 1110 1111 if (ax_pdu_need(ax, 4) == -1) 1112 return -1; 1113 ax->ax_wbuf[ax->ax_wbtlen++] = n_subid - i; 1114 ax->ax_wbuf[ax->ax_wbtlen++] = prefix; 1115 ax->ax_wbuf[ax->ax_wbtlen++] = !!include; 1116 ax->ax_wbuf[ax->ax_wbtlen++] = 0; 1117 1118 for (; i < n_subid; i++) { 1119 if (ax_pdu_add_uint32(ax, oid->aoi_id[i]) == -1) 1120 return -1; 1121 } 1122 1123 return 0; 1124 } 1125 1126 static int 1127 ax_pdu_add_str(struct ax *ax, struct ax_ostring *str) 1128 { 1129 size_t length, zeroes; 1130 1131 if (ax_pdu_add_uint32(ax, str->aos_slen) == -1) 1132 return -1; 1133 1134 if ((zeroes = (4 - (str->aos_slen % 4))) == 4) 1135 zeroes = 0; 1136 length = str->aos_slen + zeroes; 1137 if (ax_pdu_need(ax, length) == -1) 1138 return -1; 1139 1140 memcpy(&(ax->ax_wbuf[ax->ax_wbtlen]), str->aos_string, str->aos_slen); 1141 ax->ax_wbtlen += str->aos_slen; 1142 memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, zeroes); 1143 ax->ax_wbtlen += zeroes; 1144 return 0; 1145 } 1146 1147 static int 1148 ax_pdu_add_varbindlist(struct ax *ax, 1149 struct ax_varbind *vblist, size_t nvb) 1150 { 1151 size_t i; 1152 uint16_t temp; 1153 1154 for (i = 0; i < nvb; i++) { 1155 temp = (uint16_t) vblist[i].avb_type; 1156 if (ax_pdu_add_uint16(ax, temp) == -1 || 1157 ax_pdu_need(ax, 2)) 1158 return -1; 1159 memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, 2); 1160 ax->ax_wbtlen += 2; 1161 if (ax_pdu_add_oid(ax, &(vblist[i].avb_oid), 0) == -1) 1162 return -1; 1163 switch (vblist[i].avb_type) { 1164 case AX_DATA_TYPE_INTEGER: 1165 if (ax_pdu_add_uint32(ax, 1166 vblist[i].avb_data.avb_int32) == -1) 1167 return -1; 1168 break; 1169 case AX_DATA_TYPE_COUNTER32: 1170 case AX_DATA_TYPE_GAUGE32: 1171 case AX_DATA_TYPE_TIMETICKS: 1172 if (ax_pdu_add_uint32(ax, 1173 vblist[i].avb_data.avb_uint32) == -1) 1174 return -1; 1175 break; 1176 case AX_DATA_TYPE_COUNTER64: 1177 if (ax_pdu_add_uint64(ax, 1178 vblist[i].avb_data.avb_uint64) == -1) 1179 return -1; 1180 break; 1181 case AX_DATA_TYPE_OCTETSTRING: 1182 case AX_DATA_TYPE_IPADDRESS: 1183 case AX_DATA_TYPE_OPAQUE: 1184 if (ax_pdu_add_str(ax, 1185 &(vblist[i].avb_data.avb_ostring)) == -1) 1186 return -1; 1187 break; 1188 case AX_DATA_TYPE_OID: 1189 if (ax_pdu_add_oid(ax, 1190 &(vblist[i].avb_data.avb_oid), 1) == -1) 1191 return -1; 1192 break; 1193 case AX_DATA_TYPE_NULL: 1194 case AX_DATA_TYPE_NOSUCHOBJECT: 1195 case AX_DATA_TYPE_NOSUCHINSTANCE: 1196 case AX_DATA_TYPE_ENDOFMIBVIEW: 1197 break; 1198 default: 1199 errno = EINVAL; 1200 return -1; 1201 } 1202 } 1203 return 0; 1204 } 1205 1206 static uint16_t 1207 ax_pdutoh16(struct ax_pdu_header *header, uint8_t *buf) 1208 { 1209 uint16_t value; 1210 1211 memcpy(&value, buf, sizeof(value)); 1212 if (header->aph_flags & AX_PDU_FLAG_NETWORK_BYTE_ORDER) 1213 return be16toh(value); 1214 return le16toh(value); 1215 } 1216 1217 static uint32_t 1218 ax_pdutoh32(struct ax_pdu_header *header, uint8_t *buf) 1219 { 1220 uint32_t value; 1221 1222 memcpy(&value, buf, sizeof(value)); 1223 if (header->aph_flags & AX_PDU_FLAG_NETWORK_BYTE_ORDER) 1224 return be32toh(value); 1225 return le32toh(value); 1226 } 1227 1228 static uint64_t 1229 ax_pdutoh64(struct ax_pdu_header *header, uint8_t *buf) 1230 { 1231 uint64_t value; 1232 1233 memcpy(&value, buf, sizeof(value)); 1234 if (header->aph_flags & AX_PDU_FLAG_NETWORK_BYTE_ORDER) 1235 return be64toh(value); 1236 return le64toh(value); 1237 } 1238 1239 static ssize_t 1240 ax_pdutooid(struct ax_pdu_header *header, struct ax_oid *oid, 1241 uint8_t *buf, size_t rawlen) 1242 { 1243 size_t i = 0; 1244 ssize_t nread; 1245 1246 if (rawlen < 4) 1247 goto fail; 1248 rawlen -= 4; 1249 nread = 4; 1250 oid->aoi_idlen = *buf++; 1251 if (rawlen < (oid->aoi_idlen * 4)) 1252 goto fail; 1253 nread += oid->aoi_idlen * 4; 1254 if (*buf != 0) { 1255 oid->aoi_id[0] = 1; 1256 oid->aoi_id[1] = 3; 1257 oid->aoi_id[2] = 6; 1258 oid->aoi_id[3] = 1; 1259 oid->aoi_id[4] = *buf; 1260 oid->aoi_idlen += 5; 1261 i = 5; 1262 } 1263 buf++; 1264 oid->aoi_include = *buf; 1265 for (buf += 2; i < oid->aoi_idlen; i++, buf += 4) 1266 oid->aoi_id[i] = ax_pdutoh32(header, buf); 1267 1268 return nread; 1269 1270 fail: 1271 errno = EPROTO; 1272 return -1; 1273 } 1274 1275 static ssize_t 1276 ax_pdutoostring(struct ax_pdu_header *header, 1277 struct ax_ostring *ostring, uint8_t *buf, size_t rawlen) 1278 { 1279 ssize_t nread; 1280 1281 if (rawlen < 4) 1282 goto fail; 1283 1284 ostring->aos_slen = ax_pdutoh32(header, buf); 1285 rawlen -= 4; 1286 buf += 4; 1287 if (ostring->aos_slen > rawlen) 1288 goto fail; 1289 if ((ostring->aos_string = malloc(ostring->aos_slen + 1)) == NULL) 1290 return -1; 1291 memcpy(ostring->aos_string, buf, ostring->aos_slen); 1292 ostring->aos_string[ostring->aos_slen] = '\0'; 1293 1294 nread = 4 + ostring->aos_slen; 1295 if (ostring->aos_slen % 4 != 0) 1296 nread += 4 - (ostring->aos_slen % 4); 1297 1298 return nread; 1299 1300 fail: 1301 errno = EPROTO; 1302 return -1; 1303 } 1304 1305 static ssize_t 1306 ax_pdutovarbind(struct ax_pdu_header *header, 1307 struct ax_varbind *varbind, uint8_t *buf, size_t rawlen) 1308 { 1309 ssize_t nread, rread = 4; 1310 1311 if (rawlen == 0) 1312 return 0; 1313 1314 if (rawlen < 8) 1315 goto fail; 1316 varbind->avb_type = ax_pdutoh16(header, buf); 1317 1318 buf += 4; 1319 rawlen -= 4; 1320 nread = ax_pdutooid(header, &(varbind->avb_oid), buf, rawlen); 1321 if (nread == -1) 1322 return -1; 1323 rread += nread; 1324 buf += nread; 1325 rawlen -= nread; 1326 1327 switch(varbind->avb_type) { 1328 case AX_DATA_TYPE_INTEGER: 1329 if (rawlen < 4) 1330 goto fail; 1331 varbind->avb_data.avb_int32 = ax_pdutoh32(header, buf); 1332 return rread + 4; 1333 case AX_DATA_TYPE_COUNTER32: 1334 case AX_DATA_TYPE_GAUGE32: 1335 case AX_DATA_TYPE_TIMETICKS: 1336 if (rawlen < 4) 1337 goto fail; 1338 varbind->avb_data.avb_uint32 = ax_pdutoh32(header, buf); 1339 return rread + 4; 1340 case AX_DATA_TYPE_COUNTER64: 1341 if (rawlen < 8) 1342 goto fail; 1343 varbind->avb_data.avb_uint64 = ax_pdutoh64(header, buf); 1344 return rread + 8; 1345 case AX_DATA_TYPE_OCTETSTRING: 1346 case AX_DATA_TYPE_IPADDRESS: 1347 case AX_DATA_TYPE_OPAQUE: 1348 nread = ax_pdutoostring(header, 1349 &(varbind->avb_data.avb_ostring), buf, rawlen); 1350 if (nread == -1) 1351 return -1; 1352 return nread + rread; 1353 case AX_DATA_TYPE_OID: 1354 nread = ax_pdutooid(header, &(varbind->avb_data.avb_oid), 1355 buf, rawlen); 1356 if (nread == -1) 1357 return -1; 1358 return nread + rread; 1359 case AX_DATA_TYPE_NULL: 1360 case AX_DATA_TYPE_NOSUCHOBJECT: 1361 case AX_DATA_TYPE_NOSUCHINSTANCE: 1362 case AX_DATA_TYPE_ENDOFMIBVIEW: 1363 return rread; 1364 } 1365 1366 fail: 1367 errno = EPROTO; 1368 return -1; 1369 } 1370