| GCC Code Coverage Report | |||||||||||||||||||||
        
  | 
    |||||||||||||||||||||
| Line | Branch | Exec | Source | 
1  | 
    /* $OpenBSD: agentx.c,v 1.10 2015/12/05 06:42:18 mmcc Exp $ */  | 
    ||
2  | 
    /*  | 
    ||
3  | 
    * Copyright (c) 2013,2014 Bret Stephen Lambert <blambert@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  | 
    |||
18  | 
    #include <sys/types.h>  | 
    ||
19  | 
    #include <sys/socket.h>  | 
    ||
20  | 
    #include <sys/socketvar.h>  | 
    ||
21  | 
    #include <sys/uio.h>  | 
    ||
22  | 
    #include <sys/un.h>  | 
    ||
23  | 
    |||
24  | 
    #include <arpa/inet.h>  | 
    ||
25  | 
    |||
26  | 
    #include <err.h>  | 
    ||
27  | 
    #include <errno.h>  | 
    ||
28  | 
    #include <stdlib.h>  | 
    ||
29  | 
    #include <stdio.h>  | 
    ||
30  | 
    #include <string.h>  | 
    ||
31  | 
    #include <unistd.h>  | 
    ||
32  | 
    |||
33  | 
    #include "snmp.h"  | 
    ||
34  | 
    |||
35  | 
    int snmp_agentx_octetstring(struct agentx_pdu *, char *, int);  | 
    ||
36  | 
    int snmp_agentx_buffercheck(struct agentx_pdu *, size_t);  | 
    ||
37  | 
    int snmp_agentx_oid(struct agentx_pdu *, struct snmp_oid *);  | 
    ||
38  | 
    int snmp_agentx_buffer_consume(struct agentx_pdu *, u_int);  | 
    ||
39  | 
    int snmp_agentx_int(struct agentx_pdu *, uint32_t *);  | 
    ||
40  | 
    int snmp_agentx_int64(struct agentx_pdu *, uint64_t *);  | 
    ||
41  | 
    int snmp_agentx_do_read_raw(struct agentx_pdu *, void *, int, int);  | 
    ||
42  | 
    void snmp_agentx_update_ids(struct agentx_handle *, struct agentx_pdu *);  | 
    ||
43  | 
    struct agentx_pdu *  | 
    ||
44  | 
    agentx_find_inflight(struct agentx_handle *, uint32_t, uint32_t);  | 
    ||
45  | 
    int snmp_agentx_do_read_oid(struct agentx_pdu *, struct snmp_oid *, int *);  | 
    ||
46  | 
    |||
47  | 
    #ifdef DEBUG  | 
    ||
48  | 
    static void snmp_agentx_dump_hdr(struct agentx_hdr *);  | 
    ||
49  | 
    #endif  | 
    ||
50  | 
    |||
51  | 
    #define PDU_BUFLEN 256  | 
    ||
52  | 
    |||
53  | 
    /* snmpTrapOid.0 */  | 
    ||
54  | 
    struct snmp_oid trapoid_0 = { | 
    ||
55  | 
    	.o_id =	{ 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 }, | 
    ||
56  | 
    .o_n = 11  | 
    ||
57  | 
    };  | 
    ||
58  | 
    |||
59  | 
    /*  | 
    ||
60  | 
    * AgentX handle allocation and management routines.  | 
    ||
61  | 
    */  | 
    ||
62  | 
    |||
63  | 
    struct agentx_handle *  | 
    ||
64  | 
    snmp_agentx_alloc(int s)  | 
    ||
65  | 
    { | 
    ||
66  | 
    struct agentx_handle *h;  | 
    ||
67  | 
    |||
68  | 
    ✗✓ | 8  | 
    if ((h = calloc(1, sizeof(*h))) == NULL)  | 
    
69  | 
    return (NULL);  | 
    ||
70  | 
    |||
71  | 
    4  | 
    h->fd = s;  | 
    |
72  | 
    4  | 
    h->timeout = AGENTX_DEFAULT_TIMEOUT;  | 
    |
73  | 
    |||
74  | 
    4  | 
    TAILQ_INIT(&h->w);  | 
    |
75  | 
    4  | 
    TAILQ_INIT(&h->inflight);  | 
    |
76  | 
    |||
77  | 
    4  | 
    return (h);  | 
    |
78  | 
    4  | 
    }  | 
    |
79  | 
    |||
80  | 
    /*  | 
    ||
81  | 
    * Synchronous open of unix socket path.  | 
    ||
82  | 
    */  | 
    ||
83  | 
    struct agentx_handle *  | 
    ||
84  | 
    snmp_agentx_open(const char *path, char *descr, struct snmp_oid *oid)  | 
    ||
85  | 
    { | 
    ||
86  | 
    struct sockaddr_un sun;  | 
    ||
87  | 
    struct agentx_handle *h;  | 
    ||
88  | 
    int s;  | 
    ||
89  | 
    |||
90  | 
    if ((s = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)  | 
    ||
91  | 
    return (NULL);  | 
    ||
92  | 
    |||
93  | 
    bzero(&sun, sizeof(sun));  | 
    ||
94  | 
    sun.sun_family = AF_UNIX;  | 
    ||
95  | 
    if (strlcpy(sun.sun_path, path, sizeof(sun.sun_path)) >=  | 
    ||
96  | 
    sizeof(sun.sun_path))  | 
    ||
97  | 
    goto fail;  | 
    ||
98  | 
    |||
99  | 
    if (connect(s, (struct sockaddr *)&sun, sizeof(sun)) == -1)  | 
    ||
100  | 
    goto fail;  | 
    ||
101  | 
    |||
102  | 
    if ((h = snmp_agentx_fdopen(s, descr, oid)) == NULL)  | 
    ||
103  | 
    goto fail;  | 
    ||
104  | 
    |||
105  | 
    return (h);  | 
    ||
106  | 
    fail:  | 
    ||
107  | 
    close(s);  | 
    ||
108  | 
    return (NULL);  | 
    ||
109  | 
    }  | 
    ||
110  | 
    |||
111  | 
    /*  | 
    ||
112  | 
    * Synchronous AgentX open operation over previously-opened socket.  | 
    ||
113  | 
    */  | 
    ||
114  | 
    struct agentx_handle *  | 
    ||
115  | 
    snmp_agentx_fdopen(int s, char *descr, struct snmp_oid *oid)  | 
    ||
116  | 
    { | 
    ||
117  | 
    struct agentx_handle *h;  | 
    ||
118  | 
    struct agentx_pdu *pdu = NULL;  | 
    ||
119  | 
    |||
120  | 
    ✗✓ | 8  | 
    if ((h = snmp_agentx_alloc(s)) == NULL)  | 
    
121  | 
    return (NULL);  | 
    ||
122  | 
    |||
123  | 
    ✓✗✗✓ | 
    8  | 
    if ((pdu = snmp_agentx_open_pdu(h, descr, oid)) == NULL ||  | 
    
124  | 
    ✓✗ | 4  | 
    (pdu = snmp_agentx_request(h, pdu)) == NULL ||  | 
    
125  | 
    4  | 
    	    snmp_agentx_open_response(h, pdu) == -1) { | 
    |
126  | 
    if (pdu)  | 
    ||
127  | 
    snmp_agentx_pdu_free(pdu);  | 
    ||
128  | 
    snmp_agentx_free(h);  | 
    ||
129  | 
    return (NULL);  | 
    ||
130  | 
    }  | 
    ||
131  | 
    |||
132  | 
    4  | 
    return (h);  | 
    |
133  | 
    4  | 
    }  | 
    |
134  | 
    |||
135  | 
    /*  | 
    ||
136  | 
    * Synchronous close of agentx handle.  | 
    ||
137  | 
    */  | 
    ||
138  | 
    int  | 
    ||
139  | 
    snmp_agentx_close(struct agentx_handle *h, uint8_t reason)  | 
    ||
140  | 
    { | 
    ||
141  | 
    struct agentx_pdu *pdu;  | 
    ||
142  | 
    int error = 0;  | 
    ||
143  | 
    |||
144  | 
    ✗✓ | 8  | 
    if ((pdu = snmp_agentx_close_pdu(h, reason)) == NULL)  | 
    
145  | 
    return (-1);  | 
    ||
146  | 
    ✗✓ | 4  | 
    if ((pdu = snmp_agentx_request(h, pdu)) == NULL)  | 
    
147  | 
    return (-1);  | 
    ||
148  | 
    ✗✓ | 4  | 
    if (snmp_agentx_response(h, pdu) == -1)  | 
    
149  | 
    error = -1;  | 
    ||
150  | 
    |||
151  | 
    4  | 
    snmp_agentx_pdu_free(pdu);  | 
    |
152  | 
    |||
153  | 
    4  | 
    return (error);  | 
    |
154  | 
    4  | 
    }  | 
    |
155  | 
    |||
156  | 
    void  | 
    ||
157  | 
    snmp_agentx_free(struct agentx_handle *h)  | 
    ||
158  | 
    { | 
    ||
159  | 
    struct agentx_pdu *pdu;  | 
    ||
160  | 
    |||
161  | 
    if (h->fd != -1)  | 
    ||
162  | 
    close(h->fd);  | 
    ||
163  | 
    |||
164  | 
    	while ((pdu = TAILQ_FIRST(&h->w))) { | 
    ||
165  | 
    TAILQ_REMOVE(&h->w, pdu, entry);  | 
    ||
166  | 
    snmp_agentx_pdu_free(pdu);  | 
    ||
167  | 
    }  | 
    ||
168  | 
    	while ((pdu = TAILQ_FIRST(&h->inflight))) { | 
    ||
169  | 
    TAILQ_REMOVE(&h->w, pdu, entry);  | 
    ||
170  | 
    snmp_agentx_pdu_free(pdu);  | 
    ||
171  | 
    }  | 
    ||
172  | 
    if (h->r)  | 
    ||
173  | 
    snmp_agentx_pdu_free(h->r);  | 
    ||
174  | 
    |||
175  | 
    free(h);  | 
    ||
176  | 
    }  | 
    ||
177  | 
    |||
178  | 
    /*  | 
    ||
179  | 
    * AgentX pdu allocation routines.  | 
    ||
180  | 
    */  | 
    ||
181  | 
    |||
182  | 
    /*  | 
    ||
183  | 
    * Allocate an AgentX PDU.  | 
    ||
184  | 
    */  | 
    ||
185  | 
    struct agentx_pdu *  | 
    ||
186  | 
    snmp_agentx_pdu_alloc(void)  | 
    ||
187  | 
    { | 
    ||
188  | 
    struct agentx_pdu *pdu;  | 
    ||
189  | 
    |||
190  | 
    ✗✓ | 48  | 
    if ((pdu = calloc(1, sizeof(*pdu))) == NULL)  | 
    
191  | 
    return (NULL);  | 
    ||
192  | 
    ✗✓ | 24  | 
    	if ((pdu->buffer = calloc(PDU_BUFLEN, sizeof(uint8_t))) == NULL) { | 
    
193  | 
    free(pdu);  | 
    ||
194  | 
    return (NULL);  | 
    ||
195  | 
    }  | 
    ||
196  | 
    |||
197  | 
    24  | 
    pdu->buflen = PDU_BUFLEN;  | 
    |
198  | 
    |||
199  | 
    24  | 
    bzero(pdu->buffer, pdu->buflen);  | 
    |
200  | 
    24  | 
    pdu->ptr = pdu->buffer + sizeof(struct agentx_hdr);  | 
    |
201  | 
    24  | 
    pdu->ioptr = pdu->buffer;  | 
    |
202  | 
    24  | 
    pdu->hdr = (struct agentx_hdr *)pdu->buffer;  | 
    |
203  | 
    24  | 
    pdu->hdr->version = AGENTX_VERSION;  | 
    |
204  | 
    24  | 
    pdu->hdr->flags = AGENTX_LOCAL_BYTE_ORDER_FLAG;  | 
    |
205  | 
    24  | 
    pdu->hdr->reserved = 0;  | 
    |
206  | 
    24  | 
    pdu->hdr->length = 0;  | 
    |
207  | 
    24  | 
    pdu->datalen = sizeof(struct agentx_hdr);  | 
    |
208  | 
    |||
209  | 
    24  | 
    return (pdu);  | 
    |
210  | 
    24  | 
    }  | 
    |
211  | 
    |||
212  | 
    /*  | 
    ||
213  | 
    * Read the response PDU for a generic operation.  | 
    ||
214  | 
    */  | 
    ||
215  | 
    int  | 
    ||
216  | 
    snmp_agentx_response(struct agentx_handle *h, struct agentx_pdu *pdu)  | 
    ||
217  | 
    { | 
    ||
218  | 
    24  | 
    struct agentx_response_data resp;  | 
    |
219  | 
    |||
220  | 
    ✗✓ | 12  | 
    if (snmp_agentx_read_response(pdu, &resp) == -1)  | 
    
221  | 
    return (-1);  | 
    ||
222  | 
    |||
223  | 
    12  | 
    h->error = resp.error;  | 
    |
224  | 
    ✗✓ | 12  | 
    if (resp.error != AGENTX_ERR_NONE)  | 
    
225  | 
    return (-1);  | 
    ||
226  | 
    |||
227  | 
    12  | 
    return (0);  | 
    |
228  | 
    12  | 
    }  | 
    |
229  | 
    |||
230  | 
    int  | 
    ||
231  | 
    snmp_agentx_read_response(struct agentx_pdu *pdu, struct agentx_response_data *resp)  | 
    ||
232  | 
    { | 
    ||
233  | 
    ✗✓ | 24  | 
    if (snmp_agentx_read_raw(pdu, resp, sizeof(*resp)) == -1)  | 
    
234  | 
    return (-1);  | 
    ||
235  | 
    |||
236  | 
    ✗✓ | 12  | 
    	if (!snmp_agentx_byteorder_native(pdu->hdr)) { | 
    
237  | 
    resp->error = snmp_agentx_int16_byteswap(resp->error);  | 
    ||
238  | 
    resp->index = snmp_agentx_int16_byteswap(resp->index);  | 
    ||
239  | 
    }  | 
    ||
240  | 
    |||
241  | 
    12  | 
    return (0);  | 
    |
242  | 
    12  | 
    }  | 
    |
243  | 
    |||
244  | 
    /*  | 
    ||
245  | 
    * Read the response PDU for an open operation.  | 
    ||
246  | 
    */  | 
    ||
247  | 
    int  | 
    ||
248  | 
    snmp_agentx_open_response(struct agentx_handle *h, struct agentx_pdu *pdu)  | 
    ||
249  | 
    { | 
    ||
250  | 
    |||
251  | 
    ✗✓ | 8  | 
    if (snmp_agentx_response(h, pdu) == -1)  | 
    
252  | 
    return (-1);  | 
    ||
253  | 
    |||
254  | 
    4  | 
    h->sessionid = pdu->hdr->sessionid;  | 
    |
255  | 
    4  | 
    return (0);  | 
    |
256  | 
    4  | 
    }  | 
    |
257  | 
    |||
258  | 
    void  | 
    ||
259  | 
    snmp_agentx_pdu_free(struct agentx_pdu *pdu)  | 
    ||
260  | 
    { | 
    ||
261  | 
    16  | 
    free(pdu->buffer);  | 
    |
262  | 
    8  | 
    free(pdu->request);  | 
    |
263  | 
    8  | 
    free(pdu);  | 
    |
264  | 
    8  | 
    }  | 
    |
265  | 
    |||
266  | 
    int  | 
    ||
267  | 
    snmp_agentx_buffer_consume(struct agentx_pdu *b, u_int len)  | 
    ||
268  | 
    { | 
    ||
269  | 
    int padding;  | 
    ||
270  | 
    |||
271  | 
    24  | 
    padding = ((len + 3) & ~0x03) - len;  | 
    |
272  | 
    |||
273  | 
    ✗✓ | 12  | 
    if (b->datalen < (len + padding))  | 
    
274  | 
    return (-1);  | 
    ||
275  | 
    |||
276  | 
    12  | 
    b->datalen -= len + padding;  | 
    |
277  | 
    12  | 
    b->ptr += len + padding;  | 
    |
278  | 
    |||
279  | 
    12  | 
    return (0);  | 
    |
280  | 
    12  | 
    }  | 
    |
281  | 
    |||
282  | 
    /*  | 
    ||
283  | 
    * Send an AgentX PDU. Flushes any already-enqueued PDUs.  | 
    ||
284  | 
    */  | 
    ||
285  | 
    int  | 
    ||
286  | 
    snmp_agentx_send(struct agentx_handle *h, struct agentx_pdu *pdu)  | 
    ||
287  | 
    { | 
    ||
288  | 
    ssize_t n;  | 
    ||
289  | 
    |||
290  | 
    /* set the appropriate IDs in the protocol header */  | 
    ||
291  | 
    ✓✓✓✗ | 
    60  | 
    if (pdu != NULL &&  | 
    
292  | 
    12  | 
    	    (pdu->datalen == pdu->hdr->length + sizeof(struct agentx_hdr))) { | 
    |
293  | 
    12  | 
    pdu->hdr->sessionid = h->sessionid;  | 
    |
294  | 
    |||
295  | 
    ✓✗ | 12  | 
    		if (pdu->hdr->type != AGENTX_RESPONSE) { | 
    
296  | 
    12  | 
    ++h->transactid;  | 
    |
297  | 
    12  | 
    ++h->packetid;  | 
    |
298  | 
    12  | 
    }  | 
    |
299  | 
    |||
300  | 
    12  | 
    pdu->hdr->transactid = h->transactid;  | 
    |
301  | 
    12  | 
    pdu->hdr->packetid = h->packetid;  | 
    |
302  | 
    12  | 
    TAILQ_INSERT_TAIL(&h->w, pdu, entry);  | 
    |
303  | 
    12  | 
    }  | 
    |
304  | 
    |||
305  | 
    again:  | 
    ||
306  | 
    ✓✓ | 36  | 
    if ((pdu = TAILQ_FIRST(&h->w)) == NULL)  | 
    
307  | 
    24  | 
    return (0);  | 
    |
308  | 
    |||
309  | 
    ✗✓ | 12  | 
    if ((n = send(h->fd, pdu->ioptr, pdu->datalen, 0)) == -1)  | 
    
310  | 
    return (-1);  | 
    ||
311  | 
    |||
312  | 
    12  | 
    pdu->ioptr += n;  | 
    |
313  | 
    12  | 
    pdu->datalen -= n;  | 
    |
314  | 
    |||
315  | 
    ✗✓ | 12  | 
    	if (pdu->datalen > 0) { | 
    
316  | 
    errno = EAGAIN;  | 
    ||
317  | 
    return (-1);  | 
    ||
318  | 
    }  | 
    ||
319  | 
    |||
320  | 
    #ifdef DEBUG  | 
    ||
321  | 
    snmp_agentx_dump_hdr(pdu->hdr);  | 
    ||
322  | 
    #endif  | 
    ||
323  | 
    |||
324  | 
    ✗✓ | 36  | 
    TAILQ_REMOVE(&h->w, pdu, entry);  | 
    
325  | 
    12  | 
    TAILQ_INSERT_TAIL(&h->inflight, pdu, entry);  | 
    |
326  | 
    |||
327  | 
    12  | 
    goto again;  | 
    |
328  | 
    24  | 
    }  | 
    |
329  | 
    |||
330  | 
    /*  | 
    ||
331  | 
    * Attempt to read a single AgentX PDU.  | 
    ||
332  | 
    */  | 
    ||
333  | 
    struct agentx_pdu *  | 
    ||
334  | 
    snmp_agentx_recv(struct agentx_handle *h)  | 
    ||
335  | 
    { | 
    ||
336  | 
    struct agentx_pdu *pdu, *match;  | 
    ||
337  | 
    ssize_t n;  | 
    ||
338  | 
    |||
339  | 
    24  | 
    h->error = AGENTX_ERR_NONE;  | 
    |
340  | 
    |||
341  | 
    ✓✗ | 12  | 
    	if (h->r == NULL) { | 
    
342  | 
    ✗✓ | 12  | 
    if ((h->r = snmp_agentx_pdu_alloc()) == NULL)  | 
    
343  | 
    return (NULL);  | 
    ||
344  | 
    12  | 
    h->r->datalen = 0; /* XXX -- force this for receive buffers */  | 
    |
345  | 
    12  | 
    }  | 
    |
346  | 
    12  | 
    pdu = h->r;  | 
    |
347  | 
    |||
348  | 
    ✗✓ | 12  | 
    if (snmp_agentx_buffercheck(pdu, sizeof(struct agentx_hdr)) == -1)  | 
    
349  | 
    return (NULL);  | 
    ||
350  | 
    |||
351  | 
    /* read header */  | 
    ||
352  | 
    ✓✗ | 12  | 
    	if (pdu->datalen < sizeof(struct agentx_hdr)) { | 
    
353  | 
    12  | 
    n = recv(h->fd, pdu->ioptr, sizeof(struct agentx_hdr), 0);  | 
    |
354  | 
    |||
355  | 
    ✗✓ | 12  | 
    if (n == 0 || n == -1)  | 
    
356  | 
    return (NULL);  | 
    ||
357  | 
    |||
358  | 
    12  | 
    pdu->datalen += n;  | 
    |
359  | 
    12  | 
    pdu->ioptr += n;  | 
    |
360  | 
    |||
361  | 
    ✗✓ | 12  | 
    		if (pdu->datalen < sizeof(struct agentx_hdr)) { | 
    
362  | 
    errno = EAGAIN;  | 
    ||
363  | 
    return (NULL);  | 
    ||
364  | 
    }  | 
    ||
365  | 
    |||
366  | 
    ✗✓ | 12  | 
    		if (pdu->hdr->version != AGENTX_VERSION) { | 
    
367  | 
    h->error = AGENTX_ERR_PARSE_ERROR;  | 
    ||
368  | 
    return (NULL);  | 
    ||
369  | 
    }  | 
    ||
370  | 
    |||
371  | 
    ✗✓ | 12  | 
    if (snmp_agentx_buffercheck(pdu, pdu->hdr->length) == -1)  | 
    
372  | 
    return (NULL);  | 
    ||
373  | 
    }  | 
    ||
374  | 
    |||
375  | 
    /* read body */  | 
    ||
376  | 
    ✓✗ | 12  | 
    	if (pdu->hdr->length > 0) { | 
    
377  | 
    12  | 
    n = recv(h->fd, pdu->ioptr, pdu->hdr->length, 0);  | 
    |
378  | 
    |||
379  | 
    ✗✓ | 12  | 
    if (n == 0 || n == -1)  | 
    
380  | 
    return (NULL);  | 
    ||
381  | 
    |||
382  | 
    12  | 
    pdu->datalen += n;  | 
    |
383  | 
    12  | 
    pdu->ioptr += n;  | 
    |
384  | 
    12  | 
    }  | 
    |
385  | 
    |||
386  | 
    ✗✓ | 12  | 
    	if (pdu->datalen < pdu->hdr->length + sizeof(struct agentx_hdr)) { | 
    
387  | 
    errno = EAGAIN;  | 
    ||
388  | 
    return (NULL);  | 
    ||
389  | 
    }  | 
    ||
390  | 
    |||
391  | 
    ✗✓ | 12  | 
    	if (pdu->hdr->version != AGENTX_VERSION) { | 
    
392  | 
    h->error = AGENTX_ERR_PARSE_ERROR;  | 
    ||
393  | 
    goto fail;  | 
    ||
394  | 
    }  | 
    ||
395  | 
    |||
396  | 
    /* If this is an open on a new connection, fix it up */  | 
    ||
397  | 
    ✗✓✗✗ | 
    12  | 
    	if (pdu->hdr->type == AGENTX_OPEN && h->sessionid == 0) { | 
    
398  | 
    pdu->hdr->sessionid = 0; /* ignored, per RFC */  | 
    ||
399  | 
    h->transactid = pdu->hdr->transactid;  | 
    ||
400  | 
    h->packetid = pdu->hdr->packetid;  | 
    ||
401  | 
    }  | 
    ||
402  | 
    |||
403  | 
    ✓✗ | 12  | 
    	if (pdu->hdr->type == AGENTX_RESPONSE) { | 
    
404  | 
    |||
405  | 
    24  | 
    match = agentx_find_inflight(h, pdu->hdr->transactid,  | 
    |
406  | 
    12  | 
    pdu->hdr->packetid);  | 
    |
407  | 
    ✗✓ | 12  | 
    		if (match == NULL) { | 
    
408  | 
    errno = ESRCH; /* XXX */  | 
    ||
409  | 
    goto fail;  | 
    ||
410  | 
    }  | 
    ||
411  | 
    |||
412  | 
    ✗✓ | 36  | 
    TAILQ_REMOVE(&h->inflight, match, entry);  | 
    
413  | 
    12  | 
    pdu->request = match;  | 
    |
414  | 
    12  | 
    h->r = NULL;  | 
    |
415  | 
    |||
416  | 
    12  | 
    	} else { | 
    |
417  | 
    		if (pdu->hdr->sessionid != h->sessionid) { | 
    ||
418  | 
    h->error = AGENTX_ERR_NOT_OPEN;  | 
    ||
419  | 
    goto fail;  | 
    ||
420  | 
    }  | 
    ||
421  | 
    |||
422  | 
    snmp_agentx_update_ids(h, pdu); /* XXX */  | 
    ||
423  | 
    |||
424  | 
    		if (pdu->datalen != pdu->hdr->length + sizeof(*pdu->hdr)) { | 
    ||
425  | 
    h->error = AGENTX_ERR_PARSE_ERROR;  | 
    ||
426  | 
    goto fail;  | 
    ||
427  | 
    }  | 
    ||
428  | 
    |||
429  | 
    		if (pdu->hdr->flags & AGENTX_NON_DEFAULT_CONTEXT) { | 
    ||
430  | 
    pdu->context = snmp_agentx_read_octetstr(pdu,  | 
    ||
431  | 
    &pdu->contextlen);  | 
    ||
432  | 
    			if (pdu->context == NULL) { | 
    ||
433  | 
    h->error = AGENTX_ERR_PARSE_ERROR;  | 
    ||
434  | 
    goto fail;  | 
    ||
435  | 
    }  | 
    ||
436  | 
    }  | 
    ||
437  | 
    }  | 
    ||
438  | 
    |||
439  | 
    #ifdef DEBUG  | 
    ||
440  | 
    snmp_agentx_dump_hdr(pdu->hdr);  | 
    ||
441  | 
    #endif  | 
    ||
442  | 
    12  | 
    h->r = NULL;  | 
    |
443  | 
    |||
444  | 
    12  | 
    return (pdu);  | 
    |
445  | 
    |||
446  | 
    fail:  | 
    ||
447  | 
    #ifdef DEBUG  | 
    ||
448  | 
    snmp_agentx_dump_hdr(pdu->hdr);  | 
    ||
449  | 
    #endif  | 
    ||
450  | 
    snmp_agentx_pdu_free(pdu);  | 
    ||
451  | 
    h->r = NULL;  | 
    ||
452  | 
    |||
453  | 
    return (NULL);  | 
    ||
454  | 
    12  | 
    }  | 
    |
455  | 
    |||
456  | 
    /*  | 
    ||
457  | 
    * Synchonous request and receipt of response.  | 
    ||
458  | 
    */  | 
    ||
459  | 
    struct agentx_pdu *  | 
    ||
460  | 
    snmp_agentx_request(struct agentx_handle *h, struct agentx_pdu *pdu)  | 
    ||
461  | 
    { | 
    ||
462  | 
    |||
463  | 
    ✗✓ | 24  | 
    	if (snmp_agentx_send(h, pdu) == -1) { | 
    
464  | 
    if (errno != EAGAIN)  | 
    ||
465  | 
    return (NULL);  | 
    ||
466  | 
    }  | 
    ||
467  | 
    ✗✓ | 12  | 
    	while (snmp_agentx_send(h, NULL) == -1) { | 
    
468  | 
    if (errno != EAGAIN)  | 
    ||
469  | 
    return (NULL);  | 
    ||
470  | 
    }  | 
    ||
471  | 
    ✗✓ | 12  | 
    	while ((pdu = snmp_agentx_recv(h)) == NULL) { | 
    
472  | 
    if (errno != EAGAIN)  | 
    ||
473  | 
    return (NULL);  | 
    ||
474  | 
    }  | 
    ||
475  | 
    12  | 
    h->error = AGENTX_ERR_NONE;  | 
    |
476  | 
    |||
477  | 
    12  | 
    return (pdu);  | 
    |
478  | 
    12  | 
    }  | 
    |
479  | 
    |||
480  | 
    struct agentx_pdu *  | 
    ||
481  | 
    agentx_find_inflight(struct agentx_handle *h, uint32_t tid, uint32_t pid)  | 
    ||
482  | 
    { | 
    ||
483  | 
    struct agentx_pdu *pdu;  | 
    ||
484  | 
    |||
485  | 
    ✓✗ | 36  | 
    TAILQ_FOREACH(pdu, &h->inflight, entry)  | 
    
486  | 
    ✓✗✗✓ | 
    24  | 
    if (pdu->hdr->transactid == tid && pdu->hdr->packetid == pid)  | 
    
487  | 
    break;  | 
    ||
488  | 
    12  | 
    return (pdu);  | 
    |
489  | 
    }  | 
    ||
490  | 
    |||
491  | 
    int  | 
    ||
492  | 
    snmp_agentx_buffercheck(struct agentx_pdu *pdu, size_t len)  | 
    ||
493  | 
    { | 
    ||
494  | 
    uint8_t *newptr;  | 
    ||
495  | 
    size_t newlen;  | 
    ||
496  | 
    |||
497  | 
    ✓✗ | 200  | 
    if (pdu->buflen - pdu->datalen >= len)  | 
    
498  | 
    100  | 
    return (0);  | 
    |
499  | 
    |||
500  | 
    newlen = pdu->buflen + len;  | 
    ||
501  | 
    if (newlen < pdu->buflen || newlen < len)  | 
    ||
502  | 
    return (-1);  | 
    ||
503  | 
    |||
504  | 
    if ((newptr = realloc(pdu->buffer, newlen)) == NULL)  | 
    ||
505  | 
    return (-1);  | 
    ||
506  | 
    |||
507  | 
    pdu->buflen = newlen;  | 
    ||
508  | 
    pdu->ioptr = &newptr[pdu->ioptr - pdu->buffer];  | 
    ||
509  | 
    pdu->buffer = newptr;  | 
    ||
510  | 
    pdu->hdr = (struct agentx_hdr *)pdu->buffer;  | 
    ||
511  | 
    pdu->ptr = &pdu->buffer[pdu->datalen];  | 
    ||
512  | 
    |||
513  | 
    return (0);  | 
    ||
514  | 
    100  | 
    }  | 
    |
515  | 
    |||
516  | 
    /*  | 
    ||
517  | 
    * Utility routines for initializing common AgentX PDUs.  | 
    ||
518  | 
    */  | 
    ||
519  | 
    |||
520  | 
    struct agentx_pdu *  | 
    ||
521  | 
    snmp_agentx_open_pdu(struct agentx_handle *h, char *descr,  | 
    ||
522  | 
    struct snmp_oid *oid)  | 
    ||
523  | 
    { | 
    ||
524  | 
    8  | 
    struct agentx_open_timeout to;  | 
    |
525  | 
    4  | 
    struct snmp_oid nulloid;  | 
    |
526  | 
    struct agentx_pdu *pdu;  | 
    ||
527  | 
    |||
528  | 
    ✗✓ | 4  | 
    if ((pdu = snmp_agentx_pdu_alloc()) == NULL)  | 
    
529  | 
    return (NULL);  | 
    ||
530  | 
    |||
531  | 
    4  | 
    pdu->hdr->type = AGENTX_OPEN;  | 
    |
532  | 
    |||
533  | 
    ✓✗ | 4  | 
    	if (oid == NULL) { | 
    
534  | 
    4  | 
    bzero(&nulloid, sizeof(nulloid));  | 
    |
535  | 
    oid = &nulloid;  | 
    ||
536  | 
    4  | 
    }  | 
    |
537  | 
    |||
538  | 
    4  | 
    bzero(&to, sizeof(to));  | 
    |
539  | 
    4  | 
    to.timeout = AGENTX_DEFAULT_TIMEOUT;  | 
    |
540  | 
    |||
541  | 
    ✓✗✓✗ | 
    8  | 
    if (snmp_agentx_raw(pdu, &to, sizeof(to)) == -1 ||  | 
    
542  | 
    ✓✗ | 4  | 
    snmp_agentx_oid(pdu, oid) == -1 ||  | 
    
543  | 
    4  | 
    snmp_agentx_octetstring(pdu, descr, strlen(descr)) == -1)  | 
    |
544  | 
    goto fail;  | 
    ||
545  | 
    |||
546  | 
    4  | 
    return (pdu);  | 
    |
547  | 
    fail:  | 
    ||
548  | 
    snmp_agentx_pdu_free(pdu);  | 
    ||
549  | 
    return (NULL);  | 
    ||
550  | 
    4  | 
    }  | 
    |
551  | 
    |||
552  | 
    struct agentx_pdu *  | 
    ||
553  | 
    snmp_agentx_close_pdu(struct agentx_handle *h, uint8_t reason)  | 
    ||
554  | 
    { | 
    ||
555  | 
    8  | 
    struct agentx_close_request_data req;  | 
    |
556  | 
    struct agentx_pdu *pdu;  | 
    ||
557  | 
    |||
558  | 
    ✗✓ | 4  | 
    if ((pdu = snmp_agentx_pdu_alloc()) == NULL)  | 
    
559  | 
    return (NULL);  | 
    ||
560  | 
    4  | 
    pdu->hdr->type = AGENTX_CLOSE;  | 
    |
561  | 
    |||
562  | 
    4  | 
    bzero(&req, sizeof(req));  | 
    |
563  | 
    4  | 
    req.reason = reason;  | 
    |
564  | 
    |||
565  | 
    ✗✓ | 4  | 
    	if (snmp_agentx_raw(pdu, &req, sizeof(req)) == -1) { | 
    
566  | 
    snmp_agentx_pdu_free(pdu);  | 
    ||
567  | 
    return (NULL);  | 
    ||
568  | 
    }  | 
    ||
569  | 
    |||
570  | 
    4  | 
    return (pdu);  | 
    |
571  | 
    4  | 
    }  | 
    |
572  | 
    |||
573  | 
    struct agentx_pdu *  | 
    ||
574  | 
    snmp_agentx_notify_pdu(struct snmp_oid *oid)  | 
    ||
575  | 
    { | 
    ||
576  | 
    struct agentx_pdu *pdu;  | 
    ||
577  | 
    |||
578  | 
    ✗✓ | 8  | 
    if ((pdu = snmp_agentx_pdu_alloc()) == NULL)  | 
    
579  | 
    return (NULL);  | 
    ||
580  | 
    4  | 
    pdu->hdr->type = AGENTX_NOTIFY;  | 
    |
581  | 
    |||
582  | 
    ✗✓ | 8  | 
    if (snmp_agentx_varbind(pdu, &trapoid_0,  | 
    
583  | 
    8  | 
    	    AGENTX_OBJECT_IDENTIFIER, oid, sizeof(*oid)) == -1) { | 
    |
584  | 
    snmp_agentx_pdu_free(pdu);  | 
    ||
585  | 
    return (NULL);  | 
    ||
586  | 
    }  | 
    ||
587  | 
    |||
588  | 
    4  | 
    return (pdu);  | 
    |
589  | 
    4  | 
    }  | 
    |
590  | 
    |||
591  | 
    struct agentx_pdu *  | 
    ||
592  | 
    snmp_agentx_response_pdu(int uptime, int error, int idx)  | 
    ||
593  | 
    { | 
    ||
594  | 
    struct agentx_response_data resp;  | 
    ||
595  | 
    struct agentx_pdu *pdu;  | 
    ||
596  | 
    |||
597  | 
    if ((pdu = snmp_agentx_pdu_alloc()) == NULL)  | 
    ||
598  | 
    return (NULL);  | 
    ||
599  | 
    pdu->hdr->type = AGENTX_RESPONSE;  | 
    ||
600  | 
    |||
601  | 
    resp.sysuptime = uptime;  | 
    ||
602  | 
    resp.error = error;  | 
    ||
603  | 
    resp.index = idx;  | 
    ||
604  | 
    |||
605  | 
    	if (snmp_agentx_raw(pdu, &resp, sizeof(resp)) == -1) { | 
    ||
606  | 
    snmp_agentx_pdu_free(pdu);  | 
    ||
607  | 
    return (NULL);  | 
    ||
608  | 
    }  | 
    ||
609  | 
    |||
610  | 
    return (pdu);  | 
    ||
611  | 
    }  | 
    ||
612  | 
    |||
613  | 
    struct agentx_pdu *  | 
    ||
614  | 
    snmp_agentx_ping_pdu(void)  | 
    ||
615  | 
    { | 
    ||
616  | 
    struct agentx_pdu *pdu;  | 
    ||
617  | 
    |||
618  | 
    if ((pdu = snmp_agentx_pdu_alloc()) == NULL)  | 
    ||
619  | 
    return (NULL);  | 
    ||
620  | 
    pdu->hdr->version = AGENTX_VERSION;  | 
    ||
621  | 
    pdu->hdr->type = AGENTX_PING;  | 
    ||
622  | 
    |||
623  | 
    return (pdu);  | 
    ||
624  | 
    }  | 
    ||
625  | 
    |||
626  | 
    struct agentx_pdu *  | 
    ||
627  | 
    snmp_agentx_register_pdu(struct snmp_oid *oid, int timeout, int range_index,  | 
    ||
628  | 
    int range_bound)  | 
    ||
629  | 
    { | 
    ||
630  | 
    struct agentx_register_hdr rhdr;  | 
    ||
631  | 
    struct agentx_pdu *pdu;  | 
    ||
632  | 
    |||
633  | 
    if ((pdu = snmp_agentx_pdu_alloc()) == NULL)  | 
    ||
634  | 
    return (NULL);  | 
    ||
635  | 
    |||
636  | 
    pdu->hdr->version = AGENTX_VERSION;  | 
    ||
637  | 
    pdu->hdr->type = AGENTX_REGISTER;  | 
    ||
638  | 
    |||
639  | 
    rhdr.timeout = timeout;  | 
    ||
640  | 
    rhdr.priority = AGENTX_REGISTER_PRIO_DEFAULT;  | 
    ||
641  | 
    rhdr.subrange = range_index;  | 
    ||
642  | 
    rhdr.reserved = 0;  | 
    ||
643  | 
    |||
644  | 
    if (snmp_agentx_raw(pdu, &rhdr, sizeof(rhdr)) == -1 ||  | 
    ||
645  | 
    snmp_agentx_oid(pdu, oid) == -1 ||  | 
    ||
646  | 
    	    (range_index && snmp_agentx_int(pdu, &range_bound) == -1)) { | 
    ||
647  | 
    snmp_agentx_pdu_free(pdu);  | 
    ||
648  | 
    return (NULL);  | 
    ||
649  | 
    }  | 
    ||
650  | 
    |||
651  | 
    return (pdu);  | 
    ||
652  | 
    }  | 
    ||
653  | 
    |||
654  | 
    struct agentx_pdu *  | 
    ||
655  | 
    snmp_agentx_unregister_pdu(struct snmp_oid *oid, int range_index,  | 
    ||
656  | 
    int range_bound)  | 
    ||
657  | 
    { | 
    ||
658  | 
    struct agentx_unregister_hdr uhdr;  | 
    ||
659  | 
    struct agentx_pdu *pdu;  | 
    ||
660  | 
    |||
661  | 
    if ((pdu = snmp_agentx_pdu_alloc()) == NULL)  | 
    ||
662  | 
    return (NULL);  | 
    ||
663  | 
    |||
664  | 
    pdu->hdr->version = AGENTX_VERSION;  | 
    ||
665  | 
    pdu->hdr->type = AGENTX_UNREGISTER;  | 
    ||
666  | 
    |||
667  | 
    uhdr.reserved1 = 0;  | 
    ||
668  | 
    uhdr.priority = AGENTX_REGISTER_PRIO_DEFAULT;  | 
    ||
669  | 
    uhdr.subrange = range_index;  | 
    ||
670  | 
    uhdr.reserved2 = 0;  | 
    ||
671  | 
    |||
672  | 
    if (snmp_agentx_raw(pdu, &uhdr, sizeof(uhdr)) == -1 ||  | 
    ||
673  | 
    snmp_agentx_oid(pdu, oid) == -1 ||  | 
    ||
674  | 
    snmp_agentx_oid(pdu, oid) == -1 ||  | 
    ||
675  | 
    	    (range_index && snmp_agentx_int(pdu, &range_bound) == -1)) { | 
    ||
676  | 
    snmp_agentx_pdu_free(pdu);  | 
    ||
677  | 
    return (NULL);  | 
    ||
678  | 
    }  | 
    ||
679  | 
    |||
680  | 
    return (pdu);  | 
    ||
681  | 
    }  | 
    ||
682  | 
    |||
683  | 
    struct agentx_pdu *  | 
    ||
684  | 
    snmp_agentx_get_pdu(struct snmp_oid oid[], int noid)  | 
    ||
685  | 
    { | 
    ||
686  | 
    struct snmp_oid nulloid;  | 
    ||
687  | 
    struct agentx_pdu *pdu;  | 
    ||
688  | 
    int i;  | 
    ||
689  | 
    |||
690  | 
    if ((pdu = snmp_agentx_pdu_alloc()) == NULL)  | 
    ||
691  | 
    return (NULL);  | 
    ||
692  | 
    |||
693  | 
    pdu->hdr->version = AGENTX_VERSION;  | 
    ||
694  | 
    pdu->hdr->type = AGENTX_GET;  | 
    ||
695  | 
    |||
696  | 
    bzero(&nulloid, sizeof(nulloid));  | 
    ||
697  | 
    |||
698  | 
    	for (i = 0; i < noid; i++) { | 
    ||
699  | 
    if (snmp_agentx_oid(pdu, &oid[i]) == -1 ||  | 
    ||
700  | 
    		    snmp_agentx_oid(pdu, &nulloid) == -1) { | 
    ||
701  | 
    snmp_agentx_pdu_free(pdu);  | 
    ||
702  | 
    return (NULL);  | 
    ||
703  | 
    }  | 
    ||
704  | 
    }  | 
    ||
705  | 
    |||
706  | 
    return (pdu);  | 
    ||
707  | 
    }  | 
    ||
708  | 
    |||
709  | 
    struct agentx_pdu *  | 
    ||
710  | 
    snmp_agentx_getnext_pdu(struct snmp_oid oid[], int noid)  | 
    ||
711  | 
    { | 
    ||
712  | 
    struct snmp_oid nulloid;  | 
    ||
713  | 
    struct agentx_pdu *pdu;  | 
    ||
714  | 
    int i;  | 
    ||
715  | 
    |||
716  | 
    if ((pdu = snmp_agentx_pdu_alloc()) == NULL)  | 
    ||
717  | 
    return (NULL);  | 
    ||
718  | 
    |||
719  | 
    pdu->hdr->version = AGENTX_VERSION;  | 
    ||
720  | 
    pdu->hdr->type = AGENTX_GET_NEXT;  | 
    ||
721  | 
    |||
722  | 
    bzero(&nulloid, sizeof(nulloid));  | 
    ||
723  | 
    |||
724  | 
    	for (i = 0; i < noid; i++) { | 
    ||
725  | 
    if (snmp_agentx_oid(pdu, &oid[i]) == -1 ||  | 
    ||
726  | 
    		    snmp_agentx_oid(pdu, &nulloid) == -1) { | 
    ||
727  | 
    snmp_agentx_pdu_free(pdu);  | 
    ||
728  | 
    return (NULL);  | 
    ||
729  | 
    }  | 
    ||
730  | 
    }  | 
    ||
731  | 
    |||
732  | 
    return (pdu);  | 
    ||
733  | 
    }  | 
    ||
734  | 
    |||
735  | 
    /*  | 
    ||
736  | 
    * AgentX PDU write routines.  | 
    ||
737  | 
    */  | 
    ||
738  | 
    |||
739  | 
    int  | 
    ||
740  | 
    snmp_agentx_raw(struct agentx_pdu *pdu, void *data, int len)  | 
    ||
741  | 
    { | 
    ||
742  | 
    |||
743  | 
    ✗✓ | 152  | 
    if (snmp_agentx_buffercheck(pdu, len) == -1)  | 
    
744  | 
    return (-1);  | 
    ||
745  | 
    |||
746  | 
    76  | 
    memcpy(pdu->ptr, data, len);  | 
    |
747  | 
    |||
748  | 
    76  | 
    pdu->hdr->length += len;  | 
    |
749  | 
    76  | 
    pdu->ptr += len;  | 
    |
750  | 
    76  | 
    pdu->datalen += len;  | 
    |
751  | 
    |||
752  | 
    76  | 
    return (0);  | 
    |
753  | 
    76  | 
    }  | 
    |
754  | 
    |||
755  | 
    int  | 
    ||
756  | 
    snmp_agentx_int(struct agentx_pdu *pdu, uint32_t *i)  | 
    ||
757  | 
    { | 
    ||
758  | 
    88  | 
    return (snmp_agentx_raw(pdu, i, sizeof(*i)));  | 
    |
759  | 
    }  | 
    ||
760  | 
    |||
761  | 
    int  | 
    ||
762  | 
    snmp_agentx_int64(struct agentx_pdu *pdu, uint64_t *i)  | 
    ||
763  | 
    { | 
    ||
764  | 
    return (snmp_agentx_raw(pdu, i, sizeof(*i)));  | 
    ||
765  | 
    }  | 
    ||
766  | 
    |||
767  | 
    int  | 
    ||
768  | 
    snmp_agentx_octetstring(struct agentx_pdu *pdu, char *str, int len)  | 
    ||
769  | 
    { | 
    ||
770  | 
    	static uint8_t pad[4] = { 0, 0, 0, 0 }; | 
    ||
771  | 
    int padding;  | 
    ||
772  | 
    8  | 
    uint32_t l;  | 
    |
773  | 
    |||
774  | 
    4  | 
    padding = ((len + 3) & ~0x03) - len;  | 
    |
775  | 
    |||
776  | 
    4  | 
    l = len;  | 
    |
777  | 
    ✓✗✗✓ | 
    8  | 
    if (snmp_agentx_int(pdu, &l) == -1 ||  | 
    
778  | 
    ✓✗ | 4  | 
    snmp_agentx_raw(pdu, str, len) == -1 ||  | 
    
779  | 
    4  | 
    snmp_agentx_raw(pdu, pad, padding) == -1)  | 
    |
780  | 
    return (-1);  | 
    ||
781  | 
    |||
782  | 
    4  | 
    return (0);  | 
    |
783  | 
    4  | 
    }  | 
    |
784  | 
    |||
785  | 
    int  | 
    ||
786  | 
    snmp_agentx_oid(struct agentx_pdu *pdu, struct snmp_oid *oid)  | 
    ||
787  | 
    { | 
    ||
788  | 
    24  | 
    struct agentx_oid_hdr ohdr;  | 
    |
789  | 
    u_int i, prefix;  | 
    ||
790  | 
    |||
791  | 
    i = prefix = 0;  | 
    ||
792  | 
    |||
793  | 
    ✓✓✓✓ ✓✗  | 
    24  | 
    if (oid->o_id[0] == 1 && oid->o_id[1] == 3 &&  | 
    
794  | 
    ✓✗✓✗ | 
    8  | 
    oid->o_id[2] == 6 && oid->o_id[3] == 1 &&  | 
    
795  | 
    4  | 
    	    oid->o_id[4] < 256) { | 
    |
796  | 
    prefix = oid->o_id[4];  | 
    ||
797  | 
    i = 5;  | 
    ||
798  | 
    4  | 
    }  | 
    |
799  | 
    |||
800  | 
    24  | 
    if (prefix)  | 
    |
801  | 
    12  | 
    ohdr.n_subid = oid->o_n - 5;  | 
    |
802  | 
    else  | 
    ||
803  | 
    ohdr.n_subid = oid->o_n;  | 
    ||
804  | 
    12  | 
    ohdr.prefix = prefix;  | 
    |
805  | 
    12  | 
    ohdr.include = 0;  | 
    |
806  | 
    12  | 
    ohdr.reserved = 0;  | 
    |
807  | 
    |||
808  | 
    ✗✓ | 12  | 
    if (snmp_agentx_raw(pdu, &ohdr, sizeof(ohdr)) == -1)  | 
    
809  | 
    return (-1);  | 
    ||
810  | 
    |||
811  | 
    ✓✓ | 92  | 
    for (; i < oid->o_n; i++)  | 
    
812  | 
    ✗✓ | 40  | 
    if (snmp_agentx_int(pdu, &oid->o_id[i]) == -1)  | 
    
813  | 
    return (-1);  | 
    ||
814  | 
    |||
815  | 
    12  | 
    return (0);  | 
    |
816  | 
    12  | 
    }  | 
    |
817  | 
    |||
818  | 
    int  | 
    ||
819  | 
    snmp_agentx_varbind(struct agentx_pdu *pdu, struct snmp_oid *oid, int type,  | 
    ||
820  | 
    void *data, int len)  | 
    ||
821  | 
    { | 
    ||
822  | 
    8  | 
    struct agentx_varbind_hdr vbhdr;  | 
    |
823  | 
    |||
824  | 
    4  | 
    vbhdr.type = type;  | 
    |
825  | 
    4  | 
    vbhdr.reserved = 0;  | 
    |
826  | 
    ✗✓ | 4  | 
    if (snmp_agentx_raw(pdu, &vbhdr, sizeof(vbhdr)) == -1)  | 
    
827  | 
    return (-1);  | 
    ||
828  | 
    |||
829  | 
    ✗✓ | 4  | 
    if (snmp_agentx_oid(pdu, oid) == -1)  | 
    
830  | 
    return (-1);  | 
    ||
831  | 
    |||
832  | 
    ✗✗✗✗ ✗✗✗✓ ✗✗✗✗ ✗✗  | 
    4  | 
    	switch (type) { | 
    
833  | 
    |||
834  | 
    case AGENTX_NO_SUCH_OBJECT:  | 
    ||
835  | 
    case AGENTX_NO_SUCH_INSTANCE:  | 
    ||
836  | 
    case AGENTX_END_OF_MIB_VIEW:  | 
    ||
837  | 
    case AGENTX_NULL:  | 
    ||
838  | 
    /* no data follows the OID */  | 
    ||
839  | 
    return (0);  | 
    ||
840  | 
    |||
841  | 
    case AGENTX_IP_ADDRESS:  | 
    ||
842  | 
    case AGENTX_OPAQUE:  | 
    ||
843  | 
    case AGENTX_OCTET_STRING:  | 
    ||
844  | 
    return (snmp_agentx_octetstring(pdu, data, len));  | 
    ||
845  | 
    |||
846  | 
    case AGENTX_OBJECT_IDENTIFIER:  | 
    ||
847  | 
    4  | 
    return (snmp_agentx_oid(pdu, (struct snmp_oid *)data));  | 
    |
848  | 
    |||
849  | 
    case AGENTX_INTEGER:  | 
    ||
850  | 
    case AGENTX_COUNTER32:  | 
    ||
851  | 
    case AGENTX_GAUGE32:  | 
    ||
852  | 
    case AGENTX_TIME_TICKS:  | 
    ||
853  | 
    return (snmp_agentx_int(pdu, (uint32_t *)data));  | 
    ||
854  | 
    |||
855  | 
    case AGENTX_COUNTER64:  | 
    ||
856  | 
    return (snmp_agentx_int64(pdu, (uint64_t *)data));  | 
    ||
857  | 
    |||
858  | 
    default:  | 
    ||
859  | 
    return (-1);  | 
    ||
860  | 
    }  | 
    ||
861  | 
    /* NOTREACHED */  | 
    ||
862  | 
    4  | 
    }  | 
    |
863  | 
    |||
864  | 
    /*  | 
    ||
865  | 
    * AgentX PDU read routines.  | 
    ||
866  | 
    */  | 
    ||
867  | 
    |||
868  | 
    int  | 
    ||
869  | 
    snmp_agentx_read_vbhdr(struct agentx_pdu *pdu,  | 
    ||
870  | 
    struct agentx_varbind_hdr *vbhdr)  | 
    ||
871  | 
    { | 
    ||
872  | 
    if (snmp_agentx_read_raw(pdu, vbhdr, sizeof(*vbhdr)) == -1)  | 
    ||
873  | 
    return (-1);  | 
    ||
874  | 
    if (!snmp_agentx_byteorder_native(pdu->hdr))  | 
    ||
875  | 
    vbhdr->type = snmp_agentx_int16_byteswap(vbhdr->type);  | 
    ||
876  | 
    return (0);  | 
    ||
877  | 
    }  | 
    ||
878  | 
    |||
879  | 
    int  | 
    ||
880  | 
    snmp_agentx_copy_raw(struct agentx_pdu *pdu, void *v, int len)  | 
    ||
881  | 
    { | 
    ||
882  | 
    return (snmp_agentx_do_read_raw(pdu, v, len, 0));  | 
    ||
883  | 
    }  | 
    ||
884  | 
    |||
885  | 
    int  | 
    ||
886  | 
    snmp_agentx_read_raw(struct agentx_pdu *pdu, void *v, int len)  | 
    ||
887  | 
    { | 
    ||
888  | 
    24  | 
    return (snmp_agentx_do_read_raw(pdu, v, len, 1));  | 
    |
889  | 
    }  | 
    ||
890  | 
    |||
891  | 
    int  | 
    ||
892  | 
    snmp_agentx_do_read_raw(struct agentx_pdu *pdu, void *v, int len, int consume)  | 
    ||
893  | 
    { | 
    ||
894  | 
    24  | 
    void *ptr = pdu->ptr;  | 
    |
895  | 
    |||
896  | 
    ✓✗ | 12  | 
    if (consume)  | 
    
897  | 
    ✗✓ | 12  | 
    if (snmp_agentx_buffer_consume(pdu, len) == -1)  | 
    
898  | 
    return (-1);  | 
    ||
899  | 
    |||
900  | 
    12  | 
    memcpy(v, ptr, len);  | 
    |
901  | 
    |||
902  | 
    12  | 
    return (0);  | 
    |
903  | 
    12  | 
    }  | 
    |
904  | 
    |||
905  | 
    int  | 
    ||
906  | 
    snmp_agentx_read_int(struct agentx_pdu *pdu, uint32_t *i)  | 
    ||
907  | 
    { | 
    ||
908  | 
    if (snmp_agentx_read_raw(pdu, i, sizeof(*i)) == -1)  | 
    ||
909  | 
    return (-1);  | 
    ||
910  | 
    if (!snmp_agentx_byteorder_native(pdu->hdr))  | 
    ||
911  | 
    *i = snmp_agentx_int_byteswap(*i);  | 
    ||
912  | 
    return (0);  | 
    ||
913  | 
    }  | 
    ||
914  | 
    |||
915  | 
    int  | 
    ||
916  | 
    snmp_agentx_read_int64(struct agentx_pdu *pdu, uint64_t *i)  | 
    ||
917  | 
    { | 
    ||
918  | 
    if (snmp_agentx_read_raw(pdu, i, sizeof(*i)) == -1)  | 
    ||
919  | 
    return (-1);  | 
    ||
920  | 
    if (!snmp_agentx_byteorder_native(pdu->hdr))  | 
    ||
921  | 
    *i = snmp_agentx_int64_byteswap(*i);  | 
    ||
922  | 
    return (0);  | 
    ||
923  | 
    }  | 
    ||
924  | 
    |||
925  | 
    int  | 
    ||
926  | 
    snmp_agentx_read_oid(struct agentx_pdu *pdu, struct snmp_oid *oid)  | 
    ||
927  | 
    { | 
    ||
928  | 
    int dummy;  | 
    ||
929  | 
    |||
930  | 
    return (snmp_agentx_do_read_oid(pdu, oid, &dummy));  | 
    ||
931  | 
    }  | 
    ||
932  | 
    |||
933  | 
    int  | 
    ||
934  | 
    snmp_agentx_do_read_oid(struct agentx_pdu *pdu, struct snmp_oid *oid,  | 
    ||
935  | 
    int *include)  | 
    ||
936  | 
    { | 
    ||
937  | 
    struct agentx_oid_hdr ohdr;  | 
    ||
938  | 
    int i = 0;  | 
    ||
939  | 
    |||
940  | 
    if (snmp_agentx_read_raw(pdu, &ohdr, sizeof(ohdr)) == -1)  | 
    ||
941  | 
    return (-1);  | 
    ||
942  | 
    |||
943  | 
    bzero(oid, sizeof(*oid));  | 
    ||
944  | 
    |||
945  | 
    	if (ohdr.prefix != 0) { | 
    ||
946  | 
    oid->o_id[0] = 1;  | 
    ||
947  | 
    oid->o_id[1] = 3;  | 
    ||
948  | 
    oid->o_id[2] = 6;  | 
    ||
949  | 
    oid->o_id[3] = 1;  | 
    ||
950  | 
    oid->o_id[4] = ohdr.prefix;  | 
    ||
951  | 
    i = 5;  | 
    ||
952  | 
    }  | 
    ||
953  | 
    |||
954  | 
    while (ohdr.n_subid--)  | 
    ||
955  | 
    if (snmp_agentx_read_int(pdu, &oid->o_id[i++]) == -1)  | 
    ||
956  | 
    return (-1);  | 
    ||
957  | 
    |||
958  | 
    oid->o_n = i;  | 
    ||
959  | 
    *include = ohdr.include;  | 
    ||
960  | 
    |||
961  | 
    return (0);  | 
    ||
962  | 
    }  | 
    ||
963  | 
    |||
964  | 
    int  | 
    ||
965  | 
    snmp_agentx_read_searchrange(struct agentx_pdu *pdu, struct agentx_search_range *sr)  | 
    ||
966  | 
    { | 
    ||
967  | 
    if (snmp_agentx_do_read_oid(pdu, &sr->start, &sr->include) == -1 ||  | 
    ||
968  | 
    snmp_agentx_read_oid(pdu, &sr->end) == -1)  | 
    ||
969  | 
    return (-1);  | 
    ||
970  | 
    |||
971  | 
    return (0);  | 
    ||
972  | 
    }  | 
    ||
973  | 
    |||
974  | 
    char *  | 
    ||
975  | 
    snmp_agentx_read_octetstr(struct agentx_pdu *pdu, int *len)  | 
    ||
976  | 
    { | 
    ||
977  | 
    char *str;  | 
    ||
978  | 
    uint32_t l;  | 
    ||
979  | 
    |||
980  | 
    if (snmp_agentx_read_int(pdu, &l) == -1)  | 
    ||
981  | 
    return (NULL);  | 
    ||
982  | 
    |||
983  | 
    if ((str = malloc(l)) == NULL)  | 
    ||
984  | 
    return (NULL);  | 
    ||
985  | 
    |||
986  | 
    	if (snmp_agentx_read_raw(pdu, str, l) == -1) { | 
    ||
987  | 
    free(str);  | 
    ||
988  | 
    return (NULL);  | 
    ||
989  | 
    }  | 
    ||
990  | 
    *len = l;  | 
    ||
991  | 
    |||
992  | 
    return (str);  | 
    ||
993  | 
    }  | 
    ||
994  | 
    |||
995  | 
    /*  | 
    ||
996  | 
    * Synchronous AgentX calls.  | 
    ||
997  | 
    */  | 
    ||
998  | 
    |||
999  | 
    int  | 
    ||
1000  | 
    snmp_agentx_ping(struct agentx_handle *h)  | 
    ||
1001  | 
    { | 
    ||
1002  | 
    struct agentx_pdu *pdu;  | 
    ||
1003  | 
    int error = 0;  | 
    ||
1004  | 
    |||
1005  | 
    if ((pdu = snmp_agentx_ping_pdu()) == NULL)  | 
    ||
1006  | 
    return (-1);  | 
    ||
1007  | 
    |||
1008  | 
    /* Attaches the pdu to the handle; will be released later */  | 
    ||
1009  | 
    if ((pdu = snmp_agentx_request(h, pdu)) == NULL)  | 
    ||
1010  | 
    return (-1);  | 
    ||
1011  | 
    |||
1012  | 
    if (snmp_agentx_response(h, pdu) == -1)  | 
    ||
1013  | 
    error = -1;  | 
    ||
1014  | 
    snmp_agentx_pdu_free(pdu);  | 
    ||
1015  | 
    |||
1016  | 
    return (error);  | 
    ||
1017  | 
    }  | 
    ||
1018  | 
    |||
1019  | 
    /*  | 
    ||
1020  | 
    * Internal utility functions.  | 
    ||
1021  | 
    */  | 
    ||
1022  | 
    |||
1023  | 
    void  | 
    ||
1024  | 
    snmp_agentx_update_ids(struct agentx_handle *h, struct agentx_pdu *pdu)  | 
    ||
1025  | 
    { | 
    ||
1026  | 
    /* XXX -- update to reflect the new queueing semantics */  | 
    ||
1027  | 
    h->transactid = pdu->hdr->transactid;  | 
    ||
1028  | 
    h->packetid = pdu->hdr->packetid;  | 
    ||
1029  | 
    }  | 
    ||
1030  | 
    |||
1031  | 
    char *  | 
    ||
1032  | 
    snmp_oid2string(struct snmp_oid *o, char *buf, size_t len)  | 
    ||
1033  | 
    { | 
    ||
1034  | 
    char str[256];  | 
    ||
1035  | 
    size_t i;  | 
    ||
1036  | 
    |||
1037  | 
    bzero(buf, len);  | 
    ||
1038  | 
    |||
1039  | 
    	for (i = 0; i < o->o_n; i++) { | 
    ||
1040  | 
    snprintf(str, sizeof(str), "%d", o->o_id[i]);  | 
    ||
1041  | 
    strlcat(buf, str, len);  | 
    ||
1042  | 
    if (i < (o->o_n - 1))  | 
    ||
1043  | 
    strlcat(buf, ".", len);  | 
    ||
1044  | 
    }  | 
    ||
1045  | 
    |||
1046  | 
    return (buf);  | 
    ||
1047  | 
    }  | 
    ||
1048  | 
    |||
1049  | 
    int  | 
    ||
1050  | 
    snmp_oid_cmp(struct snmp_oid *a, struct snmp_oid *b)  | 
    ||
1051  | 
    { | 
    ||
1052  | 
    size_t i;  | 
    ||
1053  | 
    |||
1054  | 
    	for (i = 0; i < SNMP_MAX_OID_LEN; i++) { | 
    ||
1055  | 
    		if (a->o_id[i] != 0) { | 
    ||
1056  | 
    if (a->o_id[i] == b->o_id[i])  | 
    ||
1057  | 
    continue;  | 
    ||
1058  | 
    			else if (a->o_id[i] < b->o_id[i]) { | 
    ||
1059  | 
    /* b is a successor of a */  | 
    ||
1060  | 
    return (1);  | 
    ||
1061  | 
    			} else { | 
    ||
1062  | 
    /* b is a predecessor of a */  | 
    ||
1063  | 
    return (-1);  | 
    ||
1064  | 
    }  | 
    ||
1065  | 
    		} else if (b->o_id[i] != 0) { | 
    ||
1066  | 
    /* b is larger, but a child of a */  | 
    ||
1067  | 
    return (2);  | 
    ||
1068  | 
    } else  | 
    ||
1069  | 
    break;  | 
    ||
1070  | 
    }  | 
    ||
1071  | 
    |||
1072  | 
    /* b and a are identical */  | 
    ||
1073  | 
    return (0);  | 
    ||
1074  | 
    }  | 
    ||
1075  | 
    |||
1076  | 
    void  | 
    ||
1077  | 
    snmp_oid_increment(struct snmp_oid *o)  | 
    ||
1078  | 
    { | 
    ||
1079  | 
    u_int i;  | 
    ||
1080  | 
    |||
1081  | 
    	for (i = o->o_n; i > 0; i--) { | 
    ||
1082  | 
    o->o_id[i - 1]++;  | 
    ||
1083  | 
    if (o->o_id[i - 1] != 0)  | 
    ||
1084  | 
    break;  | 
    ||
1085  | 
    }  | 
    ||
1086  | 
    }  | 
    ||
1087  | 
    |||
1088  | 
    char *  | 
    ||
1089  | 
    snmp_agentx_type2name(int type)  | 
    ||
1090  | 
    { | 
    ||
1091  | 
    	static char *names[] = { | 
    ||
1092  | 
    "AGENTX_OPEN",  | 
    ||
1093  | 
    "AGENTX_CLOSE",  | 
    ||
1094  | 
    "AGENTX_REGISTER",  | 
    ||
1095  | 
    "AGENTX_UNREGISTER",  | 
    ||
1096  | 
    "AGENTX_GET",  | 
    ||
1097  | 
    "AGENTX_GET_NEXT",  | 
    ||
1098  | 
    "AGENTX_GET_BULK",  | 
    ||
1099  | 
    "AGENTX_TEST_SET",  | 
    ||
1100  | 
    "AGENTX_COMMIT_SET",  | 
    ||
1101  | 
    "AGENTX_UNDO_SET",  | 
    ||
1102  | 
    "AGENTX_CLEANUP_SET",  | 
    ||
1103  | 
    "AGENTX_NOTIFY",  | 
    ||
1104  | 
    "AGENTX_PING",  | 
    ||
1105  | 
    "AGENTX_INDEX_ALLOCATE",  | 
    ||
1106  | 
    "AGENTX_INDEX_DEALLOCATE",  | 
    ||
1107  | 
    "AGENTX_ADD_AGENT_CAPS",  | 
    ||
1108  | 
    "AGENTX_REMOVE_AGENT_CAPS",  | 
    ||
1109  | 
    "AGENTX_RESPONSE"  | 
    ||
1110  | 
    };  | 
    ||
1111  | 
    |||
1112  | 
    if (type > 18)  | 
    ||
1113  | 
    		return ("unknown"); | 
    ||
1114  | 
    |||
1115  | 
    return (names[type - 1]);  | 
    ||
1116  | 
    }  | 
    ||
1117  | 
    |||
1118  | 
    #ifdef DEBUG  | 
    ||
1119  | 
    static void  | 
    ||
1120  | 
    snmp_agentx_dump_hdr(struct agentx_hdr *hdr)  | 
    ||
1121  | 
    { | 
    ||
1122  | 
    	if (hdr == NULL) { | 
    ||
1123  | 
    		printf("NULL\n"); | 
    ||
1124  | 
    return;  | 
    ||
1125  | 
    }  | 
    ||
1126  | 
    |||
1127  | 
    fprintf(stderr,  | 
    ||
1128  | 
    "agentx: version %d type %s flags %d reserved %d"  | 
    ||
1129  | 
    " sessionid %d transactid %d packetid %d length %d",  | 
    ||
1130  | 
    hdr->version, snmp_agentx_type2name(hdr->type), hdr->flags,  | 
    ||
1131  | 
    hdr->reserved, hdr->sessionid, hdr->transactid,  | 
    ||
1132  | 
    hdr->packetid, hdr->length);  | 
    ||
1133  | 
    |||
1134  | 
    	if (hdr->type == AGENTX_RESPONSE) { | 
    ||
1135  | 
    struct agentx_response *r = (struct agentx_response *)hdr;  | 
    ||
1136  | 
    |||
1137  | 
    fprintf(stderr, " sysuptime %d error %d index %d",  | 
    ||
1138  | 
    r->data.sysuptime, r->data.error, r->data.index);  | 
    ||
1139  | 
    }  | 
    ||
1140  | 
    |||
1141  | 
    fprintf(stderr, "\n");  | 
    ||
1142  | 
    }  | 
    ||
1143  | 
    #endif  | 
    
| Generated by: GCOVR (Version 3.3) |