xref: /onnv-gate/usr/src/cmd/agents/snmp/snmprelayd/session.c (revision 3820:8adf9090a487)
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