Bug Summary

File:src/lib/libagentx/ax.c
Warning:line 1034, column 15
Array access (via field 'ax_packetids') results in a null pointer dereference

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple amd64-unknown-openbsd7.0 -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name ax.c -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -fno-rounding-math -mconstructor-aliases -munwind-tables -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/lib/libagentx/obj -resource-dir /usr/local/lib/clang/13.0.0 -D PIC -internal-isystem /usr/local/lib/clang/13.0.0/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/lib/libagentx/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/vmm/scan-build/2022-01-12-194120-40624-1 -x c /usr/src/lib/libagentx/ax.c
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(*__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_HEADER20 20
35
36static int ax_pdu_need(struct ax *, size_t);
37static int ax_pdu_header(struct ax *,
38 enum ax_pdu_type, uint8_t, uint32_t, uint32_t, uint32_t,
39 struct ax_ostring *);
40static uint32_t ax_packetid(struct ax *);
41static uint32_t ax_pdu_queue(struct ax *);
42static int ax_pdu_add_uint16(struct ax *, uint16_t);
43static int ax_pdu_add_uint32(struct ax *, uint32_t);
44static int ax_pdu_add_uint64(struct ax *, uint64_t);
45static int ax_pdu_add_oid(struct ax *, struct ax_oid *, int);
46static int ax_pdu_add_str(struct ax *, struct ax_ostring *);
47static int ax_pdu_add_varbindlist( struct ax *, struct ax_varbind *,
48 size_t);
49static uint16_t ax_pdutoh16(struct ax_pdu_header *, uint8_t *);
50static uint32_t ax_pdutoh32(struct ax_pdu_header *, uint8_t *);
51static uint64_t ax_pdutoh64(struct ax_pdu_header *, uint8_t *);
52static ssize_t ax_pdutooid(struct ax_pdu_header *, struct ax_oid *,
53 uint8_t *, size_t);
54static ssize_t ax_pdutoostring(struct ax_pdu_header *,
55 struct ax_ostring *, uint8_t *, size_t);
56static ssize_t ax_pdutovarbind(struct ax_pdu_header *,
57 struct ax_varbind *, uint8_t *, size_t);
58
59struct ax *
60ax_new(int fd)
61{
62 struct ax *ax;
63
64 if (fd == -1) {
65 errno(*__errno()) = EINVAL22;
66 return NULL((void *)0);
67 }
68
69 if ((ax = calloc(1, sizeof(*ax))) == NULL((void *)0))
70 return NULL((void *)0);
71 ax->ax_fd = fd;
72 ax->ax_rbsize = 512;
73 if ((ax->ax_rbuf = malloc(ax->ax_rbsize)) == NULL((void *)0))
74 goto fail;
75 ax->ax_byteorder = AX_BYTE_ORDER_NATIVEAX_BYTE_ORDER_LE;
76
77 return ax;
78
79fail:
80 free(ax);
81 return NULL((void *)0);
82}
83
84void
85ax_free(struct ax *ax)
86{
87 if (ax == NULL((void *)0))
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
96struct ax_pdu *
97ax_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((void *)0);
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_HEADER20) {
114 if ((nread = read(ax->ax_fd, ax->ax_rbuf + ax->ax_rblen,
115 AX_PDU_HEADER20 - ax->ax_rblen)) == 0) {
116 errno(*__errno()) = ECONNRESET54;
117 return NULL((void *)0);
118 }
119 if (nread == -1)
120 return NULL((void *)0);
121 ax->ax_rblen += nread;
122 if (ax->ax_rblen < AX_PDU_HEADER20) {
123 errno(*__errno()) = EAGAIN35;
124 return NULL((void *)0);
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(*__errno()) = EPROTO95;
142 return NULL((void *)0);
143 }
144 if (ax->ax_rblen < AX_PDU_HEADER20 + header.aph_plength) {
145 if (AX_PDU_HEADER20 + header.aph_plength > ax->ax_rbsize) {
146 rbsize = (((AX_PDU_HEADER20 + header.aph_plength)
147 / 512) + 1) * 512;
148 if ((rbuf = recallocarray(ax->ax_rbuf, ax->ax_rbsize,
149 rbsize, sizeof(*rbuf))) == NULL((void *)0))
150 return NULL((void *)0);
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_HEADER20));
156 if (nread == 0)
157 errno(*__errno()) = ECONNRESET54;
158 if (nread <= 0)
159 return NULL((void *)0);
160 ax->ax_rblen += nread;
161 if (ax->ax_rblen < AX_PDU_HEADER20 + header.aph_plength) {
162 errno(*__errno()) = EAGAIN35;
163 return NULL((void *)0);
164 }
165 }
166
167 if ((pdu = calloc(1, sizeof(*pdu))) == NULL((void *)0))
168 return NULL((void *)0);
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(&__sF[2]), "received packet:\n");
178 for (i = 0; i < pdu->ap_header.aph_plength + AX_PDU_HEADER20;
179 i++) {
180 fprintf(stderr(&__sF[2]), "%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(&__sF[2]), "%.4s", chars);
187 fprintf(stderr(&__sF[2]), "\n");
188 print = 1;
189 }
190 }
191 }
192#endif
193
194 u8 = (ax->ax_rbuf) + AX_PDU_HEADER20;
195 rawlen = pdu->ap_header.aph_plength;
196 if (pdu->ap_header.aph_flags & AX_PDU_FLAG_NON_DEFAULT_CONTEXT(1 << 3)) {
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(*__errno()) = EPROTO95;
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((void *)0))
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((void *)0))
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(*__errno()) = EPROTO95;
266 goto fail;
267 }
268 break;
269 case AX_PDU_TYPE_RESPONSE:
270 if (ax->ax_packetids != NULL((void *)0)) {
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(*__errno()) = EPROTO95;
285 goto fail;
286 }
287 }
288 if (rawlen < 8) {
289 errno(*__errno()) = EPROTO95;
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((void *)0))
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((void *)0))
320 goto fail;
321 memcpy(pdu->ap_payload.ap_raw, ax->ax_rbuf + AX_PDU_HEADER20,
322 pdu->ap_header.aph_plength);
323 break;
324 }
325
326 ax->ax_rblen = 0;
327
328 return pdu;
329fail:
330 ax_pdu_free(pdu);
331 return NULL((void *)0);
332}
333
334static int
335ax_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) {
5
Assuming the condition is false
6
Taking false branch
341 wbsize = (((ax->ax_wbtlen + need) / 512) + 1) * 512;
342 wbuf = recallocarray(ax->ax_wbuf, ax->ax_wbsize, wbsize, 1);
343 if (wbuf == NULL((void *)0)) {
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;
7
Returning without writing to 'ax->ax_packetids'
352}
353
354ssize_t
355ax_send(struct ax *ax)
356{
357 ssize_t nwrite;
358
359 if (ax->ax_wblen != ax->ax_wbtlen) {
360 errno(*__errno()) = EALREADY37;
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(&__sF[2]), "sending packet:\n");
374 for (i = 0; i < ax->ax_wblen; i++) {
375 fprintf(stderr(&__sF[2]), "%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(&__sF[2]), "%.4s", chars);
382 fprintf(stderr(&__sF[2]), "\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_NOSIGNAL0x400 | MSG_DONTWAIT0x80)) == -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
400uint32_t
401ax_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((void *)0)) == -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
419uint32_t
420ax_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((void *)0)) == -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
436uint32_t
437ax_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(1 << 1) | AX_PDU_FLAG_ANY_INDEX(1 << 2))) {
441 errno(*__errno()) = EINVAL22;
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
455uint32_t
456ax_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
469uint32_t
470ax_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
485uint32_t
486ax_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
499uint32_t
500ax_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(1 << 0))) {
505 errno(*__errno()) = EINVAL22;
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
529uint32_t
530ax_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
554int
555ax_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,
1
Calling 'ax_pdu_header'
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
575void
576ax_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(1 << 3))
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
603void
604ax_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
617const char *
618ax_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
681const char *
682ax_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
727const char *
728ax_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
750const char *
751ax_oid2string(struct ax_oid *oid)
752{
753 return ax_oidrange2string(oid, 0, 0);
754}
755
756const char *
757ax_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
785const char *
786ax_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_INET2, vb->avb_data.avb_ostring.aos_string,
863 tmpbuf, sizeof(tmpbuf)) == NULL((void *)0)) {
864 snprintf(buf, sizeof(buf), "%s: (ipaddress)"
865 "<unparseable>: %s",
866 ax_oid2string(&(vb->avb_oid)),
867 strerror(errno(*__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"llu",
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
927int
928ax_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
948int
949ax_oid_add(struct ax_oid *oid, uint32_t value)
950{
951 if (oid->aoi_idlen == AX_OID_MAX_LEN128)
952 return -1;
953 oid->aoi_id[oid->aoi_idlen++] = value;
954 return 0;
955}
956
957static uint32_t
958ax_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(1 << 4) : 0;
966 packetid = ax_pdutoh32(&header, &(ax->ax_wbuf[ax->ax_wblen + 12]));
967 plength = (ax->ax_wbtlen - ax->ax_wblen) - AX_PDU_HEADER20;
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
976static int
977ax_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) {
2
Assuming field 'ax_wblen' is equal to field 'ax_wbtlen'
3
Taking false branch
982 errno(*__errno()) = EALREADY37;
983 return -1;
984 }
985
986 if (ax_pdu_need(ax, 4) == -1)
4
Calling 'ax_pdu_need'
8
Returning from 'ax_pdu_need'
9
Taking false branch
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((void *)0))
10
Assuming 'context' is equal to NULL
11
Taking false branch
991 flags |= AX_PDU_FLAG_NON_DEFAULT_CONTEXT(1 << 3);
992 if (ax->ax_byteorder == AX_BYTE_ORDER_BE)
12
Assuming field 'ax_byteorder' is not equal to AX_BYTE_ORDER_BE
13
Taking false branch
993 flags |= AX_PDU_FLAG_NETWORK_BYTE_ORDER(1 << 4);
994 ax->ax_wbuf[ax->ax_wbtlen++] = flags;
995 ax->ax_wbuf[ax->ax_wbtlen++] = 0;
996 if (packetid == 0)
14
Assuming 'packetid' is equal to 0
15
Taking true branch
997 packetid = ax_packetid(ax);
16
Calling 'ax_packetid'
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((void *)0)) {
1005 if (ax_pdu_add_str(ax, context) == -1)
1006 return -1;
1007 }
1008
1009 return 0;
1010}
1011
1012static uint32_t
1013ax_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((void *)0)) {
17
Assuming field 'ax_packetids' is equal to NULL
18
Assuming pointer value is null
19
Taking false branch
1020 for (npackets = 0; ax->ax_packetids[npackets] != 0; npackets++)
1021 continue;
1022 }
1023 if (ax->ax_packetidsize == 0 || npackets == ax->ax_packetidsize - 1) {
20
Assuming field 'ax_packetidsize' is not equal to 0
21
Assuming the condition is false
22
Taking false branch
1024 packetids = recallocarray(ax->ax_packetids, ax->ax_packetidsize,
1025 ax->ax_packetidsize + 25, sizeof(*packetids));
1026 if (packetids == NULL((void *)0))
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++) {
23
Array access (via field 'ax_packetids') results in a null pointer dereference
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
1046static int
1047ax_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)(__uint16_t)(__builtin_constant_p(value) ? (__uint16_t)(((__uint16_t
)(value) & 0xffU) << 8 | ((__uint16_t)(value) &
0xff00U) >> 8) : __swap16md(value))
;
1054 else
1055 value = htole16(value)((__uint16_t)(value));
1056 memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value));
1057 ax->ax_wbtlen += sizeof(value);
1058 return 0;
1059}
1060
1061static int
1062ax_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)(__uint32_t)(__builtin_constant_p(value) ? (__uint32_t)(((__uint32_t
)(value) & 0xff) << 24 | ((__uint32_t)(value) &
0xff00) << 8 | ((__uint32_t)(value) & 0xff0000) >>
8 | ((__uint32_t)(value) & 0xff000000) >> 24) : __swap32md
(value))
;
1069 else
1070 value = htole32(value)((__uint32_t)(value));
1071 memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value));
1072 ax->ax_wbtlen += sizeof(value);
1073 return 0;
1074}
1075
1076static int
1077ax_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)(__uint64_t)(__builtin_constant_p(value) ? (__uint64_t)((((__uint64_t
)(value) & 0xff) << 56) | ((__uint64_t)(value) &
0xff00ULL) << 40 | ((__uint64_t)(value) & 0xff0000ULL
) << 24 | ((__uint64_t)(value) & 0xff000000ULL) <<
8 | ((__uint64_t)(value) & 0xff00000000ULL) >> 8 |
((__uint64_t)(value) & 0xff0000000000ULL) >> 24 | (
(__uint64_t)(value) & 0xff000000000000ULL) >> 40 | (
(__uint64_t)(value) & 0xff00000000000000ULL) >> 56)
: __swap64md(value))
;
1084 else
1085 value = htole64(value)((__uint64_t)(value));
1086 memcpy(ax->ax_wbuf + ax->ax_wbtlen, &value, sizeof(value));
1087 ax->ax_wbtlen += sizeof(value);
1088 return 0;
1089}
1090
1091
1092static int
1093ax_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((void *)0))
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_MAX0xff) {
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
1126static int
1127ax_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
1147static int
1148ax_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(*__errno()) = EINVAL22;
1200 return -1;
1201 }
1202 }
1203 return 0;
1204}
1205
1206static uint16_t
1207ax_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(1 << 4))
1213 return be16toh(value)(__uint16_t)(__builtin_constant_p(value) ? (__uint16_t)(((__uint16_t
)(value) & 0xffU) << 8 | ((__uint16_t)(value) &
0xff00U) >> 8) : __swap16md(value))
;
1214 return le16toh(value)((__uint16_t)(value));
1215}
1216
1217static uint32_t
1218ax_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(1 << 4))
1224 return be32toh(value)(__uint32_t)(__builtin_constant_p(value) ? (__uint32_t)(((__uint32_t
)(value) & 0xff) << 24 | ((__uint32_t)(value) &
0xff00) << 8 | ((__uint32_t)(value) & 0xff0000) >>
8 | ((__uint32_t)(value) & 0xff000000) >> 24) : __swap32md
(value))
;
1225 return le32toh(value)((__uint32_t)(value));
1226}
1227
1228static uint64_t
1229ax_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(1 << 4))
1235 return be64toh(value)(__uint64_t)(__builtin_constant_p(value) ? (__uint64_t)((((__uint64_t
)(value) & 0xff) << 56) | ((__uint64_t)(value) &
0xff00ULL) << 40 | ((__uint64_t)(value) & 0xff0000ULL
) << 24 | ((__uint64_t)(value) & 0xff000000ULL) <<
8 | ((__uint64_t)(value) & 0xff00000000ULL) >> 8 |
((__uint64_t)(value) & 0xff0000000000ULL) >> 24 | (
(__uint64_t)(value) & 0xff000000000000ULL) >> 40 | (
(__uint64_t)(value) & 0xff00000000000000ULL) >> 56)
: __swap64md(value))
;
1236 return le64toh(value)((__uint64_t)(value));
1237}
1238
1239static ssize_t
1240ax_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
1270fail:
1271 errno(*__errno()) = EPROTO95;
1272 return -1;
1273}
1274
1275static ssize_t
1276ax_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((void *)0))
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
1300fail:
1301 errno(*__errno()) = EPROTO95;
1302 return -1;
1303}
1304
1305static ssize_t
1306ax_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
1366fail:
1367 errno(*__errno()) = EPROTO95;
1368 return -1;
1369}