Coverage Report

Created: 2026-09-04 09:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/net-snmp/snmplib/snmp_client.c
Line
Count
Source
1
/*
2
 * snmp_client.c - a toolkit of common functions for an SNMP client.
3
 *
4
 */
5
/* Portions of this file are subject to the following copyright(s).  See
6
 * the Net-SNMP's COPYING file for more details and other copyrights
7
 * that may apply:
8
 */
9
/**********************************************************************
10
  Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University
11
12
                      All Rights Reserved
13
14
Permission to use, copy, modify, and distribute this software and its
15
documentation for any purpose and without fee is hereby granted,
16
provided that the above copyright notice appear in all copies and that
17
both that copyright notice and this permission notice appear in
18
supporting documentation, and that the name of CMU not be
19
used in advertising or publicity pertaining to distribution of the
20
software without specific, written prior permission.
21
22
CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
23
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
24
CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
25
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
26
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
27
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
28
SOFTWARE.
29
******************************************************************/
30
/*
31
 * Portions of this file are copyrighted by:
32
 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
33
 * Use is subject to license terms specified in the COPYING file
34
 * distributed with the Net-SNMP package.
35
 *
36
 * Portions of this file are copyrighted by:
37
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
38
 * Use is subject to license terms specified in the COPYING file
39
 * distributed with the Net-SNMP package.
40
 */
41
42
/** @defgroup snmp_client various PDU processing routines
43
 *  @ingroup library
44
 * 
45
 *  @{
46
 */
47
#include <net-snmp/net-snmp-config.h>
48
#include <net-snmp/net-snmp-features.h>
49
50
#include <stdio.h>
51
#include <errno.h>
52
#ifdef HAVE_INTTYPES_H
53
#include <inttypes.h>
54
#endif
55
#ifdef HAVE_STDLIB_H
56
#include <stdlib.h>
57
#endif
58
#ifdef HAVE_STRING_H
59
#include <string.h>
60
#else
61
#include <strings.h>
62
#endif
63
#ifdef HAVE_UNISTD_H
64
#include <unistd.h>
65
#endif
66
#include <sys/types.h>
67
#ifdef TIME_WITH_SYS_TIME
68
# include <sys/time.h>
69
# include <time.h>
70
#else
71
# ifdef HAVE_SYS_TIME_H
72
#  include <sys/time.h>
73
# else
74
#  include <time.h>
75
# endif
76
#endif
77
#ifdef HAVE_SYS_PARAM_H
78
#include <sys/param.h>
79
#endif
80
#ifdef HAVE_NETINET_IN_H
81
#include <netinet/in.h>
82
#endif
83
#ifdef HAVE_ARPA_INET_H
84
#include <arpa/inet.h>
85
#endif
86
#ifdef HAVE_SYS_SELECT_H
87
#include <sys/select.h>
88
#endif
89
#ifdef HAVE_SYSLOG_H
90
#include <syslog.h>
91
#endif
92
93
#include <net-snmp/types.h>
94
95
#include <net-snmp/agent/ds_agent.h>
96
#include <net-snmp/library/default_store.h>
97
#include <net-snmp/library/snmp.h>
98
#include <net-snmp/library/snmp-tc.h>
99
#include <net-snmp/library/snmp_api.h>
100
#include <net-snmp/library/snmp_client.h>
101
#include <net-snmp/library/snmp_impl.h>
102
#include <net-snmp/library/snmp_secmod.h>
103
#include <net-snmp/library/snmpusm.h>
104
#include <net-snmp/library/mib.h>
105
#include <net-snmp/library/snmp_logging.h>
106
#include <net-snmp/library/snmp_assert.h>
107
#include <net-snmp/library/large_fd_set.h>
108
#include <net-snmp/library/tools.h>
109
#include <net-snmp/pdu_api.h>
110
111
netsnmp_feature_child_of(snmp_client_all, libnetsnmp);
112
113
netsnmp_feature_child_of(snmp_split_pdu, snmp_client_all);
114
netsnmp_feature_child_of(snmp_reset_var_types, snmp_client_all);
115
netsnmp_feature_child_of(query_set_default_session, snmp_client_all);
116
netsnmp_feature_child_of(row_create, snmp_client_all);
117
118
#ifndef BSD4_3
119
#define BSD4_2
120
#endif
121
122
123
/*
124
 * Prototype definitions 
125
 */
126
static int      snmp_synch_input(int op, netsnmp_session * session,
127
                                 int reqid, netsnmp_pdu *pdu, void *magic);
128
129
netsnmp_pdu    *
130
snmp_pdu_create(int command)
131
0
{
132
0
    netsnmp_pdu    *pdu;
133
134
0
    pdu = calloc(1, sizeof(netsnmp_pdu));
135
0
    if (pdu) {
136
0
        pdu->version = SNMP_DEFAULT_VERSION;
137
0
        pdu->command = command;
138
0
        pdu->errstat = SNMP_DEFAULT_ERRSTAT;
139
0
        pdu->errindex = SNMP_DEFAULT_ERRINDEX;
140
0
        pdu->securityModel = SNMP_DEFAULT_SECMODEL;
141
0
        pdu->transport_data = NULL;
142
0
        pdu->transport_data_length = 0;
143
0
        pdu->securityNameLen = 0;
144
0
        pdu->contextNameLen = 0;
145
0
        pdu->time = 0;
146
0
        pdu->reqid = snmp_get_next_reqid();
147
0
        pdu->msgid = snmp_get_next_msgid();
148
0
    }
149
0
    return pdu;
150
151
0
}
152
153
154
/*
155
 * Add a null variable with the requested name to the end of the list of
156
 * variables for this pdu.
157
 */
158
netsnmp_variable_list *
159
snmp_add_null_var(netsnmp_pdu *pdu, const oid * name, size_t name_length)
160
452
{
161
452
    return snmp_pdu_add_variable(pdu, name, name_length, ASN_NULL, NULL, 0);
162
452
}
163
164
165
#include <net-snmp/library/snmp_debug.h>
166
static int
167
snmp_synch_input(int op,
168
                 netsnmp_session * session,
169
                 int reqid, netsnmp_pdu *pdu, void *magic)
170
0
{
171
0
    struct synch_state *state = (struct synch_state *) magic;
172
0
    int             rpt_type;
173
174
0
    if (reqid != state->reqid && pdu && pdu->command != SNMP_MSG_REPORT) {
175
0
        DEBUGMSGTL(("snmp_synch", "Unexpected response (ReqID: %d,%d - Cmd %d)\n",
176
0
                                   reqid, state->reqid, pdu->command ));
177
0
        return 0;
178
0
    }
179
180
0
    state->waiting = 0;
181
0
    DEBUGMSGTL(("snmp_synch", "Response (ReqID: %d - Cmd %d)\n",
182
0
                               reqid, (pdu ? pdu->command : -1)));
183
184
0
    if (op == NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE && pdu) {
185
0
        if (pdu->command == SNMP_MSG_REPORT) {
186
0
            rpt_type = snmpv3_get_report_type(pdu);
187
0
            if (SNMPV3_IGNORE_UNAUTH_REPORTS ||
188
0
                rpt_type == SNMPERR_NOT_IN_TIME_WINDOW) {
189
0
                state->waiting = 1;
190
0
            }
191
0
            state->pdu = NULL;
192
0
            state->status = STAT_ERROR;
193
0
            session->s_snmp_errno = rpt_type;
194
0
            SET_SNMP_ERROR(rpt_type);
195
0
        } else if (pdu->command == SNMP_MSG_RESPONSE) {
196
            /*
197
             * clone the pdu to return to snmp_synch_response 
198
             */
199
0
            state->pdu = snmp_clone_pdu(pdu);
200
0
            state->status = STAT_SUCCESS;
201
0
            session->s_snmp_errno = SNMPERR_SUCCESS;
202
0
        }
203
0
        else {
204
0
            char msg_buf[50];
205
0
            state->status = STAT_ERROR;
206
0
            session->s_snmp_errno = SNMPERR_PROTOCOL;
207
0
            SET_SNMP_ERROR(SNMPERR_PROTOCOL);
208
0
            snprintf(msg_buf, sizeof(msg_buf), "Expected RESPONSE-PDU but got %s-PDU",
209
0
                     snmp_pdu_type(pdu->command));
210
0
            snmp_set_detail(msg_buf);
211
0
            return 0;
212
0
        }
213
0
    } else if (op == NETSNMP_CALLBACK_OP_TIMED_OUT) {
214
0
        state->pdu = NULL;
215
0
        state->status = STAT_TIMEOUT;
216
0
        session->s_snmp_errno = SNMPERR_TIMEOUT;
217
0
        SET_SNMP_ERROR(SNMPERR_TIMEOUT);
218
0
    } else if (op == NETSNMP_CALLBACK_OP_SEC_ERROR) {
219
0
        state->pdu = NULL;
220
        /*
221
         * If we already have an error in status, then leave it alone.
222
         */
223
0
        if (state->status == STAT_SUCCESS) {
224
0
            state->status = STAT_ERROR;
225
0
            session->s_snmp_errno = SNMPERR_GENERR;
226
0
            SET_SNMP_ERROR(SNMPERR_GENERR);
227
0
        }
228
0
    } else if (op == NETSNMP_CALLBACK_OP_DISCONNECT) {
229
0
        state->pdu = NULL;
230
0
        state->status = STAT_ERROR;
231
0
        session->s_snmp_errno = SNMPERR_ABORT;
232
0
        SET_SNMP_ERROR(SNMPERR_ABORT);
233
0
    }
234
0
    DEBUGMSGTL(("snmp_synch", "status = %d errno = %d\n",
235
0
                               state->status, session->s_snmp_errno));
236
237
0
    return 1;
238
0
}
239
240
241
/*
242
 * Clone an SNMP variable data structure.
243
 * Sets pointers to structure private storage, or
244
 * allocates larger object identifiers and values as needed.
245
 *
246
 * Caller must make list association for cloned variable.
247
 *
248
 * Returns 0 if successful.
249
 */
250
int
251
snmp_clone_var(netsnmp_variable_list * var, netsnmp_variable_list * newvar)
252
2.18k
{
253
2.18k
    if (!newvar || !var)
254
0
        return 1;
255
256
2.18k
    memmove(newvar, var, sizeof(netsnmp_variable_list));
257
2.18k
    newvar->next_variable = NULL;
258
2.18k
    newvar->name = NULL;
259
2.18k
    newvar->val.string = NULL;
260
2.18k
    newvar->data = NULL;
261
2.18k
    newvar->dataFreeHook = NULL;
262
2.18k
    newvar->index = 0;
263
264
    /*
265
     * Clone the object identifier and the value.
266
     * Allocate memory iff original will not fit into local storage.
267
     */
268
2.18k
    if (snmp_set_var_objid(newvar, var->name, var->name_length))
269
0
        return 1;
270
271
    /*
272
     * need a pointer to copy a string value. 
273
     */
274
2.18k
    if (var->val.string) {
275
1.70k
        if (var->val.string != &var->buf[0]) {
276
599
            if (var->val_len < sizeof(var->buf)) {
277
381
                newvar->val.string = newvar->buf;
278
381
                memmove(newvar->val.string, var->val.string, var->val_len);
279
381
                newvar->val.string[var->val_len] = 0;
280
381
            } else {
281
218
                newvar->val.string = (u_char *) malloc(var->val_len + 1);
282
218
                if (!newvar->val.string)
283
0
                    return 1;
284
218
                memmove(newvar->val.string, var->val.string, var->val_len);
285
218
                newvar->val.string[var->val_len] = 0;
286
218
            }
287
1.10k
        } else {                /* fix the pointer to new local store */
288
1.10k
            newvar->val.string = newvar->buf;
289
            /*
290
             * no need for a memmove, since we copied the whole var
291
             * struct (and thus var->buf) at the beginning of this function.
292
             */
293
1.10k
        }
294
1.70k
    } else {
295
475
        newvar->val.string = NULL;
296
475
        newvar->val_len = 0;
297
475
    }
298
299
2.18k
    return 0;
300
2.18k
}
301
302
303
/*
304
 * Possibly make a copy of source memory buffer.
305
 * Will reset destination pointer if source pointer is NULL.
306
 * Returns 0 if successful, 1 if memory allocation fails.
307
 */
308
int
309
snmp_clone_mem(void **dstPtr, const void *srcPtr, unsigned len)
310
188k
{
311
188k
    *dstPtr = NULL;
312
188k
    if (srcPtr) {
313
1.54k
        *dstPtr = malloc(len + 1);
314
1.54k
        if (!*dstPtr) {
315
0
            return 1;
316
0
        }
317
1.54k
        memmove(*dstPtr, srcPtr, len);
318
        /*
319
         * this is for those routines that expect 0-terminated strings!!!
320
         * someone should rather have called strdup
321
         */
322
1.54k
        ((char *) *dstPtr)[len] = 0;
323
1.54k
    }
324
188k
    return 0;
325
188k
}
326
327
328
/*
329
 * Walks through a list of varbinds and frees and allocated memory,
330
 * restoring pointers to local buffers
331
 */
332
void
333
snmp_reset_var_buffers(netsnmp_variable_list * var)
334
0
{
335
0
    while (var) {
336
0
        if (var->name != var->name_loc) {
337
0
            if(NULL != var->name)
338
0
                free(var->name);
339
0
            var->name = var->name_loc;
340
0
            var->name_length = 0;
341
0
        }
342
0
        if (var->val.string != var->buf) {
343
0
            if (NULL != var->val.string)
344
0
                free(var->val.string);
345
0
            var->val.string = var->buf;
346
0
            var->val_len = 0;
347
0
        }
348
0
        var = var->next_variable;
349
0
    }
350
0
}
351
352
/*
353
 * Creates and allocates a clone of the input PDU,
354
 * but does NOT copy the variables.
355
 * This function should be used with another function,
356
 * such as _copy_pdu_vars.
357
 *
358
 * Returns a pointer to the cloned PDU if successful.
359
 * Returns 0 if failure.
360
 */
361
static
362
netsnmp_pdu    *
363
_clone_pdu_header(netsnmp_pdu *pdu)
364
26.8k
{
365
26.8k
    netsnmp_pdu    *newpdu;
366
26.8k
    struct snmp_secmod_def *sptr;
367
26.8k
    int ret;
368
369
26.8k
    if (!pdu)
370
0
        return NULL;
371
372
26.8k
    newpdu = netsnmp_memdup(pdu, sizeof(netsnmp_pdu));
373
26.8k
    if (!newpdu)
374
0
        return NULL;
375
376
    /*
377
     * reset copied pointers if copy fails 
378
     */
379
26.8k
    newpdu->variables = NULL;
380
26.8k
    newpdu->enterprise = NULL;
381
26.8k
    newpdu->community = NULL;
382
26.8k
    newpdu->securityEngineID = NULL;
383
26.8k
    newpdu->securityName = NULL;
384
26.8k
    newpdu->contextEngineID = NULL;
385
26.8k
    newpdu->contextName = NULL;
386
26.8k
    newpdu->transport_data = NULL;
387
26.8k
    newpdu->securityStateRef = NULL;
388
389
    /*
390
     * copy buffers individually. If any copy fails, all are freed. 
391
     */
392
26.8k
    if (snmp_clone_mem((void **) &newpdu->enterprise, pdu->enterprise,
393
26.8k
                       sizeof(oid) * pdu->enterprise_length) ||
394
26.8k
        snmp_clone_mem((void **) &newpdu->community, pdu->community,
395
26.8k
                       pdu->community_len) ||
396
26.8k
        snmp_clone_mem((void **) &newpdu->contextEngineID,
397
26.8k
                       pdu->contextEngineID, pdu->contextEngineIDLen)
398
26.8k
        || snmp_clone_mem((void **) &newpdu->securityEngineID,
399
26.8k
                          pdu->securityEngineID, pdu->securityEngineIDLen)
400
26.8k
        || snmp_clone_mem((void **) &newpdu->contextName, pdu->contextName,
401
26.8k
                          pdu->contextNameLen)
402
26.8k
        || snmp_clone_mem((void **) &newpdu->securityName,
403
26.8k
                          pdu->securityName, pdu->securityNameLen)
404
26.8k
        || snmp_clone_mem((void **) &newpdu->transport_data,
405
26.8k
                          pdu->transport_data,
406
26.8k
                          pdu->transport_data_length)) {
407
0
        snmp_free_pdu(newpdu);
408
0
        return NULL;
409
0
    }
410
411
26.8k
    sptr = find_sec_mod(newpdu->securityModel);
412
26.8k
    if (sptr && sptr->pdu_clone) {
413
        /* call security model if it needs to know about this */
414
13
        ret = sptr->pdu_clone(pdu, newpdu);
415
13
        if (ret) {
416
0
            snmp_free_pdu(newpdu);
417
0
            return NULL;
418
0
        }
419
13
    }
420
421
26.8k
    return newpdu;
422
26.8k
}
423
424
static
425
netsnmp_variable_list *
426
_copy_varlist(netsnmp_variable_list * var,      /* source varList */
427
              int errindex,     /* index of variable to drop (if any) */
428
              int copy_count)
429
26.8k
{                               /* !=0 number variables to copy */
430
26.8k
    netsnmp_variable_list *newhead, *newvar, *oldvar;
431
26.8k
    int             ii = 0;
432
433
26.8k
    newhead = NULL;
434
26.8k
    oldvar = NULL;
435
436
29.0k
    while (var && (copy_count-- > 0)) {
437
        /*
438
         * Drop the specified variable (if applicable) 
439
         * xxx hmm, is it intentional that dropping the errindex
440
         *     counts towards copy_count?
441
         */
442
2.18k
        if (++ii == errindex) {
443
0
            var = var->next_variable;
444
0
            continue;
445
0
        }
446
447
        /*
448
         * clone the next variable. Cleanup if alloc fails 
449
         */
450
2.18k
        newvar = (netsnmp_variable_list *)
451
2.18k
            malloc(sizeof(netsnmp_variable_list));
452
2.18k
        if (snmp_clone_var(var, newvar)) {
453
0
            if (newvar)
454
0
                free(newvar);
455
0
            snmp_free_varbind(newhead);
456
0
            return NULL;
457
0
        }
458
459
        /*
460
         * add cloned variable to new list  
461
         */
462
2.18k
        if (NULL == newhead)
463
1.29k
            newhead = newvar;
464
2.18k
        if (oldvar)
465
887
            oldvar->next_variable = newvar;
466
2.18k
        oldvar = newvar;
467
468
2.18k
        var = var->next_variable;
469
2.18k
    }
470
26.8k
    return newhead;
471
26.8k
}
472
473
474
/*
475
 * Copy some or all variables from source PDU to target PDU.
476
 * This function consolidates many of the needs of PDU variables:
477
 * Clone PDU : copy all the variables.
478
 * Split PDU : skip over some variables to copy other variables.
479
 * Fix PDU   : remove variable associated with error index.
480
 *
481
 * Designed to work with _clone_pdu_header.
482
 *
483
 * If drop_err is set, drop any variable associated with errindex.
484
 * If skip_count is set, skip the number of variable in pdu's list.
485
 * While copy_count is greater than zero, copy pdu variables to newpdu.
486
 *
487
 * If an error occurs, newpdu is freed and pointer is set to 0.
488
 *
489
 * Returns a pointer to the cloned PDU if successful.
490
 * Returns 0 if failure.
491
 */
492
static
493
netsnmp_pdu    *
494
_copy_pdu_vars(netsnmp_pdu *pdu,        /* source PDU */
495
               netsnmp_pdu *newpdu,     /* target PDU */
496
               int drop_err,    /* !=0 drop errored variable */
497
               int skip_count,  /* !=0 number of variables to skip */
498
               int copy_count)
499
26.8k
{                               /* !=0 number of variables to copy */
500
26.8k
    netsnmp_variable_list *var;
501
#ifdef TEMPORARILY_DISABLED
502
    int             copied;
503
#endif
504
26.8k
    int             drop_idx;
505
506
26.8k
    if (!newpdu)
507
0
        return NULL;            /* where is PDU to copy to ? */
508
509
26.8k
    if (drop_err)
510
0
        drop_idx = pdu->errindex - skip_count;
511
26.8k
    else
512
26.8k
        drop_idx = 0;
513
514
26.8k
    var = pdu->variables;
515
26.8k
    while (var && (skip_count-- > 0))   /* skip over pdu variables */
516
0
        var = var->next_variable;
517
518
#ifdef TEMPORARILY_DISABLED
519
    copied = 0;
520
    if (pdu->flags & UCD_MSG_FLAG_FORCE_PDU_COPY)
521
        copied = 1;             /* We're interested in 'empty' responses too */
522
#endif
523
524
26.8k
    newpdu->variables = _copy_varlist(var, drop_idx, copy_count);
525
#ifdef TEMPORARILY_DISABLED
526
    if (newpdu->variables)
527
        copied = 1;
528
#endif
529
530
#ifdef ALSO_TEMPORARILY_DISABLED
531
    /*
532
     * Error if bad errindex or if target PDU has no variables copied 
533
     */
534
    if ((drop_err && (ii < pdu->errindex))
535
#ifdef TEMPORARILY_DISABLED
536
        /*
537
         * SNMPv3 engineID probes are allowed to be empty.
538
         * See the comment in snmp_api.c for further details 
539
         */
540
        || copied == 0
541
#endif
542
        ) {
543
        snmp_free_pdu(newpdu);
544
        return 0;
545
    }
546
#endif
547
26.8k
    return newpdu;
548
26.8k
}
549
550
551
/*
552
 * Creates (allocates and copies) a clone of the input PDU.
553
 * If drop_err is set, don't copy any variable associated with errindex.
554
 * This function is called by snmp_clone_pdu and snmp_fix_pdu.
555
 *
556
 * Returns a pointer to the cloned PDU if successful.
557
 * Returns 0 if failure.
558
 */
559
static
560
netsnmp_pdu    *
561
_clone_pdu(netsnmp_pdu *pdu, int drop_err)
562
26.8k
{
563
26.8k
    netsnmp_pdu    *newpdu;
564
565
26.8k
    newpdu = _clone_pdu_header(pdu);
566
26.8k
    if (!newpdu)
567
0
        return newpdu;
568
26.8k
    newpdu = _copy_pdu_vars(pdu, newpdu, drop_err, 0, 10000);   /* skip none, copy all */
569
570
26.8k
    return newpdu;
571
26.8k
}
572
573
574
/*
575
 * This function will clone a full varbind list
576
 *
577
 * Returns a pointer to the cloned varbind list if successful.
578
 * Returns 0 if failure
579
 */
580
netsnmp_variable_list *
581
snmp_clone_varbind(netsnmp_variable_list * varlist)
582
0
{
583
0
    return _copy_varlist(varlist, 0, 10000);    /* skip none, copy all */
584
0
}
585
586
/*
587
 * This function will clone a PDU including all of its variables.
588
 *
589
 * Returns a pointer to the cloned PDU if successful.
590
 * Returns 0 if failure
591
 */
592
netsnmp_pdu    *
593
snmp_clone_pdu(netsnmp_pdu *pdu)
594
26.8k
{
595
26.8k
    return _clone_pdu(pdu, 0);  /* copies all variables */
596
26.8k
}
597
598
599
/*
600
 * This function will clone a PDU including some of its variables.
601
 *
602
 * If skip_count is not zero, it defines the number of variables to skip.
603
 * If copy_count is not zero, it defines the number of variables to copy.
604
 *
605
 * Returns a pointer to the cloned PDU if successful.
606
 * Returns 0 if failure.
607
 */
608
#ifndef NETSNMP_FEATURE_REMOVE_SNMP_SPLIT_PDU
609
netsnmp_pdu    *
610
snmp_split_pdu(netsnmp_pdu *pdu, int skip_count, int copy_count)
611
0
{
612
0
    netsnmp_pdu    *newpdu;
613
614
0
    newpdu = _clone_pdu_header(pdu);
615
0
    if (!newpdu)
616
0
        return newpdu;
617
0
    newpdu = _copy_pdu_vars(pdu, newpdu, 0,     /* don't drop any variables */
618
0
                            skip_count, copy_count);
619
620
0
    return newpdu;
621
0
}
622
#endif /* NETSNMP_FEATURE_REMOVE_SNMP_SPLIT_PDU */
623
624
625
/*
626
 * If there was an error in the input pdu, creates a clone of the pdu
627
 * that includes all the variables except the one marked by the errindex.
628
 * The command is set to the input command and the reqid, errstat, and
629
 * errindex are set to default values.
630
 * If the error status didn't indicate an error, the error index didn't
631
 * indicate a variable, the pdu wasn't a get response message, the
632
 * marked variable was not present in the initial request, or there
633
 * would be no remaining variables, this function will return 0.
634
 * If everything was successful, a pointer to the fixed cloned pdu will
635
 * be returned.
636
 */
637
netsnmp_pdu    *
638
snmp_fix_pdu(netsnmp_pdu *pdu, int command)
639
0
{
640
0
    netsnmp_pdu    *newpdu;
641
642
0
    if ((pdu->command != SNMP_MSG_RESPONSE)
643
0
        || (pdu->errstat == SNMP_ERR_NOERROR)
644
0
        || (NULL == pdu->variables)
645
0
        || (pdu->errindex > (int)snmp_varbind_len(pdu))
646
0
        || (pdu->errindex <= 0)) {
647
0
        return NULL;            /* pre-condition tests fail */
648
0
    }
649
650
0
    newpdu = _clone_pdu(pdu, 1);        /* copies all except errored variable */
651
0
    if (!newpdu)
652
0
        return NULL;
653
0
    if (!newpdu->variables) {
654
0
        snmp_free_pdu(newpdu);
655
0
        return NULL;            /* no variables. "should not happen" */
656
0
    }
657
0
    newpdu->command = command;
658
0
    newpdu->reqid = snmp_get_next_reqid();
659
0
    newpdu->msgid = snmp_get_next_msgid();
660
0
    newpdu->errstat = SNMP_DEFAULT_ERRSTAT;
661
0
    newpdu->errindex = SNMP_DEFAULT_ERRINDEX;
662
663
0
    return newpdu;
664
0
}
665
666
667
/*
668
 * Returns the number of variables bound to a PDU structure
669
 */
670
unsigned long
671
snmp_varbind_len(netsnmp_pdu *pdu)
672
0
{
673
0
    register netsnmp_variable_list *vars;
674
0
    unsigned long   retVal = 0;
675
0
    if (pdu)
676
0
        for (vars = pdu->variables; vars; vars = vars->next_variable) {
677
0
            retVal++;
678
0
        }
679
680
0
    return retVal;
681
0
}
682
683
/*
684
 * Add object identifier name to SNMP variable.
685
 * If the name is large, additional memory is allocated.
686
 * Returns 0 if successful.
687
 */
688
689
int
690
snmp_set_var_objid(netsnmp_variable_list * vp,
691
                   const oid * objid, size_t name_length)
692
138k
{
693
138k
    size_t          len = sizeof(oid) * name_length;
694
695
138k
    if (vp->name != vp->name_loc && vp->name != NULL) {
696
        /*
697
         * Probably previously-allocated "big storage".  Better free it
698
         * else memory leaks possible.  
699
         */
700
0
        free(vp->name);
701
0
    }
702
703
    /*
704
     * use built-in storage for smaller values 
705
     */
706
138k
    if (len <= sizeof(vp->name_loc)) {
707
138k
        vp->name = vp->name_loc;
708
138k
    } else {
709
600
        vp->name = (oid *) malloc(len);
710
600
        if (!vp->name)
711
0
            return 1;
712
600
    }
713
138k
    if (objid)
714
138k
        memmove(vp->name, objid, len);
715
138k
    vp->name_length = name_length;
716
138k
    return 0;
717
138k
}
718
719
/**
720
 * snmp_set_var_typed_value is used to set data into the netsnmp_variable_list
721
 * structure.  Used to return data to the snmp request via the
722
 * netsnmp_request_info structure's requestvb pointer.
723
 *
724
 * @param newvar   the structure gets populated with the given data, type,
725
 *                 val_str, and val_len.
726
 * @param type     is the asn data type to be copied
727
 * @param val_str  is a buffer containing the value to be copied into the
728
 *                 newvar structure. 
729
 * @param val_len  the length of val_str
730
 * 
731
 * @return returns 0 on success and 1 on a malloc error
732
 */
733
734
int
735
snmp_set_var_typed_value(netsnmp_variable_list * newvar, u_char type,
736
                         const void * val_str, size_t val_len)
737
9.95k
{
738
9.95k
    newvar->type = type;
739
9.95k
    return snmp_set_var_value(newvar, val_str, val_len);
740
9.95k
}
741
742
int
743
snmp_set_var_typed_integer(netsnmp_variable_list * newvar,
744
                           u_char type, long val)
745
0
{
746
0
    newvar->type = type;
747
0
    return snmp_set_var_value(newvar, &val, sizeof(long));
748
0
}
749
750
int
751
count_varbinds(netsnmp_variable_list * var_ptr)
752
13.4k
{
753
13.4k
    int             count = 0;
754
755
24.3k
    for (; var_ptr != NULL; var_ptr = var_ptr->next_variable)
756
10.9k
        count++;
757
758
13.4k
    return count;
759
13.4k
}
760
761
netsnmp_feature_child_of(count_varbinds_of_type, netsnmp_unused);
762
#ifndef NETSNMP_FEATURE_REMOVE_COUNT_VARBINDS_OF_TYPE
763
int
764
count_varbinds_of_type(netsnmp_variable_list * var_ptr, u_char type)
765
0
{
766
0
    int             count = 0;
767
768
0
    for (; var_ptr != NULL; var_ptr = var_ptr->next_variable)
769
0
        if (var_ptr->type == type)
770
0
            count++;
771
772
0
    return count;
773
0
}
774
#endif /* NETSNMP_FEATURE_REMOVE_COUNT_VARBINDS_OF_TYPE */
775
776
netsnmp_feature_child_of(find_varind_of_type, netsnmp_unused);
777
#ifndef NETSNMP_FEATURE_REMOVE_FIND_VARIND_OF_TYPE
778
netsnmp_variable_list *
779
find_varbind_of_type(netsnmp_variable_list * var_ptr, u_char type)
780
0
{
781
0
    for (; var_ptr != NULL && var_ptr->type != type;
782
0
         var_ptr = var_ptr->next_variable);
783
784
0
    return var_ptr;
785
0
}
786
#endif /* NETSNMP_FEATURE_REMOVE_FIND_VARIND_OF_TYPE */
787
788
netsnmp_variable_list*
789
find_varbind_in_list( netsnmp_variable_list *vblist,
790
                      const oid *name, size_t len)
791
0
{
792
0
    for (; vblist != NULL; vblist = vblist->next_variable)
793
0
        if (!snmp_oid_compare(vblist->name, vblist->name_length, name, len))
794
0
            return vblist;
795
796
0
    return NULL;
797
0
}
798
799
/*
800
 * Add some value to SNMP variable.
801
 * If the value is large, additional memory is allocated.
802
 * Returns 0 if successful.
803
 */
804
805
int
806
snmp_set_var_value(netsnmp_variable_list * vars,
807
                   const void * value, size_t len)
808
103k
{
809
103k
    int             largeval = 1;
810
811
    /*
812
     * xxx-rks: why the unconditional free? why not use existing
813
     * memory, if len < vars->val_len ?
814
     */
815
103k
    if (vars->val.string && vars->val.string != vars->buf) {
816
47
        free(vars->val.string);
817
47
    }
818
103k
    vars->val.string = NULL;
819
103k
    vars->val_len = 0;
820
821
103k
    if (value == NULL && len > 0) {
822
0
        snmp_log(LOG_ERR, "bad size for NULL value\n");
823
0
        return 1;
824
0
    }
825
826
    /*
827
     * use built-in storage for smaller values 
828
     */
829
103k
    if (len <= sizeof(vars->buf)) {
830
99.2k
        vars->val.string = (u_char *) vars->buf;
831
99.2k
        largeval = 0;
832
99.2k
    }
833
834
103k
    if ((0 == len) || (NULL == value)) {
835
20.7k
        vars->val.string[0] = 0;
836
20.7k
        return 0;
837
20.7k
    }
838
839
82.5k
    vars->val_len = len;
840
82.5k
    switch (vars->type) {
841
1.44k
    case ASN_INTEGER:
842
3.04k
    case ASN_UNSIGNED:
843
5.33k
    case ASN_TIMETICKS:
844
6.73k
    case ASN_COUNTER:
845
8.72k
    case ASN_UINTEGER:
846
8.72k
        if (vars->val_len == sizeof(int)) {
847
8.47k
            if (ASN_INTEGER == vars->type) {
848
1.35k
                const int      *val_int 
849
1.35k
                    = (const int *) value;
850
1.35k
                *(vars->val.integer) = (long) *val_int;
851
7.12k
            } else {
852
7.12k
                const u_int    *val_uint
853
7.12k
                    = (const u_int *) value;
854
7.12k
                *(vars->val.integer) = (unsigned long) *val_uint;
855
7.12k
            }
856
8.47k
        }
857
257
        else if (vars->val_len == sizeof(long)){
858
257
            const u_long   *val_ulong
859
257
                = (const u_long *) value;
860
257
            *(vars->val.integer) = *val_ulong;
861
257
            if (*(vars->val.integer) > 0xffffffff) {
862
10
                NETSNMP_LOGONCE((LOG_INFO,
863
10
                                 "truncating integer value > 32 bits\n"));
864
10
                *(vars->val.integer) &= 0xffffffff;
865
10
            }
866
257
        }
867
0
        else if (vars->val_len == sizeof(long long)){
868
0
            const unsigned long long   *val_ullong
869
0
                = (const unsigned long long *) value;
870
0
            *(vars->val.integer) = (long) *val_ullong;
871
0
            if (*(vars->val.integer) > 0xffffffff) {
872
0
                NETSNMP_LOGONCE((LOG_INFO,
873
0
                                 "truncating integer value > 32 bits\n"));
874
0
                *(vars->val.integer) &= 0xffffffff;
875
0
            }
876
0
        }
877
0
        else if (vars->val_len == sizeof(intmax_t)){
878
0
            const uintmax_t *val_uintmax_t
879
0
                = (const uintmax_t *) value;
880
0
            *(vars->val.integer) = (long) *val_uintmax_t;
881
0
            if (*(vars->val.integer) > 0xffffffff) {
882
0
                NETSNMP_LOGONCE((LOG_INFO,
883
0
                                 "truncating integer value > 32 bits\n"));
884
0
                *(vars->val.integer) &= 0xffffffff;
885
0
            }
886
0
        }
887
0
        else if (vars->val_len == sizeof(short)) {
888
0
            if (ASN_INTEGER == vars->type) {
889
0
                const short      *val_short 
890
0
                    = (const short *) value;
891
0
                *(vars->val.integer) = (long) *val_short;
892
0
            } else {
893
0
                const u_short    *val_ushort
894
0
                    = (const u_short *) value;
895
0
                *(vars->val.integer) = (unsigned long) *val_ushort;
896
0
            }
897
0
        }
898
0
        else if (vars->val_len == sizeof(char)) {
899
0
            if (ASN_INTEGER == vars->type) {
900
0
                const signed char   *val_char
901
0
                    = (const signed char *) value;
902
0
                *(vars->val.integer) = (long) *val_char;
903
0
            } else {
904
0
                    const u_char    *val_uchar
905
0
                    = (const u_char *) value;
906
0
                *(vars->val.integer) = (unsigned long) *val_uchar;
907
0
            }
908
0
        }
909
0
        else {
910
0
            snmp_log(LOG_ERR,"bad size for integer-like type (%d)\n",
911
0
                     (int)vars->val_len);
912
0
            return (1);
913
0
        }
914
8.72k
        vars->val_len = sizeof(long);
915
8.72k
        break;
916
917
1.41k
    case ASN_OBJECT_ID:
918
1.41k
    case ASN_PRIV_IMPLIED_OBJECT_ID:
919
10.1k
    case ASN_PRIV_INCL_RANGE:
920
58.1k
    case ASN_PRIV_EXCL_RANGE:
921
58.1k
        if (largeval) {
922
2.98k
            vars->val.objid = (oid *) malloc(vars->val_len);
923
2.98k
        }
924
58.1k
        if (vars->val.objid == NULL) {
925
0
            snmp_log(LOG_ERR,"no storage for OID\n");
926
0
            return 1;
927
0
        }
928
58.1k
        memmove(vars->val.objid, value, vars->val_len);
929
58.1k
        break;
930
931
1.61k
    case ASN_IPADDRESS: /* snmp_build_var_op treats IPADDR like a string */
932
1.61k
        if (4 != vars->val_len) {
933
823
            netsnmp_assert("ipaddress length == 4");
934
823
        }
935
1.61k
        NETSNMP_FALLTHROUGH;
936
1.61k
    case ASN_PRIV_IMPLIED_OCTET_STR:
937
2.79k
    case ASN_OCTET_STR:
938
2.79k
    case ASN_BIT_STR:
939
10.9k
    case ASN_OPAQUE:
940
10.9k
    case ASN_NSAP:
941
10.9k
        if (vars->val_len >= sizeof(vars->buf)) {
942
1.31k
            vars->val.string = (u_char *) malloc(vars->val_len + 1);
943
1.31k
        }
944
10.9k
        if (vars->val.string == NULL) {
945
0
            snmp_log(LOG_ERR,"no storage for string\n");
946
0
            return 1;
947
0
        }
948
10.9k
        memmove(vars->val.string, value, vars->val_len);
949
        /*
950
         * Make sure the string is zero-terminated; some bits of code make
951
         * this assumption.  Easier to do this here than fix all these wrong
952
         * assumptions.  
953
         */
954
10.9k
        vars->val.string[vars->val_len] = '\0';
955
10.9k
        break;
956
957
0
    case SNMP_NOSUCHOBJECT:
958
0
    case SNMP_NOSUCHINSTANCE:
959
0
    case SNMP_ENDOFMIBVIEW:
960
0
    case ASN_NULL:
961
0
        vars->val_len = 0;
962
0
        vars->val.string = NULL;
963
0
        break;
964
965
0
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
966
93
    case ASN_OPAQUE_U64:
967
219
    case ASN_OPAQUE_I64:
968
219
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
969
3.19k
    case ASN_COUNTER64:
970
3.19k
        if (largeval || vars->val_len != sizeof(struct counter64)) {
971
0
            snmp_log(LOG_ERR,"bad size for counter 64 (%d)\n",
972
0
                     (int)vars->val_len);
973
0
            return (1);
974
0
        }
975
3.19k
        vars->val_len = sizeof(struct counter64);
976
3.19k
        memmove(vars->val.counter64, value, vars->val_len);
977
3.19k
        break;
978
979
0
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
980
680
    case ASN_OPAQUE_FLOAT:
981
680
        if (largeval) {
982
0
            snmp_log(LOG_ERR,"bad size for opaque float (%d)\n",
983
0
                     (int)vars->val_len);
984
0
            return (1);
985
0
        }
986
680
        vars->val_len = sizeof(float);
987
680
        memmove(vars->val.floatVal, value, vars->val_len);
988
680
        break;
989
990
822
    case ASN_OPAQUE_DOUBLE:
991
822
        if (largeval) {
992
0
            snmp_log(LOG_ERR,"bad size for opaque double (%d)\n",
993
0
                     (int)vars->val_len);
994
0
            return (1);
995
0
        }
996
822
        vars->val_len = sizeof(double);
997
822
        memmove(vars->val.doubleVal, value, vars->val_len);
998
822
        break;
999
1000
0
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
1001
1002
0
    default:
1003
0
        snmp_log(LOG_ERR,"Internal error in type switching\n");
1004
0
        snmp_set_detail("Internal error in type switching\n");
1005
0
        return (1);
1006
82.5k
    }
1007
1008
82.5k
    return 0;
1009
82.5k
}
1010
1011
void
1012
snmp_replace_var_types(netsnmp_variable_list * vbl, u_char old_type,
1013
                       u_char new_type)
1014
208
{
1015
468
    while (vbl) {
1016
260
        if (vbl->type == old_type) {
1017
0
            snmp_set_var_typed_value(vbl, new_type, NULL, 0);
1018
0
        }
1019
260
        vbl = vbl->next_variable;
1020
260
    }
1021
208
}
1022
1023
#ifndef NETSNMP_FEATURE_REMOVE_SNMP_RESET_VAR_TYPES
1024
void
1025
snmp_reset_var_types(netsnmp_variable_list * vbl, u_char new_type)
1026
0
{
1027
0
    while (vbl) {
1028
0
        snmp_set_var_typed_value(vbl, new_type, NULL, 0);
1029
0
        vbl = vbl->next_variable;
1030
0
    }
1031
0
}
1032
#endif /* NETSNMP_FEATURE_REMOVE_SNMP_RESET_VAR_TYPES */
1033
1034
int
1035
snmp_synch_response_cb(netsnmp_session * ss,
1036
                       netsnmp_pdu *pdu,
1037
                       netsnmp_pdu **response, snmp_callback pcb)
1038
0
{
1039
0
    struct synch_state    lstate, *state;
1040
0
    snmp_callback         cbsav;
1041
0
    void                 *cbmagsav;
1042
0
    int                   numfds, count;
1043
0
    netsnmp_large_fd_set  fdset;
1044
0
    struct timeval        timeout, *tvp;
1045
0
    int                   block;
1046
1047
0
    memset((void *) &lstate, 0, sizeof(lstate));
1048
0
    state = &lstate;
1049
0
    cbsav = ss->callback;
1050
0
    cbmagsav = ss->callback_magic;
1051
0
    ss->callback = pcb;
1052
0
    ss->callback_magic = (void *) state;
1053
0
    netsnmp_large_fd_set_init(&fdset, FD_SETSIZE);
1054
1055
0
    if (snmp_send(ss, pdu) == 0) {
1056
0
        snmp_free_pdu(pdu);
1057
0
        state->status = STAT_ERROR;
1058
0
    } else {
1059
0
        state->reqid = pdu->reqid;
1060
0
        state->waiting = 1;
1061
0
    }
1062
1063
0
    while (state->waiting) {
1064
0
        snmp_poll();
1065
1066
0
        numfds = 0;
1067
0
        NETSNMP_LARGE_FD_ZERO(&fdset);
1068
0
        block = NETSNMP_SNMPBLOCK;
1069
0
        tvp = &timeout;
1070
0
        timerclear(tvp);
1071
0
        snmp_sess_select_info2_flags(NULL, &numfds, &fdset, tvp, &block,
1072
0
                                     NETSNMP_SELECT_NOALARMS);
1073
0
        if (block == 1)
1074
0
            tvp = NULL;         /* block without timeout */
1075
0
        count = netsnmp_large_fd_set_select(numfds, &fdset, NULL, NULL, tvp);
1076
0
        if (count > 0) {
1077
0
            snmp_read2(&fdset);
1078
0
        } else {
1079
0
            switch (count) {
1080
0
            case 0:
1081
0
                snmp_timeout();
1082
0
                break;
1083
0
            case -1:
1084
0
                if (errno == EINTR) {
1085
0
                    continue;
1086
0
                } else {
1087
0
                    snmp_errno = SNMPERR_GENERR;    /*MTCRITICAL_RESOURCE */
1088
                    /*
1089
                     * CAUTION! if another thread closed the socket(s)
1090
                     * waited on here, the session structure was freed.
1091
                     * It would be nice, but we can't rely on the pointer.
1092
                     * ss->s_snmp_errno = SNMPERR_GENERR;
1093
                     * ss->s_errno = errno;
1094
                     */
1095
0
                    snmp_set_detail(strerror(errno));
1096
0
                }
1097
0
                NETSNMP_FALLTHROUGH;
1098
0
            default:
1099
0
                state->status = STAT_ERROR;
1100
0
                state->waiting = 0;
1101
0
            }
1102
0
        }
1103
1104
0
        if ( ss->flags & SNMP_FLAGS_RESP_CALLBACK ) {
1105
0
            void (*cb)(void);
1106
0
            cb = (void (*)(void))(ss->myvoid);
1107
0
            cb();        /* Used to invoke 'netsnmp_check_outstanding_agent_requests();'
1108
                            on internal AgentX queries.  */
1109
0
        }
1110
0
    }
1111
0
    *response = state->pdu;
1112
0
    ss->callback = cbsav;
1113
0
    ss->callback_magic = cbmagsav;
1114
0
    netsnmp_large_fd_set_cleanup(&fdset);
1115
0
    return state->status;
1116
0
}
1117
1118
int
1119
snmp_synch_response(netsnmp_session * ss,
1120
                    netsnmp_pdu *pdu, netsnmp_pdu **response)
1121
0
{
1122
0
    return snmp_synch_response_cb(ss, pdu, response, snmp_synch_input);
1123
0
}
1124
1125
int
1126
snmp_sess_synch_response(struct session_list *slp,
1127
                         netsnmp_pdu *pdu, netsnmp_pdu **response)
1128
0
{
1129
0
    netsnmp_session      *ss;
1130
0
    struct synch_state    lstate, *state;
1131
0
    snmp_callback         cbsav;
1132
0
    void                 *cbmagsav;
1133
0
    int                   numfds, count;
1134
0
    netsnmp_large_fd_set  fdset;
1135
0
    struct timeval        timeout, *tvp;
1136
0
    int                   block;
1137
1138
0
    ss = snmp_sess_session(slp);
1139
0
    if (ss == NULL) {
1140
0
        return STAT_ERROR;
1141
0
    }
1142
1143
0
    memset((void *) &lstate, 0, sizeof(lstate));
1144
0
    state = &lstate;
1145
0
    cbsav = ss->callback;
1146
0
    cbmagsav = ss->callback_magic;
1147
0
    ss->callback = snmp_synch_input;
1148
0
    ss->callback_magic = (void *) state;
1149
0
    netsnmp_large_fd_set_init(&fdset, FD_SETSIZE);
1150
1151
0
    if (snmp_sess_send(slp, pdu) == 0) {
1152
0
        snmp_free_pdu(pdu);
1153
0
        state->status = STAT_ERROR;
1154
0
    } else {
1155
0
        state->waiting = 1;
1156
0
        state->reqid = pdu->reqid;
1157
0
    }
1158
1159
0
    while (state->waiting) {
1160
0
        snmp_sess_poll(slp);
1161
1162
0
        numfds = 0;
1163
0
        NETSNMP_LARGE_FD_ZERO(&fdset);
1164
0
        block = NETSNMP_SNMPBLOCK;
1165
0
        tvp = &timeout;
1166
0
        timerclear(tvp);
1167
0
        snmp_sess_select_info2_flags(slp, &numfds, &fdset, tvp, &block,
1168
0
                                     NETSNMP_SELECT_NOALARMS);
1169
0
        if (block == 1)
1170
0
            tvp = NULL;         /* block without timeout */
1171
0
        count = netsnmp_large_fd_set_select(numfds, &fdset, NULL, NULL, tvp);
1172
0
        if (count > 0) {
1173
0
            snmp_sess_read2(slp, &fdset);
1174
0
        } else
1175
0
            switch (count) {
1176
0
            case 0:
1177
0
                snmp_sess_timeout(slp);
1178
0
                break;
1179
0
            case -1:
1180
0
                if (errno == EINTR) {
1181
0
                    continue;
1182
0
                } else {
1183
0
                    snmp_errno = SNMPERR_GENERR;    /*MTCRITICAL_RESOURCE */
1184
                    /*
1185
                     * CAUTION! if another thread closed the socket(s)
1186
                     * waited on here, the session structure was freed.
1187
                     * It would be nice, but we can't rely on the pointer.
1188
                     * ss->s_snmp_errno = SNMPERR_GENERR;
1189
                     * ss->s_errno = errno;
1190
                     */
1191
0
                    snmp_set_detail(strerror(errno));
1192
0
                }
1193
0
                NETSNMP_FALLTHROUGH;
1194
0
            default:
1195
0
                state->status = STAT_ERROR;
1196
0
                state->waiting = 0;
1197
0
            }
1198
0
    }
1199
0
    *response = state->pdu;
1200
0
    ss->callback = cbsav;
1201
0
    ss->callback_magic = cbmagsav;
1202
0
    netsnmp_large_fd_set_cleanup(&fdset);
1203
0
    return state->status;
1204
0
}
1205
1206
1207
const char     *
1208
snmp_errstring(int errstat)
1209
0
{
1210
0
    const char * const error_string[19] = {
1211
0
        "(noError) No Error",
1212
0
        "(tooBig) Response message would have been too large.",
1213
0
        "(noSuchName) There is no such variable name in this MIB.",
1214
0
        "(badValue) The value given has the wrong type or length.",
1215
0
        "(readOnly) The two parties used do not have access to use the specified SNMP PDU.",
1216
0
        "(genError) A general failure occurred",
1217
0
        "noAccess",
1218
0
        "wrongType (The set datatype does not match the data type the agent expects)",
1219
0
        "wrongLength (The set value has an illegal length from what the agent expects)",
1220
0
        "wrongEncoding",
1221
0
        "wrongValue (The set value is illegal or unsupported in some way)",
1222
0
        "noCreation (That table does not support row creation or that object can not ever be created)",
1223
0
        "inconsistentValue (The set value is illegal or unsupported in some way)",
1224
0
        "resourceUnavailable (This is likely a out-of-memory failure within the agent)",
1225
0
        "commitFailed",
1226
0
        "undoFailed",
1227
0
        "authorizationError (access denied to that object)",
1228
0
        "notWritable (That object does not support modification)",
1229
0
        "inconsistentName (That object can not currently be created)"
1230
0
    };
1231
1232
0
    if (errstat <= MAX_SNMP_ERR && errstat >= SNMP_ERR_NOERROR) {
1233
0
        return error_string[errstat];
1234
0
    } else {
1235
0
        return "Unknown Error";
1236
0
    }
1237
0
}
1238
1239
1240
1241
/*
1242
 *
1243
 *  Convenience routines to make various requests
1244
 *  over the specified SNMP session.
1245
 *
1246
 */
1247
#include <net-snmp/library/snmp_debug.h>
1248
1249
static netsnmp_session *_def_query_session = NULL;
1250
1251
#ifndef NETSNMP_FEATURE_REMOVE_QUERY_SET_DEFAULT_SESSION
1252
void
1253
0
netsnmp_query_set_default_session( netsnmp_session *sess) {
1254
0
    DEBUGMSGTL(("iquery", "set default session %p\n", sess));
1255
0
    _def_query_session = sess;
1256
0
}
1257
#endif /* NETSNMP_FEATURE_REMOVE_QUERY_SET_DEFAULT_SESSION */
1258
1259
void
1260
3.40k
netsnmp_query_shutdown(void) {
1261
3.40k
    if (_def_query_session) {
1262
0
        snmp_close(_def_query_session);
1263
0
        _def_query_session = NULL;
1264
0
    }
1265
3.40k
}
1266
1267
/**
1268
 * Return a pointer to the default internal query session.
1269
 */
1270
netsnmp_session *
1271
3.34k
netsnmp_query_get_default_session_unchecked( void ) {
1272
3.34k
    DEBUGMSGTL(("iquery", "get default session %p\n", _def_query_session));
1273
3.34k
    return _def_query_session;
1274
3.34k
}
1275
1276
/**
1277
 * Return a pointer to the default internal query session and log a
1278
 * warning message once if this session does not exist.
1279
 */
1280
netsnmp_session *
1281
0
netsnmp_query_get_default_session( void ) {
1282
0
    static int warning_logged = 0;
1283
1284
0
    if (! _def_query_session && ! warning_logged) {
1285
0
        if (! netsnmp_ds_get_string(NETSNMP_DS_APPLICATION_ID,
1286
0
                                    NETSNMP_DS_AGENT_INTERNAL_SECNAME)) {
1287
0
            snmp_log(LOG_WARNING,
1288
0
                     "iquerySecName has not been configured - internal queries will fail\n");
1289
0
        } else {
1290
0
            snmp_log(LOG_WARNING,
1291
0
                     "default session is not available - internal queries will fail\n");
1292
0
        }
1293
0
        warning_logged = 1;
1294
0
    }
1295
1296
0
    return netsnmp_query_get_default_session_unchecked();
1297
0
}
1298
1299
1300
/*
1301
 * Internal utility routine to actually send the query
1302
 */
1303
static int _query(netsnmp_variable_list *list,
1304
                  int                    request,
1305
0
                  netsnmp_session       *session) {
1306
1307
0
    netsnmp_pdu *pdu;
1308
0
    netsnmp_pdu *response = NULL;
1309
0
    netsnmp_variable_list *vb1, *vb2, *vtmp;
1310
0
    int ret, count;
1311
1312
0
    DEBUGMSGTL(("iquery", "query on session %p\n", session));
1313
1314
0
    if (NULL == list) {
1315
0
        snmp_log(LOG_ERR, "empty variable list in _query\n");
1316
0
        return SNMP_ERR_GENERR;
1317
0
    }
1318
1319
0
    pdu = snmp_pdu_create( request );
1320
0
    if (NULL == pdu) {
1321
0
        snmp_log(LOG_ERR, "could not allocate pdu\n");
1322
0
        return SNMP_ERR_GENERR;
1323
0
    }
1324
1325
    /*
1326
     * Clone the varbind list into the request PDU...
1327
     */
1328
0
    pdu->variables = snmp_clone_varbind( list );
1329
0
    if (NULL == pdu->variables) {
1330
0
        snmp_log(LOG_ERR, "could not clone variable list\n");
1331
0
        snmp_free_pdu(pdu);
1332
0
        return SNMP_ERR_GENERR;
1333
0
    }
1334
1335
0
#ifndef NETSNMP_NO_WRITE_SUPPORT
1336
0
retry:
1337
0
#endif
1338
0
    if ( session )
1339
0
        ret = snmp_synch_response(            session, pdu, &response );
1340
0
    else if (_def_query_session)
1341
0
        ret = snmp_synch_response( _def_query_session, pdu, &response );
1342
0
    else {
1343
        /* No session specified */
1344
0
        snmp_free_pdu(pdu);
1345
0
        return SNMP_ERR_GENERR;
1346
0
    }
1347
0
    DEBUGMSGTL(("iquery", "query returned %d\n", ret));
1348
1349
    /*
1350
     * ....then copy the results back into the
1351
     * list (assuming the request succeeded!).
1352
     * This avoids having to worry about how this
1353
     * list was originally allocated.
1354
     */
1355
0
    if ( ret == SNMP_ERR_NOERROR ) {
1356
0
        if ( response->errstat != SNMP_ERR_NOERROR ) {
1357
0
            DEBUGMSGT(("iquery", "Error in packet: %s\n",
1358
0
                       snmp_errstring(response->errstat)));
1359
            /*
1360
             * If the request failed, then remove the
1361
             *  offending varbind and try again.
1362
             *  (all except SET requests)
1363
             *
1364
             * XXX - implement a library version of
1365
             *       NETSNMP_DS_APP_DONT_FIX_PDUS ??
1366
             */
1367
0
            ret = response->errstat;
1368
0
            if (response->errindex != 0) {
1369
0
                DEBUGMSGT(("iquery:result", "Failed object:\n"));
1370
0
                for (count = 1, vtmp = response->variables;
1371
0
                     vtmp && count != response->errindex;
1372
0
                     vtmp = vtmp->next_variable, count++)
1373
0
                    /*EMPTY*/;
1374
0
                if (vtmp)
1375
0
                    DEBUGMSGVAR(("iquery:result", vtmp));
1376
0
                DEBUGMSG(("iquery:result", "\n"));
1377
0
            }
1378
0
#ifndef NETSNMP_NO_WRITE_SUPPORT
1379
0
            if (request != SNMP_MSG_SET &&
1380
0
                response->errindex != 0) {
1381
0
                DEBUGMSGTL(("iquery", "retrying query (%d, %ld)\n", ret, response->errindex));
1382
0
                pdu = snmp_fix_pdu( response, request );
1383
0
                snmp_free_pdu( response );
1384
0
                response = NULL;
1385
0
                if ( pdu != NULL )
1386
0
                    goto retry;
1387
0
            }
1388
0
#endif /* !NETSNMP_NO_WRITE_SUPPORT */
1389
0
        } else {
1390
0
            for (vb1 = response->variables, vb2 = list;
1391
0
                 vb1;
1392
0
                 vb1 = vb1->next_variable,  vb2 = vb2->next_variable) {
1393
0
                DEBUGMSGVAR(("iquery:result", vb1));
1394
0
                DEBUGMSG(("iquery:results", "\n"));
1395
0
                if ( !vb2 ) {
1396
0
                    ret = SNMP_ERR_GENERR;
1397
0
                    break;
1398
0
                }
1399
0
                vtmp = vb2->next_variable;
1400
0
                snmp_free_var_internals( vb2 );
1401
0
                snmp_clone_var( vb1, vb2 ); /* xxx: check return? */
1402
0
                vb2->next_variable = vtmp;
1403
0
            }
1404
0
        }
1405
0
    } else {
1406
        /* Distinguish snmp_send errors from SNMP errStat errors */
1407
0
        ret = -ret;
1408
0
    }
1409
0
    snmp_free_pdu( response );
1410
0
    return ret;
1411
0
}
1412
1413
/*
1414
 * These are simple wrappers round the internal utility routine
1415
 */
1416
int netsnmp_query_get(netsnmp_variable_list *list,
1417
0
                      netsnmp_session       *session){
1418
0
    return _query( list, SNMP_MSG_GET, session );
1419
0
}
1420
1421
1422
int netsnmp_query_getnext(netsnmp_variable_list *list,
1423
0
                          netsnmp_session       *session){
1424
0
    return _query( list, SNMP_MSG_GETNEXT, session );
1425
0
}
1426
1427
1428
#ifndef NETSNMP_NO_WRITE_SUPPORT
1429
int netsnmp_query_set(netsnmp_variable_list *list,
1430
0
                      netsnmp_session       *session){
1431
0
    return _query( list, SNMP_MSG_SET, session );
1432
0
}
1433
#endif /* !NETSNMP_NO_WRITE_SUPPORT */
1434
1435
/*
1436
 * A walk needs a bit more work.
1437
 */
1438
int netsnmp_query_walk(netsnmp_variable_list *list,
1439
0
                       netsnmp_session       *session) {
1440
    /*
1441
     * Create a working copy of the original (single)
1442
     * varbind, so we can use this varbind parameter
1443
     * to check when we've finished walking this subtree.
1444
     */
1445
0
    netsnmp_variable_list *vb = snmp_clone_varbind( list );
1446
0
    netsnmp_variable_list *res_list = NULL;
1447
0
    netsnmp_variable_list *res_last = NULL;
1448
0
    int ret;
1449
1450
    /*
1451
     * Now walk the tree as usual
1452
     */
1453
0
    ret = _query( vb, SNMP_MSG_GETNEXT, session );
1454
0
    while ( ret == SNMP_ERR_NOERROR &&
1455
0
        snmp_oidtree_compare( list->name, list->name_length,
1456
0
                                vb->name,   vb->name_length ) == 0) {
1457
1458
0
  if (vb->type == SNMP_ENDOFMIBVIEW ||
1459
0
      vb->type == SNMP_NOSUCHOBJECT ||
1460
0
      vb->type == SNMP_NOSUCHINSTANCE)
1461
0
      break;
1462
1463
        /*
1464
         * Copy each response varbind to the end of the result list
1465
         * and then re-use this to ask for the next entry.
1466
         */
1467
0
        if ( res_last ) {
1468
0
            res_last->next_variable = snmp_clone_varbind( vb );
1469
0
            res_last = res_last->next_variable;
1470
0
        } else {
1471
0
            res_list = snmp_clone_varbind( vb );
1472
0
            res_last = res_list;
1473
0
        }
1474
0
        ret = _query( vb, SNMP_MSG_GETNEXT, session );
1475
0
    }
1476
    /*
1477
     * Copy the first result back into the original varbind parameter,
1478
     * add the rest of the results (if any), and clean up.
1479
     */
1480
0
    if ( res_list ) {
1481
0
        snmp_clone_var( res_list, list );
1482
0
        list->next_variable = res_list->next_variable;
1483
0
        res_list->next_variable = NULL;
1484
0
        snmp_free_varbind( res_list );
1485
0
    }
1486
0
    snmp_free_varbind( vb );
1487
0
    return ret;
1488
0
}
1489
1490
/** **************************************************************************
1491
 *
1492
 * state machine
1493
 *
1494
 */
1495
int
1496
netsnmp_state_machine_run( netsnmp_state_machine_input *input)
1497
0
{
1498
0
    netsnmp_state_machine_step *current, *last;
1499
1500
0
    netsnmp_require_ptr_LRV( input, SNMPERR_GENERR );
1501
0
    netsnmp_require_ptr_LRV( input->steps, SNMPERR_GENERR );
1502
0
    last = current = input->steps;
1503
1504
0
    DEBUGMSGT(("state_machine:run", "starting step: %s\n", current->name));
1505
1506
0
    while (current) {
1507
1508
        /*
1509
         * log step and check for required data
1510
         */
1511
0
        DEBUGMSGT(("state_machine:run", "at step: %s\n", current->name));
1512
0
        if (NULL == current->run) {
1513
0
            DEBUGMSGT(("state_machine:run", "no run step\n"));
1514
0
            current->result = last->result;
1515
0
            break;
1516
0
        }
1517
1518
        /*
1519
         * run step
1520
         */
1521
0
        DEBUGMSGT(("state_machine:run", "running step: %s\n", current->name));
1522
0
        current->result = (*current->run)( input, current );
1523
0
        ++input->steps_so_far;
1524
        
1525
        /*
1526
         * log result and move to next step
1527
         */
1528
0
        input->last_run = current;
1529
0
        DEBUGMSGT(("state_machine:run:result", "step %s returned %d\n",
1530
0
                   current->name, current->result));
1531
0
        if (SNMPERR_SUCCESS == current->result)
1532
0
            current = current->on_success;
1533
0
        else if (SNMPERR_ABORT == current->result) {
1534
0
            DEBUGMSGT(("state_machine:run:result", "ABORT from %s\n",
1535
0
                       current->name));
1536
0
            break;
1537
0
        }
1538
0
        else
1539
0
            current = current->on_error;
1540
0
    }
1541
1542
    /*
1543
     * run cleanup
1544
     */
1545
0
    if ((input->cleanup) && (input->cleanup->run))
1546
0
        (*input->cleanup->run)( input, input->last_run );
1547
1548
0
    return input->last_run->result;
1549
0
}
1550
1551
#ifndef NETSNMP_NO_WRITE_SUPPORT
1552
#ifndef NETSNMP_FEATURE_REMOVE_ROW_CREATE
1553
/** **************************************************************************
1554
 *
1555
 * row create state machine steps
1556
 *
1557
 */
1558
typedef struct rowcreate_state_s {
1559
1560
    netsnmp_session        *session;
1561
    netsnmp_variable_list  *vars;
1562
    int                     row_status_index;
1563
} rowcreate_state;
1564
1565
static netsnmp_variable_list *
1566
_get_vb_num(netsnmp_variable_list *vars, int index)
1567
0
{
1568
0
    for (; vars && index > 0; --index)
1569
0
        vars = vars->next_variable;
1570
1571
0
    if (!vars || index > 0)
1572
0
        return NULL;
1573
    
1574
0
    return vars;
1575
0
}
1576
1577
1578
/*
1579
 * cleanup
1580
 */
1581
static int 
1582
_row_status_state_cleanup(netsnmp_state_machine_input *input,
1583
                 netsnmp_state_machine_step *step)
1584
0
{
1585
0
    rowcreate_state       *ctx;
1586
1587
0
    netsnmp_require_ptr_LRV( input, SNMPERR_ABORT );
1588
0
    netsnmp_require_ptr_LRV( step, SNMPERR_ABORT );
1589
1590
0
    DEBUGMSGT(("row_create:called", "_row_status_state_cleanup, last run step was %s rc %d\n",
1591
0
               step->name, step->result));
1592
1593
0
    ctx = (rowcreate_state *)input->input_context;
1594
0
    if (ctx && ctx->vars)
1595
0
        snmp_free_varbind( ctx->vars );
1596
1597
0
    return SNMPERR_SUCCESS;
1598
0
}
1599
1600
/*
1601
 * send a request to activate the row
1602
 */
1603
static int 
1604
_row_status_state_activate(netsnmp_state_machine_input *input,
1605
                  netsnmp_state_machine_step *step)
1606
0
{
1607
0
    rowcreate_state       *ctx;
1608
0
    netsnmp_variable_list *rs_var, *var = NULL;
1609
0
    int32_t                rc, val = RS_ACTIVE;
1610
1611
0
    netsnmp_require_ptr_LRV( input, SNMPERR_GENERR );
1612
0
    netsnmp_require_ptr_LRV( step, SNMPERR_GENERR );
1613
0
    netsnmp_require_ptr_LRV( input->input_context, SNMPERR_GENERR );
1614
1615
0
    ctx = (rowcreate_state *)input->input_context;
1616
1617
0
    DEBUGMSGT(("row_create:called", "called %s\n", step->name));
1618
1619
    /*
1620
     * just send the rowstatus varbind
1621
     */
1622
0
    rs_var = _get_vb_num(ctx->vars, ctx->row_status_index);
1623
0
    netsnmp_require_ptr_LRV(rs_var, SNMPERR_GENERR);
1624
1625
0
    var = snmp_varlist_add_variable(&var, rs_var->name, rs_var->name_length,
1626
0
                                    rs_var->type, &val, sizeof(val));
1627
0
    netsnmp_require_ptr_LRV( var, SNMPERR_GENERR );
1628
1629
    /*
1630
     * send set
1631
     */
1632
0
    rc = netsnmp_query_set( var, ctx->session );
1633
0
    if (-2 == rc)
1634
0
        rc = SNMPERR_ABORT;
1635
1636
0
    snmp_free_varbind(var);
1637
1638
0
    return rc;
1639
0
}
1640
1641
/*
1642
 * send each non-row status column, one at a time
1643
 */
1644
static int 
1645
_row_status_state_single_value_cols(netsnmp_state_machine_input *input,
1646
                                    netsnmp_state_machine_step *step)
1647
0
{
1648
0
    rowcreate_state       *ctx;
1649
0
    netsnmp_variable_list *var, *tmp_next, *row_status;
1650
0
    int                    rc = SNMPERR_GENERR;
1651
1652
0
    netsnmp_require_ptr_LRV( input, SNMPERR_GENERR );
1653
0
    netsnmp_require_ptr_LRV( step, SNMPERR_GENERR );
1654
0
    netsnmp_require_ptr_LRV( input->input_context, SNMPERR_GENERR );
1655
1656
0
    ctx = (rowcreate_state *)input->input_context;
1657
1658
0
    DEBUGMSGT(("row_create:called", "called %s\n", step->name));
1659
1660
0
    row_status = _get_vb_num(ctx->vars, ctx->row_status_index);
1661
0
    netsnmp_require_ptr_LRV(row_status, SNMPERR_GENERR);
1662
1663
    /*
1664
     * try one varbind at a time
1665
     */
1666
0
    for (var = ctx->vars; var; var = var->next_variable) {
1667
0
        if (var == row_status)
1668
0
            continue;
1669
1670
0
        tmp_next = var->next_variable;
1671
0
        var->next_variable = NULL;
1672
1673
        /*
1674
         * send set
1675
         */
1676
0
        rc = netsnmp_query_set( var, ctx->session );
1677
0
        var->next_variable = tmp_next;
1678
0
        if (-2 == rc)
1679
0
            rc = SNMPERR_ABORT;
1680
0
        if (rc != SNMPERR_SUCCESS)
1681
0
            break;
1682
0
    }
1683
1684
0
    return rc;
1685
0
}
1686
1687
/*
1688
 * send all values except row status
1689
 */
1690
static int 
1691
_row_status_state_multiple_values_cols(netsnmp_state_machine_input *input,
1692
                                       netsnmp_state_machine_step *step)
1693
0
{
1694
0
    rowcreate_state       *ctx;
1695
0
    netsnmp_variable_list *vars, *var, *last, *row_status;
1696
0
    int                    rc;
1697
1698
0
    netsnmp_require_ptr_LRV( input, SNMPERR_GENERR );
1699
0
    netsnmp_require_ptr_LRV( step, SNMPERR_GENERR );
1700
0
    netsnmp_require_ptr_LRV( input->input_context, SNMPERR_GENERR );
1701
1702
0
    ctx = (rowcreate_state *)input->input_context;
1703
1704
0
    DEBUGMSGT(("row_create:called", "called %s\n", step->name));
1705
1706
0
    vars = snmp_clone_varbind(ctx->vars);
1707
0
    netsnmp_require_ptr_LRV(vars, SNMPERR_GENERR);
1708
1709
0
    row_status = _get_vb_num(vars, ctx->row_status_index);
1710
0
    if (NULL == row_status) {
1711
0
        snmp_free_varbind(vars);
1712
0
        return SNMPERR_GENERR;
1713
0
    }
1714
1715
    /*
1716
     * remove row status varbind
1717
     */
1718
0
    if (row_status == vars) {
1719
0
        vars = row_status->next_variable;
1720
0
        row_status->next_variable = NULL;
1721
0
    }
1722
0
    else {
1723
0
        for (last=vars, var=last->next_variable;
1724
0
             var;
1725
0
             last=var, var = var->next_variable) {
1726
0
            if (var == row_status) {
1727
0
                last->next_variable = var->next_variable;
1728
0
                break;
1729
0
            }
1730
0
        }
1731
0
    }
1732
0
    snmp_free_var(row_status);
1733
1734
    /*
1735
     * send set
1736
     */
1737
0
    rc = netsnmp_query_set( vars, ctx->session );
1738
0
    if (-2 == rc)
1739
0
        rc = SNMPERR_ABORT;
1740
1741
0
    snmp_free_varbind(vars);
1742
1743
0
    return rc;
1744
0
}
1745
1746
/*
1747
 * send a createAndWait request with no other values
1748
 */
1749
static int 
1750
_row_status_state_single_value_createAndWait(netsnmp_state_machine_input *input,
1751
                                             netsnmp_state_machine_step *step)
1752
0
{
1753
0
    rowcreate_state       *ctx;
1754
0
    netsnmp_variable_list *var = NULL, *rs_var;
1755
0
    int32_t                rc, val = RS_CREATEANDWAIT;
1756
1757
0
    netsnmp_require_ptr_LRV( input, SNMPERR_GENERR );
1758
0
    netsnmp_require_ptr_LRV( step, SNMPERR_GENERR );
1759
0
    netsnmp_require_ptr_LRV( input->input_context, SNMPERR_GENERR );
1760
1761
0
    ctx = (rowcreate_state *)input->input_context;
1762
1763
0
    DEBUGMSGT(("row_create:called", "called %s\n", step->name));
1764
1765
0
    rs_var = _get_vb_num(ctx->vars, ctx->row_status_index);
1766
0
    netsnmp_require_ptr_LRV(rs_var, SNMPERR_GENERR);
1767
1768
0
    var = snmp_varlist_add_variable(&var, rs_var->name, rs_var->name_length,
1769
0
                                    rs_var->type, &val, sizeof(val));
1770
0
    netsnmp_require_ptr_LRV(var, SNMPERR_GENERR);
1771
1772
    /*
1773
     * send set
1774
     */
1775
0
    rc = netsnmp_query_set( var, ctx->session );
1776
0
    if (-2 == rc)
1777
0
        rc = SNMPERR_ABORT;
1778
1779
0
    snmp_free_varbind(var);
1780
1781
0
    return rc;
1782
0
}
1783
1784
/*
1785
 * send a creatAndWait request with all values
1786
 */
1787
static int 
1788
_row_status_state_all_values_createAndWait(netsnmp_state_machine_input *input,
1789
                                           netsnmp_state_machine_step *step)
1790
0
{
1791
0
    rowcreate_state       *ctx;
1792
0
    netsnmp_variable_list *vars, *rs_var;
1793
0
    int                    rc;
1794
1795
0
    netsnmp_require_ptr_LRV( input, SNMPERR_GENERR );
1796
0
    netsnmp_require_ptr_LRV( step, SNMPERR_GENERR );
1797
0
    netsnmp_require_ptr_LRV( input->input_context, SNMPERR_GENERR );
1798
1799
0
    ctx = (rowcreate_state *)input->input_context;
1800
1801
0
    DEBUGMSGT(("row_create:called", "called %s\n", step->name));
1802
1803
0
    vars = snmp_clone_varbind(ctx->vars);
1804
0
    netsnmp_require_ptr_LRV(vars, SNMPERR_GENERR);
1805
1806
    /*
1807
     * make sure row stats is createAndWait
1808
     */
1809
0
    rs_var = _get_vb_num(vars, ctx->row_status_index);
1810
0
    if (NULL == rs_var) {
1811
0
        snmp_free_varbind(vars);
1812
0
        return SNMPERR_GENERR;
1813
0
    }
1814
1815
0
    if (*rs_var->val.integer != RS_CREATEANDWAIT)
1816
0
        *rs_var->val.integer = RS_CREATEANDWAIT;
1817
1818
    /*
1819
     * send set
1820
     */
1821
0
    rc = netsnmp_query_set( vars, ctx->session );
1822
0
    if (-2 == rc)
1823
0
        rc = SNMPERR_ABORT;
1824
1825
0
    snmp_free_varbind(vars);
1826
1827
0
    return rc;
1828
0
}
1829
1830
1831
/**
1832
 * send createAndGo request with all values
1833
 */
1834
static int 
1835
_row_status_state_all_values_createAndGo(netsnmp_state_machine_input *input,
1836
                                         netsnmp_state_machine_step *step)
1837
0
{
1838
0
    rowcreate_state       *ctx;
1839
0
    netsnmp_variable_list *vars, *rs_var;
1840
0
    int                    rc;
1841
1842
0
    netsnmp_require_ptr_LRV( input, SNMPERR_GENERR );
1843
0
    netsnmp_require_ptr_LRV( step, SNMPERR_GENERR );
1844
0
    netsnmp_require_ptr_LRV( input->input_context, SNMPERR_GENERR );
1845
1846
0
    ctx = (rowcreate_state *)input->input_context;
1847
1848
0
    DEBUGMSGT(("row_create:called", "called %s\n", step->name));
1849
1850
0
    vars = snmp_clone_varbind(ctx->vars);
1851
0
    netsnmp_require_ptr_LRV(vars, SNMPERR_GENERR);
1852
1853
    /*
1854
     * make sure row stats is createAndGo
1855
     */
1856
0
    rs_var = _get_vb_num(vars, ctx->row_status_index + 1);
1857
0
    if (NULL == rs_var) {
1858
0
        snmp_free_varbind(vars);
1859
0
        return SNMPERR_GENERR;
1860
0
    }
1861
1862
0
    if (*rs_var->val.integer != RS_CREATEANDGO)
1863
0
        *rs_var->val.integer = RS_CREATEANDGO;
1864
1865
    /*
1866
     * send set
1867
     */
1868
0
    rc = netsnmp_query_set( vars, ctx->session );
1869
0
    if (-2 == rc)
1870
0
        rc = SNMPERR_ABORT;
1871
1872
0
    snmp_free_varbind(vars);
1873
1874
0
    return rc;
1875
0
}
1876
1877
/** **************************************************************************
1878
 *
1879
 * row api
1880
 *
1881
 */
1882
int
1883
netsnmp_row_create(netsnmp_session *sess, netsnmp_variable_list *vars,
1884
                   int row_status_index)
1885
0
{
1886
0
    netsnmp_state_machine_step rc_cleanup =
1887
0
        { "row_create_cleanup", 0, _row_status_state_cleanup,
1888
0
          0, NULL, NULL, 0, NULL };
1889
0
    netsnmp_state_machine_step rc_activate =
1890
0
        { "row_create_activate", 0, _row_status_state_activate,
1891
0
          0, NULL, NULL, 0, NULL };
1892
0
    netsnmp_state_machine_step rc_sv_cols =
1893
0
        { "row_create_single_value_cols", 0,
1894
0
          _row_status_state_single_value_cols, 0, &rc_activate,NULL, 0, NULL };
1895
0
    netsnmp_state_machine_step rc_mv_cols =
1896
0
        { "row_create_multiple_values_cols", 0,
1897
0
          _row_status_state_multiple_values_cols, 0, &rc_activate, &rc_sv_cols,
1898
0
          0, NULL };
1899
0
    netsnmp_state_machine_step rc_sv_caw =
1900
0
        { "row_create_single_value_createAndWait", 0,
1901
0
          _row_status_state_single_value_createAndWait, 0, &rc_mv_cols, NULL,
1902
0
          0, NULL };
1903
0
    netsnmp_state_machine_step rc_av_caw =
1904
0
        { "row_create_all_values_createAndWait", 0,
1905
0
          _row_status_state_all_values_createAndWait, 0, &rc_activate,
1906
0
          &rc_sv_caw, 0, NULL };
1907
0
    netsnmp_state_machine_step rc_av_cag =
1908
0
        { "row_create_all_values_createAndGo", 0,
1909
0
          _row_status_state_all_values_createAndGo, 0, NULL, &rc_av_caw, 0,
1910
0
          NULL };
1911
1912
0
    netsnmp_state_machine_input sm_input = { "row_create_machine", 0,
1913
0
                                             &rc_av_cag, &rc_cleanup };
1914
0
    rowcreate_state state;
1915
1916
0
    netsnmp_require_ptr_LRV( sess, SNMPERR_GENERR);
1917
0
    netsnmp_require_ptr_LRV( vars, SNMPERR_GENERR);
1918
1919
0
    state.session = sess;
1920
0
    state.vars = vars;
1921
1922
0
    state.row_status_index = row_status_index;
1923
0
    sm_input.input_context = &state;
1924
1925
0
    netsnmp_state_machine_run( &sm_input);
1926
1927
0
    return SNMPERR_SUCCESS;
1928
0
}
1929
#endif /* NETSNMP_FEATURE_REMOVE_ROW_CREATE */
1930
#endif /* NETSNMP_NO_WRITE_SUPPORT */
1931
1932
1933
/** @} */