]> git.kernelconcepts.de Git - karo-tx-redboot.git/blob - packages/net/snmp/agent/v2_0/src/snmp_agent.c
Initial revision
[karo-tx-redboot.git] / packages / net / snmp / agent / v2_0 / src / snmp_agent.c
1 //==========================================================================
2 //
3 //      ./agent/current/src/snmp_agent.c
4 //
5 //
6 //==========================================================================
7 //####ECOSGPLCOPYRIGHTBEGIN####
8 // -------------------------------------------
9 // This file is part of eCos, the Embedded Configurable Operating System.
10 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
11 //
12 // eCos is free software; you can redistribute it and/or modify it under
13 // the terms of the GNU General Public License as published by the Free
14 // Software Foundation; either version 2 or (at your option) any later version.
15 //
16 // eCos is distributed in the hope that it will be useful, but WITHOUT ANY
17 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
18 // FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19 // for more details.
20 //
21 // You should have received a copy of the GNU General Public License along
22 // with eCos; if not, write to the Free Software Foundation, Inc.,
23 // 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
24 //
25 // As a special exception, if other files instantiate templates or use macros
26 // or inline functions from this file, or you compile this file and link it
27 // with other works to produce a work based on this file, this file does not
28 // by itself cause the resulting work to be covered by the GNU General Public
29 // License. However the source code for this file must still be made available
30 // in accordance with section (3) of the GNU General Public License.
31 //
32 // This exception does not invalidate any other reasons why a work based on
33 // this file might be covered by the GNU General Public License.
34 //
35 // Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
36 // at http://sources.redhat.com/ecos/ecos-license/
37 // -------------------------------------------
38 //####ECOSGPLCOPYRIGHTEND####
39 //####UCDSNMPCOPYRIGHTBEGIN####
40 //
41 // -------------------------------------------
42 //
43 // Portions of this software may have been derived from the UCD-SNMP
44 // project,  <http://ucd-snmp.ucdavis.edu/>  from the University of
45 // California at Davis, which was originally based on the Carnegie Mellon
46 // University SNMP implementation.  Portions of this software are therefore
47 // covered by the appropriate copyright disclaimers included herein.
48 //
49 // The release used was version 4.1.2 of May 2000.  "ucd-snmp-4.1.2"
50 // -------------------------------------------
51 //
52 //####UCDSNMPCOPYRIGHTEND####
53 //==========================================================================
54 //#####DESCRIPTIONBEGIN####
55 //
56 // Author(s):    hmt
57 // Contributors: hmt
58 // Date:         2000-05-30
59 // Purpose:      Port of UCD-SNMP distribution to eCos.
60 // Description:  
61 //              
62 //
63 //####DESCRIPTIONEND####
64 //
65 //==========================================================================
66 /********************************************************************
67        Copyright 1989, 1991, 1992 by Carnegie Mellon University
68
69                           Derivative Work -
70 Copyright 1996, 1998, 1999, 2000 The Regents of the University of California
71
72                          All Rights Reserved
73
74 Permission to use, copy, modify and distribute this software and its
75 documentation for any purpose and without fee is hereby granted,
76 provided that the above copyright notice appears in all copies and
77 that both that copyright notice and this permission notice appear in
78 supporting documentation, and that the name of CMU and The Regents of
79 the University of California not be used in advertising or publicity
80 pertaining to distribution of the software without specific written
81 permission.
82
83 CMU AND THE REGENTS OF THE UNIVERSITY OF CALIFORNIA DISCLAIM ALL
84 WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
85 WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL CMU OR
86 THE REGENTS OF THE UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY SPECIAL,
87 INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
88 FROM THE LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
89 CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
90 CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
91 *********************************************************************/
92 /*
93  * snmp_agent.c
94  *
95  * Simple Network Management Protocol (RFC 1067).
96  */
97 /***********************************************************
98         Copyright 1988, 1989 by Carnegie Mellon University
99
100                       All Rights Reserved
101
102 Permission to use, copy, modify, and distribute this software and its 
103 documentation for any purpose and without fee is hereby granted, 
104 provided that the above copyright notice appear in all copies and that
105 both that copyright notice and this permission notice appear in 
106 supporting documentation, and that the name of CMU not be
107 used in advertising or publicity pertaining to distribution of the
108 software without specific, written prior permission.  
109
110 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
111 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
112 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
113 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
114 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
115 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
116 SOFTWARE.
117 ******************************************************************/
118
119 #include <config.h>
120
121 #include <sys/types.h>
122 #ifdef HAVE_STDLIB_H
123 #include <stdlib.h>
124 #endif
125 #if HAVE_UNISTD_H
126 #include <unistd.h>
127 #endif
128 #if HAVE_STRING_H
129 #include <string.h>
130 #endif
131 #if TIME_WITH_SYS_TIME
132 # ifdef WIN32
133 #  include <sys/timeb.h>
134 # else
135 #  include <sys/time.h>
136 # endif
137 # include <time.h>
138 #else
139 # if HAVE_SYS_TIME_H
140 #  include <sys/time.h>
141 # else
142 #  include <time.h>
143 # endif
144 #endif
145 #if HAVE_SYS_SELECT_H
146 #include <sys/select.h>
147 #endif
148 #if HAVE_NETINET_IN_H
149 #include <netinet/in.h>
150 #endif
151 #include <errno.h>
152 #if HAVE_WINSOCK_H
153 #include <winsock.h>
154 #endif
155
156 #if HAVE_DMALLOC_H
157 #include <dmalloc.h>
158 #endif
159
160 #include "asn1.h"
161 #define SNMP_NEED_REQUEST_LIST
162 #include "snmp_api.h"
163 #include "snmp_impl.h"
164 #include "snmp.h"
165 #include "mib.h"
166 #include "snmp_client.h"
167
168 #include "snmp_vars.h"
169 #include "snmpd.h"
170 #include "mibgroup/struct.h"
171 #include "mibgroup/util_funcs.h"
172 #include "var_struct.h"
173 #include "read_config.h"
174 #include "snmp_logging.h"
175 #include "snmp_debug.h"
176 #include "mib_module_config.h"
177
178 #include "default_store.h"
179 #include "ds_agent.h"
180 #include "snmp_agent.h"
181 #include "agent_trap.h"
182
183 static int snmp_vars_inc;
184
185 static struct agent_snmp_session *agent_session_list = NULL;
186
187
188 static void dump_var(oid *, size_t, int, void *, size_t);
189 static int goodValue(u_char, size_t, u_char, size_t);
190 static void setVariable(u_char *, u_char, size_t, u_char *, size_t);
191
192 static void dump_var (
193     oid *var_name,
194     size_t var_name_len,
195     int statType,
196     void *statP,
197     size_t statLen)
198 {
199     char buf [SPRINT_MAX_LEN];
200     struct variable_list temp_var;
201
202     temp_var.type = statType;
203     temp_var.val.string = (u_char *)statP;
204     temp_var.val_len = statLen;
205     sprint_variable (buf, var_name, var_name_len, &temp_var);
206     snmp_log(LOG_INFO, "    >> %s\n", buf);
207 }
208
209
210 int getNextSessID()
211 {
212     static int SessionID = 0;
213
214     return ++SessionID;
215 }
216
217 int
218 agent_check_and_process(int block) {
219   int numfds;
220   fd_set fdset;
221   struct timeval        timeout, *tvp = &timeout;
222   int count;
223   int fakeblock=0;
224   
225   tvp =  &timeout;
226   tvp->tv_sec  = 0;
227   tvp->tv_usec = 0;
228
229   numfds = 0;
230   FD_ZERO(&fdset);
231   snmp_select_info(&numfds, &fdset, tvp, &fakeblock);
232   if (block == 1 && fakeblock == 1)
233     tvp = NULL; /* block without timeout */
234   else if (block == 0) {
235       tvp->tv_sec = 0;
236       tvp->tv_usec = 0;
237   }
238
239   count = select(numfds, &fdset, 0, 0, tvp);
240
241   if (count > 0){
242     /* packets found, process them */
243     snmp_read(&fdset);
244   } else switch(count){
245     case 0:
246       snmp_timeout();
247       break;
248     case -1:
249       if (errno == EINTR){
250         return -1;
251       } else {
252         snmp_log_perror("select");
253       }
254       return -1;
255     default:
256       snmp_log(LOG_ERR, "select returned %d\n", count);
257       return -1;
258   }  /* endif -- count>0 */
259   return count;
260 }
261
262
263 /*
264  * The session is created using the "traditional API" routine snmp_open()
265  * so is linked into the global library Sessions list.  It also opens a
266  * socket that listens for incoming requests.
267  * 
268  *   The agent runs in an infinite loop (in the 'receive()' routine),
269  * which calls snmp_read() when such a request is received on this socket.
270  * This routine then traverses the library 'Sessions' list to identify the
271  * relevant session and eventually invokes '_sess_read'.
272  *   This then processes the incoming packet, calling the pre_parse, parse,
273  * post_parse and callback routines in turn.
274  */
275
276         /* Global access to the primary session structure for this agent.
277                 for Index Allocation use initially. */
278 struct snmp_session *main_session;
279
280 int
281 init_master_agent(int dest_port, 
282                   int (*pre_parse) (struct snmp_session *, snmp_ipaddr),
283                   int (*post_parse) (struct snmp_session *, struct snmp_pdu *,int))
284 {
285     struct snmp_session sess, *session;
286
287     if ( ds_get_boolean(DS_APPLICATION_ID, DS_AGENT_ROLE) != MASTER_AGENT )
288         return 0; /* no error if ! MASTER_AGENT */
289
290     DEBUGMSGTL(("snmpd","installing master agent on port %d\n", dest_port));
291
292     snmp_sess_init( &sess );
293     
294     sess.version = SNMP_DEFAULT_VERSION;
295     sess.peername = SNMP_DEFAULT_PEERNAME;
296     sess.community_len = SNMP_DEFAULT_COMMUNITY_LEN;
297      
298     sess.local_port = dest_port;
299     sess.callback = handle_snmp_packet;
300     sess.authenticator = NULL;
301     sess.flags = ds_get_int(DS_APPLICATION_ID, DS_AGENT_FLAGS);
302     session = snmp_open_ex( &sess, pre_parse, 0, post_parse, 0, 0 );
303
304     if ( session == NULL ) {
305       /* diagnose snmp_open errors with the input struct snmp_session pointer */
306         snmp_sess_perror("init_master_agent", &sess);
307                 return 1;
308     }
309     main_session = session;
310         return 0;
311 }
312
313 struct agent_snmp_session  *
314 init_agent_snmp_session( struct snmp_session *session, struct snmp_pdu *pdu )
315 {
316     struct agent_snmp_session  *asp;
317
318     asp = malloc( sizeof( struct agent_snmp_session ));
319     if ( asp == NULL )
320         return NULL;
321     asp->start = pdu->variables;
322     asp->end   = pdu->variables;
323     if ( asp->end != NULL )
324         while ( asp->end->next_variable != NULL )
325             asp->end = asp->end->next_variable;
326     asp->session = session;
327     asp->pdu     = pdu;
328     asp->rw      = READ;
329     asp->exact   = TRUE;
330     asp->outstanding_requests = NULL;
331     asp->next    = NULL;
332     asp->mode    = RESERVE1;
333     asp->status  = SNMP_ERR_NOERROR;
334
335     return asp;
336 }
337
338 int
339 count_varbinds( struct snmp_pdu *pdu )
340 {
341   int count = 0;
342   struct variable_list *var_ptr;
343   
344   for ( var_ptr = pdu->variables ; var_ptr != NULL ;
345                         var_ptr = var_ptr->next_variable )
346         count++;
347
348   return count;
349 }
350
351 int
352 handle_snmp_packet(int operation, struct snmp_session *session, int reqid,
353                    struct snmp_pdu *pdu, void *magic)
354 {
355     struct agent_snmp_session  *asp;
356     int status, allDone, i;
357     struct variable_list *var_ptr, *var_ptr2;
358
359     if ( magic == NULL ) {
360         asp = init_agent_snmp_session( session, snmp_clone_pdu(pdu) );
361         status = SNMP_ERR_NOERROR;
362     }
363     else {
364         asp = (struct agent_snmp_session *)magic;
365         status =   asp->status;
366     }
367
368     if (asp->outstanding_requests != NULL)
369         return 1;
370
371     if ( check_access(pdu) != 0) {
372         /* access control setup is incorrect */
373         send_easy_trap(SNMP_TRAP_AUTHFAIL, 0);
374         if (asp->pdu->version != SNMP_VERSION_1 && asp->pdu->version != SNMP_VERSION_2c) {
375             asp->pdu->errstat = SNMP_ERR_AUTHORIZATIONERROR;
376             asp->pdu->command = SNMP_MSG_RESPONSE;
377             snmp_increment_statistic(STAT_SNMPOUTPKTS);
378             snmp_send( asp->session, asp->pdu );
379             free( asp );
380             return 1;
381         } else {
382             /* drop the request */
383             free( asp );
384             return 0;
385         }
386     }
387
388     switch (pdu->command) {
389     case SNMP_MSG_GET:
390         if ( asp->mode != RESERVE1 )
391             break;                      /* Single pass */
392         snmp_increment_statistic(STAT_SNMPINGETREQUESTS);
393         status = handle_next_pass( asp );
394         asp->mode = RESERVE2;
395         break;
396
397     case SNMP_MSG_GETNEXT:
398         if ( asp->mode != RESERVE1 )
399             break;                      /* Single pass */
400         snmp_increment_statistic(STAT_SNMPINGETNEXTS);
401         asp->exact   = FALSE;
402         status = handle_next_pass( asp );
403         asp->mode = RESERVE2;
404         break;
405
406     case SNMP_MSG_GETBULK:
407             /*
408              * GETBULKS require multiple passes. The first pass handles the
409              * explicitly requested varbinds, and subsequent passes append
410              * to the existing var_op_list.  Each pass (after the first)
411              * uses the results of the preceeding pass as the input list
412              * (delimited by the start & end pointers.
413              * Processing is terminated if all entries in a pass are
414              * EndOfMib, or the maximum number of repetitions are made.
415              */
416         if ( asp->mode == RESERVE1 ) {
417             snmp_increment_statistic(STAT_SNMPINGETREQUESTS);
418             asp->exact   = FALSE;
419                     /*
420                      * Limit max repetitions to something reasonable
421                      *  XXX: We should figure out what will fit somehow...
422                      */
423             if ( asp->pdu->errindex > 100 )
424                 asp->pdu->errindex = 100;
425     
426             status = handle_next_pass( asp );   /* First pass */
427             asp->mode = RESERVE2;
428             if ( status != SNMP_ERR_NOERROR )
429                 break;
430     
431             while ( asp->pdu->errstat-- > 0 )   /* Skip non-repeaters */
432                 asp->start = asp->start->next_variable;
433             asp->pdu->errindex--;           /* Handled first repetition */
434
435             if ( asp->outstanding_requests != NULL )
436                 return 1;
437         }
438
439         while ( asp->pdu->errindex-- > 0 ) {    /* Process repeaters */
440                 /*
441                  * Add new variable structures for the
442                  * repeating elements, ready for the next pass.
443                  * Also check that these are not all EndOfMib
444                  */
445             allDone = TRUE;             /* Check for some content */
446             for ( var_ptr = asp->start;
447                   var_ptr != asp->end->next_variable;
448                   var_ptr = var_ptr->next_variable ) {
449                                 /* XXX: we don't know the size of the next
450                                         OID, so assume the maximum length */
451                 if ( var_ptr->type != SNMP_ENDOFMIBVIEW )
452                 {
453                 var_ptr2 = snmp_add_null_var(asp->pdu, var_ptr->name, MAX_OID_LEN);
454                 for ( i=var_ptr->name_length ; i<MAX_OID_LEN ; i++)
455                     var_ptr2->name[i] = 0;
456                 var_ptr2->name_length = var_ptr->name_length;
457
458                     allDone = FALSE;
459                 }
460             }
461             if ( allDone )
462                 break;
463
464             asp->start = asp->end->next_variable;
465             while ( asp->end->next_variable != NULL )
466                 asp->end = asp->end->next_variable;
467             
468             status = handle_next_pass( asp );
469             if ( status != SNMP_ERR_NOERROR )
470                 break;
471             if ( asp->outstanding_requests != NULL )
472                 return 1;
473         }
474         break;
475
476     case SNMP_MSG_SET:
477             /*
478              * SETS require 3-4 passes through the var_op_list.  The first two
479              * passes verify that all types, lengths, and values are valid
480              * and may reserve resources and the third does the set and a
481              * fourth executes any actions.  Then the identical GET RESPONSE
482              * packet is returned.
483              * If either of the first two passes returns an error, another
484              * pass is made so that any reserved resources can be freed.
485              * If the third pass returns an error, another pass is made so that
486              * any changes can be reversed.
487              * If the fourth pass (or any of the error handling passes)
488              * return an error, we'd rather not know about it!
489              */
490         if ( asp->mode == RESERVE1 ) {
491             snmp_increment_statistic(STAT_SNMPINSETREQUESTS);
492             asp->rw      = WRITE;
493
494             status = handle_next_pass( asp );
495
496             if ( status != SNMP_ERR_NOERROR )
497                 asp->mode = FREE;
498             else
499                 asp->mode = RESERVE2;
500
501             if ( asp->outstanding_requests != NULL )
502                 return 1;
503         }
504
505         if ( asp->mode == RESERVE2 ) {
506             status = handle_next_pass( asp );
507
508             if ( status != SNMP_ERR_NOERROR )
509                 asp->mode = FREE;
510             else
511                 asp->mode = ACTION;
512
513             if ( asp->outstanding_requests != NULL )
514                 return 1;
515         }
516
517         if ( asp->mode == ACTION ) {
518             status = handle_next_pass( asp );
519
520             if ( status != SNMP_ERR_NOERROR )
521                 asp->mode = UNDO;
522             else
523                 asp->mode = COMMIT;
524
525             if ( asp->outstanding_requests != NULL )
526                 return 1;
527         }
528
529         if ( asp->mode == COMMIT ) {
530             status = handle_next_pass( asp );
531
532             if ( status != SNMP_ERR_NOERROR ) {
533                 status    = SNMP_ERR_COMMITFAILED;
534                 asp->mode = FINISHED_FAILURE;
535             }
536             else
537                 asp->mode = FINISHED_SUCCESS;
538
539             if ( asp->outstanding_requests != NULL )
540                 return 1;
541         }
542
543         if ( asp->mode == UNDO ) {
544             if (handle_next_pass( asp ) != SNMP_ERR_NOERROR )
545                 status = SNMP_ERR_UNDOFAILED;
546
547             asp->mode = FINISHED_FAILURE;
548             break;
549         }
550
551         if ( asp->mode == FREE ) {
552             (void) handle_next_pass( asp );
553             break;
554         }
555
556         break;
557
558     case SNMP_MSG_RESPONSE:
559         snmp_increment_statistic(STAT_SNMPINGETRESPONSES);
560         free( asp );
561         return 0;
562     case SNMP_MSG_TRAP:
563     case SNMP_MSG_TRAP2:
564         snmp_increment_statistic(STAT_SNMPINTRAPS);
565         free( asp );
566         return 0;
567     default:
568         snmp_increment_statistic(STAT_SNMPINASNPARSEERRS);
569         free( asp );
570         return 0;
571     }
572
573     if ( asp->outstanding_requests != NULL ) {
574         asp->status = status;
575         asp->next = agent_session_list;
576         agent_session_list = asp;
577     }
578     else {
579                 /*
580                  * May need to "dumb down" a SET error status for a
581                  *  v1 query.  See RFC2576 - section 4.3
582                  */
583         if (( asp->pdu->command == SNMP_MSG_SET ) &&
584             ( asp->pdu->version == SNMP_VERSION_1 )) {
585             switch ( status ) {
586                 case SNMP_ERR_WRONGVALUE:
587                 case SNMP_ERR_WRONGENCODING:
588                 case SNMP_ERR_WRONGTYPE:
589                 case SNMP_ERR_WRONGLENGTH:
590                 case SNMP_ERR_INCONSISTENTVALUE:
591                         status = SNMP_ERR_BADVALUE;
592                         break;
593                 case SNMP_ERR_NOACCESS:
594                 case SNMP_ERR_NOTWRITABLE:
595                 case SNMP_ERR_NOCREATION:
596                 case SNMP_ERR_INCONSISTENTNAME:
597                 case SNMP_ERR_AUTHORIZATIONERROR:
598                         status = SNMP_ERR_NOSUCHNAME;
599                         break;
600                 case SNMP_ERR_RESOURCEUNAVAILABLE:
601                 case SNMP_ERR_COMMITFAILED:
602                 case SNMP_ERR_UNDOFAILED:
603                         status = SNMP_ERR_GENERR;
604                         break;
605             }
606         }
607                 /*
608                  * Similarly we may need to "dumb down" v2 exception
609                  *  types to throw an error for a v1 query.
610                  *  See RFC2576 - section 4.1.2.3
611                  */
612         if (( asp->pdu->command != SNMP_MSG_SET ) &&
613             ( asp->pdu->version == SNMP_VERSION_1 )) {
614                 for ( var_ptr = asp->pdu->variables, i=0 ;
615                         var_ptr != NULL ;
616                         var_ptr = var_ptr->next_variable, i++ ) {
617                     switch ( var_ptr->type ) {
618                         case SNMP_NOSUCHOBJECT:
619                         case SNMP_NOSUCHINSTANCE:
620                         case SNMP_ENDOFMIBVIEW:
621                         case ASN_COUNTER64:
622                                 status = SNMP_ERR_NOSUCHNAME;
623                                 asp->pdu->errindex=i;
624                                 break;
625                     }
626                 }
627         }
628         if ( status == SNMP_ERR_NOERROR ) {
629             snmp_increment_statistic_by(
630                 (asp->pdu->command == SNMP_MSG_SET ?
631                         STAT_SNMPINTOTALSETVARS : STAT_SNMPINTOTALREQVARS ),
632                 count_varbinds( asp->pdu ));
633         }
634         else {
635                 /*
636                  * Use a copy of the original request
637                  *   to report failures.
638                  */
639             i = asp->pdu->errindex;
640             snmp_free_pdu( asp->pdu );
641             asp->pdu = snmp_clone_pdu( pdu );
642             asp->pdu->errindex = i;
643         }
644         asp->pdu->command = SNMP_MSG_RESPONSE;
645         asp->pdu->errstat = status;
646         snmp_send( asp->session, asp->pdu );
647         snmp_increment_statistic(STAT_SNMPOUTPKTS);
648         snmp_increment_statistic(STAT_SNMPOUTGETRESPONSES);
649         free( asp );
650     }
651
652     return 1;
653 }
654
655
656 int
657 handle_next_pass(struct agent_snmp_session  *asp)
658 {
659     int status;
660     struct snmp_pdu *pdu = asp->pdu;
661     struct request_list *req_p, *next_req;
662
663
664         if ( asp->outstanding_requests != NULL )
665             return SNMP_ERR_NOERROR;
666         status = handle_var_list( asp );
667         if ( asp->outstanding_requests != NULL ) {
668             if ( status == SNMP_ERR_NOERROR ) {
669                 /* Send out any subagent requests */
670                 for ( req_p = asp->outstanding_requests ;
671                         req_p != NULL ; req_p = req_p->next_request ) {
672
673                     snmp_async_send( req_p->session,  req_p->pdu,
674                                       req_p->callback, req_p->cb_data );
675                 }
676                 asp->pdu = snmp_clone_pdu( pdu );
677                 asp->pdu->variables = pdu->variables;
678                 pdu->variables = NULL;
679             }
680             else {
681                 /* discard outstanding requests */
682                 for ( req_p = asp->outstanding_requests ;
683                         req_p != NULL ; req_p = next_req ) {
684                         
685                         next_req = req_p->next_request;
686                         free( req_p );
687                 }
688                 asp->outstanding_requests = NULL;
689             }
690         }
691         return status;
692 }
693
694
695 int
696 handle_var_list(struct agent_snmp_session  *asp)
697 {
698     struct variable_list *varbind_ptr;
699     u_char  statType;
700     u_char *statP;
701     size_t  statLen;
702     u_short acl;
703     WriteMethod *write_method;
704     AddVarMethod *add_method;
705     int     noSuchObject = TRUE;
706     int     count, view;
707     
708     count = 0;
709     varbind_ptr = asp->start;
710     if ( !varbind_ptr ) {
711         return SNMP_ERR_NOERROR;
712     }
713
714     while (1) {
715     
716         count++;
717 statp_loop:
718         statP = getStatPtr(  varbind_ptr->name,
719                            &varbind_ptr->name_length,
720                            &statType, &statLen, &acl,
721                            asp->exact, &write_method, asp->pdu, &noSuchObject);
722                            
723         if (statP == NULL && (asp->rw != WRITE || write_method == NULL)) {
724                 /*  Careful -- if the varbind was lengthy, it will have
725                     allocated some memory.  */
726                 snmp_set_var_value(varbind_ptr, NULL, 0);
727                 varbind_ptr->val.integer   = NULL;
728                 varbind_ptr->val_len = 0;
729                 if ( asp->exact ) {
730                     if ( noSuchObject == TRUE ){
731                         statType = SNMP_NOSUCHOBJECT;
732                     } else {
733                         statType = SNMP_NOSUCHINSTANCE;
734                     }
735                 } else {
736                     statType = SNMP_ENDOFMIBVIEW;
737                 }
738                 if (asp->pdu->version == SNMP_VERSION_1) {
739                     asp->pdu->errstat = SNMP_ERR_NOSUCHNAME;
740                     asp->pdu->errindex = count;
741                     return SNMP_ERR_NOSUCHNAME;
742                 }
743                 else if (asp->rw == WRITE) {
744                     asp->pdu->errstat =
745                         ( noSuchObject  ? SNMP_ERR_NOTWRITABLE
746                                         : SNMP_ERR_NOCREATION );
747                     asp->pdu->errindex = count;
748                     return asp->pdu->errstat;
749                 }
750                 else
751                     varbind_ptr->type = statType;
752         }
753                 /* Delegated variables should be added to the
754                    relevant outgoing request */
755         else if ( IS_DELEGATED(statType)) {
756                 add_method = (AddVarMethod*)statP;
757                 statType = (*add_method)( asp, varbind_ptr );
758         }
759                 /* GETNEXT/GETBULK should just skip inaccessible entries */
760         else if ((view = in_a_view(varbind_ptr->name, &varbind_ptr->name_length,
761                                    asp->pdu, varbind_ptr->type))
762                          && !asp->exact) {
763                 if (view != 5) send_easy_trap(SNMP_TRAP_AUTHFAIL, 0);
764                 goto statp_loop;
765         }
766                 /* Other access problems are permanent */
767         else if (( asp->rw == WRITE && !(acl & 2)) || view) {
768             if (asp->pdu->version == SNMP_VERSION_1 || asp->rw != WRITE) {
769                 if (ds_get_boolean(DS_APPLICATION_ID, DS_AGENT_VERBOSE))
770                   DEBUGMSGTL(("snmp_agent", "    >> noSuchName (read-only)\n"));
771                 ERROR_MSG("read-only");
772                 statType = SNMP_ERR_NOSUCHNAME;
773             }
774             else {
775                 if (ds_get_boolean(DS_APPLICATION_ID, DS_AGENT_VERBOSE))
776                   DEBUGMSGTL(("snmp_agent", "    >> notWritable\n"));
777                 ERROR_MSG("Not Writable");
778                 statType = SNMP_ERR_NOTWRITABLE;
779             }
780             asp->pdu->errstat = statType;
781             asp->pdu->errindex = count;
782             send_easy_trap(SNMP_TRAP_AUTHFAIL, 0);
783             return statType;
784         }
785         else {
786             /* dump verbose info */
787             if (ds_get_boolean(DS_APPLICATION_ID, DS_AGENT_VERBOSE) && statP)
788                 dump_var(varbind_ptr->name, varbind_ptr->name_length,
789                                 statType, statP, statLen);
790
791                 /*  FINALLY we can act on SET requests ....*/
792             if ( asp->rw == WRITE ) {
793                 if ( write_method != NULL ) {
794                     statType = (*write_method)(asp->mode,
795                                                varbind_ptr->val.string,
796                                                varbind_ptr->type,
797                                                varbind_ptr->val_len, statP,
798                                                varbind_ptr->name,
799                                                varbind_ptr->name_length);
800                     if (statType != SNMP_ERR_NOERROR) {
801                       asp->pdu->errstat = statType;
802                       asp->pdu->errindex = count;
803                       return statType;
804                     }
805                 }
806                 else {
807                     if (!goodValue(varbind_ptr->type, varbind_ptr->val_len,
808                                     statType, statLen)){
809                         if (asp->pdu->version == SNMP_VERSION_1)
810                             statType = SNMP_ERR_BADVALUE;
811                         else
812                             statType = SNMP_ERR_WRONGTYPE; /* poor approximation */
813                         asp->pdu->errstat = statType;
814                         asp->pdu->errindex = count;
815                         return statType;
816                     }
817                     /* actually do the set if necessary */
818                     if (asp->mode == COMMIT)
819                         setVariable(varbind_ptr->val.string, varbind_ptr->type,
820                                     varbind_ptr->val_len, statP, statLen);
821                 }
822             }
823                 /* ... or save the results from assorted GETs */
824             else {
825                      snmp_set_var_value(varbind_ptr, statP, statLen);
826                      varbind_ptr->type = statType;
827             }
828         }
829         
830         if ( varbind_ptr == asp->end )
831              return SNMP_ERR_NOERROR;
832         varbind_ptr = varbind_ptr->next_variable;
833         if ( asp->mode == RESERVE1 )
834             snmp_vars_inc++;
835     }
836 }
837
838
839
840 static int
841 goodValue(u_char inType, 
842           size_t inLen,
843           u_char actualType,
844           size_t actualLen)
845 {
846     if (inLen > actualLen)
847         return FALSE;
848     return (inType == actualType);
849 }
850
851 static void
852 setVariable(u_char *var_val,
853             u_char var_val_type,
854             size_t var_val_len,
855             u_char *statP,
856             size_t statLen)
857 {
858     size_t buffersize = 1000;
859
860     switch(var_val_type){
861         case ASN_INTEGER:
862             asn_parse_int(var_val, &buffersize, &var_val_type, (long *)statP, statLen);
863             break;
864         case ASN_COUNTER:
865         case ASN_GAUGE:
866         case ASN_TIMETICKS:
867             asn_parse_unsigned_int(var_val, &buffersize, &var_val_type, (u_long *)statP, statLen);
868             break;
869         case ASN_COUNTER64:
870             asn_parse_unsigned_int64(var_val, &buffersize, &var_val_type,
871                                      (struct counter64 *)statP, statLen);
872             break;
873         case ASN_OCTET_STR:
874         case ASN_IPADDRESS:
875         case ASN_OPAQUE:
876         case ASN_NSAP:
877             asn_parse_string(var_val, &buffersize, &var_val_type, statP, &statLen);
878             break;
879         case ASN_OBJECT_ID:
880             asn_parse_objid(var_val, &buffersize, &var_val_type, (oid *)statP, &statLen);
881             break;
882         case ASN_BIT_STR:
883             asn_parse_bitstring(var_val, &buffersize, &var_val_type, statP, &statLen);
884             break;
885     }
886 }