1 /* $OpenBSD: ax.c,v 1.6 2024/02/20 12:51:10 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 <unistd.h> 30 31 #include "ax.h" 32 33 #define AX_PDU_HEADER 20 34 35 static int ax_pdu_need(struct ax *, size_t); 36 static int ax_pdu_header(struct ax *, 37 enum ax_pdu_type, uint8_t, uint32_t, uint32_t, uint32_t, 38 struct ax_ostring *); 39 static uint32_t ax_pdu_queue(struct ax *); 40 static int ax_pdu_add_uint16(struct ax *, uint16_t); 41 static int ax_pdu_add_uint32(struct ax *, uint32_t); 42 static int ax_pdu_add_uint64(struct ax *, uint64_t); 43 static int ax_pdu_add_oid(struct ax *, struct ax_oid *); 44 static int ax_pdu_add_str(struct ax *, struct ax_ostring *); 45 static int ax_pdu_add_varbindlist(struct ax *, struct ax_varbind *, 46 size_t); 47 static int ax_pdu_add_searchrange(struct ax *, struct ax_searchrange *); 48 static uint16_t ax_pdutoh16(struct ax_pdu_header *, uint8_t *); 49 static uint32_t ax_pdutoh32(struct ax_pdu_header *, uint8_t *); 50 static uint64_t ax_pdutoh64(struct ax_pdu_header *, uint8_t *); 51 static ssize_t ax_pdutooid(struct ax_pdu_header *, struct ax_oid *, 52 uint8_t *, size_t); 53 static ssize_t ax_pdutoostring(struct ax_pdu_header *, 54 struct ax_ostring *, uint8_t *, size_t); 55 static ssize_t ax_pdutovarbind(struct ax_pdu_header *, 56 struct ax_varbind *, uint8_t *, size_t); 57 58 struct ax * 59 ax_new(int fd) 60 { 61 struct ax *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 ax->ax_rbsize = 512; 72 if ((ax->ax_rbuf = malloc(ax->ax_rbsize)) == NULL) 73 goto fail; 74 ax->ax_byteorder = AX_BYTE_ORDER_NATIVE; 75 76 return ax; 77 78 fail: 79 free(ax); 80 return NULL; 81 } 82 83 void 84 ax_free(struct ax *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); 92 } 93 94 struct ax_pdu * 95 ax_recv(struct ax *ax) 96 { 97 struct ax_pdu *pdu; 98 struct ax_pdu_header header; 99 struct ax_pdu_response *response; 100 struct ax_varbind *varbind; 101 struct ax_pdu_searchrangelist *srl = NULL; 102 struct ax_pdu_varbindlist *vbl; 103 struct ax_searchrange *sr; 104 size_t rbsize, rawlen; 105 ssize_t nread; 106 uint8_t *u8; 107 uint8_t *rbuf; 108 109 /* Only read a single packet at a time to make sure libevent triggers */ 110 if (ax->ax_rblen < AX_PDU_HEADER) { 111 if ((nread = read(ax->ax_fd, ax->ax_rbuf + ax->ax_rblen, 112 AX_PDU_HEADER - ax->ax_rblen)) == 0) { 113 errno = ECONNRESET; 114 return NULL; 115 } 116 if (nread == -1) 117 return NULL; 118 ax->ax_rblen += nread; 119 if (ax->ax_rblen < AX_PDU_HEADER) { 120 errno = EAGAIN; 121 return NULL; 122 } 123 } 124 u8 = ax->ax_rbuf; 125 header.aph_version = *u8++; 126 header.aph_type = *u8++; 127 header.aph_flags = *u8++; 128 u8++; 129 header.aph_sessionid = ax_pdutoh32(&header, u8); 130 u8 += 4; 131 header.aph_transactionid = ax_pdutoh32(&header, u8); 132 u8 += 4; 133 header.aph_packetid = ax_pdutoh32(&header, u8); 134 u8 += 4; 135 header.aph_plength = ax_pdutoh32(&header, u8); 136 137 if (header.aph_version != 1) { 138 errno = EPROTO; 139 return NULL; 140 } 141 if (ax->ax_rblen < AX_PDU_HEADER + header.aph_plength) { 142 if (AX_PDU_HEADER + header.aph_plength > ax->ax_rbsize) { 143 rbsize = (((AX_PDU_HEADER + header.aph_plength) 144 / 512) + 1) * 512; 145 if ((rbuf = recallocarray(ax->ax_rbuf, ax->ax_rbsize, 146 rbsize, sizeof(*rbuf))) == NULL) 147 return NULL; 148 ax->ax_rbsize = rbsize; 149 ax->ax_rbuf = rbuf; 150 } 151 nread = read(ax->ax_fd, ax->ax_rbuf + ax->ax_rblen, 152 header.aph_plength - (ax->ax_rblen - AX_PDU_HEADER)); 153 if (nread == 0) 154 errno = ECONNRESET; 155 if (nread <= 0) 156 return NULL; 157 ax->ax_rblen += nread; 158 if (ax->ax_rblen < AX_PDU_HEADER + header.aph_plength) { 159 errno = EAGAIN; 160 return NULL; 161 } 162 } 163 164 if ((pdu = calloc(1, sizeof(*pdu))) == NULL) 165 return NULL; 166 167 memcpy(&(pdu->ap_header), &header, sizeof(header)); 168 169 #if defined(AX_DEBUG) && defined(AX_DEBUG_VERBOSE) 170 { 171 char chars[4]; 172 int print = 1; 173 174 fprintf(stderr, "received packet:\n"); 175 for (i = 0; i < pdu->ap_header.aph_plength + AX_PDU_HEADER; 176 i++) { 177 fprintf(stderr, "%02hhx ", ax->ax_rbuf[i]); 178 chars[i % 4] = ax->ax_rbuf[i]; 179 if (!isprint(ax->ax_rbuf[i])) 180 print = 0; 181 if (i % 4 == 3) { 182 if (print) 183 fprintf(stderr, "%.4s", chars); 184 fprintf(stderr, "\n"); 185 print = 1; 186 } 187 } 188 } 189 #endif 190 191 u8 = (ax->ax_rbuf) + AX_PDU_HEADER; 192 rawlen = pdu->ap_header.aph_plength; 193 if (pdu->ap_header.aph_flags & AX_PDU_FLAG_NON_DEFAULT_CONTEXT) { 194 nread = ax_pdutoostring(&header, &(pdu->ap_context), u8, 195 rawlen); 196 if (nread == -1) 197 goto fail; 198 rawlen -= nread; 199 u8 += nread; 200 } 201 202 switch (pdu->ap_header.aph_type) { 203 case AX_PDU_TYPE_OPEN: 204 if (rawlen < 12) { 205 errno = EPROTO; 206 goto fail; 207 } 208 pdu->ap_payload.ap_open.ap_timeout = *u8; 209 rawlen -= 4; 210 u8 += 4; 211 if ((nread = ax_pdutooid(&header, 212 &(pdu->ap_payload.ap_open.ap_oid), u8, rawlen)) == -1) 213 goto fail; 214 rawlen -= nread; 215 u8 += nread; 216 if ((nread = ax_pdutoostring(&header, 217 &(pdu->ap_payload.ap_open.ap_descr), u8, rawlen)) == -1) 218 goto fail; 219 if (rawlen - nread != 0) { 220 errno = EPROTO; 221 goto fail; 222 } 223 break; 224 case AX_PDU_TYPE_CLOSE: 225 if (rawlen != 4) { 226 errno = EPROTO; 227 goto fail; 228 } 229 if (u8[0] != AX_CLOSE_OTHER && 230 u8[0] != AX_CLOSEN_PARSEERROR && 231 u8[0] != AX_CLOSE_PROTOCOLERROR && 232 u8[0] != AX_CLOSE_TIMEOUTS && 233 u8[0] != AX_CLOSE_SHUTDOWN && 234 u8[0] != AX_CLOSE_BYMANAGER) { 235 errno = EPROTO; 236 goto fail; 237 } 238 pdu->ap_payload.ap_close.ap_reason = u8[0]; 239 break; 240 case AX_PDU_TYPE_REGISTER: 241 if (rawlen < 8) { 242 errno = EPROTO; 243 goto fail; 244 } 245 pdu->ap_payload.ap_register.ap_timeout = *u8++; 246 pdu->ap_payload.ap_register.ap_priority = *u8++; 247 pdu->ap_payload.ap_register.ap_range_subid = *u8++; 248 u8++; 249 rawlen -= 4; 250 if ((nread = ax_pdutooid(&header, 251 &(pdu->ap_payload.ap_register.ap_subtree), 252 u8, rawlen)) == -1) 253 goto fail; 254 rawlen -= nread; 255 u8 += nread; 256 if (pdu->ap_payload.ap_register.ap_range_subid) { 257 if (rawlen != 4) { 258 errno = EPROTO; 259 goto fail; 260 } 261 pdu->ap_payload.ap_register.ap_upper_bound = 262 ax_pdutoh32(&header, u8); 263 rawlen -= 4; 264 } 265 if (rawlen != 0) { 266 errno = EPROTO; 267 goto fail; 268 } 269 break; 270 case AX_PDU_TYPE_UNREGISTER: 271 if (rawlen < 8) { 272 errno = EPROTO; 273 goto fail; 274 } 275 u8++; 276 pdu->ap_payload.ap_unregister.ap_priority = *u8++; 277 pdu->ap_payload.ap_unregister.ap_range_subid = *u8++; 278 u8++; 279 rawlen -= 4; 280 if ((nread = ax_pdutooid(&header, 281 &(pdu->ap_payload.ap_unregister.ap_subtree), 282 u8, rawlen)) == -1) 283 goto fail; 284 rawlen -= nread; 285 u8 += nread; 286 if (pdu->ap_payload.ap_unregister.ap_range_subid) { 287 if (rawlen != 4) { 288 errno = EPROTO; 289 goto fail; 290 } 291 pdu->ap_payload.ap_unregister.ap_upper_bound = 292 ax_pdutoh32(&header, u8); 293 rawlen -= 4; 294 } 295 if (rawlen != 0) { 296 errno = EPROTO; 297 goto fail; 298 } 299 break; 300 case AX_PDU_TYPE_GETBULK: 301 if (rawlen < 4) { 302 errno = EPROTO; 303 goto fail; 304 } 305 pdu->ap_payload.ap_getbulk.ap_nonrep = 306 ax_pdutoh16(&header, u8); 307 u8 += 2; 308 pdu->ap_payload.ap_getbulk.ap_maxrep = 309 ax_pdutoh16(&header, u8); 310 u8 += 2; 311 srl = &(pdu->ap_payload.ap_getbulk.ap_srl); 312 rawlen -= 4; 313 /* FALLTHROUGH */ 314 case AX_PDU_TYPE_GET: 315 case AX_PDU_TYPE_GETNEXT: 316 if (pdu->ap_header.aph_type != AX_PDU_TYPE_GETBULK) 317 srl = &(pdu->ap_payload.ap_srl); 318 while (rawlen > 0 ) { 319 srl->ap_nsr++; 320 sr = reallocarray(srl->ap_sr, srl->ap_nsr, sizeof(*sr)); 321 if (sr == NULL) 322 goto fail; 323 srl->ap_sr = sr; 324 sr += (srl->ap_nsr - 1); 325 if ((nread = ax_pdutooid(&header, &(sr->asr_start), 326 u8, rawlen)) == -1) 327 goto fail; 328 rawlen -= nread; 329 u8 += nread; 330 if ((nread = ax_pdutooid(&header, &(sr->asr_stop), 331 u8, rawlen)) == -1) 332 goto fail; 333 rawlen -= nread; 334 u8 += nread; 335 } 336 break; 337 case AX_PDU_TYPE_TESTSET: 338 case AX_PDU_TYPE_INDEXALLOCATE: 339 case AX_PDU_TYPE_INDEXDEALLOCATE: 340 case AX_PDU_TYPE_NOTIFY: 341 vbl = &(pdu->ap_payload.ap_vbl); 342 while (rawlen > 0) { 343 varbind = recallocarray(vbl->ap_varbind, 344 vbl->ap_nvarbind, vbl->ap_nvarbind + 1, 345 sizeof(*(vbl->ap_varbind))); 346 if (varbind == NULL) 347 goto fail; 348 vbl->ap_varbind = varbind; 349 nread = ax_pdutovarbind(&header, 350 &(vbl->ap_varbind[vbl->ap_nvarbind]), u8, rawlen); 351 if (nread == -1) 352 goto fail; 353 vbl->ap_nvarbind++; 354 u8 += nread; 355 rawlen -= nread; 356 } 357 break; 358 case AX_PDU_TYPE_COMMITSET: 359 case AX_PDU_TYPE_UNDOSET: 360 case AX_PDU_TYPE_CLEANUPSET: 361 case AX_PDU_TYPE_PING: 362 if (rawlen != 0) { 363 errno = EPROTO; 364 goto fail; 365 } 366 break; 367 case AX_PDU_TYPE_ADDAGENTCAPS: 368 nread = ax_pdutooid(&header, 369 &(pdu->ap_payload.ap_addagentcaps.ap_oid), u8, rawlen); 370 if (nread == -1) 371 goto fail; 372 rawlen -= nread; 373 u8 += nread; 374 nread = ax_pdutoostring(&header, 375 &(pdu->ap_payload.ap_addagentcaps.ap_descr), u8, rawlen); 376 if (nread == -1) 377 goto fail; 378 if (rawlen - nread != 0) { 379 errno = EPROTO; 380 goto fail; 381 } 382 break; 383 case AX_PDU_TYPE_REMOVEAGENTCAPS: 384 nread = ax_pdutooid(&header, 385 &(pdu->ap_payload.ap_removeagentcaps.ap_oid), u8, rawlen); 386 if (nread == -1) 387 goto fail; 388 if (rawlen - nread != 0) { 389 errno = EPROTO; 390 goto fail; 391 } 392 break; 393 case AX_PDU_TYPE_RESPONSE: 394 if (rawlen < 8) { 395 errno = EPROTO; 396 goto fail; 397 } 398 response = &(pdu->ap_payload.ap_response); 399 response->ap_uptime = ax_pdutoh32(&header, u8); 400 u8 += 4; 401 response->ap_error = ax_pdutoh16(&header, u8); 402 u8 += 2; 403 response->ap_index = ax_pdutoh16(&header, u8); 404 u8 += 2; 405 rawlen -= 8; 406 while (rawlen > 0) { 407 varbind = recallocarray(response->ap_varbindlist, 408 response->ap_nvarbind, response->ap_nvarbind + 1, 409 sizeof(*(response->ap_varbindlist))); 410 if (varbind == NULL) 411 goto fail; 412 response->ap_varbindlist = varbind; 413 nread = ax_pdutovarbind(&header, 414 &(response->ap_varbindlist[response->ap_nvarbind]), 415 u8, rawlen); 416 if (nread == -1) 417 goto fail; 418 response->ap_nvarbind++; 419 u8 += nread; 420 rawlen -= nread; 421 } 422 break; 423 default: 424 errno = EPROTO; 425 goto fail; 426 } 427 428 ax->ax_rblen = 0; 429 430 return pdu; 431 fail: 432 ax_pdu_free(pdu); 433 return NULL; 434 } 435 436 static int 437 ax_pdu_need(struct ax *ax, size_t need) 438 { 439 uint8_t *wbuf; 440 size_t wbsize; 441 442 if (ax->ax_wbtlen + need >= ax->ax_wbsize) { 443 wbsize = (((ax->ax_wbtlen + need) / 512) + 1) * 512; 444 wbuf = recallocarray(ax->ax_wbuf, ax->ax_wbsize, wbsize, 1); 445 if (wbuf == NULL) { 446 ax->ax_wbtlen = ax->ax_wblen; 447 return -1; 448 } 449 ax->ax_wbsize = wbsize; 450 ax->ax_wbuf = wbuf; 451 } 452 453 return 0; 454 } 455 456 ssize_t 457 ax_send(struct ax *ax) 458 { 459 ssize_t nwrite; 460 461 if (ax->ax_wblen != ax->ax_wbtlen) { 462 errno = EALREADY; 463 return -1; 464 } 465 466 if (ax->ax_wblen == 0) 467 return 0; 468 469 #if defined(AX_DEBUG) && defined(AX_DEBUG_VERBOSE) 470 { 471 size_t i; 472 char chars[4]; 473 int print = 1; 474 475 fprintf(stderr, "sending packet:\n"); 476 for (i = 0; i < ax->ax_wblen; i++) { 477 fprintf(stderr, "%02hhx ", ax->ax_wbuf[i]); 478 chars[i % 4] = ax->ax_wbuf[i]; 479 if (!isprint(ax->ax_wbuf[i])) 480 print = 0; 481 if (i % 4 == 3) { 482 if (print) 483 fprintf(stderr, "%.4s", chars); 484 fprintf(stderr, "\n"); 485 print = 1; 486 } 487 } 488 } 489 #endif 490 491 if ((nwrite = send(ax->ax_fd, ax->ax_wbuf, ax->ax_wblen, 492 MSG_NOSIGNAL | MSG_DONTWAIT)) == -1) 493 return -1; 494 495 memmove(ax->ax_wbuf, ax->ax_wbuf + nwrite, ax->ax_wblen - nwrite); 496 ax->ax_wblen -= nwrite; 497 ax->ax_wbtlen = ax->ax_wblen; 498 499 return ax->ax_wblen; 500 } 501 502 uint32_t 503 ax_open(struct ax *ax, uint8_t timeout, struct ax_oid *oid, 504 struct ax_ostring *descr) 505 { 506 if (ax_pdu_header(ax, AX_PDU_TYPE_OPEN, 0, 0, 0, 0, 507 NULL) == -1) 508 return 0; 509 ax_pdu_need(ax, 4); 510 ax->ax_wbuf[ax->ax_wbtlen++] = timeout; 511 memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, 3); 512 ax->ax_wbtlen += 3; 513 if (ax_pdu_add_oid(ax, oid) == -1) 514 return 0; 515 if (ax_pdu_add_str(ax, descr) == -1) 516 return 0; 517 518 return ax_pdu_queue(ax); 519 } 520 521 uint32_t 522 ax_close(struct ax *ax, uint32_t sessionid, 523 enum ax_close_reason reason) 524 { 525 if (ax_pdu_header(ax, AX_PDU_TYPE_CLOSE, 0, sessionid, arc4random(), 0, 526 NULL) == -1) 527 return 0; 528 529 if (ax_pdu_need(ax, 4) == -1) 530 return 0; 531 ax->ax_wbuf[ax->ax_wbtlen++] = (uint8_t)reason; 532 memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, 3); 533 ax->ax_wbtlen += 3; 534 535 return ax_pdu_queue(ax); 536 } 537 538 int 539 ax_get(struct ax *ax, uint32_t sessionid, uint32_t transactionid, 540 uint32_t packetid, struct ax_ostring *context, struct ax_searchrange *srl, 541 size_t nsr) 542 { 543 size_t i; 544 545 if (ax_pdu_header(ax, AX_PDU_TYPE_GET, 0, sessionid, transactionid, 546 packetid, context) == -1) 547 return -1; 548 549 for (i = 0; i < nsr; i++) { 550 if (ax_pdu_add_searchrange(ax, &(srl[i])) == -1) 551 return 0; 552 } 553 554 return ax_pdu_queue(ax); 555 } 556 557 int 558 ax_getnext(struct ax *ax, uint32_t sessionid, uint32_t transactionid, 559 uint32_t packetid, struct ax_ostring *context, struct ax_searchrange *srl, 560 size_t nsr) 561 { 562 size_t i; 563 564 if (ax_pdu_header(ax, AX_PDU_TYPE_GETNEXT, 0, sessionid, transactionid, 565 packetid, context) == -1) 566 return -1; 567 568 for (i = 0; i < nsr; i++) { 569 if (ax_pdu_add_searchrange(ax, &(srl[i])) == -1) 570 return 0; 571 } 572 573 return ax_pdu_queue(ax); 574 } 575 576 uint32_t 577 ax_indexallocate(struct ax *ax, uint8_t flags, uint32_t sessionid, 578 struct ax_ostring *context, struct ax_varbind *vblist, size_t nvb) 579 { 580 if (flags & ~(AX_PDU_FLAG_NEW_INDEX | AX_PDU_FLAG_ANY_INDEX)) { 581 errno = EINVAL; 582 return 0; 583 } 584 585 if (ax_pdu_header(ax, AX_PDU_TYPE_INDEXALLOCATE, flags, 586 sessionid, 0, 0, context) == -1) 587 return 0; 588 589 if (ax_pdu_add_varbindlist(ax, vblist, nvb) == -1) 590 return 0; 591 592 return ax_pdu_queue(ax); 593 } 594 595 uint32_t 596 ax_indexdeallocate(struct ax *ax, uint32_t sessionid, 597 struct ax_ostring *context, struct ax_varbind *vblist, size_t nvb) 598 { 599 if (ax_pdu_header(ax, AX_PDU_TYPE_INDEXDEALLOCATE, 0, 600 sessionid, 0, 0, context) == -1) 601 return 0; 602 603 if (ax_pdu_add_varbindlist(ax, vblist, nvb) == -1) 604 return 0; 605 606 return ax_pdu_queue(ax); 607 } 608 609 uint32_t 610 ax_addagentcaps(struct ax *ax, uint32_t sessionid, 611 struct ax_ostring *context, struct ax_oid *id, 612 struct ax_ostring *descr) 613 { 614 if (ax_pdu_header(ax, AX_PDU_TYPE_ADDAGENTCAPS, 0, 615 sessionid, 0, 0, context) == -1) 616 return 0; 617 if (ax_pdu_add_oid(ax, id) == -1) 618 return 0; 619 if (ax_pdu_add_str(ax, descr) == -1) 620 return 0; 621 622 return ax_pdu_queue(ax); 623 } 624 625 uint32_t 626 ax_removeagentcaps(struct ax *ax, uint32_t sessionid, 627 struct ax_ostring *context, struct ax_oid *id) 628 { 629 if (ax_pdu_header(ax, AX_PDU_TYPE_REMOVEAGENTCAPS, 0, 630 sessionid, 0, 0, context) == -1) 631 return 0; 632 if (ax_pdu_add_oid(ax, id) == -1) 633 return 0; 634 635 return ax_pdu_queue(ax); 636 637 } 638 639 uint32_t 640 ax_register(struct ax *ax, uint8_t flags, uint32_t sessionid, 641 struct ax_ostring *context, uint8_t timeout, uint8_t priority, 642 uint8_t range_subid, struct ax_oid *subtree, uint32_t upperbound) 643 { 644 if (flags & ~(AX_PDU_FLAG_INSTANCE_REGISTRATION)) { 645 errno = EINVAL; 646 return 0; 647 } 648 649 if (ax_pdu_header(ax, AX_PDU_TYPE_REGISTER, flags, 650 sessionid, 0, 0, context) == -1) 651 return 0; 652 653 if (ax_pdu_need(ax, 4) == -1) 654 return 0; 655 ax->ax_wbuf[ax->ax_wbtlen++] = timeout; 656 ax->ax_wbuf[ax->ax_wbtlen++] = priority; 657 ax->ax_wbuf[ax->ax_wbtlen++] = range_subid; 658 ax->ax_wbuf[ax->ax_wbtlen++] = 0; 659 if (ax_pdu_add_oid(ax, subtree) == -1) 660 return 0; 661 if (range_subid != 0) { 662 if (ax_pdu_add_uint32(ax, upperbound) == -1) 663 return 0; 664 } 665 666 return ax_pdu_queue(ax); 667 } 668 669 uint32_t 670 ax_unregister(struct ax *ax, uint32_t sessionid, 671 struct ax_ostring *context, uint8_t priority, uint8_t range_subid, 672 struct ax_oid *subtree, uint32_t upperbound) 673 { 674 if (ax_pdu_header(ax, AX_PDU_TYPE_UNREGISTER, 0, 675 sessionid, 0, 0, context) == -1) 676 return 0; 677 678 if (ax_pdu_need(ax, 4) == -1) 679 return 0; 680 ax->ax_wbuf[ax->ax_wbtlen++] = 0; 681 ax->ax_wbuf[ax->ax_wbtlen++] = priority; 682 ax->ax_wbuf[ax->ax_wbtlen++] = range_subid; 683 ax->ax_wbuf[ax->ax_wbtlen++] = 0; 684 if (ax_pdu_add_oid(ax, subtree) == -1) 685 return 0; 686 if (range_subid != 0) { 687 if (ax_pdu_add_uint32(ax, upperbound) == -1) 688 return 0; 689 } 690 691 return ax_pdu_queue(ax); 692 } 693 694 int 695 ax_response(struct ax *ax, uint32_t sessionid, uint32_t transactionid, 696 uint32_t packetid, uint32_t sysuptime, uint16_t error, uint16_t index, 697 struct ax_varbind *vblist, size_t nvb) 698 { 699 if (ax_pdu_header(ax, AX_PDU_TYPE_RESPONSE, 0, sessionid, 700 transactionid, packetid, NULL) == -1) 701 return -1; 702 703 if (ax_pdu_add_uint32(ax, sysuptime) == -1 || 704 ax_pdu_add_uint16(ax, error) == -1 || 705 ax_pdu_add_uint16(ax, index) == -1) 706 return -1; 707 708 if (ax_pdu_add_varbindlist(ax, vblist, nvb) == -1) 709 return -1; 710 if (ax_pdu_queue(ax) == 0) 711 return -1; 712 return 0; 713 } 714 715 void 716 ax_pdu_free(struct ax_pdu *pdu) 717 { 718 size_t i; 719 struct ax_pdu_response *response; 720 struct ax_pdu_varbindlist *vblist; 721 722 if (pdu->ap_header.aph_flags & AX_PDU_FLAG_NON_DEFAULT_CONTEXT) 723 free(pdu->ap_context.aos_string); 724 725 switch (pdu->ap_header.aph_type) { 726 case AX_PDU_TYPE_OPEN: 727 free(pdu->ap_payload.ap_open.ap_descr.aos_string); 728 break; 729 case AX_PDU_TYPE_GET: 730 case AX_PDU_TYPE_GETNEXT: 731 case AX_PDU_TYPE_GETBULK: 732 free(pdu->ap_payload.ap_srl.ap_sr); 733 break; 734 case AX_PDU_TYPE_TESTSET: 735 case AX_PDU_TYPE_INDEXALLOCATE: 736 case AX_PDU_TYPE_INDEXDEALLOCATE: 737 vblist = &(pdu->ap_payload.ap_vbl); 738 for (i = 0; i < vblist->ap_nvarbind; i++) 739 ax_varbind_free(&(vblist->ap_varbind[i])); 740 free(vblist->ap_varbind); 741 break; 742 case AX_PDU_TYPE_RESPONSE: 743 response = &(pdu->ap_payload.ap_response); 744 for (i = 0; i < response->ap_nvarbind; i++) 745 ax_varbind_free(&(response->ap_varbindlist[i])); 746 free(response->ap_varbindlist); 747 break; 748 default: 749 break; 750 } 751 free(pdu); 752 } 753 754 void 755 ax_varbind_free(struct ax_varbind *varbind) 756 { 757 switch (varbind->avb_type) { 758 case AX_DATA_TYPE_OCTETSTRING: 759 case AX_DATA_TYPE_IPADDRESS: 760 case AX_DATA_TYPE_OPAQUE: 761 free(varbind->avb_data.avb_ostring.aos_string); 762 break; 763 default: 764 break; 765 } 766 } 767 768 const char * 769 ax_error2string(enum ax_pdu_error error) 770 { 771 static char buffer[64]; 772 switch (error) { 773 case AX_PDU_ERROR_NOERROR: 774 return "No error"; 775 case AX_PDU_ERROR_GENERR: 776 return "Generic error"; 777 case AX_PDU_ERROR_NOACCESS: 778 return "No access"; 779 case AX_PDU_ERROR_WRONGTYPE: 780 return "Wrong type"; 781 case AX_PDU_ERROR_WRONGLENGTH: 782 return "Wrong length"; 783 case AX_PDU_ERROR_WRONGENCODING: 784 return "Wrong encoding"; 785 case AX_PDU_ERROR_WRONGVALUE: 786 return "Wrong value"; 787 case AX_PDU_ERROR_NOCREATION: 788 return "No creation"; 789 case AX_PDU_ERROR_INCONSISTENTVALUE: 790 return "Inconsistent value"; 791 case AX_PDU_ERROR_RESOURCEUNAVAILABLE: 792 return "Resource unavailable"; 793 case AX_PDU_ERROR_COMMITFAILED: 794 return "Commit failed"; 795 case AX_PDU_ERROR_UNDOFAILED: 796 return "Undo failed"; 797 case AX_PDU_ERROR_NOTWRITABLE: 798 return "Not writable"; 799 case AX_PDU_ERROR_INCONSISTENTNAME: 800 return "Inconsistent name"; 801 case AX_PDU_ERROR_OPENFAILED: 802 return "Open Failed"; 803 case AX_PDU_ERROR_NOTOPEN: 804 return "Not open"; 805 case AX_PDU_ERROR_INDEXWRONGTYPE: 806 return "Index wrong type"; 807 case AX_PDU_ERROR_INDEXALREADYALLOCATED: 808 return "Index already allocated"; 809 case AX_PDU_ERROR_INDEXNONEAVAILABLE: 810 return "Index none available"; 811 case AX_PDU_ERROR_INDEXNOTALLOCATED: 812 return "Index not allocated"; 813 case AX_PDU_ERROR_UNSUPPORTEDCONETXT: 814 return "Unsupported context"; 815 case AX_PDU_ERROR_DUPLICATEREGISTRATION: 816 return "Duplicate registration"; 817 case AX_PDU_ERROR_UNKNOWNREGISTRATION: 818 return "Unkown registration"; 819 case AX_PDU_ERROR_UNKNOWNAGENTCAPS: 820 return "Unknown agent capabilities"; 821 case AX_PDU_ERROR_PARSEERROR: 822 return "Parse error"; 823 case AX_PDU_ERROR_REQUESTDENIED: 824 return "Request denied"; 825 case AX_PDU_ERROR_PROCESSINGERROR: 826 return "Processing error"; 827 } 828 snprintf(buffer, sizeof(buffer), "Unknown error: %d", error); 829 return buffer; 830 } 831 832 const char * 833 ax_pdutype2string(enum ax_pdu_type type) 834 { 835 static char buffer[64]; 836 switch(type) { 837 case AX_PDU_TYPE_OPEN: 838 return "agentx-Open-PDU"; 839 case AX_PDU_TYPE_CLOSE: 840 return "agentx-Close-PDU"; 841 case AX_PDU_TYPE_REGISTER: 842 return "agentx-Register-PDU"; 843 case AX_PDU_TYPE_UNREGISTER: 844 return "agentx-Unregister-PDU"; 845 case AX_PDU_TYPE_GET: 846 return "agentx-Get-PDU"; 847 case AX_PDU_TYPE_GETNEXT: 848 return "agentx-GetNext-PDU"; 849 case AX_PDU_TYPE_GETBULK: 850 return "agentx-GetBulk-PDU"; 851 case AX_PDU_TYPE_TESTSET: 852 return "agentx-TestSet-PDU"; 853 case AX_PDU_TYPE_COMMITSET: 854 return "agentx-CommitSet-PDU"; 855 case AX_PDU_TYPE_UNDOSET: 856 return "agentx-UndoSet-PDU"; 857 case AX_PDU_TYPE_CLEANUPSET: 858 return "agentx-CleanupSet-PDU"; 859 case AX_PDU_TYPE_NOTIFY: 860 return "agentx-Notify-PDU"; 861 case AX_PDU_TYPE_PING: 862 return "agentx-Ping-PDU"; 863 case AX_PDU_TYPE_INDEXALLOCATE: 864 return "agentx-IndexAllocate-PDU"; 865 case AX_PDU_TYPE_INDEXDEALLOCATE: 866 return "agentx-IndexDeallocate-PDU"; 867 case AX_PDU_TYPE_ADDAGENTCAPS: 868 return "agentx-AddAgentCaps-PDU"; 869 case AX_PDU_TYPE_REMOVEAGENTCAPS: 870 return "agentx-RemoveAgentCaps-PDU"; 871 case AX_PDU_TYPE_RESPONSE: 872 return "agentx-Response-PDU"; 873 } 874 snprintf(buffer, sizeof(buffer), "Unknown type: %d", type); 875 return buffer; 876 } 877 878 const char * 879 ax_closereason2string(enum ax_close_reason reason) 880 { 881 static char buffer[64]; 882 883 switch (reason) { 884 case AX_CLOSE_OTHER: 885 return "Undefined reason"; 886 case AX_CLOSEN_PARSEERROR: 887 return "Too many AgentX parse errors from peer"; 888 case AX_CLOSE_PROTOCOLERROR: 889 return "Too many AgentX protocol errors from peer"; 890 case AX_CLOSE_TIMEOUTS: 891 return "Too many timeouts waiting for peer"; 892 case AX_CLOSE_SHUTDOWN: 893 return "shutting down"; 894 case AX_CLOSE_BYMANAGER: 895 return "Manager shuts down"; 896 } 897 snprintf(buffer, sizeof(buffer), "Unknown reason: %d", reason); 898 return buffer; 899 } 900 901 const char * 902 ax_oid2string(struct ax_oid *oid) 903 { 904 return ax_oidrange2string(oid, 0, 0); 905 } 906 907 const char * 908 ax_oidrange2string(struct ax_oid *oid, uint8_t range_subid, 909 uint32_t upperbound) 910 { 911 static char buf[1024]; 912 char *p; 913 size_t i, rest; 914 int ret; 915 916 rest = sizeof(buf); 917 p = buf; 918 for (i = 0; i < oid->aoi_idlen; i++) { 919 if (range_subid != 0 && range_subid - 1 == (uint8_t)i) 920 ret = snprintf(p, rest, ".[%u-%u]", oid->aoi_id[i], 921 upperbound); 922 else 923 ret = snprintf(p, rest, ".%u", oid->aoi_id[i]); 924 if ((size_t) ret >= rest) { 925 snprintf(buf, sizeof(buf), "Couldn't parse oid"); 926 return buf; 927 } 928 p += ret; 929 rest -= (size_t) ret; 930 } 931 return buf; 932 } 933 934 const char * 935 ax_varbind2string(struct ax_varbind *vb) 936 { 937 static char buf[1024]; 938 char tmpbuf[1024]; 939 size_t i, bufleft; 940 int ishex = 0; 941 char *p; 942 int ret; 943 944 switch (vb->avb_type) { 945 case AX_DATA_TYPE_INTEGER: 946 snprintf(buf, sizeof(buf), "%s: (int)%d", 947 ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_int32); 948 break; 949 case AX_DATA_TYPE_OCTETSTRING: 950 for (i = 0; 951 i < vb->avb_data.avb_ostring.aos_slen && !ishex; i++) { 952 if (!isprint(vb->avb_data.avb_ostring.aos_string[i])) 953 ishex = 1; 954 } 955 if (ishex) { 956 p = tmpbuf; 957 bufleft = sizeof(tmpbuf); 958 for (i = 0; 959 i < vb->avb_data.avb_ostring.aos_slen; i++) { 960 ret = snprintf(p, bufleft, " %02hhX", 961 vb->avb_data.avb_ostring.aos_string[i]); 962 if (ret >= (int) bufleft) { 963 p = strrchr(p, ' '); 964 strlcpy(p, "...", 4); 965 break; 966 } 967 p += 3; 968 bufleft -= 3; 969 } 970 ret = snprintf(buf, sizeof(buf), "%s: (hex-string)%s", 971 ax_oid2string(&(vb->avb_oid)), tmpbuf); 972 if (ret >= (int) sizeof(buf)) { 973 p = strrchr(buf, ' '); 974 strlcpy(p, "...", 4); 975 } 976 } else { 977 ret = snprintf(buf, sizeof(buf), "%s: (string)", 978 ax_oid2string(&(vb->avb_oid))); 979 if (ret >= (int) sizeof(buf)) { 980 snprintf(buf, sizeof(buf), "<too large OID>: " 981 "(string)<too large string>"); 982 break; 983 } 984 p = buf + ret; 985 bufleft = (int) sizeof(buf) - ret; 986 if (snprintf(p, bufleft, "%.*s", 987 vb->avb_data.avb_ostring.aos_slen, 988 vb->avb_data.avb_ostring.aos_string) >= 989 (int) bufleft) { 990 p = buf + sizeof(buf) - 4; 991 strlcpy(p, "...", 4); 992 } 993 } 994 break; 995 case AX_DATA_TYPE_NULL: 996 snprintf(buf, sizeof(buf), "%s: <null>", 997 ax_oid2string(&(vb->avb_oid))); 998 break; 999 case AX_DATA_TYPE_OID: 1000 strlcpy(tmpbuf, 1001 ax_oid2string(&(vb->avb_data.avb_oid)), sizeof(tmpbuf)); 1002 snprintf(buf, sizeof(buf), "%s: (oid)%s", 1003 ax_oid2string(&(vb->avb_oid)), tmpbuf); 1004 break; 1005 case AX_DATA_TYPE_IPADDRESS: 1006 if (vb->avb_data.avb_ostring.aos_slen != 4) { 1007 snprintf(buf, sizeof(buf), "%s: (ipaddress)<invalid>", 1008 ax_oid2string(&(vb->avb_oid))); 1009 break; 1010 } 1011 if (inet_ntop(PF_INET, vb->avb_data.avb_ostring.aos_string, 1012 tmpbuf, sizeof(tmpbuf)) == NULL) { 1013 snprintf(buf, sizeof(buf), "%s: (ipaddress)" 1014 "<unparseable>: %s", 1015 ax_oid2string(&(vb->avb_oid)), 1016 strerror(errno)); 1017 break; 1018 } 1019 snprintf(buf, sizeof(buf), "%s: (ipaddress)%s", 1020 ax_oid2string(&(vb->avb_oid)), tmpbuf); 1021 break; 1022 case AX_DATA_TYPE_COUNTER32: 1023 snprintf(buf, sizeof(buf), "%s: (counter32)%u", 1024 ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32); 1025 break; 1026 case AX_DATA_TYPE_GAUGE32: 1027 snprintf(buf, sizeof(buf), "%s: (gauge32)%u", 1028 ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32); 1029 break; 1030 case AX_DATA_TYPE_TIMETICKS: 1031 snprintf(buf, sizeof(buf), "%s: (timeticks)%u", 1032 ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint32); 1033 break; 1034 case AX_DATA_TYPE_OPAQUE: 1035 p = tmpbuf; 1036 bufleft = sizeof(tmpbuf); 1037 for (i = 0; 1038 i < vb->avb_data.avb_ostring.aos_slen; i++) { 1039 ret = snprintf(p, bufleft, " %02hhX", 1040 vb->avb_data.avb_ostring.aos_string[i]); 1041 if (ret >= (int) bufleft) { 1042 p = strrchr(p, ' '); 1043 strlcpy(p, "...", 4); 1044 break; 1045 } 1046 p += 3; 1047 bufleft -= 3; 1048 } 1049 ret = snprintf(buf, sizeof(buf), "%s: (opaque)%s", 1050 ax_oid2string(&(vb->avb_oid)), tmpbuf); 1051 if (ret >= (int) sizeof(buf)) { 1052 p = strrchr(buf, ' '); 1053 strlcpy(p, "...", 4); 1054 } 1055 break; 1056 case AX_DATA_TYPE_COUNTER64: 1057 snprintf(buf, sizeof(buf), "%s: (counter64)%"PRIu64, 1058 ax_oid2string(&(vb->avb_oid)), vb->avb_data.avb_uint64); 1059 break; 1060 case AX_DATA_TYPE_NOSUCHOBJECT: 1061 snprintf(buf, sizeof(buf), "%s: <noSuchObject>", 1062 ax_oid2string(&(vb->avb_oid))); 1063 break; 1064 case AX_DATA_TYPE_NOSUCHINSTANCE: 1065 snprintf(buf, sizeof(buf), "%s: <noSuchInstance>", 1066 ax_oid2string(&(vb->avb_oid))); 1067 break; 1068 case AX_DATA_TYPE_ENDOFMIBVIEW: 1069 snprintf(buf, sizeof(buf), "%s: <endOfMibView>", 1070 ax_oid2string(&(vb->avb_oid))); 1071 break; 1072 } 1073 return buf; 1074 } 1075 1076 int 1077 ax_oid_cmp(struct ax_oid *o1, struct ax_oid *o2) 1078 { 1079 size_t i, min; 1080 1081 min = o1->aoi_idlen < o2->aoi_idlen ? o1->aoi_idlen : o2->aoi_idlen; 1082 for (i = 0; i < min; i++) { 1083 if (o1->aoi_id[i] < o2->aoi_id[i]) 1084 return -1; 1085 if (o1->aoi_id[i] > o2->aoi_id[i]) 1086 return 1; 1087 } 1088 /* o1 is parent of o2 */ 1089 if (o1->aoi_idlen < o2->aoi_idlen) 1090 return -2; 1091 /* o1 is child of o2 */ 1092 if (o1->aoi_idlen > o2->aoi_idlen) 1093 return 2; 1094 return 0; 1095 } 1096 1097 int 1098 ax_oid_add(struct ax_oid *oid, uint32_t value) 1099 { 1100 if (oid->aoi_idlen == AX_OID_MAX_LEN) 1101 return -1; 1102 oid->aoi_id[oid->aoi_idlen++] = value; 1103 return 0; 1104 } 1105 1106 static uint32_t 1107 ax_pdu_queue(struct ax *ax) 1108 { 1109 struct ax_pdu_header header; 1110 uint32_t packetid, plength; 1111 size_t wbtlen = ax->ax_wbtlen; 1112 1113 header.aph_flags = ax->ax_byteorder == AX_BYTE_ORDER_BE ? 1114 AX_PDU_FLAG_NETWORK_BYTE_ORDER : 0; 1115 packetid = ax_pdutoh32(&header, &(ax->ax_wbuf[ax->ax_wblen + 12])); 1116 plength = (ax->ax_wbtlen - ax->ax_wblen) - AX_PDU_HEADER; 1117 ax->ax_wbtlen = ax->ax_wblen + 16; 1118 (void)ax_pdu_add_uint32(ax, plength); 1119 1120 ax->ax_wblen = ax->ax_wbtlen = wbtlen; 1121 1122 return packetid; 1123 } 1124 1125 static int 1126 ax_pdu_header(struct ax *ax, enum ax_pdu_type type, uint8_t flags, 1127 uint32_t sessionid, uint32_t transactionid, uint32_t packetid, 1128 struct ax_ostring *context) 1129 { 1130 if (ax->ax_wblen != ax->ax_wbtlen) { 1131 errno = EALREADY; 1132 return -1; 1133 } 1134 1135 if (ax_pdu_need(ax, 4) == -1) 1136 return -1; 1137 ax->ax_wbuf[ax->ax_wbtlen++] = 1; 1138 ax->ax_wbuf[ax->ax_wbtlen++] = (uint8_t) type; 1139 if (context != NULL) 1140 flags |= AX_PDU_FLAG_NON_DEFAULT_CONTEXT; 1141 if (ax->ax_byteorder == AX_BYTE_ORDER_BE) 1142 flags |= AX_PDU_FLAG_NETWORK_BYTE_ORDER; 1143 ax->ax_wbuf[ax->ax_wbtlen++] = flags; 1144 ax->ax_wbuf[ax->ax_wbtlen++] = 0; 1145 if (ax_pdu_add_uint32(ax, sessionid) == -1 || 1146 ax_pdu_add_uint32(ax, transactionid) == -1 || 1147 ax_pdu_add_uint32(ax, packetid) == -1 || 1148 ax_pdu_need(ax, 4) == -1) 1149 return -1; 1150 ax->ax_wbtlen += 4; 1151 if (context != NULL) { 1152 if (ax_pdu_add_str(ax, context) == -1) 1153 return -1; 1154 } 1155 1156 return 0; 1157 } 1158 1159 static int 1160 ax_pdu_add_uint16(struct ax *ax, uint16_t value) 1161 { 1162 if (ax_pdu_need(ax, sizeof(value)) == -1) 1163 return -1; 1164 1165 if (ax->ax_byteorder == AX_BYTE_ORDER_BE) 1166 value = htobe16(value); 1167 else 1168 value = htole16(value); 1169 memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value)); 1170 ax->ax_wbtlen += sizeof(value); 1171 return 0; 1172 } 1173 1174 static int 1175 ax_pdu_add_uint32(struct ax *ax, uint32_t value) 1176 { 1177 if (ax_pdu_need(ax, sizeof(value)) == -1) 1178 return -1; 1179 1180 if (ax->ax_byteorder == AX_BYTE_ORDER_BE) 1181 value = htobe32(value); 1182 else 1183 value = htole32(value); 1184 memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value)); 1185 ax->ax_wbtlen += sizeof(value); 1186 return 0; 1187 } 1188 1189 static int 1190 ax_pdu_add_uint64(struct ax *ax, uint64_t value) 1191 { 1192 if (ax_pdu_need(ax, sizeof(value)) == -1) 1193 return -1; 1194 1195 if (ax->ax_byteorder == AX_BYTE_ORDER_BE) 1196 value = htobe64(value); 1197 else 1198 value = htole64(value); 1199 memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value)); 1200 ax->ax_wbtlen += sizeof(value); 1201 return 0; 1202 } 1203 1204 1205 static int 1206 ax_pdu_add_oid(struct ax *ax, struct ax_oid *oid) 1207 { 1208 static struct ax_oid nulloid = {0}; 1209 uint8_t prefix = 0, n_subid, i = 0; 1210 1211 n_subid = oid->aoi_idlen; 1212 1213 if (oid == NULL) 1214 oid = &nulloid; 1215 1216 if (oid->aoi_idlen > 4 && 1217 oid->aoi_id[0] == 1 && oid->aoi_id[1] == 3 && 1218 oid->aoi_id[2] == 6 && oid->aoi_id[3] == 1 && 1219 oid->aoi_id[4] <= UINT8_MAX) { 1220 prefix = oid->aoi_id[4]; 1221 i = 5; 1222 } 1223 1224 if (ax_pdu_need(ax, 4) == -1) 1225 return -1; 1226 ax->ax_wbuf[ax->ax_wbtlen++] = n_subid - i; 1227 ax->ax_wbuf[ax->ax_wbtlen++] = prefix; 1228 ax->ax_wbuf[ax->ax_wbtlen++] = oid->aoi_include; 1229 ax->ax_wbuf[ax->ax_wbtlen++] = 0; 1230 1231 for (; i < n_subid; i++) { 1232 if (ax_pdu_add_uint32(ax, oid->aoi_id[i]) == -1) 1233 return -1; 1234 } 1235 1236 return 0; 1237 } 1238 1239 static int 1240 ax_pdu_add_str(struct ax *ax, struct ax_ostring *str) 1241 { 1242 size_t length, zeroes; 1243 1244 if (ax_pdu_add_uint32(ax, str->aos_slen) == -1) 1245 return -1; 1246 1247 if ((zeroes = (4 - (str->aos_slen % 4))) == 4) 1248 zeroes = 0; 1249 length = str->aos_slen + zeroes; 1250 if (ax_pdu_need(ax, length) == -1) 1251 return -1; 1252 1253 memcpy(&(ax->ax_wbuf[ax->ax_wbtlen]), str->aos_string, str->aos_slen); 1254 ax->ax_wbtlen += str->aos_slen; 1255 memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, zeroes); 1256 ax->ax_wbtlen += zeroes; 1257 return 0; 1258 } 1259 1260 static int 1261 ax_pdu_add_varbindlist(struct ax *ax, 1262 struct ax_varbind *vblist, size_t nvb) 1263 { 1264 size_t i; 1265 uint16_t temp; 1266 1267 for (i = 0; i < nvb; i++) { 1268 temp = (uint16_t) vblist[i].avb_type; 1269 if (ax_pdu_add_uint16(ax, temp) == -1 || 1270 ax_pdu_need(ax, 2)) 1271 return -1; 1272 memset(&(ax->ax_wbuf[ax->ax_wbtlen]), 0, 2); 1273 ax->ax_wbtlen += 2; 1274 if (ax_pdu_add_oid(ax, &(vblist[i].avb_oid)) == -1) 1275 return -1; 1276 switch (vblist[i].avb_type) { 1277 case AX_DATA_TYPE_INTEGER: 1278 if (ax_pdu_add_uint32(ax, 1279 vblist[i].avb_data.avb_int32) == -1) 1280 return -1; 1281 break; 1282 case AX_DATA_TYPE_COUNTER32: 1283 case AX_DATA_TYPE_GAUGE32: 1284 case AX_DATA_TYPE_TIMETICKS: 1285 if (ax_pdu_add_uint32(ax, 1286 vblist[i].avb_data.avb_uint32) == -1) 1287 return -1; 1288 break; 1289 case AX_DATA_TYPE_COUNTER64: 1290 if (ax_pdu_add_uint64(ax, 1291 vblist[i].avb_data.avb_uint64) == -1) 1292 return -1; 1293 break; 1294 case AX_DATA_TYPE_OCTETSTRING: 1295 case AX_DATA_TYPE_IPADDRESS: 1296 case AX_DATA_TYPE_OPAQUE: 1297 if (ax_pdu_add_str(ax, 1298 &(vblist[i].avb_data.avb_ostring)) == -1) 1299 return -1; 1300 break; 1301 case AX_DATA_TYPE_OID: 1302 if (ax_pdu_add_oid(ax, 1303 &(vblist[i].avb_data.avb_oid)) == -1) 1304 return -1; 1305 break; 1306 case AX_DATA_TYPE_NULL: 1307 case AX_DATA_TYPE_NOSUCHOBJECT: 1308 case AX_DATA_TYPE_NOSUCHINSTANCE: 1309 case AX_DATA_TYPE_ENDOFMIBVIEW: 1310 break; 1311 default: 1312 errno = EINVAL; 1313 return -1; 1314 } 1315 } 1316 return 0; 1317 } 1318 1319 static int 1320 ax_pdu_add_searchrange(struct ax *ax, struct ax_searchrange *sr) 1321 { 1322 if (ax_pdu_add_oid(ax, &(sr->asr_start)) == -1 || 1323 ax_pdu_add_oid(ax, &(sr->asr_stop)) == -1) 1324 return -1; 1325 return 0; 1326 } 1327 1328 static uint16_t 1329 ax_pdutoh16(struct ax_pdu_header *header, uint8_t *buf) 1330 { 1331 uint16_t value; 1332 1333 memcpy(&value, buf, sizeof(value)); 1334 if (header->aph_flags & AX_PDU_FLAG_NETWORK_BYTE_ORDER) 1335 return be16toh(value); 1336 return le16toh(value); 1337 } 1338 1339 static uint32_t 1340 ax_pdutoh32(struct ax_pdu_header *header, uint8_t *buf) 1341 { 1342 uint32_t value; 1343 1344 memcpy(&value, buf, sizeof(value)); 1345 if (header->aph_flags & AX_PDU_FLAG_NETWORK_BYTE_ORDER) 1346 return be32toh(value); 1347 return le32toh(value); 1348 } 1349 1350 static uint64_t 1351 ax_pdutoh64(struct ax_pdu_header *header, uint8_t *buf) 1352 { 1353 uint64_t value; 1354 1355 memcpy(&value, buf, sizeof(value)); 1356 if (header->aph_flags & AX_PDU_FLAG_NETWORK_BYTE_ORDER) 1357 return be64toh(value); 1358 return le64toh(value); 1359 } 1360 1361 static ssize_t 1362 ax_pdutooid(struct ax_pdu_header *header, struct ax_oid *oid, 1363 uint8_t *buf, size_t rawlen) 1364 { 1365 size_t i = 0; 1366 ssize_t nread; 1367 1368 if (rawlen < 4) 1369 goto fail; 1370 rawlen -= 4; 1371 nread = 4; 1372 oid->aoi_idlen = *buf++; 1373 if (rawlen < (oid->aoi_idlen * 4)) 1374 goto fail; 1375 nread += oid->aoi_idlen * 4; 1376 if (*buf != 0) { 1377 oid->aoi_id[0] = 1; 1378 oid->aoi_id[1] = 3; 1379 oid->aoi_id[2] = 6; 1380 oid->aoi_id[3] = 1; 1381 oid->aoi_id[4] = *buf; 1382 oid->aoi_idlen += 5; 1383 i = 5; 1384 } 1385 buf++; 1386 oid->aoi_include = *buf; 1387 if (oid->aoi_idlen > AX_OID_MAX_LEN) 1388 goto fail; 1389 for (buf += 2; i < oid->aoi_idlen; i++, buf += 4) 1390 oid->aoi_id[i] = ax_pdutoh32(header, buf); 1391 1392 return nread; 1393 1394 fail: 1395 errno = EPROTO; 1396 return -1; 1397 } 1398 1399 static ssize_t 1400 ax_pdutoostring(struct ax_pdu_header *header, 1401 struct ax_ostring *ostring, uint8_t *buf, size_t rawlen) 1402 { 1403 ssize_t nread; 1404 1405 if (rawlen < 4) 1406 goto fail; 1407 1408 ostring->aos_slen = ax_pdutoh32(header, buf); 1409 rawlen -= 4; 1410 buf += 4; 1411 if (ostring->aos_slen > rawlen) 1412 goto fail; 1413 if ((ostring->aos_string = malloc(ostring->aos_slen + 1)) == NULL) 1414 return -1; 1415 memcpy(ostring->aos_string, buf, ostring->aos_slen); 1416 ostring->aos_string[ostring->aos_slen] = '\0'; 1417 1418 nread = 4 + ostring->aos_slen; 1419 if (ostring->aos_slen % 4 != 0) 1420 nread += 4 - (ostring->aos_slen % 4); 1421 1422 return nread; 1423 1424 fail: 1425 errno = EPROTO; 1426 return -1; 1427 } 1428 1429 static ssize_t 1430 ax_pdutovarbind(struct ax_pdu_header *header, 1431 struct ax_varbind *varbind, uint8_t *buf, size_t rawlen) 1432 { 1433 ssize_t nread, rread = 4; 1434 1435 if (rawlen == 0) 1436 return 0; 1437 1438 if (rawlen < 8) 1439 goto fail; 1440 varbind->avb_type = ax_pdutoh16(header, buf); 1441 1442 buf += 4; 1443 rawlen -= 4; 1444 nread = ax_pdutooid(header, &(varbind->avb_oid), buf, rawlen); 1445 if (nread == -1) 1446 return -1; 1447 rread += nread; 1448 buf += nread; 1449 rawlen -= nread; 1450 1451 switch(varbind->avb_type) { 1452 case AX_DATA_TYPE_INTEGER: 1453 if (rawlen < 4) 1454 goto fail; 1455 varbind->avb_data.avb_int32 = ax_pdutoh32(header, buf); 1456 return rread + 4; 1457 case AX_DATA_TYPE_COUNTER32: 1458 case AX_DATA_TYPE_GAUGE32: 1459 case AX_DATA_TYPE_TIMETICKS: 1460 if (rawlen < 4) 1461 goto fail; 1462 varbind->avb_data.avb_uint32 = ax_pdutoh32(header, buf); 1463 return rread + 4; 1464 case AX_DATA_TYPE_COUNTER64: 1465 if (rawlen < 8) 1466 goto fail; 1467 varbind->avb_data.avb_uint64 = ax_pdutoh64(header, buf); 1468 return rread + 8; 1469 case AX_DATA_TYPE_OCTETSTRING: 1470 case AX_DATA_TYPE_IPADDRESS: 1471 case AX_DATA_TYPE_OPAQUE: 1472 nread = ax_pdutoostring(header, 1473 &(varbind->avb_data.avb_ostring), buf, rawlen); 1474 if (nread == -1) 1475 return -1; 1476 return nread + rread; 1477 case AX_DATA_TYPE_OID: 1478 nread = ax_pdutooid(header, &(varbind->avb_data.avb_oid), 1479 buf, rawlen); 1480 if (nread == -1) 1481 return -1; 1482 return nread + rread; 1483 case AX_DATA_TYPE_NULL: 1484 case AX_DATA_TYPE_NOSUCHOBJECT: 1485 case AX_DATA_TYPE_NOSUCHINSTANCE: 1486 case AX_DATA_TYPE_ENDOFMIBVIEW: 1487 return rread; 1488 } 1489 1490 fail: 1491 errno = EPROTO; 1492 return -1; 1493 } 1494