Coverage Report

Created: 2025-07-23 06:49

/src/net-snmp/agent/mibgroup/agentx/client.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 *   AgentX utility routines
3
 */
4
5
#include <net-snmp/net-snmp-config.h>
6
#include <net-snmp/net-snmp-features.h>
7
8
#include <stdio.h>
9
#include <errno.h>
10
#ifdef HAVE_STDLIB_H
11
#include <stdlib.h>
12
#endif
13
#ifdef HAVE_STRING_H
14
#include <string.h>
15
#else
16
#include <strings.h>
17
#endif
18
#ifdef HAVE_UNISTD_H
19
#include <unistd.h>
20
#endif
21
#include <sys/types.h>
22
#ifdef TIME_WITH_SYS_TIME
23
# include <sys/time.h>
24
# include <time.h>
25
#else
26
# ifdef HAVE_SYS_TIME_H
27
#  include <sys/time.h>
28
# else
29
#  include <time.h>
30
# endif
31
#endif
32
33
#ifdef HAVE_NETINET_IN_H
34
#include <netinet/in.h>
35
#endif
36
37
#include <net-snmp/net-snmp-includes.h>
38
#include <net-snmp/agent/net-snmp-agent-includes.h>
39
#include <net-snmp/agent/agent_index.h>
40
#include "agent_global_vars.h"
41
42
#include "agentx/protocol.h"
43
#include "agentx/client.h"
44
#include "agentx/subagent.h"
45
46
netsnmp_feature_require(set_agent_uptime);
47
48
        /*
49
         * AgentX handling utility routines
50
         *
51
         * Mostly wrappers round, or re-writes of
52
         *   the SNMP equivalents
53
         */
54
55
static int
56
agentx_synch_input(int op,
57
                   netsnmp_session * session,
58
                   int reqid, netsnmp_pdu *pdu, void *magic)
59
0
{
60
0
    struct synch_state *state = (struct synch_state *) magic;
61
62
0
    if (!state || reqid != state->reqid) {
63
0
        return handle_agentx_packet(op, session, reqid, pdu, magic);
64
0
    }
65
66
0
    DEBUGMSGTL(("agentx/subagent", "synching input, op 0x%02x\n", op));
67
0
    state->waiting = 0;
68
0
    if (op == NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) {
69
0
        if (pdu->command == AGENTX_MSG_RESPONSE) {
70
0
            state->pdu = snmp_clone_pdu(pdu);
71
0
            state->status = STAT_SUCCESS;
72
0
            session->s_snmp_errno = SNMPERR_SUCCESS;
73
74
            /*
75
             * Synchronise sysUpTime with the master agent
76
             */
77
0
            netsnmp_set_agent_uptime(pdu->time);
78
0
        }
79
0
    } else if (op == NETSNMP_CALLBACK_OP_TIMED_OUT) {
80
0
        state->pdu = NULL;
81
0
        state->status = STAT_TIMEOUT;
82
0
        session->s_snmp_errno = SNMPERR_TIMEOUT;
83
0
    } else if (op == NETSNMP_CALLBACK_OP_DISCONNECT) {
84
0
        return handle_agentx_packet(op, session, reqid, pdu, magic);
85
0
    }
86
87
0
    return 1;
88
0
}
89
90
91
92
static int
93
agentx_synch_response(netsnmp_session * ss, netsnmp_pdu *pdu,
94
                      netsnmp_pdu **response)
95
0
{
96
0
    return snmp_synch_response_cb(ss, pdu, response, agentx_synch_input);
97
0
}
98
99
100
        /*
101
         * AgentX PofE convenience functions
102
         */
103
104
int
105
agentx_open_session(netsnmp_session * ss)
106
0
{
107
0
    netsnmp_pdu    *pdu, *response;
108
0
    int       timeout;
109
110
0
    DEBUGMSGTL(("agentx/subagent", "opening session \n"));
111
0
    if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) {
112
0
        return 0;
113
0
    }
114
115
0
    pdu = snmp_pdu_create(AGENTX_MSG_OPEN);
116
0
    if (pdu == NULL)
117
0
        return 0;
118
0
    timeout = netsnmp_ds_get_int(NETSNMP_DS_APPLICATION_ID,
119
0
                                   NETSNMP_DS_AGENT_AGENTX_TIMEOUT);
120
0
    if (timeout < 0) 
121
0
        pdu->time = 0;
122
0
    else
123
        /* for master TIMEOUT is usec, but Agentx Open specifies sec */
124
0
        pdu->time = timeout / (1000L * 1000L);
125
126
0
    snmp_add_var(pdu, version_sysoid, version_sysoid_len,
127
0
     's', "Net-SNMP AgentX sub-agent");
128
129
0
    if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS)
130
0
        return 0;
131
132
0
    if (!response)
133
0
        return 0;
134
135
0
    if (response->errstat != SNMP_ERR_NOERROR) {
136
0
        snmp_free_pdu(response);
137
0
        return 0;
138
0
    }
139
140
0
    ss->sessid = response->sessid;
141
0
    snmp_free_pdu(response);
142
143
0
    DEBUGMSGTL(("agentx/subagent", "open \n"));
144
0
    return 1;
145
0
}
146
147
int
148
agentx_close_session(netsnmp_session * ss, int why)
149
0
{
150
0
    netsnmp_pdu    *pdu, *response;
151
0
    DEBUGMSGTL(("agentx/subagent", "closing session\n"));
152
153
0
    if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) {
154
0
        return 0;
155
0
    }
156
157
0
    pdu = snmp_pdu_create(AGENTX_MSG_CLOSE);
158
0
    if (pdu == NULL)
159
0
        return 0;
160
0
    pdu->time = 0;
161
0
    pdu->errstat = why;
162
0
    pdu->sessid = ss->sessid;
163
164
0
    if (agentx_synch_response(ss, pdu, &response) == STAT_SUCCESS)
165
0
        snmp_free_pdu(response);
166
0
    DEBUGMSGTL(("agentx/subagent", "closed\n"));
167
168
0
    return 1;
169
0
}
170
171
int
172
agentx_register(netsnmp_session * ss, oid start[], size_t startlen,
173
                int priority, int range_subid, oid range_ubound,
174
                int timeout, u_char flags, const char *contextName)
175
0
{
176
0
    netsnmp_pdu    *pdu, *response;
177
178
0
    DEBUGMSGTL(("agentx/subagent", "registering: "));
179
0
    DEBUGMSGOIDRANGE(("agentx/subagent", start, startlen, range_subid,
180
0
                      range_ubound));
181
0
    DEBUGMSG(("agentx/subagent", "\n"));
182
183
0
    if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) {
184
0
        return 0;
185
0
    }
186
187
0
    pdu = snmp_pdu_create(AGENTX_MSG_REGISTER);
188
0
    if (pdu == NULL) {
189
0
        return 0;
190
0
    }
191
0
    pdu->time = timeout;
192
0
    pdu->priority = priority;
193
0
    pdu->sessid = ss->sessid;
194
0
    pdu->range_subid = range_subid;
195
0
    if (contextName) {
196
0
        pdu->flags |= AGENTX_MSG_FLAG_NON_DEFAULT_CONTEXT;
197
0
        pdu->community = (u_char *) strdup(contextName);
198
0
        pdu->community_len = strlen(contextName);
199
0
    }
200
201
0
    if (flags & FULLY_QUALIFIED_INSTANCE) {
202
0
        pdu->flags |= AGENTX_MSG_FLAG_INSTANCE_REGISTER;
203
0
    }
204
205
0
    if (range_subid) {
206
0
        snmp_pdu_add_variable(pdu, start, startlen, ASN_OBJECT_ID,
207
0
                              (u_char *) start, startlen * sizeof(oid));
208
0
        pdu->variables->val.objid[range_subid - 1] = range_ubound;
209
0
    } else {
210
0
        snmp_add_null_var(pdu, start, startlen);
211
0
    }
212
213
0
    if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS) {
214
0
        DEBUGMSGTL(("agentx/subagent", "registering failed!\n"));
215
0
        return 0;
216
0
    }
217
218
0
    if (response->errstat != SNMP_ERR_NOERROR) {
219
0
        snmp_log(LOG_ERR,"registering pdu failed: %ld!\n", response->errstat);
220
0
        snmp_free_pdu(response);
221
0
        return 0;
222
0
    }
223
224
0
    snmp_free_pdu(response);
225
0
    DEBUGMSGTL(("agentx/subagent", "registered\n"));
226
0
    return 1;
227
0
}
228
229
int
230
agentx_unregister(netsnmp_session * ss, oid start[], size_t startlen,
231
                  int priority, int range_subid, oid range_ubound,
232
                  const char *contextName)
233
0
{
234
0
    netsnmp_pdu    *pdu, *response;
235
236
0
    if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) {
237
0
        return 0;
238
0
    }
239
240
0
    DEBUGMSGTL(("agentx/subagent", "unregistering: "));
241
0
    DEBUGMSGOIDRANGE(("agentx/subagent", start, startlen, range_subid,
242
0
                      range_ubound));
243
0
    DEBUGMSG(("agentx/subagent", "\n"));
244
0
    pdu = snmp_pdu_create(AGENTX_MSG_UNREGISTER);
245
0
    if (pdu == NULL) {
246
0
        return 0;
247
0
    }
248
0
    pdu->time = 0;
249
0
    pdu->priority = priority;
250
0
    pdu->sessid = ss->sessid;
251
0
    pdu->range_subid = range_subid;
252
0
    if (contextName) {
253
0
        pdu->flags |= AGENTX_MSG_FLAG_NON_DEFAULT_CONTEXT;
254
0
        pdu->community = (u_char *) strdup(contextName);
255
0
        pdu->community_len = strlen(contextName);
256
0
    }
257
258
0
    if (range_subid) {
259
0
        snmp_pdu_add_variable(pdu, start, startlen, ASN_OBJECT_ID,
260
0
                              (u_char *) start, startlen * sizeof(oid));
261
0
        pdu->variables->val.objid[range_subid - 1] = range_ubound;
262
0
    } else {
263
0
        snmp_add_null_var(pdu, start, startlen);
264
0
    }
265
266
0
    if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS)
267
0
        return 0;
268
269
0
    if (response->errstat != SNMP_ERR_NOERROR) {
270
0
        snmp_free_pdu(response);
271
0
        return 0;
272
0
    }
273
274
0
    snmp_free_pdu(response);
275
0
    DEBUGMSGTL(("agentx/subagent", "unregistered\n"));
276
0
    return 1;
277
0
}
278
279
netsnmp_variable_list *
280
agentx_register_index(netsnmp_session * ss,
281
                      netsnmp_variable_list * varbind, int flags)
282
0
{
283
0
    netsnmp_pdu    *pdu, *response;
284
0
    netsnmp_variable_list *varbind2;
285
286
0
    if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) {
287
0
        return NULL;
288
0
    }
289
290
    /*
291
     * Make a copy of the index request varbind
292
     *    for the AgentX request PDU
293
     *    (since the pdu structure will be freed)
294
     */
295
0
    varbind2 =
296
0
        (netsnmp_variable_list *) malloc(sizeof(netsnmp_variable_list));
297
0
    if (varbind2 == NULL)
298
0
        return NULL;
299
0
    if (snmp_clone_var(varbind, varbind2)) {
300
0
        snmp_free_varbind(varbind2);
301
0
        return NULL;
302
0
    }
303
0
    if (varbind2->val.string == NULL)
304
0
        varbind2->val.string = varbind2->buf;   /* ensure it points somewhere */
305
306
0
    pdu = snmp_pdu_create(AGENTX_MSG_INDEX_ALLOCATE);
307
0
    if (pdu == NULL) {
308
0
        snmp_free_varbind(varbind2);
309
0
        return NULL;
310
0
    }
311
0
    pdu->time = 0;
312
0
    pdu->sessid = ss->sessid;
313
0
    if (flags == ALLOCATE_ANY_INDEX)
314
0
        pdu->flags |= AGENTX_MSG_FLAG_ANY_INSTANCE;
315
0
    if (flags == ALLOCATE_NEW_INDEX)
316
0
        pdu->flags |= AGENTX_MSG_FLAG_NEW_INSTANCE;
317
318
    /*
319
     *  Just send a single index request varbind.
320
     *  Although the AgentX protocol supports
321
     *    multiple index allocations in a single
322
     *    request, the model used in the net-snmp agent
323
     *    doesn't currently take advantage of this.
324
     *  I believe this is our prerogative - just as
325
     *    long as the master side Index request handler
326
     *    can cope with multiple index requests.
327
     */
328
0
    pdu->variables = varbind2;
329
330
0
    if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS)
331
0
        return NULL;
332
333
0
    if (response->errstat != SNMP_ERR_NOERROR) {
334
0
        snmp_free_pdu(response);
335
0
        return NULL;
336
0
    }
337
338
    /*
339
     * Unlink the (single) response varbind to return
340
     *  to the main driving index request routine.
341
     *
342
     * This is a memory leak, as nothing will ever
343
     *  release this varbind.  If this becomes a problem,
344
     *  we'll need to keep a list of these here, and
345
     *  free the memory in the "index release" routine.
346
     * But the master side never frees these either (by
347
     *  design, since it still needs them), so expecting
348
     *  the subagent to is discrimination, pure & simple :-)
349
     */
350
0
    varbind2 = response->variables;
351
0
    response->variables = NULL;
352
0
    snmp_free_pdu(response);
353
0
    return varbind2;
354
0
}
355
356
int
357
agentx_unregister_index(netsnmp_session * ss,
358
                        netsnmp_variable_list * varbind)
359
0
{
360
0
    netsnmp_pdu    *pdu, *response;
361
0
    netsnmp_variable_list *varbind2;
362
363
0
    if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) {
364
0
        return -1;
365
0
    }
366
367
    /*
368
     * Make a copy of the index request varbind
369
     *    for the AgentX request PDU
370
     *    (since the pdu structure will be freed)
371
     */
372
0
    varbind2 =
373
0
        (netsnmp_variable_list *) malloc(sizeof(netsnmp_variable_list));
374
0
    if (varbind2 == NULL)
375
0
        return -1;
376
0
    if (snmp_clone_var(varbind, varbind2)) {
377
0
        snmp_free_varbind(varbind2);
378
0
        return -1;
379
0
    }
380
381
0
    pdu = snmp_pdu_create(AGENTX_MSG_INDEX_DEALLOCATE);
382
0
    if (pdu == NULL) {
383
0
        snmp_free_varbind(varbind2);
384
0
        return -1;
385
0
    }
386
0
    pdu->time = 0;
387
0
    pdu->sessid = ss->sessid;
388
389
    /*
390
     *  Just send a single index release varbind.
391
     *      (as above)
392
     */
393
0
    pdu->variables = varbind2;
394
395
0
    if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS)
396
0
        return -1;
397
398
0
    if (response->errstat != SNMP_ERR_NOERROR) {
399
0
        snmp_free_pdu(response);
400
0
        return -1;              /* XXX - say why */
401
0
    }
402
403
0
    snmp_free_pdu(response);
404
0
    return SNMP_ERR_NOERROR;
405
0
}
406
407
int
408
agentx_add_agentcaps(netsnmp_session * ss,
409
                     const oid * agent_cap, size_t agent_caplen,
410
                     const char *descr)
411
0
{
412
0
    netsnmp_pdu    *pdu, *response;
413
414
0
    if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) {
415
0
        return 0;
416
0
    }
417
418
0
    pdu = snmp_pdu_create(AGENTX_MSG_ADD_AGENT_CAPS);
419
0
    if (pdu == NULL)
420
0
        return 0;
421
0
    pdu->time = 0;
422
0
    pdu->sessid = ss->sessid;
423
0
    snmp_add_var(pdu, agent_cap, agent_caplen, 's', descr);
424
425
0
    if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS)
426
0
        return 0;
427
428
0
    if (response->errstat != SNMP_ERR_NOERROR) {
429
0
        snmp_free_pdu(response);
430
0
        return 0;
431
0
    }
432
433
0
    snmp_free_pdu(response);
434
0
    return 1;
435
0
}
436
437
int
438
agentx_remove_agentcaps(netsnmp_session * ss,
439
                        const oid * agent_cap, size_t agent_caplen)
440
0
{
441
0
    netsnmp_pdu    *pdu, *response;
442
443
0
    if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) {
444
0
        return 0;
445
0
    }
446
447
0
    pdu = snmp_pdu_create(AGENTX_MSG_REMOVE_AGENT_CAPS);
448
0
    if (pdu == NULL)
449
0
        return 0;
450
0
    pdu->time = 0;
451
0
    pdu->sessid = ss->sessid;
452
0
    snmp_add_null_var(pdu, agent_cap, agent_caplen);
453
454
0
    if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS)
455
0
        return 0;
456
457
0
    if (response->errstat != SNMP_ERR_NOERROR) {
458
0
        snmp_free_pdu(response);
459
0
        return 0;
460
0
    }
461
462
0
    snmp_free_pdu(response);
463
0
    return 1;
464
0
}
465
466
int
467
agentx_send_ping(netsnmp_session * ss)
468
0
{
469
0
    netsnmp_pdu    *pdu, *response;
470
471
0
    if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) {
472
0
        return 0;
473
0
    }
474
475
0
    pdu = snmp_pdu_create(AGENTX_MSG_PING);
476
0
    if (pdu == NULL)
477
0
        return 0;
478
0
    pdu->time = 0;
479
0
    pdu->sessid = ss->sessid;
480
481
0
    if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS)
482
0
        return 0;
483
484
0
    if (response->errstat != SNMP_ERR_NOERROR) {
485
0
        snmp_free_pdu(response);
486
0
        return 0;
487
0
    }
488
489
0
    snmp_free_pdu(response);
490
0
    return 1;
491
0
}