Coverage Report

Created: 2023-06-07 06:42

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