1 /*
2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5 #pragma ident "%Z%%M% %I% %E% SMI"
6
7 /***********************************************************
8 Copyright 1989 by Carnegie Mellon University
9
10 All Rights Reserved
11
12 Permission to use, copy, modify, and distribute this software and its
13 documentation for any purpose and without fee is hereby granted,
14 provided that the above copyright notice appear in all copies and that
15 both that copyright notice and this permission notice appear in
16 supporting documentation, and that the name of CMU not be
17 used in advertising or publicity pertaining to distribution of the
18 software without specific, written prior permission.
19
20 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
21 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
22 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
23 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
24 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
25 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
26 SOFTWARE.
27 ******************************************************************/
28 /************
29 * HISTORY
30 * 5-14-96 Jerry Yeung add request filter
31 * 5-28-96 Jerry Yeung Three phase set protocol(Three Phase)
32 * 9-18-96 Jerry Yeung agent_process has wrong arg.
33 ***********/
34
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <string.h>
38 #include <sys/types.h>
39 #include <sys/time.h>
40 #include <sys/param.h>
41 #include <netinet/in.h>
42 #include <sys/socket.h>
43 #include <netinet/in.h>
44 #include <arpa/inet.h>
45 #include <netdb.h>
46 #include <sys/times.h>
47 #include <limits.h>
48
49 #include "impl.h"
50 #include "error.h"
51 #include "trace.h"
52 #include "asn1.h"
53 #include "snmp.h"
54 #include "pdu.h"
55 #include "request.h"
56
57 #include "snmprelay_msg.h"
58 #include "agent.h"
59 #include "subtree.h"
60 #include "access.h"
61 #include "session.h"
62 #include "dispatcher.h"
63 #include "trap.h"
64
65
66
67 /***** LOCAL CONSTANTS *****/
68
69 #define SESSION_ID_MASK 0xffffff00
70 #define SESSION_ID_INCREMENT_VALUE 256
71 #define REQUEST_ID_MASK 0x000000ff
72 #define INVALID_ERROR_INDEX 0
73
74 /***** LOCAL VARIABLES *****/
75
76 Session *first_session = NULL;
77
78 static u_long session_id = 0;
79
80 static int session_internal_error = FALSE; /* only used bu session_open() */
81
82 /**** Three Phase ****/
83 static Three_Phase three_phase;
84
85
86 /***** LOCAL FUNCTIONS *****/
87
88 static void trace_session(Session *session);
89 static void trace_request(Request *request);
90
91 static Session *session_open(Address *address, SNMP_pdu *pdu);
92 void session_close(Session *session);
93
94 static int session_build_request_list(Session *session, int index, SNMP_variable *variable, Subtree *subtree);
95 static int session_build_local_sysUptime(Session *session, int index, SNMP_variable *variable);
96
97
98 void session_remove_from_list(Session *session);
99
100 void session_free(Session *session);
101 void request_list_free(Request *request_list);
102 void request_free(Request *request);
103
104 static void session_respond(Session *session);
105 static void session_respond_error(Session *session, int status, int index);
106
107 static Session *session_find(Address *address, u_long request_id);
108
109 static int session_send_request(Request *request);
110
111 static Request *session_move_request(Request *request, Subtree *subtree);
112
113 static int session_timeout_loop(struct timeval *now);
114
115 /* (5-14-96) */
116 static void session_process_response(SNMP_pdu *pdu_read,int doRespondHere);
117
118 static int session_send_loopback_request(Request *request,int doRespondHere);
119
120 static int community_check(Address * address, Agent* agent, int pdu_type, char * community);
121
122 /* These 3 functions are used to prevent oscillations between */
123 /* 2 agents when we try to retreive an empty table */
124 /* Example: */
125 /* Suppose that we have a table and the columns */
126 /* with an index 1.x are supported by agent A and the */
127 /* columns with an index 2.y are supporeted by agent B */
128 /* Suppose that in fact this table is empty and we send */
129 /* send the request Get-Next(columnA) */
130 /* */
131 /* Here is the sequence: */
132 /* Get-Next(columnA) on subtree columnA ==> No Such Name */
133 /* Get-Next(columnA) on subtree columnA.2 ==> No Such Name */
134 /* Get-Next(columnA) on subtree columnB ==> No Such Name */
135 /* Get-Next(columnA) on subtree columnB.2 ==> No Such Name */
136 /* .... */
137 /* */
138 /* That is why we have to register which agents we have */
139 /* already visited and not only the last one */
140
141 static int request_add_visited_agent(Request *request, Agent *agent);
142 static void agent_list_free(Agent_List *alp);
143 static int is_in_agent_list(Agent_List *agent_list, Agent *agent);
144
145
146 /************************************************************************/
147
trace_sessions()148 void trace_sessions()
149 {
150 Session *sp;
151 int count = 0;
152
153
154 trace("SESSIONS:\n");
155 trace("---------\n");
156 for(sp = first_session; sp; sp = sp->next_session)
157 {
158 trace("session %d:\n", sp->session_id);
159
160 trace_session(sp);
161
162 count++;
163 }
164 trace("NUMBER OF SESSIONS: %d\n", count);
165 trace("\n");
166 }
167
168
169 /************************************************************************/
170
trace_session(Session * session)171 static void trace_session(Session *session)
172 {
173 Request *request;
174
175
176 trace("\taddress: %s\n",
177 address_string(&(session->address)));
178 if(trace_level > 2)
179 {
180 trace("\tn_variables: %d\n", session->n_variables);
181 trace("\to_flags: 0x%x\n", session->o_flags);
182 trace("\ti_flags: 0x%x\n", session->i_flags);
183 }
184 for(request = session->first_request; request; request = request->next_request)
185 {
186 trace_request(request);
187 }
188 }
189
190
191 /************************************************************************/
192
trace_request(Request * request)193 static void trace_request(Request *request)
194 {
195 Session *session = request->session;
196 Subtree *subtree = request->subtree;
197 Agent *agent = NULL;
198 SNMP_variable *variable;
199
200
201 if(subtree)
202 {
203 agent = subtree->agent;
204 }
205
206 trace("\trequest %d:\n", request->request_id);
207 if(trace_level > 2)
208 {
209 trace("\t\tsession: %d\n", session->session_id);
210 }
211 trace("\t\tsubtree: %s\n", (subtree)? SSAOidString(&(subtree->name)): "NULL");
212 trace("\t\tvisited agents:\n");
213 if(trace_level > 2)
214 {
215 Agent_List *alp;
216
217
218 for(alp = request->visited_agent_list; alp; alp = alp->next)
219 {
220 trace("\t\t\t%s\n", alp->agent->name);
221 }
222 }
223 if(agent)
224 {
225 trace("\t\tagent: %s (%s)\n",
226 agent->name,
227 address_string(&(agent->address)));
228 }
229 else
230 {
231 trace("\t\tagent: %s\n", "NULL");
232 }
233 if(trace_level > 2)
234 {
235 trace("\t\tflags: 0x%x\n", request->flags);
236 }
237 trace("\t\tstate: %d\n", request->state);
238 trace("\t\tvariables:\n");
239 for(variable = request->pdu->first_variable; variable; variable = variable->next_variable)
240 {
241 trace("\t\t\t%s\n", SSAOidString(&(variable->name)));
242 }
243
244 if(trace_level > 3)
245 {
246 trace("\t\ttime: %s\n", timeval_string(&request->time));
247 trace("\t\texpire: %s\n", timeval_string(&request->expire));
248 }
249 }
250
251
252 /************************************************************************/
253
254 /* Three Phase: check for whether multiple agents are involved */
three_phase_protocol_in_action(SNMP_pdu * pdu)255 int three_phase_protocol_in_action(SNMP_pdu *pdu)
256 {
257 SNMP_variable *variable;
258 int local_access=0;
259 int subagent_access=0;
260 Subtree* subtree;
261 Agent *agent, *prev_agent=NULL;
262
263 if( pdu->type != SET_REQ_MSG) return(FALSE);
264
265 for(variable=pdu->first_variable;variable;variable=variable->next_variable){
266 subtree=subtree_match(pdu->type,&(variable->name));
267 if(subtree != NULL){
268 if( (agent=subtree->agent) != NULL){
269 if(prev_agent == NULL){
270 prev_agent = agent;
271 }else if(prev_agent != agent){
272 return(TRUE);
273 }
274 }
275 }
276 }
277 return(FALSE);
278 }
279
any_outstanding_session()280 int any_outstanding_session()
281 {
282 return(first_session!=NULL ? TRUE: FALSE);
283 }
284
anyOutstandingSetRequestRunning()285 int anyOutstandingSetRequestRunning()
286 {
287 Session *s;
288 for(s=first_session;s;s=s->next_session){
289 if(s->pdu && s->pdu->type == SET_REQ_MSG) return(TRUE);
290 }
291 return(FALSE);
292 }
293
294
session_dispatch()295 void session_dispatch()
296 {
297 SNMP_pdu *pdu;
298 Address address;
299 Session *session;
300 SNMP_variable *variable;
301 static int VersionWarnings = 10 ;
302
303 pdu = snmp_pdu_receive(clients_sd, &address, error_label);
304 if(pdu == NULL)
305 {
306
307 /* To avoid flooding the console and log, print trace "wrong version" messages */
308 /* after 10 console messages. */
309 if (strncmp (error_label, "The message has a wrong version", 31) == 0 && --VersionWarnings >= 0 ) {
310 error(ERR_MSG_PDU_RECEIVED,
311 address_string(&address),
312 error_label);
313 } else {
314 trace(ERR_MSG_PDU_RECEIVED,
315 address_string(&address),
316 error_label);
317 }
318 return;
319 }
320 if(pdu->type != GET_REQ_MSG
321 && pdu->type != GETNEXT_REQ_MSG
322 && pdu->type != SET_REQ_MSG)
323 {
324 error("bad PDU type (0x%x) received from %s",
325 pdu->type,
326 address_string(&address));
327 snmp_pdu_free(pdu);
328 return;
329 }
330 if(pdu->first_variable == NULL)
331 {
332 error("no variable in PDU received from %s",
333 address_string(&address));
334 snmp_pdu_free(pdu);
335 return;
336 }
337
338
339 session = session_find(&address, pdu->request_id);
340 if(session)
341 {
342 if(trace_level > 0)
343 {
344 trace("!! This request is already being processed by session %d\n\n",
345 session->session_id);
346 }
347 snmp_pdu_free(pdu);
348 return;
349 }
350
351
352 /* Three Phase: if the request across multi-subagents
353 * create the Three Phase object, pass the pdu from the
354 * session->three_phase->cur_pdu
355 */
356 if(three_phase_protocol_in_action(pdu)){
357 three_phase.origin_pdu = pdu;
358 /* create a corresponding get pdu */
359 three_phase.cur_pdu = snmp_pdu_dup(pdu, error_label);
360 if(three_phase.cur_pdu == NULL)
361 {
362 error("snmp_pdu_dup() failed: %s",error_label);
363 snmp_pdu_free(pdu);
364 three_phase.origin_pdu = NULL;
365 return;
366 }
367 three_phase.cur_pdu->type = GET_REQ_MSG;
368 /* form a get variable list.
369 * append to the cur_pdu */
370 for(variable=pdu->first_variable;variable;
371 variable=variable->next_variable){
372 if(snmp_pdu_append_null_variable(three_phase.cur_pdu,
373 &(variable->name),error_label) == NULL){
374 error("snmp_pdu_append_null_variable() failed: %s",
375 error_label);
376 snmp_pdu_free(pdu);
377 }
378 }
379 pdu = three_phase.cur_pdu;
380 three_phase.state = PHASE_1;
381 }
382
383 session = session_open(&address, pdu);
384 if(session == NULL)
385 {
386 if(session_internal_error == TRUE)
387 {
388 error("session_open() failed for a pdu received from %s",
389 address_string(&address));
390 }
391 return;
392 }
393
394
395 if(session->i_flags == session->o_flags)
396 {
397 session_respond(session);
398 }
399
400
401 return;
402 }
403
404 /****** (5-14-96) ****/
local_agent(Agent * agent)405 int local_agent(Agent *agent)
406 {
407 return(!strcmp(agent->name,relay_agent_name)? 1 : 0);
408 }
409
local_request(Request * request)410 int local_request(Request* request)
411 {
412 Agent* agent;
413
414 if(request && request->subtree){
415 agent = request->subtree->agent;
416 return( local_agent(agent));
417 }
418 return(FALSE); /* NOT LOCAL */
419 }
420
421
422 /************************************************************************/
423
424 /*
425 * If this function returns NULL and session_internal_error is
426 * TRUE, an internal error occured.
427 *
428 * But if we succeed to answer the SNMP request before the
429 * end of this function, it returns NULL and session_errno
430 * is FALSE.
431 *
432 *
433 * The pdu must have at least one variable in
434 * its variable list. (This has to be checked before calling
435 * this function)
436 *
437 * As the pdu is attached in a session structure,
438 * you must not free the pdu when this function
439 * returns whether the function succeeds or fails.
440 */
441
session_open(Address * address,SNMP_pdu * pdu)442 static Session *session_open(Address *address, SNMP_pdu *pdu)
443 {
444 Session *session;
445 SNMP_variable *variable;
446 Request *request;
447 static Subid ent_subids[] = {1, 3, 6, 1, 4, 1, 42, 2, 1, 1};
448 static Oid ent_oid = {ent_subids, 10};
449 struct tms buffer;
450 u_long time_stamp;
451
452
453
454
455 if(trace_level > 1)
456 {
457 trace("## Open session %d\n\n", session_id);
458 }
459
460
461 session = (Session *) malloc(sizeof(Session));
462 if(session == NULL)
463 {
464 error("malloc() failed");
465 session_internal_error = TRUE;
466 return NULL;
467 }
468 session->next_session = NULL;
469 session->pdu = NULL;
470 session->first_request = NULL;
471
472
473 /* session_id */
474 session->session_id = session_id;
475 session_id = session_id + SESSION_ID_INCREMENT_VALUE;
476
477 /* address */
478 memcpy(&(session->address), address, sizeof(Address));
479
480 /* pdu, n_variables, o_falgs, i_flags */
481 session->pdu = pdu;
482 session->n_variables = 0;
483 session->o_flags = 0;
484 session->i_flags = 0;
485
486
487 /* insert session in the session list */
488 session->next_session = first_session;
489 first_session = session;
490
491
492 /* build the requests list */
493 for(variable = pdu->first_variable; variable; variable = variable->next_variable)
494 {
495 Subtree *subtree;
496
497
498 (session->n_variables)++;
499
500 if(session->n_variables > 32)
501 {
502 error(ERR_MSG_VARBIND_LIMIT);
503 session_close(session);
504 session_internal_error = TRUE;
505 return NULL;
506 }
507
508 if( (
509 ( (pdu->type == GETNEXT_REQ_MSG) && (SSAOidCmp(&(variable->name), &sysUptime_name) == 0) )
510 ||
511 ( (pdu->type == GET_REQ_MSG) && (SSAOidCmp(&(variable->name), &sysUptime_instance) == 0) ) )
512 &&
513 (subtree_match(GET_REQ_MSG, &(variable->name)) == NULL) )
514 {
515 if(session_build_local_sysUptime(session, session->n_variables, variable) == -1)
516 {
517 error("session_build_local_sysUptime() failed");
518 session_close(session);
519 session_internal_error = TRUE;
520 return NULL;
521 }
522 }
523 else
524 {
525 subtree = subtree_match(pdu->type, &(variable->name));
526 if(subtree == NULL)
527 {
528 /* session_respond_error() closes the session */
529 session_respond_error(session, SNMP_ERR_NOSUCHNAME, session->n_variables);
530 session_internal_error = FALSE;
531 return NULL;
532 }
533
534 if (subtree->agent)
535 set_first_manager (subtree->agent->first_manager);
536 else
537 set_first_manager (NULL);
538 if (community_check(address, subtree->agent, pdu->type,
539 pdu->community) == FALSE) {
540 session_respond_error(session,
541 SNMP_ERR_AUTHORIZATIONERROR,
542 session->n_variables);
543 /* send authentication trap after error response */
544 time_stamp = (Integer) times(&buffer);
545 trap_filter_action(&ent_oid,SNMP_TRAP_AUTHFAIL,0,time_stamp,NULL);
546
547 /*
548 session_close(session);
549 */
550 session_internal_error = TRUE;
551 return NULL;
552 }
553 if(session_build_request_list(session, session->n_variables, variable, subtree) == -1)
554 {
555 error("session_build_request_list() failed");
556 session_close(session);
557 session_internal_error = TRUE;
558 return NULL;
559 }
560 }
561 }
562
563
564 if(trace_level > 1)
565 {
566 trace_session(session);
567 trace("\n");
568 }
569
570
571 /* send the requests */
572 for(request = session->first_request; request; request = request->next_request)
573 {
574 if(request->state == 0) /* request not sent/process yet */
575 {
576 if(local_request(request)){
577 if(session_send_loopback_request(request,FALSE) == -1){
578 error("session_send_loopback_request() failed");
579 session_close(session);
580 session_internal_error = TRUE;
581 return NULL;
582 }
583 }else if(session_send_request(request) == -1)
584 {
585 error("session_send_request() failed");
586 session_close(session);
587 session_internal_error = TRUE;
588 return NULL;
589 }
590 }
591 }
592
593
594 return session;
595 }
596
597
598 /************************************************************************/
599
session_build_local_sysUptime(Session * session,int index,SNMP_variable * variable)600 static int session_build_local_sysUptime(Session *session, int index, SNMP_variable *variable)
601 {
602 Request *last_request = NULL;
603 Request *request;
604 u_long request_id = 0;
605 SNMP_value value;
606 struct tms buffer;
607
608
609 for(request = session->first_request; request; request = request->next_request)
610 {
611 request_id++;
612 last_request = request;
613 }
614
615
616 request = (Request *) malloc(sizeof(Request));
617 if(request == NULL)
618 {
619 error("malloc() failed");
620 return -1;
621 }
622 memset(request, 0, sizeof(Request));
623
624 request->session = session;
625 request->subtree = NULL;
626
627 request->request_id = request_id;
628
629 request->pdu = snmp_pdu_dup(session->pdu, error_label);
630 if(request->pdu == NULL)
631 {
632 error("snmp_pdu_dup() failed: %s", error_label);
633 request_free(request);
634 return -1;
635 }
636 request->pdu->request_id = session->session_id + request->request_id;
637
638 request->pdu->first_variable = snmp_variable_dup(variable, error_label);
639 if(request->pdu->first_variable == NULL)
640 {
641 error("snmp_variable_dup() failed: %s", error_label);
642 request_free(request);
643 return -1;
644 }
645
646 request->flags = (1 << (index - 1));
647
648 request->state = 0;
649
650 /* append this request to the request */
651 /* list of the session */
652 if(last_request)
653 {
654 last_request->next_request = request;
655 }
656 else
657 {
658 session->first_request = request;
659 }
660
661 request->flags = (1 << (index - 1));
662
663
664 /* now answer! */
665 request->response = snmp_pdu_dup(session->pdu, error_label);
666 if(request->response == NULL)
667 {
668 error("snmp_pdu_dup() failed: %s", error_label);
669 return -1;
670 }
671 request->response->type = GET_RSP_MSG;
672 request->response->request_id = session->session_id + request->request_id;
673
674 value.v_integer = (Integer) times(&buffer);
675 request->response->first_variable = snmp_typed_variable_new(&sysUptime_instance, TIMETICKS,
676 &value, error_label);
677 if(request->response->first_variable == NULL)
678 {
679 error("snmp_typed_variable_new() failed: %s", error_label);
680 return -1;
681 }
682
683 session->o_flags = session->o_flags | request->flags;
684
685 request->state = REQUEST_COMPLETED;
686 session->i_flags = session->i_flags | request->flags;
687
688
689 return 0;
690 }
691
692
693 /************************************************************************/
694
session_build_request_list(Session * session,int index,SNMP_variable * variable,Subtree * subtree)695 static int session_build_request_list(Session *session, int index, SNMP_variable *variable, Subtree *subtree)
696 {
697 Request *last_request = NULL;
698 Request *request;
699 u_long request_id = 0;
700 SNMP_variable *new_variable;
701
702
703 if(mode == MODE_GROUP)
704 {
705 for(request = session->first_request; request; request = request->next_request)
706 {
707 if(request->subtree && request->subtree->agent == subtree->agent)
708 {
709 break;
710 }
711
712 request_id++;
713 last_request = request;
714 }
715 }
716 else /* MODE_SPLIT */
717 {
718 for(request = session->first_request; request; request = request->next_request)
719 {
720 request_id++;
721 last_request = request;
722 }
723 }
724
725
726 if(request == NULL)
727 {
728 request = (Request *) malloc(sizeof(Request));
729 if(request == NULL)
730 {
731 error("malloc() failed");
732 return -1;
733 }
734 request->next_request = NULL;
735 request->visited_agent_list = NULL;
736 request->pdu = NULL;
737 request->response = NULL;
738
739 request->session = session;
740 request->subtree = subtree;
741 if(request_add_visited_agent(request, subtree->agent) == -1)
742 {
743 request_free(request);
744 return -1;
745 }
746
747 request->request_id = request_id;
748
749 request->pdu = snmp_pdu_dup(session->pdu, error_label);
750 if(request->pdu == NULL)
751 {
752 error("snmp_pdu_dup() failed: %s", error_label);
753 request_free(request);
754 return -1;
755 }
756
757 request->flags = 0;
758 request->state = 0;
759
760 /* append this request to the request */
761 /* list of the session */
762 if(last_request)
763 {
764 last_request->next_request = request;
765 }
766 else
767 {
768 session->first_request = request;
769 }
770 }
771
772
773 new_variable = snmp_variable_dup(variable, error_label);
774 if(new_variable == NULL)
775 {
776 error("snmp_variable_dup() failed: %s", error_label);
777 return -1;
778 }
779
780 request->flags = request->flags | (1 << (index - 1));
781
782
783 /* append the new variable to the variable list of request->pdu */
784 if(request->pdu->first_variable)
785 {
786 SNMP_variable *current_variable;
787 SNMP_variable *last_variable;
788
789
790 for(current_variable = request->pdu->first_variable; current_variable; current_variable = current_variable->next_variable)
791 {
792 last_variable = current_variable;
793 }
794 last_variable->next_variable = new_variable;
795 }
796 else
797 {
798 request->pdu->first_variable = new_variable;
799 }
800
801
802 return 0;
803 }
804
805
806 /************************************************************************/
807
session_close(Session * session)808 void session_close(Session *session)
809 {
810 Three_Phase *tp;
811
812 if(trace_level > 1)
813 {
814 trace("## Close session %d\n\n", session->session_id);
815 }
816
817 /* remove it from the session list */
818 session_remove_from_list(session);
819
820 /* free the space allocated for the session */
821 session_free(session);
822
823
824 return;
825 }
826
827
828 /************************************************************************/
829
session_list_delete()830 void session_list_delete()
831 {
832 Session *sp = first_session;
833 Session *next;
834
835
836 while(sp)
837 {
838 next = sp->next_session;
839
840 session_free(sp);
841
842 sp = next;
843 }
844
845 first_session = NULL;
846 }
847
848
849 /************************************************************************/
850
session_remove_from_list(Session * session)851 void session_remove_from_list(Session *session)
852 {
853 Session *sp;
854 Session *osp;
855
856
857 osp = NULL;
858 for(sp = first_session; sp; sp = sp->next_session)
859 {
860 if(sp == session)
861 {
862 break;
863 }
864
865 osp = sp;
866 }
867
868 if(sp == NULL)
869 {
870 error("session_remove_from_list() : session (0x%x) not found", session);
871 return;
872 }
873
874 if(osp == NULL)
875 {
876 first_session = sp->next_session;
877 }
878 else
879 {
880 osp->next_session = sp->next_session;
881 }
882
883
884 return;
885 }
886
887
888 /************************************************************************/
889
session_free(Session * session)890 void session_free(Session *session)
891 {
892 if(session == NULL)
893 {
894 return;
895 }
896
897 snmp_pdu_free(session->pdu);
898
899 request_list_free(session->first_request);
900
901 free(session);
902
903
904 return;
905 }
906
907
908 /************************************************************************/
909
request_list_free(Request * request_list)910 void request_list_free(Request *request_list)
911 {
912 Request *next_request;
913
914
915 while(request_list)
916 {
917 next_request = request_list->next_request;
918 request_free(request_list);
919 request_list = next_request;
920 }
921 }
922
923
924 /************************************************************************/
925
926 /* This function will send a response and close the session */
927 /* It should be invoked when o_flags == i_flags */
928
session_respond(Session * session)929 static void session_respond(Session *session)
930 {
931 SNMP_variable *first_variable = NULL;
932 SNMP_variable *variable;
933 SNMP_variable *last_variable;
934 Request *request;
935 int i;
936 SNMP_pdu *response;
937 Address address;
938
939 /* Three Phase:
940 * If the session is the three_phase session, basing on the state
941 * we will have different process:
942 * state is 1: if successful, store the variable list. close the
943 * current session. The free the cur_pdu's variable
944 * list, attach the variable list from get.
945 * change cur_pdu->type=SET_REQ_MSG. create a
946 * new session(session_open) for next state. the pdu
947 * is origin_pdu.
948 * state = PHASE_2;
949 * state is PHASE_2: if successful. follows thru. else close the
950 * current session. create a new session with the
951 * cur_pdu. wait for response.
952 * In addition, send error response to appl.
953 * state = PHASE_3;
954 * state is PHASE_3:
955 * drop the response.
956 */
957
958 for(request = session->first_request; request; request = request->next_request)
959 {
960 if(request->state != REQUEST_COMPLETED)
961 {
962 error("BUG: session_respond() : session %d - request %d: state is not COMPLETED",
963 session->session_id,
964 request->request_id);
965 }
966 }
967
968
969
970 /* we will extract the variables from the request->reponse */
971 /* variable list and append them to the variable list */
972 /* pointed by first_variable */
973
974 for(i = 0; i < session->n_variables; i++)
975 {
976 for(request = session->first_request; request; request = request->next_request)
977 {
978 if(request->flags & (1 << i))
979 {
980 break;
981 }
982 }
983
984 if(request == NULL)
985 {
986 error("BUG: session_respond(): request is NULL");
987 }
988
989 if(request->response == NULL)
990 {
991 /* request timeout */
992 if(request->subtree != NULL &&
993 request->subtree->agent !=NULL){
994 /*request->subtree->agent->numOfFailRequest++*/;
995 }
996
997 /* session_respond_error() closes the session */
998 session_respond_error(session, SNMP_ERR_NOSUCHNAME, i + 1);
999 snmp_variable_list_free(first_variable);
1000 return;
1001 }
1002
1003 if(request->response->error_status != SNMP_ERR_NOERROR)
1004 {
1005 int j;
1006 int index = 0;
1007
1008
1009 /* find the index in the variables list */
1010 /* of the variable we are currently dealing with*/
1011 for(j = 0; j <= i; j++)
1012 {
1013 if(request->flags & (1<< j))
1014 {
1015 index++;
1016 }
1017 }
1018
1019 if(request->response->error_index == index)
1020 {
1021 /* session_respond_error() closes the session */
1022 session_respond_error(session, request->response->error_status, i + 1);
1023 snmp_variable_list_free(first_variable);
1024 return;
1025 }
1026
1027 /*
1028 * error index should not be zero for a non-zero
1029 * error status
1030 */
1031 if (request->response->error_index ==
1032 INVALID_ERROR_INDEX) {
1033 /* invalid error packet from sub agent */
1034 error("session_respond(): the agent %s \
1035 responded with zero error index, on error status : %d \n",
1036 request->subtree->agent->name,
1037 request->response->error_status);
1038 snmp_variable_list_free(first_variable);
1039 session_close(session);
1040 return;
1041 }
1042 /* we are no more interested in building the */
1043 /* variable list fist_variable */
1044 continue;
1045 }
1046
1047 /* remove the first variable from the request->response */
1048 variable = request->response->first_variable;
1049 if(variable == NULL)
1050 {
1051 error("session_respond(): the agent %s responded with less variables than it was asked",
1052 request->subtree->agent->name);
1053 session_close(session);
1054 return;
1055 }
1056 request->response->first_variable = variable->next_variable;
1057
1058 if(first_variable == NULL)
1059 {
1060 first_variable = variable;
1061 last_variable = variable;
1062 }
1063 else
1064 {
1065 last_variable->next_variable = variable;
1066 last_variable = variable;
1067 }
1068 } /* for */
1069
1070 /* Three Phase: save the variable list */
1071 if(three_phase.state == PHASE_1){
1072 three_phase.variable = first_variable;
1073 memcpy(&address,&(session->address),sizeof(Address));
1074 session_close(session);
1075 three_phase.cur_pdu = NULL;
1076 three_phase.state = PHASE_2;
1077 session_open(&address,three_phase.origin_pdu);
1078 return;
1079 }else if(three_phase.state == PHASE_2){
1080 /* successful*/
1081 three_phase.state = 0;
1082 snmp_variable_list_free(three_phase.variable);
1083 three_phase.variable = NULL;
1084 three_phase.origin_pdu = NULL;
1085 /* follows thru */
1086 }else if(three_phase.state == PHASE_3){
1087 /* drop the response */
1088 session_close(session);
1089 return;
1090 }
1091
1092 response = snmp_pdu_dup(session->pdu, error_label);
1093 if(response == NULL)
1094 {
1095 error("snmp_pdu_dup() failed: %s", error_label);
1096 /* return ??? */
1097 }
1098 response->type = GET_RSP_MSG;
1099 response->first_variable = first_variable;
1100
1101 if( (response->error_status != SNMP_ERR_NOERROR)
1102 && (response->error_status != SNMP_ERR_NOSUCHNAME) )
1103 {
1104 error(ERR_MSG_SNMP_ERROR,
1105 error_status_string(response->error_status), response->error_index,
1106 address_string(&(session->address)));
1107 }
1108
1109 if(snmp_pdu_send(clients_sd, &(session->address), response, error_label))
1110 {
1111 error(ERR_MSG_PDU_SEND_BACK,
1112 address_string(&(session->address)),
1113 error_label);
1114 snmp_pdu_free(response);
1115 session_close(session);
1116 return;
1117 }
1118 snmp_pdu_free(response);
1119 session_close(session);
1120
1121
1122 return;
1123 }
1124
1125
1126 /************************************************************************/
1127
1128 /*
1129 * This function sends a error response and closes the session
1130 */
1131
session_respond_error(Session * session,int status,int index)1132 static void session_respond_error(Session *session, int status, int index)
1133 {
1134 SNMP_pdu *pdu = session->pdu;
1135 Address address;
1136
1137 /* Three Phase: if errors occurs with three phase undertaking.
1138 * change the pdu to the three_phase->origin_pdu
1139 */
1140 if(three_phase.state == PHASE_1){
1141 /* clean up three_phase */
1142 session->pdu = three_phase.origin_pdu;
1143 pdu = session->pdu;
1144 snmp_pdu_free(three_phase.cur_pdu);
1145 three_phase.cur_pdu = NULL;
1146 three_phase.origin_pdu = NULL;
1147 three_phase.state = 0;
1148 }else if(three_phase.state == PHASE_2){
1149 /* set fail, the session->pdu pts to origin_pdu */
1150 three_phase.state = PHASE_3;
1151 /* rollback */
1152 memcpy(&address,&(session->address),sizeof(Address));
1153 three_phase.cur_pdu = snmp_pdu_dup(three_phase.origin_pdu,
1154 error_label);
1155 three_phase.origin_pdu = NULL;
1156 if(three_phase.cur_pdu != NULL){
1157 three_phase.cur_pdu->first_variable =
1158 three_phase.variable;
1159 session_open(&address,three_phase.cur_pdu);
1160 three_phase.cur_pdu = NULL;
1161 }
1162 }else if(three_phase.state == PHASE_3){
1163 /* drop the packet */
1164 three_phase.state = 0;
1165 session_close(session);
1166 return;
1167 }
1168
1169 pdu->type = GET_RSP_MSG;
1170 pdu->error_status = status;
1171 pdu->error_index = index;
1172
1173 if (pdu->error_status == SNMP_ERR_AUTHORIZATIONERROR) {
1174 session_close(session);
1175 return;
1176 }
1177
1178 if( (pdu->error_status != SNMP_ERR_NOERROR)
1179 && (pdu->error_status != SNMP_ERR_NOSUCHNAME) )
1180 {
1181 error(ERR_MSG_SNMP_ERROR,
1182 error_status_string(pdu->error_status), pdu->error_index,
1183 address_string(&(session->address)));
1184 }
1185
1186 if(snmp_pdu_send(clients_sd, &(session->address), pdu, error_label))
1187 {
1188 error(ERR_MSG_PDU_SEND_BACK,
1189 address_string(&(session->address)),
1190 error_label);
1191 session_close(session);
1192 return;
1193 }
1194 session_close(session);
1195
1196 return;
1197 }
1198
1199
1200 /************************************************************************/
1201
session_find(Address * address,u_long request_id)1202 static Session *session_find(Address *address, u_long request_id)
1203 {
1204 Session *session;
1205
1206
1207 for(session = first_session; session; session = session->next_session)
1208 {
1209 if( (session->pdu->request_id == request_id)
1210 && (session->address.sin_port == address->sin_port)
1211 && (session->address.sin_addr.s_addr == address->sin_addr.s_addr) )
1212 {
1213 return session;
1214 }
1215 }
1216
1217
1218 return NULL;
1219 }
1220
1221 /* (5-14-96) */
session_send_loopback_request(Request * request,int doRespondHere)1222 static int session_send_loopback_request(Request *request,int doRespondHere)
1223 {
1224 Session *session = request->session;
1225 SNMP_pdu *pdu;
1226 Subtree *subtree = request->subtree;
1227 Agent *agent;
1228 struct timeval tv;
1229 SNMP_variable *new_variable, *variable;
1230
1231 gettimeofday(&tv, (struct timezone *) 0);
1232
1233 if(subtree == NULL || request->pdu == NULL)
1234 {
1235 error("BUG: session_send_loopback_request(): subtree is NULL");
1236 return -1;
1237 }
1238 agent = subtree->agent;
1239
1240
1241 request->time = tv;
1242 tv.tv_usec = tv.tv_usec + agent->timeout;
1243 tv.tv_sec = tv.tv_sec + tv.tv_usec / 1000000L;
1244 tv.tv_usec = tv.tv_usec % 1000000L;
1245 request->expire = tv;
1246
1247 session->o_flags = session->o_flags | request->flags;
1248 request->state = REQUEST_STARTED;
1249 /* duplicate the pdu */
1250 pdu = snmp_pdu_dup(request->pdu, error_label);
1251 pdu->request_id = session->session_id + request->request_id;
1252
1253 for(variable = request->pdu->first_variable; variable;
1254 variable = variable->next_variable)
1255 {
1256 new_variable = snmp_variable_dup(variable, error_label);
1257 if(pdu->first_variable)
1258 {
1259 SNMP_variable *current_variable;
1260 SNMP_variable *last_variable;
1261
1262 for(current_variable = pdu->first_variable;
1263 current_variable;
1264 current_variable = current_variable->next_variable)
1265 {
1266 last_variable = current_variable;
1267 }
1268 last_variable->next_variable = new_variable;
1269 }
1270 else
1271 {
1272 pdu->first_variable = new_variable;
1273 }
1274 }
1275
1276 if (agent_process(&(session->address), pdu) == -1) {
1277 if (trace_level > 1) {
1278 trace("local pdu process error \n");
1279 }
1280 snmp_pdu_free(pdu);
1281 return (-1);
1282 }
1283 /* pdu stores the response */
1284 session_process_response(pdu,doRespondHere);
1285
1286 return 1;
1287 }
1288
1289 /************************************************************************/
1290
session_send_request(Request * request)1291 static int session_send_request(Request *request)
1292 {
1293 Session *session = request->session;
1294 SNMP_pdu *pdu = request->pdu;
1295 Subtree *subtree = request->subtree;
1296 Agent *agent;
1297 struct timeval tv;
1298
1299
1300 pdu->request_id = session->session_id + request->request_id;
1301 gettimeofday(&tv, (struct timezone *) 0);
1302
1303 if(subtree == NULL)
1304 {
1305 error("BUG: session_send_request(): subtree is NULL");
1306 return -1;
1307 }
1308 agent = subtree->agent;
1309
1310 if(snmp_pdu_send(agents_sd, &(agent->address), pdu, error_label))
1311 {
1312 error(ERR_MSG_PDU_SEND_TO,
1313 address_string(&(agent->address)),
1314 error_label);
1315 return -1;
1316 }
1317
1318 request->time = tv;
1319 tv.tv_usec = tv.tv_usec + agent->timeout;
1320 tv.tv_sec = tv.tv_sec + tv.tv_usec / 1000000L;
1321 tv.tv_usec = tv.tv_usec % 1000000L;
1322 request->expire = tv;
1323
1324 session->o_flags = session->o_flags | request->flags;
1325 request->state = REQUEST_STARTED;
1326
1327
1328 return 0;
1329 }
1330
1331
1332 /************************************************************************/
1333
session_move_request(Request * request,Subtree * subtree)1334 static Request *session_move_request(Request *request, Subtree *subtree)
1335 {
1336 Session *session = request->session;
1337
1338
1339 if(trace_level > 0)
1340 {
1341 trace("!! session %d - request %d: trying another subtree %s supported by %s\n\n",
1342 session->session_id,
1343 request->request_id,
1344 SSAOidString(&(subtree->name)),
1345 subtree->agent->name);
1346 }
1347
1348 request->subtree = subtree;
1349
1350 if (subtree->agent->first_manager != NULL)
1351 set_first_manager(subtree->agent->first_manager);
1352
1353 if(request_add_visited_agent(request, subtree->agent) == -1)
1354 {
1355 error("request_add_visited_agent() failed");
1356 return NULL;
1357 }
1358
1359 if (local_request(request)) {
1360 if (session_send_loopback_request(request, TRUE) == -1) {
1361 if (trace_level > 1) {
1362 trace("session_send_loopback_request() \
1363 failed\n");
1364 }
1365 return (NULL);
1366 }
1367 } else if(session_send_request(request) == -1) {
1368 error("session_send_request() failed");
1369 return NULL;
1370 }
1371
1372 return request;
1373 }
1374
1375
1376 /************************************************************************/
1377
request_free(Request * request)1378 void request_free(Request *request)
1379 {
1380 if(request == NULL)
1381 {
1382 return;
1383 }
1384
1385 agent_list_free(request->visited_agent_list);
1386
1387 snmp_pdu_free(request->pdu);
1388
1389 snmp_pdu_free(request->response);
1390
1391 free(request);
1392
1393 return;
1394 }
1395
trap_processing()1396 void trap_processing()
1397 {
1398 Address address;
1399 SNMP_pdu *trap_request;
1400 struct tms buffer;
1401 u_long time_stamp;
1402
1403 trap_request = snmp_pdu_receive(trap_sd, &address, error_label);
1404 if(trap_request == NULL)
1405 {
1406 error(ERR_MSG_PDU_RECEIVED,
1407 address_string(&address),
1408 error_label);
1409 return;
1410 }
1411
1412
1413 if(trap_request->type != TRP_REQ_MSG)
1414 {
1415 error("bad PDU type (0x%x) received from %s",
1416 trap_request->type,
1417 address_string(&address));
1418 snmp_pdu_free(trap_request);
1419 return;
1420 }
1421
1422 /* filter the trap_request */
1423 /* currently, base on the trap-community names to decide which
1424 are the list of target hosts */
1425 time_stamp = (Integer) times(&buffer);
1426
1427 /* propagate those traps registered by managers */
1428 trap_filter_action(&(trap_request->enterprise),
1429 trap_request->generic,trap_request->specific,time_stamp,
1430 trap_request->first_variable);
1431
1432 snmp_pdu_free(trap_request);
1433 return;
1434 }
1435
1436
forward_subtree_match(Subtree * subtree,Oid * name)1437 static Subtree *forward_subtree_match(Subtree *subtree, Oid *name)
1438 {
1439 Subtree *sp;
1440 Subtree *last=NULL;
1441 Subtree *first_valid_subtree;
1442
1443
1444 if(name == NULL || subtree == NULL || first_subtree == NULL)
1445 {
1446 return NULL;
1447 }
1448
1449 for(sp = subtree->next_subtree; sp; sp = sp->next_subtree)
1450 {
1451 /* subtree is invalid skip (vsb)*/
1452 if(subtree_is_valid(sp)==FALSE) continue;
1453
1454 if(SSAOidCmp(name, &(sp->name)) >= 0 &&
1455 sp->agent !=0 && subtree->agent !=0 &&
1456 sp->agent != subtree->agent)
1457 {
1458 return sp;
1459 }
1460
1461 }
1462
1463
1464 return last;
1465 }
1466
1467 /************************************************************************/
1468 /* (5-14-96) partition into two functions */
1469 /* pdu_read is not null, this routine is used for local response
1470 there is a catch the session_respond is skipped, because, it will
1471 be processed later in the session_open call */
1472
session_process_response(SNMP_pdu * pdu_read,int doRespondHere)1473 static void session_process_response(SNMP_pdu *pdu_read,int doRespondHere)
1474 {
1475 Address address;
1476 SNMP_pdu *response;
1477 Session *session;
1478 SNMP_pdu *pdu;
1479 Subtree *subtree;
1480 Subtree *sub;
1481 Request *request;
1482
1483
1484 if(pdu_read == NULL)
1485 response = snmp_pdu_receive(agents_sd, &address, error_label);
1486 else
1487 response = pdu_read;
1488
1489 if(response == NULL)
1490 {
1491 error(ERR_MSG_PDU_RECEIVED,
1492 address_string(&address),
1493 error_label);
1494 return;
1495 }
1496
1497
1498 if(response->type != GET_RSP_MSG)
1499 {
1500 error("bad PDU type (0x%x) received from %s",
1501 response->type,
1502 address_string(&address));
1503 snmp_pdu_free(response);
1504 return;
1505 }
1506
1507
1508 for(session = first_session; session; session = session->next_session)
1509 {
1510 if((response->request_id & SESSION_ID_MASK) == session->session_id)
1511 {
1512 break;
1513 }
1514 }
1515 if(session == NULL)
1516 {
1517 Agent *agent;
1518
1519
1520 agent = agent_find(&address);
1521 /*
1522 error(ERR_MSG_UNKNOWN_FRAGMENT,
1523 agent? agent->name: "???",
1524 address_string(&address));
1525 */
1526 snmp_pdu_free(response);
1527 return;
1528 }
1529
1530
1531 for(request = session->first_request; request; request = request->next_request)
1532 {
1533 if((response->request_id & REQUEST_ID_MASK) == request->request_id)
1534 {
1535 break;
1536 }
1537 }
1538 if(request == NULL)
1539 {
1540 error("request not found for the session %d for a PDU received from %s",
1541 session->session_id,
1542 address_string(&address));
1543 snmp_pdu_free(response);
1544 return;
1545 }
1546 if(request->state == REQUEST_COMPLETED)
1547 {
1548 error("a PDU has been received from %s for session %d - request %d whereas the request is already completed",
1549 address_string(&address),
1550 session->session_id,
1551 request->request_id);
1552 snmp_pdu_free(response);
1553 return;
1554 }
1555 if(request->response)
1556 {
1557 error("BUG: session_read(): response is not NULL");
1558 }
1559
1560
1561 pdu = session->pdu;
1562 subtree = request->subtree;
1563 if(subtree == NULL)
1564 {
1565 error("BUG: session_read(): subtree is NULL");
1566 snmp_pdu_free(response);
1567 return;
1568 }
1569
1570 if (subtree->agent->numOfFailRequest > 0)
1571 trace("Agent %s is now OK", subtree->agent->name) ;
1572 subtree->agent->numOfFailRequest=0;
1573
1574 if(pdu->type == GETNEXT_REQ_MSG)
1575 {
1576 if( (response->error_status == SNMP_ERR_NOSUCHNAME)
1577 && (response->error_index == 1)
1578 && (response->first_variable != NULL) )
1579 {
1580 if(trace_level > 0)
1581 {
1582 trace("!! session %d - request %d: the Get-Next returned No Such Name\n\n",
1583 session->session_id,
1584 request->request_id);
1585 }
1586
1587 /* Check if another agent supports some */
1588 /* variables greater than the first one */
1589 /* of the PDU */
1590
1591 for(sub = subtree->next_subtree; sub; sub = sub->next_subtree)
1592 {
1593 /* skip invalid subtree (vsb) */
1594 if(subtree_is_valid(sub)==FALSE) continue;
1595 if(!is_in_agent_list(request->visited_agent_list, sub->agent))
1596 {
1597 session_move_request(request, sub);
1598 snmp_pdu_free(response);
1599 return;
1600 }
1601 }
1602 }
1603 else
1604 if( (response->first_variable != NULL)
1605 /*&& ((sub = forward_subtree_match(subtree, &(response->first_variable->name))) != NULL)*/
1606
1607 && ((sub = subtree_match(GET_REQ_MSG, &(response->first_variable->name))) != NULL)
1608
1609 && (sub != subtree)
1610 && (SSAOidCmp(&(subtree->name),&(sub->name)) < 0)
1611 /*
1612 &&(sub->agent!=NULL && subtree->agent!=NULL && sub->agent!=subtree->agent)
1613 */
1614 )
1615 {
1616 /* we are in another subtree */
1617
1618 Subtree *s;
1619
1620
1621 if(trace_level > 0)
1622 {
1623 trace("!! session %d - request %d: the Get-Next issued in the subtree %s supported by %s",
1624 session->session_id,
1625 request->request_id,
1626 SSAOidString(&(subtree->name)),
1627 subtree->agent->name);
1628 trace(" returned a response in the subtree %s supported by %s\n\n",
1629 SSAOidString(&(sub->name)),
1630 sub->agent->name);
1631 }
1632
1633
1634 /* Is there a subtree supported by another agent between */
1635 /* subtree and sub ? */
1636
1637 /* 12-19-96 snmpgetnext
1638 for(s = subtree->next_subtree; s; s = s->next_subtree)
1639 {
1640 if(subtree_is_valid(s)==FALSE) continue;
1641 if(s == sub)
1642 {
1643 break;
1644 }
1645 */
1646 s = sub;
1647
1648 if(subtree->agent != s->agent)
1649 {
1650 /* There is a subtree supported by another agent */
1651 /* between subtree and sub */
1652
1653 session_move_request(request, s);
1654 snmp_pdu_free(response);
1655 return;
1656 }
1657 /*
1658 }
1659 */
1660 }
1661 }
1662
1663
1664 /* we consider response a valid response for the request request */
1665 if(request->response)
1666 {
1667 error("BUG: session_read(): request->response is not NULL");
1668 }
1669 request->response = response;
1670 request->state = REQUEST_COMPLETED;
1671 session->i_flags = session->i_flags | request->flags;
1672
1673
1674 if(doRespondHere && session->i_flags == session->o_flags)
1675 {
1676 session_respond(session);
1677 }
1678
1679 return;
1680 }
1681
session_read()1682 void session_read()
1683 {
1684 session_process_response(NULL,TRUE);
1685
1686 }
1687
1688 /************************************************************************/
1689
session_select_info(struct timeval * timeout)1690 void session_select_info(struct timeval *timeout)
1691 {
1692 Session *sp;
1693 Request *rp;
1694 struct timeval now, earliest;
1695
1696
1697 if(first_session == NULL)
1698 {
1699 return;
1700 }
1701
1702 /* For each request in each session, if it is the */
1703 /* earliest timeout to expire, mark it as lowest. */
1704
1705 timerclear(&earliest);
1706 for(sp = first_session; sp; sp = sp->next_session)
1707 {
1708 for(rp = sp->first_request; rp; rp = rp->next_request)
1709 {
1710 if(rp->state == REQUEST_COMPLETED)
1711 {
1712 continue;
1713 }
1714
1715 if(!timerisset(&earliest) || timercmp(&rp->expire, &earliest, <))
1716 {
1717 earliest = rp->expire;
1718 }
1719 }
1720 }
1721
1722
1723 /* Now find out how much time until the earliest timeout. This */
1724 /* transforms earliest from an absolute time into a delta time, the */
1725 /* time left until the select should timeout. */
1726
1727 gettimeofday(&now, (struct timezone *)0);
1728 earliest.tv_sec--; /* adjust time to make arithmetic easier */
1729 earliest.tv_usec += 1000000L;
1730 earliest.tv_sec -= now.tv_sec;
1731 earliest.tv_usec -= now.tv_usec;
1732 while (earliest.tv_usec >= 1000000L)
1733 {
1734 earliest.tv_usec -= 1000000L;
1735 earliest.tv_sec += 1;
1736 }
1737 if(earliest.tv_sec < 0)
1738 {
1739 earliest.tv_sec = 0;
1740 earliest.tv_usec = 0;
1741 }
1742
1743 /* if our delta time is less, reset timeout */
1744 if(timercmp(&earliest, timeout, <))
1745 {
1746 *timeout = earliest;
1747 }
1748
1749
1750 return;
1751 }
1752
1753
1754 /************************************************************************/
1755
session_timeout()1756 void session_timeout()
1757 {
1758 struct timeval now;
1759
1760
1761 gettimeofday(&now, (struct timezone *)0);
1762
1763 while(session_timeout_loop(&now) == 1);
1764 destroy_hanging_agent(); /* destroy one agent at a time */
1765
1766 }
1767
1768
1769 /************************************************************************/
1770
1771 int max_requests = 1000;
1772
session_timeout_loop(struct timeval * now)1773 static int session_timeout_loop(struct timeval *now)
1774 {
1775 Session *sp;
1776 Request *rp;
1777 int nrequests = 0;
1778
1779
1780 /* For each session outstanding, check to see if the timeout has expired. */
1781
1782 for(sp = first_session; sp; sp = sp->next_session)
1783 {
1784
1785
1786 for(rp = sp->first_request; rp; rp = rp->next_request)
1787 {
1788 nrequests ++;
1789
1790 if(rp->state == REQUEST_COMPLETED)
1791 {
1792 continue;
1793 }
1794
1795 if(timercmp(&rp->expire, now, <) || nrequests > max_requests)
1796 {
1797 Subtree *subtree = rp->subtree;
1798
1799
1800 if(subtree == NULL)
1801 {
1802 error("BUG: session_timeout_loop(): subtree is NULL");
1803 /* session_respond_error() closes the session */
1804 session_respond_error(sp, SNMP_ERR_GENERR, 1);
1805 return 1;
1806 }
1807
1808 if (subtree->agent->numOfFailRequest == 0 )
1809 trace(ERR_MSG_AGENT_NOT_RESPONDING, subtree->agent->name);
1810 subtree->agent->numOfFailRequest++;
1811
1812 /* this timer has expired */
1813 if(trace_level > 0)
1814 {
1815 trace("!! session %d - request %d: timeout\n\n",
1816 sp->session_id,
1817 rp->request_id);
1818 }
1819
1820 if(sp->pdu->type == GETNEXT_REQ_MSG)
1821 {
1822 /* Check if there is a subtree supported */
1823 /* by another agent after subtree */
1824
1825 Subtree *sub;
1826
1827
1828 for(sub = subtree->next_subtree; sub; sub = sub->next_subtree)
1829 {
1830 if(!is_in_agent_list(rp->visited_agent_list, sub->agent))
1831 {
1832 session_move_request(rp, sub);
1833 return 1;
1834 }
1835 }
1836 }
1837
1838
1839 /* No Such Name */
1840
1841 sp->i_flags = sp->i_flags | rp->flags;
1842 rp->state = REQUEST_COMPLETED;
1843
1844 if(sp->i_flags == sp->o_flags)
1845 {
1846 session_respond(sp);
1847 return 1;
1848 }
1849 }
1850 }
1851 }
1852
1853 return 0;
1854 }
1855
1856
1857 /************************************************************************/
1858
request_add_visited_agent(Request * request,Agent * agent)1859 static int request_add_visited_agent(Request *request, Agent *agent)
1860 {
1861 Agent_List *new;
1862
1863
1864 if(request == NULL)
1865 {
1866 error("BUG: request_add_visited_agent(): request is NULL");
1867 return -1;
1868 }
1869
1870 if(agent == NULL)
1871 {
1872 error("BUG: request_add_visited_agent(): agent is NULL");
1873 return -1;
1874 }
1875
1876 new = (Agent_List *) malloc(sizeof(Agent_List));
1877 if(new == NULL)
1878 {
1879 error("malloc() failed");
1880 return -1;
1881 }
1882 new->next = request->visited_agent_list;
1883 request->visited_agent_list = new;
1884 new->agent = agent;
1885
1886
1887 return 0;
1888 }
1889
1890
1891 /************************************************************************/
1892
agent_list_free(Agent_List * alp)1893 static void agent_list_free(Agent_List *alp)
1894 {
1895 Agent_List *next;
1896
1897
1898 while(alp)
1899 {
1900 next = alp->next;
1901 free(alp);
1902 alp = next;
1903 }
1904 }
1905
1906
1907 /************************************************************************/
1908
is_in_agent_list(Agent_List * agent_list,Agent * agent)1909 static int is_in_agent_list(Agent_List *agent_list, Agent *agent)
1910 {
1911 Agent_List *alp;
1912
1913
1914 for(alp = agent_list; alp; alp = alp->next)
1915 {
1916 if(alp->agent == agent)
1917 {
1918 return True;
1919 }
1920 }
1921
1922 return False;
1923 }
1924
no_outstanding_session_for_the_agent(Agent * ap)1925 int no_outstanding_session_for_the_agent(Agent* ap)
1926 {
1927 Session *sp;
1928 Request *rp;
1929
1930 for(sp = first_session; sp; sp = sp->next_session){
1931 for(rp = sp->first_request; rp; rp = rp->next_request){
1932 if(rp->subtree && rp->subtree->agent==ap)
1933 return 0;
1934 }
1935 }
1936
1937 return 1;
1938 }
1939
1940
community_check(Address * address,Agent * agent,int pdu_type,char * community)1941 static int community_check (Address * address, Agent * agent, int pdu_type, char * community)
1942 {
1943 Manager *mgr;
1944 int ret;
1945
1946
1947 if (agent == NULL) {
1948 return TRUE;
1949 }
1950 if (agent->first_manager == NULL) {
1951 return TRUE;
1952 }
1953 /* check host */
1954
1955 mgr = is_valid_manager(address, &mgr);
1956
1957 if(mgr == NULL)
1958 {
1959 error("community_check(): unauthorized manager (%s)",
1960 ip_address_string(&(address->sin_addr)));
1961 return FALSE;
1962 }
1963
1964 if (is_valid_community(community, pdu_type, mgr))
1965 return TRUE;
1966 else {
1967 error("community_check() : bad community from %s",
1968 ip_address_string(&(address->sin_addr)));
1969 return FALSE;
1970 }
1971 }
1972