hostres_scalars.c revision 200953
1154133Sharti/*-
2154133Sharti * Copyright (c) 2005-2006 The FreeBSD Project
3154133Sharti * All rights reserved.
4154133Sharti *
5154133Sharti * Author: Victor Cruceru <soc-victor@freebsd.org>
6154133Sharti *
7154133Sharti * Redistribution of this software and documentation and use in source and
8154133Sharti * binary forms, with or without modification, are permitted provided that
9154133Sharti * the following conditions are met:
10154133Sharti *
11154133Sharti * 1. Redistributions of source code or documentation must retain the above
12154133Sharti *    copyright notice, this list of conditions and the following disclaimer.
13154133Sharti * 2. Redistributions in binary form must reproduce the above copyright
14154133Sharti *    notice, this list of conditions and the following disclaimer in the
15154133Sharti *    documentation and/or other materials provided with the distribution.
16154133Sharti *
17154133Sharti * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18154133Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19154133Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20154133Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21154133Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22154133Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23154133Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24154133Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25154133Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26154133Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27154133Sharti * SUCH DAMAGE.
28154133Sharti *
29154133Sharti * $FreeBSD: head/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_scalars.c 200953 2009-12-24 17:55:47Z ed $
30154133Sharti */
31154133Sharti
32154133Sharti/*
33154133Sharti * Host Resources MIB scalars implementation for SNMPd.
34154133Sharti */
35154133Sharti
36154133Sharti#include <sys/types.h>
37154133Sharti#include <sys/sysctl.h>
38154133Sharti
39154133Sharti#include <pwd.h>
40154133Sharti#include <stdlib.h>
41154133Sharti#include <stdint.h>
42154133Sharti#include <string.h>
43154133Sharti#include <syslog.h>
44200953Sed#define	_ULOG_POSIX_NAMES
45200953Sed#include <ulog.h>
46154133Sharti
47154133Sharti#include "hostres_snmp.h"
48154133Sharti#include "hostres_oid.h"
49154133Sharti#include "hostres_tree.h"
50154133Sharti
51154133Sharti/* boot timestamp in centi-seconds */
52154133Shartistatic uint64_t kernel_boot;
53154133Sharti
54154133Sharti/* physical memory size in Kb */
55154133Shartistatic uint64_t phys_mem_size;
56154133Sharti
57154133Sharti/* boot line (malloced) */
58154133Shartistatic u_char *boot_line;
59154133Sharti
60154133Sharti/* maximum number of processes */
61154133Shartistatic uint32_t max_proc;
62154133Sharti
63154133Sharti/**
64154133Sharti * Free all static data
65154133Sharti */
66154133Shartivoid
67154133Shartifini_scalars(void)
68154133Sharti{
69154133Sharti
70154133Sharti	free(boot_line);
71154133Sharti}
72154133Sharti
73154133Sharti/**
74154133Sharti * Get system uptime in hundredths of seconds since the epoch
75154133Sharti * Returns 0 in case of an error
76154133Sharti */
77154133Shartistatic int
78154133ShartiOS_getSystemUptime(uint32_t *ut)
79154133Sharti{
80154133Sharti	struct timeval right_now;
81154133Sharti	uint64_t now;
82154133Sharti
83154133Sharti	if (kernel_boot == 0) {
84154133Sharti		/* first time, do the sysctl */
85154133Sharti		struct timeval kernel_boot_timestamp;
86154133Sharti		int mib[2] = { CTL_KERN, KERN_BOOTTIME };
87154133Sharti		size_t len = sizeof(kernel_boot_timestamp);
88154133Sharti
89154133Sharti		if (sysctl(mib, 2, &kernel_boot_timestamp,
90154133Sharti		    &len, NULL, 0) == -1) {
91154133Sharti			syslog(LOG_ERR, "sysctl KERN_BOOTTIME failed: %m");
92154133Sharti			return (SNMP_ERR_GENERR);
93154133Sharti		}
94154133Sharti
95154249Sharti		HRDBG("boot timestamp from kernel: {%lld, %ld}",
96154249Sharti		    (long long)kernel_boot_timestamp.tv_sec,
97154249Sharti		    (long)kernel_boot_timestamp.tv_usec);
98154133Sharti
99154133Sharti		kernel_boot = ((uint64_t)kernel_boot_timestamp.tv_sec * 100) +
100154133Sharti		    (kernel_boot_timestamp.tv_usec / 10000);
101154133Sharti	}
102154133Sharti
103154133Sharti	if (gettimeofday(&right_now, NULL) < 0) {
104154133Sharti		syslog(LOG_ERR, "gettimeofday failed: %m");
105154133Sharti		return (SNMP_ERR_GENERR);
106154133Sharti	}
107154133Sharti	now = ((uint64_t)right_now.tv_sec * 100) + (right_now.tv_usec / 10000);
108154133Sharti
109154133Sharti	if (now - kernel_boot > UINT32_MAX)
110154133Sharti		*ut = UINT32_MAX;
111154133Sharti	else
112154133Sharti		*ut = now - kernel_boot;
113154133Sharti
114154133Sharti	return (SNMP_ERR_NOERROR);
115154133Sharti}
116154133Sharti
117154133Sharti/**
118154133Sharti * Get system local date and time in a foramt suitable for DateAndTime TC:
119154133Sharti *           field  octets  contents                  range
120154133Sharti *           -----  ------  --------                  -----
121154133Sharti *             1      1-2   year*                     0..65536
122154133Sharti *             2       3    month                     1..12
123154133Sharti *             3       4    day                       1..31
124154133Sharti *             4       5    hour                      0..23
125154133Sharti *             5       6    minutes                   0..59
126154133Sharti *             6       7    seconds                   0..60
127154133Sharti *                          (use 60 for leap-second)
128154133Sharti *             7       8    deci-seconds              0..9
129154133Sharti *             8       9    direction from UTC        '+' / '-'
130154133Sharti *             9      10    hours from UTC*           0..13
131154133Sharti *            10      11    minutes from UTC          0..59
132154133Sharti *
133154133Sharti *           * Notes:
134154133Sharti *           - the value of year is in network-byte order
135154133Sharti *           - daylight saving time in New Zealand is +13
136154133Sharti *
137154133Sharti *           For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be
138154133Sharti *           displayed as:
139154133Sharti *
140154133Sharti *                            1992-5-26,13:30:15.0,-4:0
141154133Sharti *
142154133Sharti * Returns -1 in case of an error or the length of the string (8 or 11)
143154133Sharti * Actually returns always 11 on freebsd
144154133Sharti */
145154133Shartistatic int
146154133ShartiOS_getSystemDate(struct snmp_value *value)
147154133Sharti{
148154133Sharti	u_char s_date_time[11];
149154133Sharti	struct tm tloc_tm;
150154133Sharti	time_t tloc_time_t;
151154133Sharti	struct timeval right_now;
152154133Sharti	int string_len;
153154133Sharti
154154133Sharti	if (gettimeofday(&right_now, NULL) < 0) {
155154133Sharti		syslog(LOG_ERR, "gettimeofday failed: %m");
156154133Sharti		return (SNMP_ERR_GENERR);
157154133Sharti	}
158154133Sharti
159154133Sharti	tloc_time_t = right_now.tv_sec;
160154133Sharti
161154133Sharti	if (localtime_r(&tloc_time_t, &tloc_tm) == NULL) {
162154133Sharti		syslog(LOG_ERR, "localtime_r() failed: %m ");
163154133Sharti		return (SNMP_ERR_GENERR);
164154133Sharti	}
165154133Sharti
166154133Sharti	string_len = make_date_time(s_date_time, &tloc_tm,
167154133Sharti	    right_now.tv_usec / 100000);
168154133Sharti
169154133Sharti	return (string_get(value, s_date_time, string_len));
170154133Sharti}
171154133Sharti
172154133Sharti/**
173154133Sharti * Get kernel boot path. For FreeBSD it seems that no arguments are
174154133Sharti * present. Returns NULL if an error occured. The returned data is a
175154133Sharti * pointer to a global strorage.
176154133Sharti */
177154133Shartiint
178154133ShartiOS_getSystemInitialLoadParameters(u_char **params)
179154133Sharti{
180154133Sharti
181154133Sharti	if (boot_line == NULL) {
182154133Sharti		int mib[2] = { CTL_KERN, KERN_BOOTFILE };
183154133Sharti		char *buf;
184154133Sharti		size_t buf_len = 0;
185154133Sharti
186154133Sharti		/* get the needed buffer len */
187154133Sharti		if (sysctl(mib, 2, NULL, &buf_len, NULL, 0) != 0) {
188154133Sharti			syslog(LOG_ERR,
189154133Sharti			    "sysctl({CTL_KERN,KERN_BOOTFILE}) failed: %m");
190154133Sharti			return (SNMP_ERR_GENERR);
191154133Sharti		}
192154133Sharti
193154133Sharti		if ((buf = malloc(buf_len)) == NULL) {
194154133Sharti			syslog(LOG_ERR, "malloc failed");
195154133Sharti			return (SNMP_ERR_GENERR);
196154133Sharti		}
197154133Sharti                if (sysctl(mib, 2, buf, &buf_len, NULL, 0)) {
198154133Sharti			syslog(LOG_ERR,
199154133Sharti			    "sysctl({CTL_KERN,KERN_BOOTFILE}) failed: %m");
200154133Sharti			free(buf);
201154133Sharti			return (SNMP_ERR_GENERR);
202154133Sharti		}
203154133Sharti
204154133Sharti		boot_line = buf;
205154133Sharti		HRDBG("kernel boot file: %s", boot_line);
206154133Sharti	}
207154133Sharti
208154133Sharti	*params = boot_line;
209154133Sharti	return (SNMP_ERR_NOERROR);
210154133Sharti}
211154133Sharti
212154133Sharti/**
213154133Sharti * Get number of current users which are logged in
214154133Sharti */
215154133Shartistatic int
216154133ShartiOS_getSystemNumUsers(uint32_t *nu)
217154133Sharti{
218200953Sed	struct utmpx *utmp;
219154133Sharti
220200953Sed	setutxent();
221154133Sharti	*nu = 0;
222200953Sed	while ((utmp = getutxent()) != NULL) {
223200953Sed		if (utmp->ut_type == USER_PROCESS)
224154133Sharti			(*nu)++;
225154133Sharti	}
226200953Sed	endutxent();
227154133Sharti
228154133Sharti	return (SNMP_ERR_NOERROR);
229154133Sharti}
230154133Sharti
231154133Sharti/**
232154133Sharti * Get number of current processes existing into the system
233154133Sharti */
234154133Shartistatic int
235154133ShartiOS_getSystemProcesses(uint32_t *proc_count)
236154133Sharti{
237154133Sharti	int pc;
238154133Sharti
239154133Sharti	if (hr_kd == NULL)
240154133Sharti		return (SNMP_ERR_GENERR);
241154133Sharti
242154133Sharti	if (kvm_getprocs(hr_kd, KERN_PROC_ALL, 0, &pc) == NULL) {
243154133Sharti		syslog(LOG_ERR, "kvm_getprocs failed: %m");
244154133Sharti		return (SNMP_ERR_GENERR);
245154133Sharti	}
246154133Sharti
247154133Sharti	*proc_count = pc;
248154133Sharti	return (SNMP_ERR_NOERROR);
249154133Sharti}
250154133Sharti
251154133Sharti/**
252154133Sharti * Get maximum number of processes allowed on this system
253154133Sharti */
254154133Shartistatic int
255154133ShartiOS_getSystemMaxProcesses(uint32_t *mproc)
256154133Sharti{
257154133Sharti
258154133Sharti	if (max_proc == 0) {
259154133Sharti		int mib[2] = { CTL_KERN, KERN_MAXPROC };
260154133Sharti		int mp;
261154133Sharti		size_t len = sizeof(mp);
262154133Sharti
263154133Sharti		if (sysctl(mib, 2, &mp, &len, NULL, 0) == -1) {
264154133Sharti			syslog(LOG_ERR, "sysctl KERN_MAXPROC failed: %m");
265154133Sharti			return (SNMP_ERR_GENERR);
266154133Sharti		}
267154133Sharti		max_proc = mp;
268154133Sharti	}
269154133Sharti
270154133Sharti	*mproc = max_proc;
271154133Sharti	return (SNMP_ERR_NOERROR);
272154133Sharti}
273154133Sharti
274154133Sharti/*
275154133Sharti * Get the physical memeory size in Kbytes.
276154133Sharti * Returns SNMP error code.
277154133Sharti */
278154133Shartistatic int
279154133ShartiOS_getMemorySize(uint32_t *ms)
280154133Sharti{
281154133Sharti
282154133Sharti	if (phys_mem_size == 0) {
283154133Sharti		int mib[2] = { CTL_HW, HW_PHYSMEM };
284154133Sharti		u_long physmem;
285154133Sharti		size_t len = sizeof(physmem);
286154133Sharti
287154133Sharti		if (sysctl(mib, 2, &physmem, &len, NULL, 0) == -1) {
288154133Sharti			syslog(LOG_ERR,
289154133Sharti			    "sysctl({ CTL_HW, HW_PHYSMEM }) failed: %m");
290154133Sharti			return (SNMP_ERR_GENERR);
291154133Sharti		}
292154133Sharti
293154133Sharti		phys_mem_size = physmem / 1024;
294154133Sharti	}
295154133Sharti
296154133Sharti	if (phys_mem_size > UINT32_MAX)
297154133Sharti		*ms = UINT32_MAX;
298154133Sharti	else
299154133Sharti		*ms = phys_mem_size;
300154133Sharti        return (SNMP_ERR_NOERROR);
301154133Sharti}
302154133Sharti
303154133Sharti/*
304154133Sharti * Try to use the s_date_time parameter as a DateAndTime TC to fill in
305154133Sharti * the second parameter.
306154133Sharti * Returns 0 on succes and -1 for an error.
307154133Sharti * Bug: time zone info is not used
308154133Sharti */
309154133Shartistatic struct timeval *
310154133ShartiOS_checkSystemDateInput(const u_char *str, u_int len)
311154133Sharti{
312154133Sharti	struct tm tm_to_set;
313154133Sharti	time_t t;
314154133Sharti	struct timeval *tv;
315154133Sharti
316154133Sharti	if (len != 8 && len != 11)
317154133Sharti		return (NULL);
318154133Sharti
319154133Sharti	if (str[2] == 0 || str[2] > 12 ||
320154133Sharti	    str[3] == 0 || str[3] > 31 ||
321154133Sharti	    str[4] > 23 || str[5] > 59 || str[6] > 60 || str[7] > 9)
322154133Sharti		return (NULL);
323154133Sharti
324154133Sharti	tm_to_set.tm_year = ((str[0] << 8) + str[1]) - 1900;
325154133Sharti	tm_to_set.tm_mon = str[2] - 1;
326154133Sharti	tm_to_set.tm_mday = str[3];
327154133Sharti	tm_to_set.tm_hour = str[4];
328154133Sharti	tm_to_set.tm_min = str[5];
329154133Sharti	tm_to_set.tm_sec = str[6];
330154133Sharti	tm_to_set.tm_isdst = 0;
331154133Sharti
332154133Sharti	/* now make UTC from it */
333154133Sharti	if ((t = timegm(&tm_to_set)) == (time_t)-1)
334154133Sharti		return (NULL);
335154133Sharti
336154133Sharti	/* now apply timezone if specified */
337154133Sharti	if (len == 11) {
338154133Sharti		if (str[9] > 13 || str[10] > 59)
339154133Sharti			return (NULL);
340154133Sharti		if (str[8] == '+')
341154133Sharti			t += 3600 * str[9] + 60 * str[10];
342154133Sharti		else
343154133Sharti			t -= 3600 * str[9] + 60 * str[10];
344154133Sharti	}
345154133Sharti
346154133Sharti	if ((tv = malloc(sizeof(*tv))) == NULL)
347154133Sharti		return (NULL);
348154133Sharti
349154133Sharti	tv->tv_sec = t;
350154133Sharti	tv->tv_usec = (int32_t)str[7] * 100000;
351154133Sharti
352154133Sharti	return (tv);
353154133Sharti}
354154133Sharti
355154133Sharti/*
356154133Sharti * Set system date and time. Timezone is not changed
357154133Sharti */
358154133Shartistatic int
359154133ShartiOS_setSystemDate(const struct timeval *timeval_to_set)
360154133Sharti{
361154133Sharti	if (settimeofday(timeval_to_set, NULL) == -1) {
362154133Sharti		syslog(LOG_ERR, "settimeofday failed: %m");
363154133Sharti		return (SNMP_ERR_GENERR);
364154133Sharti        }
365154133Sharti	return (SNMP_ERR_NOERROR);
366154133Sharti}
367154133Sharti
368154133Sharti/*
369154133Sharti * prototype of this function was genrated by gensnmptree tool in header file
370154133Sharti * hostres_tree.h
371154133Sharti * Returns SNMP_ERR_NOERROR on success
372154133Sharti */
373154133Shartiint
374154133Shartiop_hrSystem(struct snmp_context *ctx, struct snmp_value *value,
375154133Sharti    u_int sub, u_int iidx __unused, enum snmp_op curr_op)
376154133Sharti{
377154133Sharti	int err;
378154133Sharti	u_char *str;
379154133Sharti
380154133Sharti	switch (curr_op) {
381154133Sharti
382154133Sharti          case SNMP_OP_GET:
383154133Sharti		switch (value->var.subs[sub - 1]) {
384154133Sharti
385154133Sharti		case LEAF_hrSystemUptime:
386154133Sharti			return (OS_getSystemUptime(&value->v.uint32));
387154133Sharti
388154133Sharti		case LEAF_hrSystemDate:
389154133Sharti			return (OS_getSystemDate(value));
390154133Sharti
391154133Sharti		case LEAF_hrSystemInitialLoadDevice:
392154133Sharti			value->v.uint32 = 0; /* FIXME */
393154133Sharti			return (SNMP_ERR_NOERROR);
394154133Sharti
395154133Sharti		case LEAF_hrSystemInitialLoadParameters:
396154133Sharti			if ((err = OS_getSystemInitialLoadParameters(&str)) !=
397154133Sharti			    SNMP_ERR_NOERROR)
398154133Sharti				return (err);
399154133Sharti			return (string_get(value, str, -1));
400154133Sharti
401154133Sharti		case LEAF_hrSystemNumUsers:
402154133Sharti			return (OS_getSystemNumUsers(&value->v.uint32));
403154133Sharti
404154133Sharti		case LEAF_hrSystemProcesses:
405154133Sharti			return (OS_getSystemProcesses(&value->v.uint32));
406154133Sharti
407154133Sharti		case LEAF_hrSystemMaxProcesses:
408154133Sharti			return (OS_getSystemMaxProcesses(&value->v.uint32));
409154133Sharti		}
410154133Sharti		abort();
411154133Sharti
412154133Sharti	  case SNMP_OP_SET:
413154133Sharti		switch (value->var.subs[sub - 1]) {
414154133Sharti
415154133Sharti		case LEAF_hrSystemDate:
416154133Sharti			if ((ctx->scratch->ptr1 =
417154133Sharti			    OS_checkSystemDateInput(value->v.octetstring.octets,
418154133Sharti			    value->v.octetstring.len)) == NULL)
419154133Sharti				return (SNMP_ERR_WRONG_VALUE);
420154133Sharti
421154133Sharti			return (SNMP_ERR_NOERROR);
422154133Sharti
423154133Sharti		case LEAF_hrSystemInitialLoadDevice:
424154133Sharti		case LEAF_hrSystemInitialLoadParameters:
425154133Sharti			return (SNMP_ERR_NOT_WRITEABLE);
426154133Sharti
427154133Sharti		}
428154133Sharti		abort();
429154133Sharti
430154133Sharti	  case SNMP_OP_ROLLBACK:
431154133Sharti		switch (value->var.subs[sub - 1]) {
432154133Sharti
433154133Sharti		case LEAF_hrSystemDate:
434154133Sharti			free(ctx->scratch->ptr1);
435154133Sharti			return (SNMP_ERR_NOERROR);
436154133Sharti
437154133Sharti		case LEAF_hrSystemInitialLoadDevice:
438154133Sharti		case LEAF_hrSystemInitialLoadParameters:
439154133Sharti			abort();
440154133Sharti		}
441154133Sharti		abort();
442154133Sharti
443154133Sharti	  case SNMP_OP_COMMIT:
444154133Sharti		switch (value->var.subs[sub - 1]) {
445154133Sharti
446154133Sharti		case LEAF_hrSystemDate:
447154133Sharti			(void)OS_setSystemDate(ctx->scratch->ptr1);
448154133Sharti			free(ctx->scratch->ptr1);
449154133Sharti			return (SNMP_ERR_NOERROR);
450154133Sharti
451154133Sharti		case LEAF_hrSystemInitialLoadDevice:
452154133Sharti		case LEAF_hrSystemInitialLoadParameters:
453154133Sharti			abort();
454154133Sharti		}
455154133Sharti		abort();
456154133Sharti
457154133Sharti	  case SNMP_OP_GETNEXT:
458154133Sharti		abort();
459154133Sharti	}
460154133Sharti	abort();
461154133Sharti}
462154133Sharti
463154133Sharti/*
464154133Sharti * prototype of this function was genrated by gensnmptree tool
465154133Sharti * in the header file hostres_tree.h
466154133Sharti * Returns SNMP_ERR_NOERROR on success
467154133Sharti */
468154133Shartiint
469154133Shartiop_hrStorage(struct snmp_context *ctx __unused, struct snmp_value *value,
470154133Sharti    u_int sub, u_int iidx __unused, enum snmp_op curr_op)
471154133Sharti{
472154133Sharti
473154133Sharti	/* only GET is possible */
474154133Sharti	switch (curr_op) {
475154133Sharti
476154133Sharti	case SNMP_OP_GET:
477154133Sharti		switch (value->var.subs[sub - 1]) {
478154133Sharti
479154133Sharti		case LEAF_hrMemorySize:
480154133Sharti			return (OS_getMemorySize(&value->v.uint32));
481154133Sharti		}
482154133Sharti		abort();
483154133Sharti
484154133Sharti	case SNMP_OP_SET:
485154133Sharti		return (SNMP_ERR_NOT_WRITEABLE);
486154133Sharti
487154133Sharti	case SNMP_OP_ROLLBACK:
488154133Sharti	case SNMP_OP_COMMIT:
489154133Sharti	case SNMP_OP_GETNEXT:
490154133Sharti		abort();
491154133Sharti	}
492154133Sharti	abort();
493154133Sharti}
494