diff usr/src/cmd/agents/snmp/agent/agent.c @ 0:c9caec207d52 b86

Initial porting based on b86
author Koji Uno <koji.uno@sun.com>
date Tue, 02 Jun 2009 18:56:50 +0900
parents
children 1a15d5aaf794
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/agents/snmp/agent/agent.c	Tue Jun 02 18:56:50 2009 +0900
@@ -0,0 +1,1446 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the 
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"@(#)agent.c	1.25	05/06/12 SMI"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <strings.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+
+#include "impl.h"
+#include "error.h"
+#include "trace.h"
+#include "snmp.h"
+#include "pdu.h"
+#include "request.h"
+#include "trap.h"
+
+#include "node.h"
+#include "access.h"
+
+static int ssa_mem_free = 1; /* on */
+
+#if defined(_LP64)
+#define	COLUMN_OFFSET(x)	(x) * 2
+#else
+#define	COLUMN_OFFSET(x)	(x)
+#endif
+
+#define OCTET_STRING 2
+
+/***** LOCAL VARIABLES *****/
+
+/*
+ *	The idea of these cache variables is to avoid to call
+ *	the same *(entry->get) function for variables contained
+ *	in a single SNMP PDU.
+ *
+ *	There is still a problem in this mechanism.
+ *	When you query a whole table row by row and when
+ *	you reached the end of the table, the *(entry->get)
+ *	will be called several times:
+ *	- for the first column, *(entry->get) will be called
+ *	  once to find that the end of the table is reached
+ *	  (==> the knowledge that we reached the last row is cached)
+ *	  and then *(entry->get) will be called on the first row of
+ *	  the same table (==> the first row is cached).
+ *	- Same behaviour for all the remaining columns
+ *
+ *	Possible solutions:
+ *	- two caches but this implies the copy of the cached
+ *	  structures + all theis pointers
+ *	- only one cache + caching the knowledge that we reached the last
+ *	  row ???
+ *
+ */
+
+static Entry *cache_input_entry = NULL;
+static Subid cache_input_index[MAX_OID_LEN];
+static void *cache_output_pointer = NULL;
+static int cache_output_snmp_error = -1;
+static Subid cache_output_index[MAX_OID_LEN];
+
+
+/***** LOCAL FUNCTIONS *****/
+
+static int agent_get_next(SNMP_pdu *pdu, char *error_label);
+static int agent_get_next_loop(SNMP_variable *variable, Node *node, Oid *suffix);
+static int agent_get(SNMP_pdu *pdu, char *error_label);
+static int agent_set(int pass, SNMP_pdu *pdu, char *error_label);
+
+
+/****************************************************************/
+
+/* returns:						*/
+/*	0 in case of success (the pdu should be sent	*/
+/*	  back to its originator even if an SNMP error	*/
+/*	  was detected)					*/
+/*	-1 in case of failure (no pdu should be sent	*/
+/*	  back)						*/
+
+int agent_process(Address *address, SNMP_pdu *pdu)
+{
+	int snmpEnableAuthTraps = FALSE;
+	Manager *mngr;
+
+
+	if(pdu == NULL)
+	{
+		error("BUG: agent_process(): pdu is NULL");
+		return -1;
+	}
+
+
+	/* check host */
+	if(is_valid_manager(address,&mngr) == NULL)
+	{
+		error("agent_process(): unauthorized manager (%s)",
+			ip_address_string(&(address->sin_addr)));
+
+		snmpEnableAuthTraps = request_snmpEnableAuthTraps(error_label);
+		switch(snmpEnableAuthTraps)
+		{
+			case TRUE:
+				if(trap_send_to_all_destinators(NULL,
+					SNMP_TRAP_AUTHFAIL, 0,
+					NULL, error_label))
+				{
+					error("trap_send_to_all_destinators() failed: %s\n",
+						error_label);
+				}
+				break;
+
+			case FALSE:
+			default:
+				break;
+		}
+
+		return -1;
+	}
+
+	/* if mngr == NULL -> allow requests from any hosts */
+
+	/* check pdu type */
+	if(pdu->type != GETNEXT_REQ_MSG
+		&& (pdu->type != GET_REQ_MSG)
+		&& (pdu->type != SET_REQ_MSG) )
+	{
+		error("agent_process(): bad PDU type (0x%x)", pdu->type);
+		return -1;
+	}
+
+
+	/* check host */
+	if(!is_valid_community(pdu->community, pdu->type,mngr))
+	{
+		/*
+		 * Earlier, the community name is displayed here
+		 * in this error message. But since these error
+		 * messages are readable by all users, it is not advisible
+		 * to display community names in the error messages.
+		 */
+		error("agent_process() : bad community from %s",
+			ip_address_string(&(address->sin_addr)));
+
+		snmpEnableAuthTraps = request_snmpEnableAuthTraps(error_label);
+		switch(snmpEnableAuthTraps)
+		{
+			case TRUE:
+				if(trap_send_to_all_destinators(NULL,
+					SNMP_TRAP_AUTHFAIL, 0,
+					NULL, error_label))
+				{
+					error("trap_send_to_all_destinators() failed: %s\n",
+						error_label);
+				}
+				break;
+
+			case FALSE:
+			default:
+				break;
+		}
+
+		return -1;
+	}
+
+
+	if(cache_input_entry != NULL && cache_output_pointer != NULL)
+		if(ssa_mem_free != 0 && cache_input_entry->dealloc != NULL){
+				(*(cache_input_entry->dealloc))(cache_output_pointer);
+				cache_output_pointer = NULL;
+		}
+
+	cache_input_entry = NULL;
+
+	switch(pdu->type)
+	{
+		case GETNEXT_REQ_MSG:
+			if(agent_get_next(pdu, error_label))
+			{
+				error("agent_get_next() failed: %s", error_label);
+				return -1;
+			}
+			return 0;
+
+		case GET_REQ_MSG:
+			if(agent_get(pdu, error_label))
+			{
+				error("agent_get() failed: %s", error_label);
+				return -1;
+			}
+			return 0;
+
+		case SET_REQ_MSG:
+			switch(agent_set(FIRST_PASS, pdu, error_label))
+			{
+				case 0:
+					switch(agent_set(SECOND_PASS, pdu, error_label))
+					{
+						case 0:
+						case 1:
+							return 0;
+
+						case -1:
+							error("agent_set(SECOND_PASS) failed: %s",
+								error_label);
+							return -1;
+					}
+
+					/* never reached */
+					break;
+
+				case 1:
+					return 0;
+
+				case -1:
+					error("agent_set(FIRST_PASS) failed: %s",
+						error_label);
+					return -1;
+			}
+	}
+
+	/* never reached */
+	return -1;
+}
+
+
+/****************************************************************/
+
+/* returns:						*/
+/*	0 in case of success (the pdu should be sent	*/
+/*	  back to its originator even if an SNMP error	*/
+/*	  was detected)					*/
+/*	-1 in case of failure (no pdu should be sent	*/
+/*	  back)						*/
+
+static int agent_get_next(SNMP_pdu *pdu, char *error_label)
+{
+	SNMP_variable *variable;
+	Node *node;
+	Oid suffix;
+	int index = 1;
+	int snmp_error;
+
+
+	error_label[0] = '\0';
+
+	pdu->type = GET_RSP_MSG;
+
+	for(variable = pdu->first_variable; variable; variable = variable->next_variable)
+	{
+		node = node_find(NEXT_ENTRY, &(variable->name), &suffix);
+		if(node == NULL)
+		{
+			pdu->error_status = SNMP_ERR_NOSUCHNAME;
+			pdu->error_index = index;
+			return 0;
+		}
+		/* we should not forget to free suffix.subids */
+
+		if(trace_level > 0)
+		{
+			trace("!! getnext(): processing the variable %s\n\n",
+				node->label);
+		}
+
+		if(variable->type != NULLOBJ)
+		{
+			error("ASN.1 type (0x%x) is not NULL for node %s",
+				variable->type, node->label);
+			variable->type = NULLOBJ;
+		}
+
+		if(variable->val.string)
+		{
+			error("val is not NULL for node %s",
+				node->label);
+			free(variable->val.string);
+			variable->val.string = NULL;
+		}
+
+		if(variable->val_len)
+		{
+			error("val_len is not 0 for node %s",
+				node->label);
+			variable->val_len = 0;
+		}
+
+		snmp_error = agent_get_next_loop(variable, node, &suffix);
+
+		if(snmp_error != SNMP_ERR_NOERROR)
+		{
+			pdu->error_status = snmp_error;
+			pdu->error_index = index;
+			return 0;
+		}
+
+		index++;
+	}
+
+	return 0;
+}
+
+
+/* This function will free suffix->subids	*/
+/* It returns a positive snmp_error code.	*/
+static int
+agent_get_next_loop(SNMP_variable *variable, Node *node, Oid *suffix)
+{
+	Object *object;
+	Column *column;
+	Entry *entry;
+	Integer integer = 0;
+	Integer *integer_ptr;
+	String string = { NULL, 0 };
+	String *string_ptr;
+	Oid oid = { NULL, 0 };
+	Oid *oid_ptr;
+	char *pointer;
+	int snmp_error;
+        Subid index[MAX_OID_LEN];
+        Index *pIndex;
+        int index_len;
+
+	/* create index struct */
+	IndexType index_obj;
+	int index_buffer[256];
+
+        int was_cached ;
+        int i;
+	int get_entry;
+
+	bzero(index, sizeof(Subid) * MAX_OID_LEN);
+	bzero(&index_obj, sizeof(index_obj));
+	bzero(index_buffer, sizeof(index_buffer));
+        index_obj.value = index_buffer;
+
+	if(node == NULL)
+	{
+		if(trace_level > 0)
+		{
+			trace("!! End of MIB\n\n");
+		}
+
+		SSAOidZero(suffix);
+		return SNMP_ERR_NOSUCHNAME;
+	}
+
+	if(trace_level > 0)
+		trace("!! Trying %s with suffix %s\n\n",
+			node->label, SSAOidString(suffix));
+
+	switch(node->type)
+	{
+		case OBJECT:
+			object = node->data.object;
+
+			switch(suffix->len)
+			{
+				case 0:
+					if( !(object->access & READ_FLAG) )
+						return SNMP_ERR_NOSUCHNAME;
+						
+					switch(object->asn1_type)
+					{
+						case INTEGER:
+						case COUNTER:
+						case GAUGE:
+						case TIMETICKS:
+							snmp_error = (*(object->get))(&integer);
+							break;
+
+						case OBJID:
+							snmp_error = (*(object->get))(&oid);
+							if(snmp_error != SNMP_ERR_NOERROR  &&
+							   ssa_mem_free != 0){
+								if(object->dealloc != NULL)
+								  (*(object->dealloc))(&oid);
+							}
+						break;
+
+						case STRING:
+						case IPADDRESS:
+						case OPAQUE:
+							snmp_error = (*(object->get))(&string);
+							if(snmp_error != SNMP_ERR_NOERROR  &&
+							   ssa_mem_free != 0){
+								if(object->dealloc != NULL)
+								  (*(object->dealloc))(&string);
+							}
+							break;
+					}
+
+					if(snmp_error != SNMP_ERR_NOERROR)
+					{
+						if(snmp_error < 0)
+						{
+							error("the get() method of %s returned %d",
+								node->label,
+								snmp_error);
+							snmp_error = SNMP_ERR_GENERR;
+						}
+						return snmp_error;
+					}
+
+					/* variable->name */
+					SSAOidZero(&(variable->name));
+					variable->name.subids = (Subid *) malloc((object->name.len + 1) *
+							(int32_t)sizeof(Subid));
+					(void)memcpy(variable->name.subids, object->name.subids,
+						object->name.len * (int32_t)sizeof(Subid));
+					variable->name.subids[object->name.len] = 0;
+					variable->name.len = object->name.len + 1;
+
+					/* variable->type */
+					variable->type = object->asn1_type;
+
+					/* variable->val, variable->val_len */
+					switch(object->asn1_type)
+					{
+						case INTEGER:
+						case COUNTER:
+						case GAUGE:
+						case TIMETICKS:
+							variable->val.integer = (Integer *) malloc(sizeof(Integer));
+							*(variable->val.integer) = integer;
+							variable->val_len = sizeof(Integer);
+							break;
+
+						case OBJID:
+							variable->val.objid = (Subid *) malloc(oid.len *
+								(int32_t)sizeof(Subid));
+							(void)memcpy(variable->val.objid, oid.subids, oid.len *
+								(int32_t)sizeof(Subid));
+							variable->val_len = oid.len *
+								(int32_t)sizeof(Subid);
+							if(ssa_mem_free !=0 && object->dealloc != NULL)
+								  (*(object->dealloc))(&oid);
+							break;
+
+						case STRING:
+						case IPADDRESS:
+						case OPAQUE:
+							variable->val.string = (u_char *) malloc(string.len);
+							(void)memcpy(variable->val.string, string.chars, string.len);
+							variable->val_len = string.len;
+							if(ssa_mem_free != 0 && object->dealloc != NULL)
+								  (*(object->dealloc))(&string);
+							break;
+
+					}
+
+					return SNMP_ERR_NOERROR;
+
+
+				case 1:
+					if(suffix->subids[0] != 0)
+					{
+						SSAOidZero(suffix);
+						return SNMP_ERR_NOSUCHNAME;
+					}
+					SSAOidZero(suffix);
+
+					return agent_get_next_loop(variable, node->next, suffix);
+
+				default:
+					SSAOidZero(suffix);
+					return SNMP_ERR_NOSUCHNAME;
+			}
+
+
+		case COLUMN:
+			column = node->data.column;
+			entry = column->entry;
+                        pIndex = entry->first_index;
+
+			if( !(column->access & READ_FLAG) )
+			{
+				SSAOidZero(suffix);
+				return SNMP_ERR_NOSUCHNAME;
+			}
+
+			if (entry->n_indexs < 0 || entry->n_indexs > MAX_OID_LEN) { 
+					SSAOidZero(suffix);
+					return SNMP_ERR_NOSUCHNAME;
+			}
+
+                       index_len = 0;
+                       for (pIndex=entry->first_index; pIndex; pIndex=pIndex->next_index)
+                       {
+			   if (pIndex->index_type == OCTET_STRING)
+                               index_len = index_len + (pIndex->index_len)+1; /* add extra suffix for str len */
+                           else
+                               index_len = index_len +1;    /* one subid per index */
+                       }     
+                       index_obj.len = index_len;
+
+                       for (i=0; i < suffix->len; i++)
+                       {
+                                index[i] = suffix->subids[i];
+                                index_obj.value[i] = suffix->subids[i];
+                       }
+
+                       for (i = suffix->len; i < index_len; i++)   /* Zero out remainder of suffixes */
+                       {
+                                index[i] = 0;
+                                index_obj.value[i] = 0;
+                       }
+
+                       for (i=0; i < index_len; i++)
+                       {
+                            if ((cache_input_entry == entry) && (cache_input_index[i] == index[i]))
+                                 was_cached = 1;
+                            else
+                            {
+                                 was_cached = 0;
+                                 break;
+                            }
+
+                       }
+
+                       if (was_cached)
+                       {
+                            pointer = cache_output_pointer;
+                            snmp_error = cache_output_snmp_error;
+                            for (i=0;i < index_len; i++)
+                                index[i]= cache_output_index[i];
+                       }
+                       else
+                       {
+                            if (cache_input_entry != NULL && cache_output_pointer != NULL)
+                                if (ssa_mem_free!=0 && cache_input_entry->dealloc != NULL)
+                                {
+                                    (*(cache_input_entry->dealloc))(cache_output_pointer);
+                                    cache_output_pointer = NULL;
+                                }
+                            cache_input_entry= entry;
+                            for (i=0; i < index_len; i++)
+                                 cache_input_index[i] = index[i];
+			
+			    if (suffix->len == 0)
+				get_entry = FIRST_ENTRY;
+			    else
+				get_entry = NEXT_ENTRY;
+
+                            snmp_error = (*(entry->get)) (get_entry, &pointer,&index_obj);
+
+                            for (i=0; i< index_len; i++)
+                                 index[i] = index_obj.value[i];
+                            cache_output_pointer = pointer;
+                            cache_output_snmp_error = snmp_error;
+                            for (i=0; i < index_len; i++)
+                                 cache_output_index[i] = index[i];
+                       }
+
+                       if (suffix->len !=0)
+                           SSAOidZero(suffix);
+
+                       if(pointer == NULL)
+                       {
+                          if(snmp_error == END_OF_TABLE)
+                          {
+                               if(trace_level > 0)
+                               {
+                                   trace("!! End of table %s\n\n",
+                                          node->parent->parent->label);
+                               }
+                               return agent_get_next_loop(variable, node->next, suffix);
+                          }
+
+                                if(snmp_error < 0)
+                                {
+                                      error("the get() method of %s returned %d",
+                                             node->parent->label,
+                                             snmp_error);
+                                      snmp_error = SNMP_ERR_GENERR;
+                                }
+                                return snmp_error;
+                       }
+
+			/* variable->name */
+		       SSAOidZero(&(variable->name));
+                       variable->name.subids = (Subid *) malloc((column->name.len + index_len) * sizeof(Subid));
+                       memcpy(variable->name.subids, column->name.subids, column->name.len * sizeof(Subid));
+                       for (i=0; i < index_len; i++)
+                            variable->name.subids[column->name.len + i] = index[i];
+                       variable->name.len = column->name.len + index_len;
+
+			/* variable->type */
+			variable->type = column->asn1_type;
+
+			/* variable->val, variable->val_len */
+			switch(column->asn1_type)
+			{
+				case INTEGER:
+				case COUNTER:
+				case GAUGE:
+				case TIMETICKS:
+					integer_ptr = (Integer *) (pointer +
+						COLUMN_OFFSET(column->offset));
+					variable->val.integer = (Integer *) malloc(sizeof(Integer));
+					*(variable->val.integer) = *integer_ptr;
+					variable->val_len = sizeof(Integer);
+					break;
+
+				case OBJID:
+					oid_ptr = (Oid *) (pointer +
+						COLUMN_OFFSET(column->offset));
+					/* fix the null subid */
+					if(oid_ptr->subids == NULL){
+					  variable->val.objid = NULL;
+					}else{
+					variable->val.objid = (Subid *) malloc(oid_ptr->len *
+						(int32_t)sizeof(Subid));
+					(void)memcpy(variable->val.objid, oid_ptr->subids, oid_ptr->len * 
+						(int32_t)sizeof(Subid));
+					}
+					variable->val_len = oid_ptr->len * 
+						(int32_t)sizeof(Subid);
+					break;
+
+				case STRING:
+				case IPADDRESS:
+				case OPAQUE:
+					string_ptr = (String *) (pointer +
+						COLUMN_OFFSET(column->offset));
+					if(string_ptr->chars == NULL){
+					  variable->val.string =(u_char*)NULL;
+					}else{
+					variable->val.string = (u_char *) malloc(string_ptr->len);
+					(void)memcpy(variable->val.string, string_ptr->chars, string_ptr->len);
+					}
+					variable->val_len = string_ptr->len;
+					break;
+			}
+
+
+			return SNMP_ERR_NOERROR;
+
+
+		case NODE:
+			return agent_get_next_loop(variable, node->next, suffix);
+	}
+
+	/* never reached */
+	return -1;
+}
+
+	
+/****************************************************************/
+
+/* returns:						*/
+/*	0 in case of success (the pdu should be sent	*/
+/*	  back to its originator even if an SNMP error	*/
+/*	  was detected)					*/
+/*	-1 in case of failure (no pdu should be sent	*/
+/*	  back)						*/
+
+static int agent_get(SNMP_pdu *pdu, char *error_label)
+{
+	SNMP_variable *variable;
+	Node *node;
+	Object *object;
+	Column *column;
+	Entry *entry=NULL;
+	Oid suffix;
+	int index_err = 1;
+	Integer integer;
+	Oid oid;
+	String string;
+	Integer *integer_ptr;
+	Oid *oid_ptr;
+	String *string_ptr;
+	int snmp_error;
+	char *pointer=NULL;
+        Subid index[MAX_OID_LEN];
+
+	/* create index struct */
+	IndexType index_obj;
+	int index_buffer[256];
+
+        int was_cached;
+        int i;
+        Index *pIndex;
+        int index_len;
+
+	index_obj.len = 0;
+	index_obj.type = 0;
+	index_obj.value = index_buffer; 
+
+
+	error_label[0] = '\0';
+
+	pdu->type = GET_RSP_MSG;
+
+	for(variable = pdu->first_variable; variable; variable = variable->next_variable)
+	{
+		node = node_find(EXACT_ENTRY, &(variable->name), &suffix);
+		if(node == NULL)
+		{
+			pdu->error_status = SNMP_ERR_NOSUCHNAME;
+			pdu->error_index = index_err;
+			return 0;
+		}
+		/* we should not forget to free suffix.subids */
+
+		if(trace_level > 0)
+		{
+			trace("!! get(): processing the variable %s\n\n",
+				node->label);
+		}
+
+		if(variable->type != NULLOBJ)
+		{
+			error("agent_get(): ASN.1 type (0x%x) is not NULL for node %s",
+					variable->type,
+					node->label);
+			variable->type = NULLOBJ;
+		}
+
+		if(variable->val.string)
+		{
+			error("agent_get(): val is not NULL for node %s", node->label);
+			free(variable->val.string);
+			variable->val.string = NULL;
+		}
+
+		if(variable->val_len)
+		{
+			error("agent_get(): val_len is not 0 for node %s", node->label);
+			variable->val_len = 0;
+		}
+
+		switch(node->type)
+		{
+			case OBJECT:
+				object = node->data.object;
+
+				if( (suffix.len != 1)
+					|| (suffix.subids[0] != 0) )
+				{
+					pdu->error_status = SNMP_ERR_NOSUCHNAME;
+					pdu->error_index = index_err;
+					SSAOidZero(&suffix);
+					return 0;
+				}
+
+				if( !(object->access & READ_FLAG) )
+				{
+					pdu->error_status = SNMP_ERR_NOSUCHNAME;
+					pdu->error_index = index_err;
+					SSAOidZero(&suffix);
+					return 0;
+				}
+
+				switch(object->asn1_type)
+				{
+					case INTEGER:
+					case COUNTER:
+					case GAUGE:
+					case TIMETICKS:
+						snmp_error = (*(object->get))(&integer);
+						break;
+
+					case OBJID:
+						snmp_error = (*(object->get))(&oid);
+                                                if(snmp_error != SNMP_ERR_NOERROR  &&
+                                                   ssa_mem_free != 0){
+                                                       if(object->dealloc != NULL)
+                                                         (*(object->dealloc))(&oid);
+						}
+						break;
+
+					case STRING:
+					case IPADDRESS:
+					case OPAQUE:
+						snmp_error = (*(object->get))(&string);
+                                                if(snmp_error != SNMP_ERR_NOERROR  &&
+                                                   ssa_mem_free != 0){
+                                                       if(object->dealloc != NULL)
+                                                         (*(object->dealloc))(&string);
+						}
+						break;
+				}
+
+				if(snmp_error != SNMP_ERR_NOERROR)
+				{
+					if(snmp_error < 0)
+					{
+						error("the get() method of %s returned %d",
+							node->label,
+							snmp_error);
+						snmp_error = SNMP_ERR_GENERR;
+					}
+					pdu->error_status = snmp_error;
+					pdu->error_index = index_err;
+					SSAOidZero(&suffix);
+					return 0;
+				}
+
+				/* variable->name */
+
+				/* variable->type */
+				variable->type = object->asn1_type;
+
+				/* variable->val, variable->val_len */
+				switch(object->asn1_type)
+				{
+					case INTEGER:
+					case COUNTER:
+					case GAUGE:
+					case TIMETICKS:
+						variable->val.integer = (Integer *) malloc(sizeof(Integer));
+						*(variable->val.integer) = integer;
+						variable->val_len = sizeof(Integer);
+						break;
+
+					case OBJID:
+						variable->val.objid = (Subid *) malloc(oid.len * 
+							(int32_t)sizeof(Subid));
+						(void)memcpy(variable->val.objid, oid.subids, oid.len *
+							(int32_t)sizeof(Subid));
+						variable->val_len = oid.len * 
+							(int32_t)sizeof(Subid);
+                                                  if (ssa_mem_free != 0){
+                                                       if(object->dealloc != NULL)
+                                                         (*(object->dealloc))(&oid);
+						}
+						break;
+
+					case STRING:
+					case IPADDRESS:
+					case OPAQUE:
+						variable->val.string = (u_char *) malloc(string.len);
+						(void)memcpy(variable->val.string, string.chars, string.len);
+						variable->val_len = string.len;
+                                                /*if(snmp_error != SNMP_ERR_NOERROR  &&*/
+                                                  if (ssa_mem_free != 0){
+                                                       if(object->dealloc != NULL)
+                                                         (*(object->dealloc))(&string);
+						}
+						break;
+				}
+
+
+				break;
+
+
+			case COLUMN:
+				column = node->data.column;
+				entry = column->entry;
+                                pIndex=entry->first_index;
+
+				if( !(column->access & READ_FLAG) )
+				{
+					pdu->error_status = SNMP_ERR_NOSUCHNAME;
+					pdu->error_index = index_err;
+					SSAOidZero(&suffix);
+					return 0;
+				}
+                               
+                                if (suffix.subids == NULL) {
+					pdu->error_status = SNMP_ERR_NOSUCHNAME;
+                                        pdu->error_index = index_err;
+                                        SSAOidZero(&suffix);
+                                        return 0;
+                                }
+
+			        index_len = 0;
+                                for (pIndex=entry->first_index; pIndex; pIndex=pIndex->next_index)
+                       		{
+                           	    if (pIndex->index_type == OCTET_STRING)
+                               		index_len = index_len + (pIndex->index_len)+1; /* add extra suffix for str len */
+                                    else
+                                       index_len = index_len +1;    /* one subid per index */
+                                }
+
+ 
+                  	        for (i=0; i < index_len; i++)
+                                {
+                                        index[i] = suffix.subids[i];
+                                        index_obj.value[i] = suffix.subids[i];
+                                }
+                                index_obj.len = index_len;
+                                for (i=0; i < index_len; i++)
+                                {
+                                     if( (cache_input_entry == entry) && (cache_input_index[i] == index[i]) )
+                                         was_cached = 1;
+                                     else
+                                     {
+                                         was_cached = 0;
+                                         break;
+                                     }
+                                }
+                                if (was_cached)
+                                {
+                                     pointer = cache_output_pointer;
+                                     snmp_error = cache_output_snmp_error;
+                                }
+                                else
+                                {
+                                     if(cache_input_entry != NULL && cache_output_pointer != NULL)
+                                        if(ssa_mem_free != 0 && cache_input_entry->dealloc != NULL)
+                                        {
+                                              (*(cache_input_entry->dealloc))(cache_output_pointer);
+                                              cache_output_pointer = NULL;
+                                        }
+                                              cache_input_entry = entry;
+                                              for (i=0; i < index_len; i++)
+                                                   cache_input_index[i] = index[i];
+                                              snmp_error = (*(entry->get))(EXACT_ENTRY,&pointer,&index_obj);
+                                              cache_output_pointer = pointer;
+                                              cache_output_snmp_error = snmp_error;
+                                }
+
+
+				if(pointer == NULL)
+				{
+					if(snmp_error < 0)
+					{
+						error("the get() method of %s returned %d",
+							node->parent->label,
+							snmp_error);
+						snmp_error = SNMP_ERR_GENERR;
+					}
+					
+					pdu->error_status = snmp_error;
+					pdu->error_index = index_err;
+					SSAOidZero(&suffix);
+					return 0;
+				}
+
+				/* variable->type */
+				variable->type = column->asn1_type;
+
+				/* variable->val, variable->val_len */
+				switch(column->asn1_type)
+				{
+					case INTEGER:
+					case COUNTER:
+					case GAUGE:
+					case TIMETICKS:
+						integer_ptr = (Integer *) (pointer +
+							COLUMN_OFFSET(column->offset));
+						variable->val.integer = (Integer *) malloc(sizeof(Integer));
+						*(variable->val.integer) = *integer_ptr;
+						variable->val_len = sizeof(Integer);
+						break;
+
+					case OBJID:
+						oid_ptr = (Oid *) (pointer +
+							COLUMN_OFFSET(column->offset));
+						variable->val.objid = (Subid *) malloc(oid_ptr->len *
+							(int32_t)sizeof(Subid));
+						(void)memcpy(variable->val.objid, oid_ptr->subids, oid_ptr->len *
+							(int32_t)sizeof(Subid));
+						variable->val_len = oid_ptr->len * 
+							(int32_t)sizeof(Subid);
+						break;
+
+					case STRING:
+					case IPADDRESS:
+					case OPAQUE:
+						string_ptr = (String *) (pointer +
+							COLUMN_OFFSET(column->offset));
+						variable->val.string = (u_char *) malloc(string_ptr->len);
+						(void)memcpy(variable->val.string, string_ptr->chars, string_ptr->len);
+						variable->val_len = string_ptr->len;
+						break;
+				}
+
+				break;
+
+
+			case NODE:
+				pdu->error_status = SNMP_ERR_NOSUCHNAME;
+				pdu->error_index = index_err;
+				SSAOidZero(&suffix);
+				return 0;
+		}
+
+		SSAOidZero(&suffix);
+
+		index_err++;
+	}
+	/* Moved this down from the column loop because the cache must be
+	   freed only when the required columns in the row are all read.
+	   - Added pointer check because pointer will point to nothing
+	   if this is a non-column get. 
+	   - Added setting cache_output_pointer to NULL because if it is not
+	   NULL, the next iteration of agent_process will try to delete it */
+	/* Bug fix 4127458 . Added check to see if entry has been initialized */
+	if(ssa_mem_free != 0 && entry != NULL && entry->dealloc != NULL && pointer != NULL){
+	/* remember to turn off the caching */
+	(*(entry->dealloc))(pointer);
+	pointer = cache_output_pointer = NULL;
+				}
+
+	return 0;
+}
+
+
+/****************************************************************/
+
+/* returns							*/
+/*	0	in case of success. If we are in the		*/
+/*		FIRST_PASS, we should go to the second pass.	*/
+/*	-1	in case of failure. If we are in the		*/
+/*		FIRST_PASS, we should not go to the		*/
+/*		second pass and no pdu should be sent back.	*/
+/*	1	If we are in the FIRST_PASS, we should not go	*/
+/*		to the second pass but a pdu			*/
+/*		with an SNMP error should be sent back to its	*/
+/*		originator					*/
+
+static int agent_set(int pass, SNMP_pdu *pdu, char *error_label)
+{
+	SNMP_variable *variable;
+	Node *node;
+	Object *object;
+	Column *column;
+	Entry *entry;
+	Oid suffix;
+	int index = 1;
+	Integer integer = 0;
+	Oid oid = { NULL, 0 };
+	String string = { NULL, 0 };
+	int snmp_error;
+        int i;
+
+	/* create index struct */
+	IndexType index_obj;
+	int index_buffer[256];
+
+	index_obj.len = 0;
+	index_obj.value = index_buffer; 
+
+	error_label[0] = '\0';
+
+	pdu->type = GET_RSP_MSG;
+
+	for(variable = pdu->first_variable; variable; variable = variable->next_variable)
+	{
+		node = node_find(EXACT_ENTRY, &(variable->name), &suffix);
+		if(node == NULL)
+		{
+			pdu->error_status = SNMP_ERR_NOSUCHNAME;
+			pdu->error_index = index;
+			return 1;
+		}
+		/* we should not forget to free suffix.subids */
+
+		if(trace_level > 0)
+		{
+			trace("!! set(%s): processing the variable %s\n\n",
+				(pass == FIRST_PASS)? "FIRST_PASS": "SECOND_PASS",
+				node->label);
+		}
+
+/*
+		if(variable->val.string == NULL)
+		{
+			(void)sprintf(error_label, "val.string is NULL for node %s",
+				node->label);
+			SSAOidZero(&suffix);
+			return -1;
+		}
+
+		if(variable->val_len == 0)
+		{
+			(void)sprintf(error_label, "val_len is 0 for node %s",
+				node->label);
+			SSAOidZero(&suffix);
+			return -1;
+		}
+*/
+
+		switch(node->type)
+		{
+			case OBJECT:
+				object = node->data.object;
+
+				/* check the ASN.1 type */
+				if(variable->type != object->asn1_type)
+				{
+					(void)sprintf(error_label, "wrong ASN.1 type (0x%x) for node %s",
+						variable->type, node->label);
+					SSAOidZero(&suffix);
+					return -1;
+				}
+
+				/* check the suffix */
+				if( (suffix.len != 1)
+					|| (suffix.subids[0] != 0) )
+				{
+					pdu->error_status = SNMP_ERR_NOSUCHNAME;
+					pdu->error_index = index;
+					SSAOidZero(&suffix);
+					return 1;
+				}
+
+				/* check the access */
+				if( !(object->access & WRITE_FLAG) )
+				{
+					pdu->error_status = SNMP_ERR_READONLY;
+					pdu->error_index = index;
+					SSAOidZero(&suffix);
+					return 1;
+				}
+
+				/* check the value length */
+				switch(object->asn1_type)
+				{
+					case INTEGER:
+					case COUNTER:
+					case GAUGE:
+					case TIMETICKS:
+					case IPADDRESS:
+						if(variable->val_len != 4)
+						{
+							(void)sprintf(error_label, "val_len is not 4 (%d) for node %s",
+								variable->val_len, node->label);
+							SSAOidZero(&suffix);
+							return -1;
+						}
+
+						if(variable->val.integer == NULL)
+						{
+							(void)sprintf(error_label, "val.integer is NULL for node %s",
+								node->label);
+							SSAOidZero(&suffix);
+							return -1;
+						}
+
+						break;
+				}
+
+				/* in case of enumerated integer, check the value */
+				if( (object->asn1_type == INTEGER)
+					&& (object->first_enum != NULL) )
+				{
+					Enum *enums;
+
+
+					integer = *(variable->val.integer);
+
+					for(enums = object->first_enum; enums; enums = enums->next_enum)
+					{
+						if(enums->value == integer)
+						{
+							break;
+						}
+					}
+
+					if(enums == NULL)
+					{
+						pdu->error_status = SNMP_ERR_BADVALUE;
+						pdu->error_index = index;
+						SSAOidZero(&suffix);
+						return 1;
+					}
+				}
+
+				switch(object->asn1_type)
+				{
+					case INTEGER:
+					case COUNTER:
+					case GAUGE:
+					case TIMETICKS:
+						integer = *(variable->val.integer);
+
+						snmp_error = (*(object->set))(pass, &integer);
+						break;
+
+					case OBJID:
+						if(SSAOidInit(&oid, variable->val.objid,
+							variable->val_len / (int32_t)sizeof(Subid),
+							error_label)) {
+							SSAOidZero(&suffix);
+							return -1;
+						}
+
+						snmp_error = (*(object->set))(pass, &oid);
+						SSAOidZero(&oid);
+						break;
+
+					case STRING:
+					case IPADDRESS:
+					case OPAQUE:
+						if(SSAStringInit(&string, variable->val.string,
+							variable->val_len, error_label)) {
+							SSAOidZero(&suffix);
+							return -1;
+						}
+
+						snmp_error = (*(object->set))(pass, &string);
+						SSAStringZero(&string);
+						break;
+				}
+
+				if(snmp_error != SNMP_ERR_NOERROR)
+				{
+					if(snmp_error < 0)
+					{
+						error("the set(%s) method of %s returned %d",
+							(pass == FIRST_PASS)? "FIRST_PASS": "SECOND_PASS",
+							node->label, snmp_error);
+						snmp_error = SNMP_ERR_GENERR;
+					}
+					pdu->error_status = snmp_error;
+					pdu->error_index = index;
+					SSAOidZero(&suffix);
+					return 1;
+				}
+
+				break;
+
+
+			case COLUMN:
+				column = node->data.column;
+				entry = column->entry;
+
+				/* check the ASN.1 type */
+				if(variable->type != column->asn1_type)
+				{
+					(void)sprintf(error_label, "wrong ASN.1 type (0x%x) for node %s",
+						variable->type, node->label);
+					SSAOidZero(&suffix);
+					return -1;
+				}
+
+				/* check the suffix */
+				if (suffix.subids == NULL)
+				{
+					pdu->error_status = SNMP_ERR_NOSUCHNAME;
+					pdu->error_index = index;
+					SSAOidZero(&suffix);
+					return 1;
+				}
+
+				/* check the access */
+				if( !(column->access & WRITE_FLAG) )
+				{
+					pdu->error_status = SNMP_ERR_READONLY;
+					pdu->error_index = index;
+					SSAOidZero(&suffix);
+					return 1;
+				}
+
+				/* check the value length */
+				switch(column->asn1_type)
+				{
+					case INTEGER:
+					case COUNTER:
+					case GAUGE:
+					case TIMETICKS:
+					case IPADDRESS:
+						if(variable->val_len != 4)
+						{
+							(void)sprintf(error_label, "val_len is not 4 (%d) for node %s",
+								variable->val_len, node->label);
+							SSAOidZero(&suffix);
+							return -1;
+						}
+
+						if(variable->val.integer == NULL)
+						{
+							(void)sprintf(error_label, "val.integer is NULL for node %s",
+								node->label);
+							SSAOidZero(&suffix);
+							return -1;
+						}
+
+						break;
+				}
+
+				/* in case of enumerated integer, check the value */
+				if( (column->asn1_type == INTEGER)
+					&& (column->first_enum != NULL) )
+				{
+					Enum *enums;
+
+
+					integer = *(variable->val.integer);
+
+					for(enums = column->first_enum; enums; enums = enums->next_enum)
+					{
+						if(enums->value == integer)
+						{
+							break;
+						}
+					}
+
+					if(enums == NULL)
+					{
+						pdu->error_status = SNMP_ERR_BADVALUE;
+						pdu->error_index = index;
+						SSAOidZero(&suffix);
+						return 1;
+					}
+				}
+
+				switch(column->asn1_type)
+				{
+					case INTEGER:
+					case COUNTER:
+					case GAUGE:
+					case TIMETICKS:
+						integer = *(variable->val.integer);
+
+						break;
+
+					case OBJID:
+						if(SSAOidInit(&oid, variable->val.objid,
+							variable->val_len / (int32_t)sizeof(Subid), error_label)) {
+							SSAOidZero(&suffix);
+							return -1;
+						}
+
+						break;
+
+					case STRING:
+					case IPADDRESS:
+					case OPAQUE:
+						if(SSAStringInit(&string, variable->val.string, variable->val_len, error_label))
+						{
+							SSAOidZero(&suffix);
+							return -1;
+						}
+
+						break;
+				}
+
+				index_obj.len = suffix.len;
+				for (i = 0; i < suffix.len; i++)
+                                {
+                                    index_obj.value[i] = suffix.subids[i];
+                                }
+
+						
+						switch(column->asn1_type)
+						{
+							case INTEGER:
+							case COUNTER:
+							case GAUGE:
+							case TIMETICKS:
+								snmp_error = (*(column->set))(pass, index_obj, &integer);
+								break;
+
+							case OBJID:
+								snmp_error = (*(column->set))(pass, index_obj, &oid);
+								break;
+
+							case STRING:
+							case IPADDRESS:
+							case OPAQUE:
+								snmp_error = (*(column->set))(pass, index_obj, &string);
+								break;
+				}
+
+				switch(column->asn1_type)
+				{
+					case OBJID:
+						SSAOidZero(&oid);
+						break;
+
+					case STRING:
+					case IPADDRESS:
+					case OPAQUE:
+						SSAStringZero(&string);
+						break;
+				}
+
+				if(snmp_error != SNMP_ERR_NOERROR)
+				{
+					if(snmp_error < 0)
+					{
+						error("the set(%s) method of %s returned %d",
+							(pass == FIRST_PASS)? "FIRST_PASS": "SECOND_PASS",
+							node->parent->label,
+							snmp_error);
+							snmp_error = SNMP_ERR_GENERR;
+					}
+					
+					pdu->error_status = snmp_error;
+					pdu->error_index = index;
+					SSAOidZero(&suffix);
+					return 1;
+				}
+
+				break;
+
+
+			case NODE:
+				pdu->error_status = SNMP_ERR_NOSUCHNAME;
+				pdu->error_index = index;
+				SSAOidZero(&suffix);
+				return 1;
+		}
+
+		SSAOidZero(&suffix);
+
+		index++;
+	}
+
+	return 0;
+}
+
+
+/****************************************************************/
+
+/* flag == 0 means turn off auto mem free */
+void SSAAutoMemFree(int flag)
+{
+  ssa_mem_free = flag;
+}
+
+