1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <unistd.h>
30#include <sys/types.h>
31#include <sys/times.h>
32#include <netinet/in.h>
33#include <stdio.h>
34#include <sys/socket.h>
35#include <errno.h>
36#include <syslog.h>
37#include <string.h>
38#include <arpa/inet.h>
39#include <netdb.h>
40#include <nlist.h>
41
42#include "snmp_msg.h"
43#include "impl.h"
44#include "trace.h"
45#include "snmp.h"
46#include "pdu.h"
47#include "request.h"
48#include "error.h"
49
50
51
52/***** GLOBAL VARIABLES *****/
53
54static Subid sysUptime_subids[] = { 1, 3, 6, 1, 2, 1, 1, 3, 0 };
55
56Oid sysUptime_name = { sysUptime_subids, 8 };
57Oid sysUptime_instance = { sysUptime_subids, 9 };
58
59
60/***** LOCAL VARIABLES *****/
61
62static uint32_t request_id = 0;
63
64static Subid snmpEnableAuthTraps_subids[] = { 1, 3, 6, 1, 2, 1, 11, 30, 0 };
65static Oid snmpEnableAuthTraps_name = { snmpEnableAuthTraps_subids, 9 };
66
67
68/********************************************************************/
69
70/* static */ SNMP_pdu *request_create(char *community, int type, char *error_label)
71{
72	SNMP_pdu *request;
73
74
75	error_label[0] = '\0';
76
77	switch(type)
78	{
79		case GET_REQ_MSG:
80		case GETNEXT_REQ_MSG:
81		case SET_REQ_MSG:
82			break;
83
84		default:
85			sprintf(error_label, "BUG: request_create(): bad type (0x%x)",
86				type);
87			return NULL;
88	}
89
90	request = snmp_pdu_new(error_label);
91	if(request == NULL)
92	{
93		return NULL;
94	}
95
96	request->version = SNMP_VERSION_1;
97	request->community = strdup(community);
98	if(request->community == NULL)
99	{
100		sprintf(error_label, ERR_MSG_ALLOC);
101		snmp_pdu_free(request);
102		return NULL;
103	}
104	request->type = type;
105	request->request_id = request_id++;
106
107
108	return request;
109}
110
111
112/********************************************************************/
113
114SNMP_pdu *request_send_to_port_time_out_blocking(IPAddress *ip_address, int port,struct timeval *timeout,SNMP_pdu *request, char *error_label)
115{
116	int sd;
117	Address address;
118	SNMP_pdu *response;
119	Address me;
120	int numfds;
121	fd_set fdset;
122	int count;
123
124
125	error_label[0] = '\0';
126
127	if(request == NULL)
128	{
129		sprintf(error_label, "BUG: request_send_blocking(): request is NULL");
130		return NULL;
131	}
132
133	switch(request->type)
134	{
135		case GET_REQ_MSG:
136		case GETNEXT_REQ_MSG:
137		case SET_REQ_MSG:
138			break;
139
140		default:
141			sprintf(error_label, "BUG: request_send_blocking(): bad type (0x%x)",
142				request->type);
143			return NULL;
144	}
145
146	/* sd */
147	sd = socket(AF_INET, SOCK_DGRAM, 0);
148	if(sd < 0)
149	{
150		sprintf(error_label, ERR_MSG_SOCKET,
151			errno_string());
152		return (NULL);
153	}
154
155	memset(&me, 0, sizeof (Address));
156	me.sin_family = AF_INET;
157	if ((request->type) == SET_REQ_MSG)
158		me.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
159	else
160		me.sin_addr.s_addr = htonl(INADDR_ANY);
161	me.sin_port = htons(0);
162	if(bind(sd, (struct sockaddr *)&me, sizeof(me)) != 0)
163	{
164		sprintf(error_label, ERR_MSG_BIND,
165			errno_string());
166		(void)close(sd);
167		return NULL;
168	}
169
170	/* address */
171	memset(&address, 0, sizeof(Address));
172	address.sin_family = AF_INET;
173	/* LINTED */
174	address.sin_port = (short)port;
175	address.sin_addr.s_addr = ip_address->s_addr;
176
177	if(snmp_pdu_send(sd, &address, request, error_label))
178	{
179		(void)close(sd);
180		return NULL;
181	}
182
183
184	for (;;)
185	{
186		numfds = 0;
187		FD_ZERO(&fdset);
188
189		numfds = sd + 1;
190		FD_SET(sd, &fdset);
191
192		count = select(numfds, &fdset, 0, 0, timeout);
193		if(count > 0)
194		{
195			if(FD_ISSET(sd, &fdset))
196			{
197				response = snmp_pdu_receive(sd, &address, error_label);
198				if(response == NULL)
199				{
200					(void)close(sd);
201					return NULL;
202				}
203				(void)close(sd);
204
205				return response;
206			}
207		}
208		else
209		{
210			switch(count)
211			{
212				case 0:
213					sprintf(error_label, ERR_MSG_TIMEOUT);
214					(void)close(sd);
215					return NULL;
216
217				case -1:
218					if(errno == EINTR)
219					{
220						continue;
221					}
222					else
223					{
224						sprintf(error_label, ERR_MSG_SELECT,
225							errno_string());
226						(void)close(sd);
227						return NULL;
228					}
229			}
230		}
231	}
232	/* NOTREACHED */
233}
234
235
236SNMP_pdu *request_send_to_port_blocking(IPAddress *ip_address, int port,SNMP_pdu *request, char *error_label)
237{
238	struct timeval timeout;
239
240	timeout.tv_sec = 100;
241	timeout.tv_usec = 0;
242	return(request_send_to_port_time_out_blocking
243		(ip_address,port,&timeout,request,error_label));
244}
245
246
247/*static*/ SNMP_pdu *request_send_blocking(IPAddress *ip_address, SNMP_pdu *request, char *error_label)
248{
249  return(request_send_to_port_blocking(ip_address,SNMP_PORT,request,error_label));
250}
251
252/********************************************************************/
253
254/*
255 *	if the request failed, this function returns 0
256 *	otherwise it returns sysUpTime
257 */
258
259int32_t request_sysUpTime(char *error_label, char *community_name)
260{
261	static int my_ip_address_initialized = False;
262	static IPAddress my_ip_address;
263	SNMP_pdu *request;
264	SNMP_pdu *response;
265	SNMP_variable *variable;
266	static int32_t sysUpTime = 0;
267	static clock_t last = 0;
268	clock_t now;
269	struct tms buffer;
270
271
272	error_label[0] = '\0';
273
274	now = times(&buffer);
275	if( (last == 0) || ((now - last) > 360000) )	/* 1 hour */
276	{
277		if(my_ip_address_initialized == False)
278		{
279			if(get_my_ip_address(&my_ip_address, error_label))
280			{
281				return 0;
282			}
283
284			my_ip_address_initialized = True;
285		}
286
287		if(community_name == NULL)
288			request = request_create("public", GET_REQ_MSG, error_label);
289		else
290			request = request_create(community_name, GET_REQ_MSG, error_label);
291
292		if(request == NULL)
293		{
294			return 0;
295		}
296
297		if(snmp_pdu_append_null_variable(request, &sysUptime_instance, error_label) == NULL)
298		{
299			snmp_pdu_free(request);
300			return 0;
301		}
302
303		response = request_send_blocking(&my_ip_address, request, error_label);
304		if(response == NULL)
305		{
306			snmp_pdu_free(request);
307			return 0;
308		}
309		snmp_pdu_free(request);
310
311		if(response->error_status)
312		{
313			sprintf(error_label, "%s",
314				error_status_string(response->error_status));
315			snmp_pdu_free(response);
316			return 0;
317		}
318
319		variable = response->first_variable;
320		if(variable->next_variable
321			|| SSAOidCmp(&(variable->name), &sysUptime_instance)
322			|| (variable->type != TIMETICKS)
323			|| (variable->val.integer == NULL)
324			|| (variable->val_len != sizeof(int32_t)) )
325		{
326			sprintf(error_label, ERR_MSG_BAD_RESPONSE);
327			snmp_pdu_free(response);
328			return 0;
329		}
330		sysUpTime = *(variable->val.integer);
331		last = now;
332		snmp_pdu_free(response);
333
334		if(trace_level > 0)
335		{
336			trace("sysUpTime: %d\n\n", sysUpTime);
337		}
338
339		return sysUpTime;
340	}
341
342	/* LINTED */
343	return (sysUpTime + (int32_t)(now - last));
344}
345
346
347/********************************************************************/
348
349/*
350 *	if the request failed, this function returns  -1
351 *	otherwise it returns True or False accordind to the
352 *	value of snmpEnableAuthTraps
353 */
354
355int request_snmpEnableAuthTraps(char *error_label)
356{
357	static int my_ip_address_initialized = False;
358	static IPAddress my_ip_address;
359	SNMP_pdu *request;
360	SNMP_pdu *response;
361	SNMP_variable *variable;
362	int snmpEnableAuthTraps;
363	struct timeval timeout;
364
365	timeout.tv_sec = 5;
366	timeout.tv_usec = 0;
367
368
369	error_label[0] = '\0';
370
371	if(my_ip_address_initialized == False)
372	{
373		if(get_my_ip_address(&my_ip_address, error_label))
374		{
375			return -1;
376		}
377
378		my_ip_address_initialized = True;
379	}
380
381	request = request_create("public", GET_REQ_MSG, error_label);
382	if(request == NULL)
383	{
384		return -1;
385	}
386
387	if(snmp_pdu_append_null_variable(request, &snmpEnableAuthTraps_name, error_label) == NULL)
388	{
389		snmp_pdu_free(request);
390		return -1;
391	}
392
393	response = request_send_to_port_time_out_blocking(&my_ip_address, \
394		SNMP_PORT, &timeout, request, error_label);
395	if(response == NULL)
396	{
397		snmp_pdu_free(request);
398		return -1;
399	}
400	snmp_pdu_free(request);
401
402	if(response->error_status)
403	{
404		sprintf(error_label, "%s",
405			error_status_string(response->error_status));
406		snmp_pdu_free(response);
407		return -1;
408	}
409
410	variable = response->first_variable;
411	if(variable->next_variable
412		|| SSAOidCmp(&(variable->name), &snmpEnableAuthTraps_name)
413		|| (variable->type != INTEGER)
414		|| (variable->val.integer == NULL)
415		|| (variable->val_len != sizeof(int32_t)) )
416	{
417		sprintf(error_label, ERR_MSG_BAD_RESPONSE);
418		snmp_pdu_free(response);
419		return -1;
420	}
421	snmpEnableAuthTraps = *(variable->val.integer);
422	snmp_pdu_free(response);
423
424	if(trace_level > 0)
425	{
426		trace("snmpAuthTraps: %s\n\n",
427			(snmpEnableAuthTraps == 1)? "enabled(1)": "disabled(2)");
428	}
429
430	switch(snmpEnableAuthTraps)
431	{
432		case 1: /* enabled(1) */
433			return TRUE;
434		case 2: /* disable(2) */
435			return FALSE;
436		default:
437			sprintf(error_label, ERR_MSG_BAD_VALUE);
438			return -1;
439	}
440}
441
442
443/********************************************************************/
444
445