Coverage Report

Created: 2026-10-19 06:44

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