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: stable/11/usr.sbin/bsnmpd/modules/snmp_hostres/hostres_scalars.c 311719 2017-01-09 01:05:44Z ngie $ 30154133Sharti */ 31154133Sharti 32154133Sharti/* 33154133Sharti * Host Resources MIB scalars implementation for SNMPd. 34154133Sharti */ 35154133Sharti 36311719Sngie#include <sys/param.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> 44202206Sed#include <utmpx.h> 45154133Sharti 46154133Sharti#include "hostres_snmp.h" 47154133Sharti#include "hostres_oid.h" 48154133Sharti#include "hostres_tree.h" 49154133Sharti 50154133Sharti/* boot timestamp in centi-seconds */ 51154133Shartistatic uint64_t kernel_boot; 52154133Sharti 53154133Sharti/* physical memory size in Kb */ 54154133Shartistatic uint64_t phys_mem_size; 55154133Sharti 56154133Sharti/* boot line (malloced) */ 57154133Shartistatic u_char *boot_line; 58154133Sharti 59154133Sharti/* maximum number of processes */ 60154133Shartistatic uint32_t max_proc; 61154133Sharti 62154133Sharti/** 63154133Sharti * Free all static data 64154133Sharti */ 65154133Shartivoid 66154133Shartifini_scalars(void) 67154133Sharti{ 68154133Sharti 69154133Sharti free(boot_line); 70154133Sharti} 71154133Sharti 72154133Sharti/** 73154133Sharti * Get system uptime in hundredths of seconds since the epoch 74154133Sharti * Returns 0 in case of an error 75154133Sharti */ 76154133Shartistatic int 77154133ShartiOS_getSystemUptime(uint32_t *ut) 78154133Sharti{ 79154133Sharti struct timeval right_now; 80154133Sharti uint64_t now; 81154133Sharti 82154133Sharti if (kernel_boot == 0) { 83154133Sharti /* first time, do the sysctl */ 84154133Sharti struct timeval kernel_boot_timestamp; 85154133Sharti int mib[2] = { CTL_KERN, KERN_BOOTTIME }; 86154133Sharti size_t len = sizeof(kernel_boot_timestamp); 87154133Sharti 88311719Sngie if (sysctl(mib, nitems(mib), &kernel_boot_timestamp, 89154133Sharti &len, NULL, 0) == -1) { 90154133Sharti syslog(LOG_ERR, "sysctl KERN_BOOTTIME failed: %m"); 91154133Sharti return (SNMP_ERR_GENERR); 92154133Sharti } 93154133Sharti 94154249Sharti HRDBG("boot timestamp from kernel: {%lld, %ld}", 95154249Sharti (long long)kernel_boot_timestamp.tv_sec, 96154249Sharti (long)kernel_boot_timestamp.tv_usec); 97154133Sharti 98154133Sharti kernel_boot = ((uint64_t)kernel_boot_timestamp.tv_sec * 100) + 99154133Sharti (kernel_boot_timestamp.tv_usec / 10000); 100154133Sharti } 101154133Sharti 102154133Sharti if (gettimeofday(&right_now, NULL) < 0) { 103154133Sharti syslog(LOG_ERR, "gettimeofday failed: %m"); 104154133Sharti return (SNMP_ERR_GENERR); 105154133Sharti } 106154133Sharti now = ((uint64_t)right_now.tv_sec * 100) + (right_now.tv_usec / 10000); 107154133Sharti 108154133Sharti if (now - kernel_boot > UINT32_MAX) 109154133Sharti *ut = UINT32_MAX; 110154133Sharti else 111154133Sharti *ut = now - kernel_boot; 112154133Sharti 113154133Sharti return (SNMP_ERR_NOERROR); 114154133Sharti} 115154133Sharti 116154133Sharti/** 117154133Sharti * Get system local date and time in a foramt suitable for DateAndTime TC: 118154133Sharti * field octets contents range 119154133Sharti * ----- ------ -------- ----- 120154133Sharti * 1 1-2 year* 0..65536 121154133Sharti * 2 3 month 1..12 122154133Sharti * 3 4 day 1..31 123154133Sharti * 4 5 hour 0..23 124154133Sharti * 5 6 minutes 0..59 125154133Sharti * 6 7 seconds 0..60 126154133Sharti * (use 60 for leap-second) 127154133Sharti * 7 8 deci-seconds 0..9 128154133Sharti * 8 9 direction from UTC '+' / '-' 129154133Sharti * 9 10 hours from UTC* 0..13 130154133Sharti * 10 11 minutes from UTC 0..59 131154133Sharti * 132154133Sharti * * Notes: 133154133Sharti * - the value of year is in network-byte order 134154133Sharti * - daylight saving time in New Zealand is +13 135154133Sharti * 136154133Sharti * For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be 137154133Sharti * displayed as: 138154133Sharti * 139154133Sharti * 1992-5-26,13:30:15.0,-4:0 140154133Sharti * 141154133Sharti * Returns -1 in case of an error or the length of the string (8 or 11) 142154133Sharti * Actually returns always 11 on freebsd 143154133Sharti */ 144154133Shartistatic int 145154133ShartiOS_getSystemDate(struct snmp_value *value) 146154133Sharti{ 147154133Sharti u_char s_date_time[11]; 148154133Sharti struct tm tloc_tm; 149154133Sharti time_t tloc_time_t; 150154133Sharti struct timeval right_now; 151154133Sharti int string_len; 152154133Sharti 153154133Sharti if (gettimeofday(&right_now, NULL) < 0) { 154154133Sharti syslog(LOG_ERR, "gettimeofday failed: %m"); 155154133Sharti return (SNMP_ERR_GENERR); 156154133Sharti } 157154133Sharti 158154133Sharti tloc_time_t = right_now.tv_sec; 159154133Sharti 160154133Sharti if (localtime_r(&tloc_time_t, &tloc_tm) == NULL) { 161154133Sharti syslog(LOG_ERR, "localtime_r() failed: %m "); 162154133Sharti return (SNMP_ERR_GENERR); 163154133Sharti } 164154133Sharti 165154133Sharti string_len = make_date_time(s_date_time, &tloc_tm, 166154133Sharti right_now.tv_usec / 100000); 167154133Sharti 168154133Sharti return (string_get(value, s_date_time, string_len)); 169154133Sharti} 170154133Sharti 171154133Sharti/** 172154133Sharti * Get kernel boot path. For FreeBSD it seems that no arguments are 173228990Suqs * present. Returns NULL if an error occurred. The returned data is a 174228990Suqs * pointer to a global storage. 175154133Sharti */ 176154133Shartiint 177154133ShartiOS_getSystemInitialLoadParameters(u_char **params) 178154133Sharti{ 179154133Sharti 180154133Sharti if (boot_line == NULL) { 181154133Sharti int mib[2] = { CTL_KERN, KERN_BOOTFILE }; 182154133Sharti char *buf; 183154133Sharti size_t buf_len = 0; 184154133Sharti 185154133Sharti /* get the needed buffer len */ 186154133Sharti if (sysctl(mib, 2, NULL, &buf_len, NULL, 0) != 0) { 187154133Sharti syslog(LOG_ERR, 188154133Sharti "sysctl({CTL_KERN,KERN_BOOTFILE}) failed: %m"); 189154133Sharti return (SNMP_ERR_GENERR); 190154133Sharti } 191154133Sharti 192154133Sharti if ((buf = malloc(buf_len)) == NULL) { 193154133Sharti syslog(LOG_ERR, "malloc failed"); 194154133Sharti return (SNMP_ERR_GENERR); 195154133Sharti } 196310899Sngie if (sysctl(mib, 2, buf, &buf_len, NULL, 0)) { 197154133Sharti syslog(LOG_ERR, 198154133Sharti "sysctl({CTL_KERN,KERN_BOOTFILE}) failed: %m"); 199154133Sharti free(buf); 200154133Sharti return (SNMP_ERR_GENERR); 201154133Sharti } 202154133Sharti 203154133Sharti boot_line = buf; 204154133Sharti HRDBG("kernel boot file: %s", boot_line); 205154133Sharti } 206154133Sharti 207154133Sharti *params = boot_line; 208154133Sharti return (SNMP_ERR_NOERROR); 209154133Sharti} 210154133Sharti 211154133Sharti/** 212154133Sharti * Get number of current users which are logged in 213154133Sharti */ 214154133Shartistatic int 215154133ShartiOS_getSystemNumUsers(uint32_t *nu) 216154133Sharti{ 217200953Sed struct utmpx *utmp; 218154133Sharti 219200953Sed setutxent(); 220154133Sharti *nu = 0; 221200953Sed while ((utmp = getutxent()) != NULL) { 222200953Sed if (utmp->ut_type == USER_PROCESS) 223154133Sharti (*nu)++; 224154133Sharti } 225200953Sed endutxent(); 226154133Sharti 227154133Sharti return (SNMP_ERR_NOERROR); 228154133Sharti} 229154133Sharti 230154133Sharti/** 231154133Sharti * Get number of current processes existing into the system 232154133Sharti */ 233154133Shartistatic int 234154133ShartiOS_getSystemProcesses(uint32_t *proc_count) 235154133Sharti{ 236154133Sharti int pc; 237154133Sharti 238154133Sharti if (hr_kd == NULL) 239154133Sharti return (SNMP_ERR_GENERR); 240154133Sharti 241240354Sglebius if (kvm_getprocs(hr_kd, KERN_PROC_PROC, 0, &pc) == NULL) { 242154133Sharti syslog(LOG_ERR, "kvm_getprocs failed: %m"); 243154133Sharti return (SNMP_ERR_GENERR); 244154133Sharti } 245154133Sharti 246154133Sharti *proc_count = pc; 247154133Sharti return (SNMP_ERR_NOERROR); 248154133Sharti} 249154133Sharti 250154133Sharti/** 251154133Sharti * Get maximum number of processes allowed on this system 252154133Sharti */ 253154133Shartistatic int 254154133ShartiOS_getSystemMaxProcesses(uint32_t *mproc) 255154133Sharti{ 256154133Sharti 257154133Sharti if (max_proc == 0) { 258154133Sharti int mib[2] = { CTL_KERN, KERN_MAXPROC }; 259154133Sharti int mp; 260154133Sharti size_t len = sizeof(mp); 261154133Sharti 262154133Sharti if (sysctl(mib, 2, &mp, &len, NULL, 0) == -1) { 263154133Sharti syslog(LOG_ERR, "sysctl KERN_MAXPROC failed: %m"); 264154133Sharti return (SNMP_ERR_GENERR); 265154133Sharti } 266154133Sharti max_proc = mp; 267154133Sharti } 268154133Sharti 269154133Sharti *mproc = max_proc; 270154133Sharti return (SNMP_ERR_NOERROR); 271154133Sharti} 272154133Sharti 273154133Sharti/* 274154133Sharti * Get the physical memeory size in Kbytes. 275154133Sharti * Returns SNMP error code. 276154133Sharti */ 277154133Shartistatic int 278154133ShartiOS_getMemorySize(uint32_t *ms) 279154133Sharti{ 280154133Sharti 281154133Sharti if (phys_mem_size == 0) { 282154133Sharti int mib[2] = { CTL_HW, HW_PHYSMEM }; 283154133Sharti u_long physmem; 284154133Sharti size_t len = sizeof(physmem); 285154133Sharti 286154133Sharti if (sysctl(mib, 2, &physmem, &len, NULL, 0) == -1) { 287154133Sharti syslog(LOG_ERR, 288154133Sharti "sysctl({ CTL_HW, HW_PHYSMEM }) failed: %m"); 289154133Sharti return (SNMP_ERR_GENERR); 290154133Sharti } 291154133Sharti 292154133Sharti phys_mem_size = physmem / 1024; 293154133Sharti } 294154133Sharti 295154133Sharti if (phys_mem_size > UINT32_MAX) 296154133Sharti *ms = UINT32_MAX; 297154133Sharti else 298154133Sharti *ms = phys_mem_size; 299310899Sngie return (SNMP_ERR_NOERROR); 300154133Sharti} 301154133Sharti 302154133Sharti/* 303154133Sharti * Try to use the s_date_time parameter as a DateAndTime TC to fill in 304154133Sharti * the second parameter. 305154133Sharti * Returns 0 on succes and -1 for an error. 306154133Sharti * Bug: time zone info is not used 307154133Sharti */ 308154133Shartistatic struct timeval * 309154133ShartiOS_checkSystemDateInput(const u_char *str, u_int len) 310154133Sharti{ 311154133Sharti struct tm tm_to_set; 312154133Sharti time_t t; 313154133Sharti struct timeval *tv; 314154133Sharti 315154133Sharti if (len != 8 && len != 11) 316154133Sharti return (NULL); 317154133Sharti 318154133Sharti if (str[2] == 0 || str[2] > 12 || 319154133Sharti str[3] == 0 || str[3] > 31 || 320154133Sharti str[4] > 23 || str[5] > 59 || str[6] > 60 || str[7] > 9) 321154133Sharti return (NULL); 322154133Sharti 323154133Sharti tm_to_set.tm_year = ((str[0] << 8) + str[1]) - 1900; 324154133Sharti tm_to_set.tm_mon = str[2] - 1; 325154133Sharti tm_to_set.tm_mday = str[3]; 326154133Sharti tm_to_set.tm_hour = str[4]; 327154133Sharti tm_to_set.tm_min = str[5]; 328154133Sharti tm_to_set.tm_sec = str[6]; 329154133Sharti tm_to_set.tm_isdst = 0; 330154133Sharti 331154133Sharti /* now make UTC from it */ 332154133Sharti if ((t = timegm(&tm_to_set)) == (time_t)-1) 333154133Sharti return (NULL); 334154133Sharti 335154133Sharti /* now apply timezone if specified */ 336154133Sharti if (len == 11) { 337154133Sharti if (str[9] > 13 || str[10] > 59) 338154133Sharti return (NULL); 339154133Sharti if (str[8] == '+') 340154133Sharti t += 3600 * str[9] + 60 * str[10]; 341154133Sharti else 342154133Sharti t -= 3600 * str[9] + 60 * str[10]; 343154133Sharti } 344154133Sharti 345154133Sharti if ((tv = malloc(sizeof(*tv))) == NULL) 346154133Sharti return (NULL); 347154133Sharti 348154133Sharti tv->tv_sec = t; 349154133Sharti tv->tv_usec = (int32_t)str[7] * 100000; 350154133Sharti 351154133Sharti return (tv); 352154133Sharti} 353154133Sharti 354154133Sharti/* 355154133Sharti * Set system date and time. Timezone is not changed 356154133Sharti */ 357154133Shartistatic int 358154133ShartiOS_setSystemDate(const struct timeval *timeval_to_set) 359154133Sharti{ 360154133Sharti if (settimeofday(timeval_to_set, NULL) == -1) { 361154133Sharti syslog(LOG_ERR, "settimeofday failed: %m"); 362154133Sharti return (SNMP_ERR_GENERR); 363310899Sngie } 364154133Sharti return (SNMP_ERR_NOERROR); 365154133Sharti} 366154133Sharti 367154133Sharti/* 368154133Sharti * prototype of this function was genrated by gensnmptree tool in header file 369154133Sharti * hostres_tree.h 370154133Sharti * Returns SNMP_ERR_NOERROR on success 371154133Sharti */ 372154133Shartiint 373154133Shartiop_hrSystem(struct snmp_context *ctx, struct snmp_value *value, 374154133Sharti u_int sub, u_int iidx __unused, enum snmp_op curr_op) 375154133Sharti{ 376154133Sharti int err; 377154133Sharti u_char *str; 378154133Sharti 379154133Sharti switch (curr_op) { 380154133Sharti 381310899Sngie case SNMP_OP_GET: 382154133Sharti switch (value->var.subs[sub - 1]) { 383154133Sharti 384154133Sharti case LEAF_hrSystemUptime: 385154133Sharti return (OS_getSystemUptime(&value->v.uint32)); 386154133Sharti 387154133Sharti case LEAF_hrSystemDate: 388154133Sharti return (OS_getSystemDate(value)); 389154133Sharti 390154133Sharti case LEAF_hrSystemInitialLoadDevice: 391154133Sharti value->v.uint32 = 0; /* FIXME */ 392154133Sharti return (SNMP_ERR_NOERROR); 393154133Sharti 394154133Sharti case LEAF_hrSystemInitialLoadParameters: 395154133Sharti if ((err = OS_getSystemInitialLoadParameters(&str)) != 396154133Sharti SNMP_ERR_NOERROR) 397154133Sharti return (err); 398154133Sharti return (string_get(value, str, -1)); 399154133Sharti 400154133Sharti case LEAF_hrSystemNumUsers: 401154133Sharti return (OS_getSystemNumUsers(&value->v.uint32)); 402154133Sharti 403154133Sharti case LEAF_hrSystemProcesses: 404154133Sharti return (OS_getSystemProcesses(&value->v.uint32)); 405154133Sharti 406154133Sharti case LEAF_hrSystemMaxProcesses: 407154133Sharti return (OS_getSystemMaxProcesses(&value->v.uint32)); 408154133Sharti } 409154133Sharti abort(); 410154133Sharti 411154133Sharti case SNMP_OP_SET: 412154133Sharti switch (value->var.subs[sub - 1]) { 413154133Sharti 414154133Sharti case LEAF_hrSystemDate: 415154133Sharti if ((ctx->scratch->ptr1 = 416154133Sharti OS_checkSystemDateInput(value->v.octetstring.octets, 417154133Sharti value->v.octetstring.len)) == NULL) 418154133Sharti return (SNMP_ERR_WRONG_VALUE); 419154133Sharti 420154133Sharti return (SNMP_ERR_NOERROR); 421154133Sharti 422154133Sharti case LEAF_hrSystemInitialLoadDevice: 423154133Sharti case LEAF_hrSystemInitialLoadParameters: 424154133Sharti return (SNMP_ERR_NOT_WRITEABLE); 425154133Sharti 426154133Sharti } 427154133Sharti abort(); 428154133Sharti 429154133Sharti case SNMP_OP_ROLLBACK: 430154133Sharti switch (value->var.subs[sub - 1]) { 431154133Sharti 432154133Sharti case LEAF_hrSystemDate: 433154133Sharti free(ctx->scratch->ptr1); 434154133Sharti return (SNMP_ERR_NOERROR); 435154133Sharti 436154133Sharti case LEAF_hrSystemInitialLoadDevice: 437154133Sharti case LEAF_hrSystemInitialLoadParameters: 438154133Sharti abort(); 439154133Sharti } 440154133Sharti abort(); 441154133Sharti 442154133Sharti case SNMP_OP_COMMIT: 443154133Sharti switch (value->var.subs[sub - 1]) { 444154133Sharti 445154133Sharti case LEAF_hrSystemDate: 446154133Sharti (void)OS_setSystemDate(ctx->scratch->ptr1); 447154133Sharti free(ctx->scratch->ptr1); 448154133Sharti return (SNMP_ERR_NOERROR); 449154133Sharti 450154133Sharti case LEAF_hrSystemInitialLoadDevice: 451154133Sharti case LEAF_hrSystemInitialLoadParameters: 452154133Sharti abort(); 453154133Sharti } 454154133Sharti abort(); 455154133Sharti 456154133Sharti case SNMP_OP_GETNEXT: 457154133Sharti abort(); 458154133Sharti } 459154133Sharti abort(); 460154133Sharti} 461154133Sharti 462154133Sharti/* 463154133Sharti * prototype of this function was genrated by gensnmptree tool 464154133Sharti * in the header file hostres_tree.h 465154133Sharti * Returns SNMP_ERR_NOERROR on success 466154133Sharti */ 467154133Shartiint 468154133Shartiop_hrStorage(struct snmp_context *ctx __unused, struct snmp_value *value, 469154133Sharti u_int sub, u_int iidx __unused, enum snmp_op curr_op) 470154133Sharti{ 471154133Sharti 472154133Sharti /* only GET is possible */ 473154133Sharti switch (curr_op) { 474154133Sharti 475154133Sharti case SNMP_OP_GET: 476154133Sharti switch (value->var.subs[sub - 1]) { 477154133Sharti 478154133Sharti case LEAF_hrMemorySize: 479154133Sharti return (OS_getMemorySize(&value->v.uint32)); 480154133Sharti } 481154133Sharti abort(); 482154133Sharti 483154133Sharti case SNMP_OP_SET: 484154133Sharti return (SNMP_ERR_NOT_WRITEABLE); 485154133Sharti 486154133Sharti case SNMP_OP_ROLLBACK: 487154133Sharti case SNMP_OP_COMMIT: 488154133Sharti case SNMP_OP_GETNEXT: 489154133Sharti abort(); 490154133Sharti } 491154133Sharti abort(); 492154133Sharti} 493