Blame snmplib/system.c

Packit fcad23
/*
Packit fcad23
 * system.c
Packit fcad23
 */
Packit fcad23
/* Portions of this file are subject to the following copyright(s).  See
Packit fcad23
 * the Net-SNMP's COPYING file for more details and other copyrights
Packit fcad23
 * that may apply:
Packit fcad23
 */
Packit fcad23
/***********************************************************
Packit fcad23
        Copyright 1992 by Carnegie Mellon University
Packit fcad23
Packit fcad23
                      All Rights Reserved
Packit fcad23
Packit fcad23
Permission to use, copy, modify, and distribute this software and its
Packit fcad23
documentation for any purpose and without fee is hereby granted,
Packit fcad23
provided that the above copyright notice appear in all copies and that
Packit fcad23
both that copyright notice and this permission notice appear in
Packit fcad23
supporting documentation, and that the name of CMU not be
Packit fcad23
used in advertising or publicity pertaining to distribution of the
Packit fcad23
software without specific, written prior permission.
Packit fcad23
Packit fcad23
CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
Packit fcad23
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
Packit fcad23
CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
Packit fcad23
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
Packit fcad23
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
Packit fcad23
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
Packit fcad23
SOFTWARE.
Packit fcad23
******************************************************************/
Packit fcad23
/*
Packit fcad23
 * Portions of this file are copyrighted by:
Packit fcad23
 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
Packit fcad23
 * Use is subject to license terms specified in the COPYING file
Packit fcad23
 * distributed with the Net-SNMP package.
Packit fcad23
 */
Packit fcad23
/*
Packit fcad23
 * Portions of this file are copyrighted by:
Packit fcad23
 * Copyright (C) 2007 Apple, Inc. All rights reserved.
Packit fcad23
 * Use is subject to license terms specified in the COPYING file
Packit fcad23
 * distributed with the Net-SNMP package.
Packit fcad23
 *
Packit fcad23
 * Portions of this file are copyrighted by:
Packit fcad23
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
Packit fcad23
 * Use is subject to license terms specified in the COPYING file
Packit fcad23
 * distributed with the Net-SNMP package.
Packit fcad23
 */
Packit fcad23
/*
Packit fcad23
 * System dependent routines go here
Packit fcad23
 */
Packit fcad23
#include <net-snmp/net-snmp-config.h>
Packit fcad23
#include <net-snmp/net-snmp-features.h>
Packit fcad23
#include <stdio.h>
Packit fcad23
#include <ctype.h>
Packit fcad23
#include <errno.h>
Packit fcad23
Packit fcad23
#if HAVE_IO_H
Packit fcad23
#include <io.h>
Packit fcad23
#endif
Packit fcad23
#if HAVE_DIRECT_H
Packit fcad23
#include <direct.h>
Packit fcad23
#endif
Packit fcad23
#if HAVE_UNISTD_H
Packit fcad23
#include <unistd.h>
Packit fcad23
#endif
Packit fcad23
#if HAVE_STDLIB_H
Packit fcad23
#include <stdlib.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#if TIME_WITH_SYS_TIME
Packit fcad23
# include <sys/time.h>
Packit fcad23
# include <time.h>
Packit fcad23
#else
Packit fcad23
# if HAVE_SYS_TIME_H
Packit fcad23
#  include <sys/time.h>
Packit fcad23
# else
Packit fcad23
#  include <time.h>
Packit fcad23
# endif
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#include <sys/types.h>
Packit fcad23
Packit fcad23
#if HAVE_NETINET_IN_H
Packit fcad23
#include <netinet/in.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#if HAVE_SYS_SOCKET_H
Packit fcad23
#include <sys/socket.h>
Packit fcad23
#endif
Packit fcad23
#if HAVE_NET_IF_H
Packit fcad23
#include <net/if.h>
Packit fcad23
#endif
Packit fcad23
#if HAVE_NETDB_H
Packit fcad23
#include <netdb.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
Packit fcad23
#if HAVE_SYS_SOCKIO_H
Packit fcad23
#include <sys/sockio.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#if HAVE_SYS_IOCTL_H
Packit fcad23
#include <sys/ioctl.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#ifdef HAVE_NLIST_H
Packit fcad23
#include <nlist.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#if HAVE_SYS_FILE_H
Packit fcad23
#include <sys/file.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#if HAVE_KSTAT_H
Packit fcad23
#include <kstat.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#if HAVE_SYS_PARAM_H
Packit fcad23
#include <sys/param.h>
Packit fcad23
#endif
Packit fcad23
#if HAVE_SYS_SYSCTL_H
Packit fcad23
#include <sys/sysctl.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#if HAVE_STRING_H
Packit fcad23
#include <string.h>
Packit fcad23
#else
Packit fcad23
#include <strings.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#if HAVE_DMALLOC_H
Packit fcad23
#include <dmalloc.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#ifdef HAVE_SYS_STAT_H
Packit fcad23
#include <sys/stat.h>
Packit fcad23
#endif
Packit fcad23
#if HAVE_FCNTL_H
Packit fcad23
#include <fcntl.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#if defined(hpux10) || defined(hpux11)
Packit fcad23
#include <sys/pstat.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#if HAVE_SYS_UTSNAME_H
Packit fcad23
#include <sys/utsname.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#if HAVE_SYS_SYSTEMCFG_H
Packit fcad23
#include <sys/systemcfg.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#if HAVE_SYS_SYSTEMINFO_H
Packit fcad23
#include <sys/systeminfo.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#if defined(darwin9)
Packit fcad23
#include <crt_externs.h>        /* for _NSGetArgv() */
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#if HAVE_PWD_H
Packit fcad23
#include <pwd.h>
Packit fcad23
#endif
Packit fcad23
#if HAVE_GRP_H
Packit fcad23
#include <grp.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#if HAVE_LIMITS_H
Packit fcad23
#include <limits.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#if HAVE_ARPA_INET_H
Packit fcad23
#include <arpa/inet.h>
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#ifdef DNSSEC_LOCAL_VALIDATION
Packit fcad23
#if 1 /*HAVE_ARPA_NAMESER_H*/
Packit fcad23
#include <arpa/nameser.h>
Packit fcad23
#endif
Packit fcad23
#include <validator/validator.h>
Packit fcad23
/* NetSNMP and DNSSEC-Tools both define FREE. We'll not use either here. */
Packit fcad23
#undef FREE
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#include <net-snmp/types.h>
Packit fcad23
#include <net-snmp/output_api.h>
Packit fcad23
#include <net-snmp/utilities.h>
Packit fcad23
#include <net-snmp/library/system.h>    /* for "internal" definitions */
Packit fcad23
Packit fcad23
#include <net-snmp/library/snmp_api.h>
Packit fcad23
#include <net-snmp/library/read_config.h> /* for get_temp_file_pattern() */
Packit fcad23
Packit fcad23
#include "inet_ntop.h"
Packit fcad23
Packit fcad23
/* NetSNMP and DNSSEC-Tools both define FREE. We'll not use either here. */
Packit fcad23
#undef FREE
Packit fcad23
Packit fcad23
netsnmp_feature_child_of(system_all, libnetsnmp)
Packit fcad23
Packit fcad23
netsnmp_feature_child_of(user_information, system_all)
Packit fcad23
netsnmp_feature_child_of(calculate_sectime_diff, system_all)
Packit fcad23
Packit fcad23
#ifndef IFF_LOOPBACK
Packit fcad23
#	define IFF_LOOPBACK 0
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#ifdef  INADDR_LOOPBACK
Packit fcad23
# define LOOPBACK    INADDR_LOOPBACK
Packit fcad23
#else
Packit fcad23
# define LOOPBACK    0x7f000001
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#ifndef EAI_FAIL
Packit fcad23
# define EAI_FAIL    -4    /* Non-recoverable failure in name res.  */
Packit fcad23
#endif
Packit fcad23
Packit fcad23
#if defined(HAVE_FORK)
Packit fcad23
static void
Packit fcad23
_daemon_prep(int stderr_log)
Packit fcad23
{
Packit fcad23
    int fd;
Packit fcad23
Packit fcad23
    /* Avoid keeping any directory in use. */
Packit fcad23
    chdir("/");
Packit fcad23
Packit fcad23
    if (stderr_log)
Packit fcad23
        return;
Packit fcad23
Packit fcad23
    fd = open("/dev/null", O_RDWR);
Packit fcad23
    
Packit fcad23
    /*
Packit fcad23
     * Close inherited file descriptors to avoid
Packit fcad23
     * keeping unnecessary references.
Packit fcad23
     */
Packit fcad23
    close(STDIN_FILENO);
Packit fcad23
    close(STDOUT_FILENO);
Packit fcad23
    close(STDERR_FILENO);
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * Redirect std{in,out,err} to /dev/null, just in case.
Packit fcad23
     */
Packit fcad23
    if (fd >= 0) {
Packit fcad23
        dup2(fd, STDIN_FILENO);
Packit fcad23
        dup2(fd, STDOUT_FILENO);
Packit fcad23
        dup2(fd, STDERR_FILENO);
Packit fcad23
        close(fd);
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
#endif
Packit fcad23
Packit fcad23
/**
Packit fcad23
 * fork current process into the background.
Packit fcad23
 *
Packit fcad23
 * This function forks a process into the background, in order to
Packit fcad23
 * become a daemon process. It does a few things along the way:
Packit fcad23
 *
Packit fcad23
 * - becoming a process/session group leader, and  forking a second time so
Packit fcad23
 *   that process/session group leader can exit.
Packit fcad23
 *
Packit fcad23
 * - changing the working directory to /
Packit fcad23
 *
Packit fcad23
 * - closing stdin, stdout and stderr (unless stderr_log is set) and
Packit fcad23
 *   redirecting them to /dev/null
Packit fcad23
 *
Packit fcad23
 * @param quit_immediately : indicates if the parent process should
Packit fcad23
 *                           exit after a successful fork.
Packit fcad23
 * @param stderr_log       : indicates if stderr is being used for
Packit fcad23
 *                           logging and shouldn't be closed
Packit fcad23
 * @returns -1 : fork error
Packit fcad23
 *           0 : child process returning
Packit fcad23
 *          >0 : parent process returning. returned value is the child PID.
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
netsnmp_daemonize(int quit_immediately, int stderr_log)
Packit fcad23
{
Packit fcad23
    int i = 0;
Packit fcad23
    DEBUGMSGT(("daemonize","deamonizing...\n"));
Packit fcad23
#if HAVE_FORK
Packit fcad23
#if defined(darwin9)
Packit fcad23
     char            path [PATH_MAX] = "";
Packit fcad23
     uint32_t        size = sizeof (path);
Packit fcad23
Packit fcad23
     /*
Packit fcad23
      * if we are already launched in a "daemonized state", just
Packit fcad23
      * close & redirect the file descriptors
Packit fcad23
      */
Packit fcad23
     if(getppid() <= 2) {
Packit fcad23
         _daemon_prep(stderr_log);
Packit fcad23
         return 0;
Packit fcad23
     }
Packit fcad23
Packit fcad23
     if (_NSGetExecutablePath (path, &size))
Packit fcad23
         return -1;
Packit fcad23
#endif
Packit fcad23
    /*
Packit fcad23
     * Fork to return control to the invoking process and to
Packit fcad23
     * guarantee that we aren't a process group leader.
Packit fcad23
     */
Packit fcad23
#if HAVE_FORKALL
Packit fcad23
    i = forkall();
Packit fcad23
#else
Packit fcad23
    i = fork();
Packit fcad23
#endif
Packit fcad23
    if (i != 0) {
Packit fcad23
        /* Parent. */
Packit fcad23
        DEBUGMSGT(("daemonize","first fork returned %d.\n", i));
Packit fcad23
        if(i == -1) {
Packit fcad23
            snmp_log(LOG_ERR,"first fork failed (errno %d) in "
Packit fcad23
                     "netsnmp_daemonize()\n", errno);
Packit fcad23
            return -1;
Packit fcad23
        }
Packit fcad23
        if (quit_immediately) {
Packit fcad23
            DEBUGMSGT(("daemonize","parent exiting\n"));
Packit fcad23
            exit(0);
Packit fcad23
        }
Packit fcad23
    } else {
Packit fcad23
        /* Child. */
Packit fcad23
#ifdef HAVE_SETSID
Packit fcad23
        /* Become a process/session group leader. */
Packit fcad23
        setsid();
Packit fcad23
#endif
Packit fcad23
        /*
Packit fcad23
         * Fork to let the process/session group leader exit.
Packit fcad23
         */
Packit fcad23
#if HAVE_FORKALL
Packit fcad23
	i = forkall();
Packit fcad23
#else
Packit fcad23
	i = fork();
Packit fcad23
#endif
Packit fcad23
        if (i != 0) {
Packit fcad23
            DEBUGMSGT(("daemonize","second fork returned %d.\n", i));
Packit fcad23
            if(i == -1) {
Packit fcad23
                snmp_log(LOG_ERR,"second fork failed (errno %d) in "
Packit fcad23
                         "netsnmp_daemonize()\n", errno);
Packit fcad23
            }
Packit fcad23
            /* Parent. */
Packit fcad23
            exit(0);
Packit fcad23
        }
Packit fcad23
#ifndef WIN32
Packit fcad23
        else {
Packit fcad23
            /* Child. */
Packit fcad23
            
Packit fcad23
            DEBUGMSGT(("daemonize","child continuing\n"));
Packit fcad23
Packit fcad23
#if ! defined(darwin9)
Packit fcad23
            _daemon_prep(stderr_log);
Packit fcad23
#else
Packit fcad23
             /*
Packit fcad23
              * Some darwin calls (using mach ports) don't work after
Packit fcad23
              * a fork. So, now that we've forked, we re-exec ourself
Packit fcad23
              * to ensure that the child's mach ports are all set up correctly,
Packit fcad23
              * the getppid call above will prevent the exec child from
Packit fcad23
              * forking...
Packit fcad23
              */
Packit fcad23
             char * const *argv = *_NSGetArgv ();
Packit fcad23
             DEBUGMSGT(("daemonize","re-execing forked child\n"));
Packit fcad23
             execv (path, argv);
Packit fcad23
             snmp_log(LOG_ERR,"Forked child unable to re-exec - %s.\n", strerror (errno));
Packit fcad23
             exit (0);
Packit fcad23
#endif
Packit fcad23
        }
Packit fcad23
#endif /* !WIN32 */
Packit fcad23
    }
Packit fcad23
#endif /* HAVE_FORK */
Packit fcad23
    return i;
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * ********************************************* 
Packit fcad23
 */
Packit fcad23
#ifdef							WIN32
Packit fcad23
in_addr_t
Packit fcad23
get_myaddr(void)
Packit fcad23
{
Packit fcad23
    char            local_host[130];
Packit fcad23
    int             result;
Packit fcad23
    LPHOSTENT       lpstHostent;
Packit fcad23
    SOCKADDR_IN     in_addr, remote_in_addr;
Packit fcad23
    SOCKET          hSock;
Packit fcad23
    int             nAddrSize = sizeof(SOCKADDR);
Packit fcad23
Packit fcad23
    in_addr.sin_addr.s_addr = INADDR_ANY;
Packit fcad23
Packit fcad23
    result = gethostname(local_host, sizeof(local_host));
Packit fcad23
    if (result == 0) {
Packit fcad23
        lpstHostent = gethostbyname((LPSTR) local_host);
Packit fcad23
        if (lpstHostent) {
Packit fcad23
            in_addr.sin_addr.s_addr =
Packit fcad23
                *((u_long FAR *) (lpstHostent->h_addr));
Packit fcad23
            return ((in_addr_t) in_addr.sin_addr.s_addr);
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * if we are here, than we don't have host addr 
Packit fcad23
     */
Packit fcad23
    hSock = socket(AF_INET, SOCK_DGRAM, 0);
Packit fcad23
    if (hSock != INVALID_SOCKET) {
Packit fcad23
        /*
Packit fcad23
         * connect to any port and address 
Packit fcad23
         */
Packit fcad23
        remote_in_addr.sin_family = AF_INET;
Packit fcad23
        remote_in_addr.sin_port = htons(IPPORT_ECHO);
Packit fcad23
        remote_in_addr.sin_addr.s_addr = inet_addr("0.0.0.0");
Packit fcad23
        result =
Packit fcad23
            connect(hSock, (LPSOCKADDR) & remote_in_addr,
Packit fcad23
                    sizeof(SOCKADDR));
Packit fcad23
        if (result != SOCKET_ERROR) {
Packit fcad23
            /*
Packit fcad23
             * get local ip address 
Packit fcad23
             */
Packit fcad23
            getsockname(hSock, (LPSOCKADDR) & in_addr,
Packit fcad23
                        (int FAR *) &nAddrSize);
Packit fcad23
        }
Packit fcad23
        closesocket(hSock);
Packit fcad23
    }
Packit fcad23
    return ((in_addr_t) in_addr.sin_addr.s_addr);
Packit fcad23
}
Packit fcad23
Packit fcad23
long
Packit fcad23
get_uptime(void)
Packit fcad23
{
Packit fcad23
    long            return_value = 0;
Packit fcad23
    DWORD           buffersize = (sizeof(PERF_DATA_BLOCK) +
Packit fcad23
                                  sizeof(PERF_OBJECT_TYPE)),
Packit fcad23
        type = REG_EXPAND_SZ;
Packit fcad23
    PPERF_DATA_BLOCK perfdata = NULL;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * min requirement is one PERF_DATA_BLOCK plus one PERF_OBJECT_TYPE 
Packit fcad23
     */
Packit fcad23
    perfdata = (PPERF_DATA_BLOCK) malloc(buffersize);
Packit fcad23
    if (!perfdata)
Packit fcad23
        return 0;
Packit fcad23
Packit fcad23
    memset(perfdata, 0, buffersize);
Packit fcad23
Packit fcad23
    RegQueryValueEx(HKEY_PERFORMANCE_DATA,
Packit fcad23
                    "Global", NULL, &type, (LPBYTE) perfdata, &buffersize);
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * we can not rely on the return value since there is always more so
Packit fcad23
     * we check the signature 
Packit fcad23
     */
Packit fcad23
Packit fcad23
    if (wcsncmp(perfdata->Signature, L"PERF", 4) == 0) {
Packit fcad23
        /*
Packit fcad23
         * signature ok, and all we need is in the in the PERF_DATA_BLOCK 
Packit fcad23
         */
Packit fcad23
        return_value = (long) ((perfdata->PerfTime100nSec.QuadPart /
Packit fcad23
                                (LONGLONG) 100000));
Packit fcad23
    } else
Packit fcad23
        return_value = GetTickCount() / 10;
Packit fcad23
Packit fcad23
    RegCloseKey(HKEY_PERFORMANCE_DATA);
Packit fcad23
    free(perfdata);
Packit fcad23
Packit fcad23
    return return_value;
Packit fcad23
}
Packit fcad23
Packit fcad23
char           *
Packit fcad23
winsock_startup(void)
Packit fcad23
{
Packit fcad23
    WORD            VersionRequested;
Packit fcad23
    WSADATA         stWSAData;
Packit fcad23
    int             i;
Packit fcad23
    static char     errmsg[100];
Packit fcad23
Packit fcad23
	/* winsock 1: use MAKEWORD(1,1) */
Packit fcad23
	/* winsock 2: use MAKEWORD(2,2) */
Packit fcad23
Packit fcad23
    VersionRequested = MAKEWORD(2,2);
Packit fcad23
    i = WSAStartup(VersionRequested, &stWSAData);
Packit fcad23
    if (i != 0) {
Packit fcad23
        if (i == WSAVERNOTSUPPORTED)
Packit fcad23
            sprintf(errmsg,
Packit fcad23
                    "Unable to init. socket lib, does not support 1.1");
Packit fcad23
        else {
Packit fcad23
            sprintf(errmsg, "Socket Startup error %d", i);
Packit fcad23
        }
Packit fcad23
        return (errmsg);
Packit fcad23
    }
Packit fcad23
    return (NULL);
Packit fcad23
}
Packit fcad23
Packit fcad23
void
Packit fcad23
winsock_cleanup(void)
Packit fcad23
{
Packit fcad23
    WSACleanup();
Packit fcad23
}
Packit fcad23
Packit fcad23
#else                           /* ! WIN32 */
Packit fcad23
/*******************************************************************/
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * XXX  What if we have multiple addresses?  Or no addresses for that matter?
Packit fcad23
 * XXX  Could it be computed once then cached?  Probably not worth it (not
Packit fcad23
 *                                                           used very often).
Packit fcad23
 */
Packit fcad23
in_addr_t
Packit fcad23
get_myaddr(void)
Packit fcad23
{
Packit fcad23
    int             sd, i, lastlen = 0;
Packit fcad23
    struct ifconf   ifc;
Packit fcad23
    struct ifreq   *ifrp = NULL;
Packit fcad23
    in_addr_t       addr;
Packit fcad23
    char           *buf = NULL;
Packit fcad23
Packit fcad23
    if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
Packit fcad23
        return 0;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * Cope with lots of interfaces and brokenness of ioctl SIOCGIFCONF on
Packit fcad23
     * some platforms; see W. R. Stevens, ``Unix Network Programming Volume
Packit fcad23
     * I'', p.435.  
Packit fcad23
     */
Packit fcad23
Packit fcad23
    for (i = 8;; i += 8) {
Packit fcad23
        buf = (char *) calloc(i, sizeof(struct ifreq));
Packit fcad23
        if (buf == NULL) {
Packit fcad23
            close(sd);
Packit fcad23
            return 0;
Packit fcad23
        }
Packit fcad23
        ifc.ifc_len = i * sizeof(struct ifreq);
Packit fcad23
        ifc.ifc_buf = (caddr_t) buf;
Packit fcad23
Packit fcad23
        if (ioctl(sd, SIOCGIFCONF, (char *) &ifc) < 0) {
Packit fcad23
            if (errno != EINVAL || lastlen != 0) {
Packit fcad23
                /*
Packit fcad23
                 * Something has gone genuinely wrong.  
Packit fcad23
                 */
Packit fcad23
                free(buf);
Packit fcad23
                close(sd);
Packit fcad23
                return 0;
Packit fcad23
            }
Packit fcad23
            /*
Packit fcad23
             * Otherwise, it could just be that the buffer is too small.  
Packit fcad23
             */
Packit fcad23
        } else {
Packit fcad23
            if (ifc.ifc_len == lastlen) {
Packit fcad23
                /*
Packit fcad23
                 * The length is the same as the last time; we're done.  
Packit fcad23
                 */
Packit fcad23
                break;
Packit fcad23
            }
Packit fcad23
            lastlen = ifc.ifc_len;
Packit fcad23
        }
Packit fcad23
        free(buf);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    for (ifrp = ifc.ifc_req;
Packit fcad23
        (char *)ifrp < (char *)ifc.ifc_req + ifc.ifc_len;
Packit fcad23
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
Packit fcad23
        ifrp = (struct ifreq *)(((char *) ifrp) +
Packit fcad23
                                sizeof(ifrp->ifr_name) +
Packit fcad23
                                ifrp->ifr_addr.sa_len)
Packit fcad23
#else
Packit fcad23
        ifrp++
Packit fcad23
#endif
Packit fcad23
        ) {
Packit fcad23
        if (ifrp->ifr_addr.sa_family != AF_INET) {
Packit fcad23
            continue;
Packit fcad23
        }
Packit fcad23
        addr = ((struct sockaddr_in *) &(ifrp->ifr_addr))->sin_addr.s_addr;
Packit fcad23
Packit fcad23
        if (ioctl(sd, SIOCGIFFLAGS, (char *) ifrp) < 0) {
Packit fcad23
            continue;
Packit fcad23
        }
Packit fcad23
        if ((ifrp->ifr_flags & IFF_UP)
Packit fcad23
#ifdef IFF_RUNNING
Packit fcad23
            && (ifrp->ifr_flags & IFF_RUNNING)
Packit fcad23
#endif                          /* IFF_RUNNING */
Packit fcad23
            && !(ifrp->ifr_flags & IFF_LOOPBACK)
Packit fcad23
            && addr != LOOPBACK) {
Packit fcad23
            /*
Packit fcad23
             * I *really* don't understand why this is necessary.  Perhaps for
Packit fcad23
             * some broken platform?  Leave it for now.  JBPN  
Packit fcad23
             */
Packit fcad23
#ifdef SYS_IOCTL_H_HAS_SIOCGIFADDR
Packit fcad23
            if (ioctl(sd, SIOCGIFADDR, (char *) ifrp) < 0) {
Packit fcad23
                continue;
Packit fcad23
            }
Packit fcad23
            addr =
Packit fcad23
                ((struct sockaddr_in *) &(ifrp->ifr_addr))->sin_addr.
Packit fcad23
                s_addr;
Packit fcad23
#endif
Packit fcad23
            free(buf);
Packit fcad23
            close(sd);
Packit fcad23
            return addr;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
    free(buf);
Packit fcad23
    close(sd);
Packit fcad23
    return 0;
Packit fcad23
}
Packit fcad23
Packit fcad23
Packit fcad23
#if !defined(solaris2) && !defined(linux) && !defined(cygwin)
Packit fcad23
/*
Packit fcad23
 * Returns boottime in centiseconds(!).
Packit fcad23
 *      Caches this for future use.
Packit fcad23
 */
Packit fcad23
long
Packit fcad23
get_boottime(void)
Packit fcad23
{
Packit fcad23
    static long     boottime_csecs = 0;
Packit fcad23
#if defined(hpux10) || defined(hpux11)
Packit fcad23
    struct pst_static pst_buf;
Packit fcad23
#else
Packit fcad23
    struct timeval  boottime;
Packit fcad23
#ifdef	NETSNMP_CAN_USE_SYSCTL
Packit fcad23
    int             mib[2];
Packit fcad23
    size_t          len;
Packit fcad23
#elif defined(NETSNMP_CAN_USE_NLIST)
Packit fcad23
    int             kmem;
Packit fcad23
#if !defined(hpux)
Packit fcad23
    static char boottime_name[] = "_boottime";
Packit fcad23
#else
Packit fcad23
    static char boottime_name[] = "boottime";
Packit fcad23
#endif
Packit fcad23
    static char empty_name[] = "";
Packit fcad23
    struct nlist nl[2];
Packit fcad23
Packit fcad23
    memset(nl, 0, sizeof(nl));
Packit fcad23
    nl[0].n_name = boottime_name;
Packit fcad23
    nl[1].n_name = empty_name;
Packit fcad23
#endif                          /* NETSNMP_CAN_USE_SYSCTL */
Packit fcad23
#endif                          /* hpux10 || hpux 11 */
Packit fcad23
Packit fcad23
Packit fcad23
    if (boottime_csecs != 0)
Packit fcad23
        return (boottime_csecs);
Packit fcad23
Packit fcad23
#if defined(hpux10) || defined(hpux11)
Packit fcad23
    pstat_getstatic(&pst_buf, sizeof(struct pst_static), 1, 0);
Packit fcad23
    boottime_csecs = pst_buf.boot_time * 100;
Packit fcad23
#elif NETSNMP_CAN_USE_SYSCTL
Packit fcad23
    mib[0] = CTL_KERN;
Packit fcad23
    mib[1] = KERN_BOOTTIME;
Packit fcad23
Packit fcad23
    len = sizeof(boottime);
Packit fcad23
Packit fcad23
    sysctl(mib, 2, &boottime, &len, NULL, 0);
Packit fcad23
    boottime_csecs = (boottime.tv_sec * 100) + (boottime.tv_usec / 10000);
Packit fcad23
#elif defined(NETSNMP_CAN_USE_NLIST)
Packit fcad23
    if ((kmem = open("/dev/kmem", 0)) < 0)
Packit fcad23
        return 0;
Packit fcad23
    nlist(KERNEL_LOC, nl);
Packit fcad23
    if (nl[0].n_type == 0) {
Packit fcad23
        close(kmem);
Packit fcad23
        return 0;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    lseek(kmem, (long) nl[0].n_value, L_SET);
Packit fcad23
    read(kmem, &boottime, sizeof(boottime));
Packit fcad23
    close(kmem);
Packit fcad23
    boottime_csecs = (boottime.tv_sec * 100) + (boottime.tv_usec / 10000);
Packit fcad23
#else
Packit fcad23
    return 0;
Packit fcad23
#endif                          /* hpux10 || hpux 11 */
Packit fcad23
Packit fcad23
    return (boottime_csecs);
Packit fcad23
}
Packit fcad23
#endif
Packit fcad23
Packit fcad23
/**
Packit fcad23
 * Returns the system uptime in centiseconds.
Packit fcad23
 *
Packit fcad23
 * @note The value returned by this function is not identical to sysUpTime
Packit fcad23
 *   defined in RFC 1213. get_uptime() returns the system uptime while
Packit fcad23
 *   sysUpTime represents the time that has elapsed since the most recent
Packit fcad23
 *   restart of the network manager (snmpd).
Packit fcad23
 *
Packit fcad23
 * @see See also netsnmp_get_agent_uptime().
Packit fcad23
 */
Packit fcad23
long
Packit fcad23
get_uptime(void)
Packit fcad23
{
Packit fcad23
#if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
Packit fcad23
    static char lbolt_name[] = "lbolt";
Packit fcad23
    struct nlist nl;
Packit fcad23
    int kmem;
Packit fcad23
    time_t lbolt;
Packit fcad23
    nl.n_name = lbolt_name;
Packit fcad23
    if(knlist(&nl, 1, sizeof(struct nlist)) != 0) return(0);
Packit fcad23
    if(nl.n_type == 0 || nl.n_value == 0) return(0);
Packit fcad23
    if((kmem = open("/dev/mem", 0)) < 0) return 0;
Packit fcad23
    lseek(kmem, (long) nl.n_value, L_SET);
Packit fcad23
    read(kmem, &lbolt, sizeof(lbolt));
Packit fcad23
    close(kmem);
Packit fcad23
    return(lbolt);
Packit fcad23
#elif defined(solaris2)
Packit fcad23
    kstat_ctl_t    *ksc = kstat_open();
Packit fcad23
    kstat_t        *ks;
Packit fcad23
    kid_t           kid;
Packit fcad23
    kstat_named_t  *named;
Packit fcad23
    u_long          lbolt = 0;
Packit fcad23
Packit fcad23
    if (ksc) {
Packit fcad23
        ks = kstat_lookup(ksc, "unix", -1, "system_misc");
Packit fcad23
        if (ks) {
Packit fcad23
            kid = kstat_read(ksc, ks, NULL);
Packit fcad23
            if (kid != -1) {
Packit fcad23
                named = kstat_data_lookup(ks, "lbolt");
Packit fcad23
                if (named) {
Packit fcad23
#ifdef KSTAT_DATA_UINT32
Packit fcad23
                    lbolt = named->value.ui32;
Packit fcad23
#else
Packit fcad23
                    lbolt = named->value.ul;
Packit fcad23
#endif
Packit fcad23
                }
Packit fcad23
            }
Packit fcad23
        }
Packit fcad23
        kstat_close(ksc);
Packit fcad23
    }
Packit fcad23
    return lbolt;
Packit fcad23
#elif defined(linux) || defined(cygwin)
Packit fcad23
    FILE           *in = fopen("/proc/uptime", "r");
Packit fcad23
    long            uptim = 0, a, b;
Packit fcad23
    if (in) {
Packit fcad23
        if (2 == fscanf(in, "%ld.%ld", &a, &b))
Packit fcad23
            uptim = a * 100 + b;
Packit fcad23
        fclose(in);
Packit fcad23
    }
Packit fcad23
    return uptim;
Packit fcad23
#else
Packit fcad23
    struct timeval  now;
Packit fcad23
    long            boottime_csecs, nowtime_csecs;
Packit fcad23
Packit fcad23
    boottime_csecs = get_boottime();
Packit fcad23
    if (boottime_csecs == 0)
Packit fcad23
        return 0;
Packit fcad23
    gettimeofday(&now, (struct timezone *) 0);
Packit fcad23
    nowtime_csecs = (now.tv_sec * 100) + (now.tv_usec / 10000);
Packit fcad23
Packit fcad23
    return (nowtime_csecs - boottime_csecs);
Packit fcad23
#endif
Packit fcad23
}
Packit fcad23
Packit fcad23
#endif                          /* ! WIN32 */
Packit fcad23
/*******************************************************************/
Packit fcad23
Packit fcad23
#ifdef DNSSEC_LOCAL_VALIDATION
Packit fcad23
static val_context_t *_val_context = NULL;
Packit fcad23
Packit fcad23
static val_context_t *
Packit fcad23
netsnmp_validator_context(void)
Packit fcad23
{
Packit fcad23
    if (NULL == _val_context) {
Packit fcad23
        int rc;
Packit fcad23
        char *apptype = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
Packit fcad23
                                              NETSNMP_DS_LIB_APPTYPE);
Packit fcad23
        DEBUGMSGTL(("dns:sec:context", "creating dnssec context for %s\n",
Packit fcad23
                    apptype));
Packit fcad23
        rc = val_create_context(apptype, &_val_context);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return _val_context;
Packit fcad23
}
Packit fcad23
#endif /* DNSSEC_LOCAL_VALIDATION */
Packit fcad23
Packit fcad23
int
Packit fcad23
netsnmp_gethostbyname_v4(const char* name, in_addr_t *addr_out)
Packit fcad23
{
Packit fcad23
    static int use_dns_workaround = -1;
Packit fcad23
Packit fcad23
    if (use_dns_workaround < 0)
Packit fcad23
        use_dns_workaround = getenv("NETSNMP_DNS_WORKAROUND") != 0;
Packit fcad23
    if (use_dns_workaround) {
Packit fcad23
        /*
Packit fcad23
         * A hack that avoids that T070com2sec_simple fails due to the DNS
Packit fcad23
         * client filtering out 127.0.0.x addresses and/or redirecting DNS
Packit fcad23
         * resolution failures to a web page.
Packit fcad23
         */
Packit fcad23
        if (strcmp(name, "onea.net-snmp.org") == 0) {
Packit fcad23
            *addr_out = htonl(INADDR_LOOPBACK);
Packit fcad23
            return 0;
Packit fcad23
        } else if (strcmp(name, "twoa.net-snmp.org") == 0) {
Packit fcad23
            *addr_out = htonl(INADDR_LOOPBACK + 1);
Packit fcad23
            return 0;
Packit fcad23
        } else if (strcmp(name, "no.such.address.") == 0) {
Packit fcad23
            return -1;
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
Packit fcad23
    {
Packit fcad23
#if HAVE_GETADDRINFO
Packit fcad23
    struct addrinfo *addrs = NULL;
Packit fcad23
    struct addrinfo hint;
Packit fcad23
    int             err;
Packit fcad23
Packit fcad23
    memset(&hint, 0, sizeof hint);
Packit fcad23
    hint.ai_flags = 0;
Packit fcad23
    hint.ai_family = PF_INET;
Packit fcad23
    hint.ai_socktype = SOCK_DGRAM;
Packit fcad23
    hint.ai_protocol = 0;
Packit fcad23
Packit fcad23
    err = netsnmp_getaddrinfo(name, NULL, &hint, &addrs);
Packit fcad23
    if (err != 0) {
Packit fcad23
        return -1;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (addrs != NULL) {
Packit fcad23
        memcpy(addr_out,
Packit fcad23
               &((struct sockaddr_in *) addrs->ai_addr)->sin_addr,
Packit fcad23
               sizeof(in_addr_t));
Packit fcad23
        freeaddrinfo(addrs);
Packit fcad23
    } else {
Packit fcad23
        DEBUGMSGTL(("get_thisaddr",
Packit fcad23
                    "Failed to resolve IPv4 hostname\n"));
Packit fcad23
    }
Packit fcad23
    return 0;
Packit fcad23
Packit fcad23
#elif HAVE_GETHOSTBYNAME
Packit fcad23
    struct hostent *hp = NULL;
Packit fcad23
Packit fcad23
    hp = netsnmp_gethostbyname(name);
Packit fcad23
    if (hp == NULL) {
Packit fcad23
        DEBUGMSGTL(("get_thisaddr",
Packit fcad23
                    "hostname (couldn't resolve)\n"));
Packit fcad23
        return -1;
Packit fcad23
    } else if (hp->h_addrtype != AF_INET) {
Packit fcad23
        DEBUGMSGTL(("get_thisaddr",
Packit fcad23
                    "hostname (not AF_INET!)\n"));
Packit fcad23
        return -1;
Packit fcad23
    } else {
Packit fcad23
        DEBUGMSGTL(("get_thisaddr",
Packit fcad23
                    "hostname (resolved okay)\n"));
Packit fcad23
        memcpy(addr_out, hp->h_addr, sizeof(in_addr_t));
Packit fcad23
    }
Packit fcad23
    return 0;
Packit fcad23
Packit fcad23
#elif HAVE_GETIPNODEBYNAME
Packit fcad23
    struct hostent *hp = NULL;
Packit fcad23
    int             err;
Packit fcad23
Packit fcad23
    hp = getipnodebyname(peername, AF_INET, 0, &err;;
Packit fcad23
    if (hp == NULL) {
Packit fcad23
        DEBUGMSGTL(("get_thisaddr",
Packit fcad23
                    "hostname (couldn't resolve = %d)\n", err));
Packit fcad23
        return -1;
Packit fcad23
    }
Packit fcad23
    DEBUGMSGTL(("get_thisaddr",
Packit fcad23
                "hostname (resolved okay)\n"));
Packit fcad23
    memcpy(addr_out, hp->h_addr, sizeof(in_addr_t));
Packit fcad23
    return 0;
Packit fcad23
Packit fcad23
#else /* HAVE_GETIPNODEBYNAME */
Packit fcad23
    return -1;
Packit fcad23
#endif
Packit fcad23
    }
Packit fcad23
}
Packit fcad23
Packit fcad23
int
Packit fcad23
netsnmp_getaddrinfo(const char *name, const char *service,
Packit fcad23
                    const struct addrinfo *hints, struct addrinfo **res)
Packit fcad23
{
Packit fcad23
#if HAVE_GETADDRINFO
Packit fcad23
    struct addrinfo *addrs = NULL;
Packit fcad23
    struct addrinfo hint;
Packit fcad23
    int             err;
Packit fcad23
#ifdef DNSSEC_LOCAL_VALIDATION
Packit fcad23
    val_status_t    val_status;
Packit fcad23
#endif
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("dns:getaddrinfo", "looking up "));
Packit fcad23
    if (name)
Packit fcad23
        DEBUGMSG(("dns:getaddrinfo", "\"%s\"", name));
Packit fcad23
    else
Packit fcad23
        DEBUGMSG(("dns:getaddrinfo", "<NULL>"));
Packit fcad23
Packit fcad23
    if (service)
Packit fcad23
	DEBUGMSG(("dns:getaddrinfo", ":\"%s\"", service));
Packit fcad23
Packit fcad23
    if (hints)
Packit fcad23
	DEBUGMSG(("dns:getaddrinfo", " with hint ({ ... })"));
Packit fcad23
    else
Packit fcad23
	DEBUGMSG(("dns:getaddrinfo", " with no hint"));
Packit fcad23
Packit fcad23
    DEBUGMSG(("dns:getaddrinfo", "\n"));
Packit fcad23
Packit fcad23
    if (NULL == hints) {
Packit fcad23
        memset(&hint, 0, sizeof hint);
Packit fcad23
        hint.ai_flags = 0;
Packit fcad23
        hint.ai_family = PF_INET;
Packit fcad23
        hint.ai_socktype = SOCK_DGRAM;
Packit fcad23
        hint.ai_protocol = 0;
Packit fcad23
        hints = &hint;
Packit fcad23
    } else {
Packit fcad23
        memcpy(&hint, hints, sizeof hint);
Packit fcad23
    }
Packit fcad23
Packit fcad23
#ifndef DNSSEC_LOCAL_VALIDATION
Packit fcad23
    err = getaddrinfo(name, NULL, &hint, &addrs);
Packit fcad23
#else /* DNSSEC_LOCAL_VALIDATION */
Packit fcad23
    err = val_getaddrinfo(netsnmp_validator_context(), name, NULL, &hint,
Packit fcad23
                          &addrs, &val_status);
Packit fcad23
    DEBUGMSGTL(("dns:sec:val", "err %d, val_status %d / %s; trusted: %d\n",
Packit fcad23
                err, val_status, p_val_status(val_status),
Packit fcad23
                val_istrusted(val_status)));
Packit fcad23
    if (! val_istrusted(val_status)) {
Packit fcad23
        int rc;
Packit fcad23
        if ((err != 0) && VAL_GETADDRINFO_HAS_STATUS(err)) {
Packit fcad23
            snmp_log(LOG_WARNING,
Packit fcad23
                     "WARNING: UNTRUSTED error in DNS resolution for %s!\n",
Packit fcad23
                     name);
Packit fcad23
            rc = EAI_FAIL;
Packit fcad23
        } else {
Packit fcad23
            snmp_log(LOG_WARNING,
Packit fcad23
                     "The authenticity of DNS response is not trusted (%s)\n",
Packit fcad23
                     p_val_status(val_status));
Packit fcad23
            rc = EAI_NONAME;
Packit fcad23
        }
Packit fcad23
        /** continue anyways if DNSSEC_WARN_ONLY is set */
Packit fcad23
        if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
Packit fcad23
                                    NETSNMP_DS_LIB_DNSSEC_WARN_ONLY))
Packit fcad23
            return rc;
Packit fcad23
    }
Packit fcad23
Packit fcad23
Packit fcad23
#endif /* DNSSEC_LOCAL_VALIDATION */
Packit fcad23
    *res = addrs;
Packit fcad23
    if ((0 == err) && addrs && addrs->ai_addr) {
Packit fcad23
        DEBUGMSGTL(("dns:getaddrinfo", "answer { AF_INET, %s:%hu }\n",
Packit fcad23
                    inet_ntoa(((struct sockaddr_in*)addrs->ai_addr)->sin_addr),
Packit fcad23
                    ntohs(((struct sockaddr_in*)addrs->ai_addr)->sin_port)));
Packit fcad23
    }
Packit fcad23
    return err;
Packit fcad23
#else
Packit fcad23
    NETSNMP_LOGONCE((LOG_ERR, "getaddrinfo not available"));
Packit fcad23
    return EAI_FAIL;
Packit fcad23
#endif /* getaddrinfo */
Packit fcad23
}
Packit fcad23
Packit fcad23
struct hostent *
Packit fcad23
netsnmp_gethostbyname(const char *name)
Packit fcad23
{
Packit fcad23
#if HAVE_GETHOSTBYNAME
Packit fcad23
#ifdef DNSSEC_LOCAL_VALIDATION
Packit fcad23
    val_status_t val_status;
Packit fcad23
#endif
Packit fcad23
    struct hostent *hp = NULL;
Packit fcad23
Packit fcad23
    if (NULL == name)
Packit fcad23
        return NULL;
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("dns:gethostbyname", "looking up %s\n", name));
Packit fcad23
Packit fcad23
#ifdef DNSSEC_LOCAL_VALIDATION
Packit fcad23
    hp  = val_gethostbyname(netsnmp_validator_context(), name, &val_status);
Packit fcad23
    DEBUGMSGTL(("dns:sec:val", "val_status %d / %s; trusted: %d\n",
Packit fcad23
                val_status, p_val_status(val_status),
Packit fcad23
                val_istrusted(val_status)));
Packit fcad23
    if (!val_istrusted(val_status)) {
Packit fcad23
        snmp_log(LOG_WARNING,
Packit fcad23
                 "The authenticity of DNS response is not trusted (%s)\n",
Packit fcad23
                 p_val_status(val_status));
Packit fcad23
        /** continue anyways if DNSSEC_WARN_ONLY is set */
Packit fcad23
        if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
Packit fcad23
                                    NETSNMP_DS_LIB_DNSSEC_WARN_ONLY))
Packit fcad23
            hp = NULL;
Packit fcad23
    }
Packit fcad23
    else if (val_does_not_exist(val_status) && hp)
Packit fcad23
        hp = NULL;
Packit fcad23
#else
Packit fcad23
    hp = gethostbyname(name);
Packit fcad23
#endif
Packit fcad23
    if (hp == NULL) {
Packit fcad23
        DEBUGMSGTL(("dns:gethostbyname",
Packit fcad23
                    "couldn't resolve %s\n", name));
Packit fcad23
    } else if (hp->h_addrtype != AF_INET
Packit fcad23
#ifdef AF_INET6
Packit fcad23
               && hp->h_addrtype != AF_INET6
Packit fcad23
#endif
Packit fcad23
        ) {
Packit fcad23
#ifdef AF_INET6
Packit fcad23
        DEBUGMSGTL(("dns:gethostbyname",
Packit fcad23
                    "warning: response for %s not AF_INET/AF_INET6!\n", name));
Packit fcad23
#else
Packit fcad23
        DEBUGMSGTL(("dns:gethostbyname",
Packit fcad23
                    "warning: response for %s not AF_INET!\n", name));
Packit fcad23
#endif
Packit fcad23
    } else {
Packit fcad23
        DEBUGMSGTL(("dns:gethostbyname",
Packit fcad23
                    "%s resolved okay\n", name));
Packit fcad23
    }
Packit fcad23
    return hp;
Packit fcad23
#else
Packit fcad23
    NETSNMP_LOGONCE((LOG_ERR, "gethostbyname not available"));
Packit fcad23
    return NULL;
Packit fcad23
#endif /* HAVE_GETHOSTBYNAME */
Packit fcad23
}
Packit fcad23
Packit fcad23
/**
Packit fcad23
 * Look up the host name via DNS.
Packit fcad23
 *
Packit fcad23
 * @param[in] addr Pointer to the address to resolve. This argument points e.g.
Packit fcad23
 *   to a struct in_addr for AF_INET or to a struct in6_addr for AF_INET6.
Packit fcad23
 * @param[in] len  Length in bytes of *addr.
Packit fcad23
 * @param[in] type Address family, e.g. AF_INET or AF_INET6.
Packit fcad23
 *
Packit fcad23
 * @return Pointer to a hostent structure if address lookup succeeded or NULL
Packit fcad23
 *   if the lookup failed.
Packit fcad23
 *
Packit fcad23
 * @see See also the gethostbyaddr() man page.
Packit fcad23
 */
Packit fcad23
struct hostent *
Packit fcad23
netsnmp_gethostbyaddr(const void *addr, socklen_t len, int type)
Packit fcad23
{
Packit fcad23
#if HAVE_GETHOSTBYADDR
Packit fcad23
    struct hostent *hp = NULL;
Packit fcad23
    char buf[64];
Packit fcad23
Packit fcad23
    DEBUGMSGTL(("dns:gethostbyaddr", "resolving %s\n",
Packit fcad23
                inet_ntop(type, addr, buf, sizeof(buf))));
Packit fcad23
Packit fcad23
#ifdef DNSSEC_LOCAL_VALIDATION
Packit fcad23
    val_status_t val_status;
Packit fcad23
    hp = val_gethostbyaddr(netsnmp_validator_context(), addr, len, type,
Packit fcad23
                           &val_status);
Packit fcad23
    DEBUGMSGTL(("dns:sec:val", "val_status %d / %s; trusted: %d\n",
Packit fcad23
                val_status, p_val_status(val_status),
Packit fcad23
                val_istrusted(val_status)));
Packit fcad23
    if (!val_istrusted(val_status)) {
Packit fcad23
        snmp_log(LOG_WARNING,
Packit fcad23
                 "The authenticity of DNS response is not trusted (%s)\n",
Packit fcad23
                 p_val_status(val_status));
Packit fcad23
        /** continue anyways if DNSSEC_WARN_ONLY is set */
Packit fcad23
        if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
Packit fcad23
                                    NETSNMP_DS_LIB_DNSSEC_WARN_ONLY))
Packit fcad23
            hp = NULL;
Packit fcad23
    }
Packit fcad23
    else if (val_does_not_exist(val_status) && hp)
Packit fcad23
        hp = NULL;
Packit fcad23
#else
Packit fcad23
    hp = gethostbyaddr(addr, len, type);
Packit fcad23
#endif
Packit fcad23
    if (hp == NULL) {
Packit fcad23
        DEBUGMSGTL(("dns:gethostbyaddr", "couldn't resolve addr\n"));
Packit fcad23
    } else if (hp->h_addrtype != AF_INET) {
Packit fcad23
        DEBUGMSGTL(("dns:gethostbyaddr",
Packit fcad23
                    "warning: response for addr not AF_INET!\n"));
Packit fcad23
    } else {
Packit fcad23
        DEBUGMSGTL(("dns:gethostbyaddr", "addr resolved okay\n"));
Packit fcad23
    }
Packit fcad23
    return hp;
Packit fcad23
#else
Packit fcad23
    NETSNMP_LOGONCE((LOG_ERR, "gethostbyaddr not available"));
Packit fcad23
    return NULL;
Packit fcad23
#endif
Packit fcad23
}
Packit fcad23
Packit fcad23
/*******************************************************************/
Packit fcad23
Packit fcad23
#ifndef HAVE_STRNCASECMP
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * test for NULL pointers before and NULL characters after
Packit fcad23
 * * comparing possibly non-NULL strings.
Packit fcad23
 * * WARNING: This function does NOT check for array overflow.
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
strncasecmp(const char *s1, const char *s2, size_t nch)
Packit fcad23
{
Packit fcad23
    size_t          ii;
Packit fcad23
    int             res = -1;
Packit fcad23
Packit fcad23
    if (!s1) {
Packit fcad23
        if (!s2)
Packit fcad23
            return 0;
Packit fcad23
        return (-1);
Packit fcad23
    }
Packit fcad23
    if (!s2)
Packit fcad23
        return (1);
Packit fcad23
Packit fcad23
    for (ii = 0; (ii < nch) && *s1 && *s2; ii++, s1++, s2++) {
Packit fcad23
        res = (int) (tolower(*s1) - tolower(*s2));
Packit fcad23
        if (res != 0)
Packit fcad23
            break;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (ii == nch) {
Packit fcad23
        s1--;
Packit fcad23
        s2--;
Packit fcad23
    }
Packit fcad23
Packit fcad23
    if (!*s1) {
Packit fcad23
        if (!*s2)
Packit fcad23
            return 0;
Packit fcad23
        return (-1);
Packit fcad23
    }
Packit fcad23
    if (!*s2)
Packit fcad23
        return (1);
Packit fcad23
Packit fcad23
    return (res);
Packit fcad23
}
Packit fcad23
Packit fcad23
int
Packit fcad23
strcasecmp(const char *s1, const char *s2)
Packit fcad23
{
Packit fcad23
    return strncasecmp(s1, s2, 1000000);
Packit fcad23
}
Packit fcad23
Packit fcad23
#endif                          /* HAVE_STRNCASECMP */
Packit fcad23
Packit fcad23
Packit fcad23
#ifndef HAVE_STRDUP
Packit fcad23
char           *
Packit fcad23
strdup(const char *src)
Packit fcad23
{
Packit fcad23
    int             len;
Packit fcad23
    char           *dst;
Packit fcad23
Packit fcad23
    len = strlen(src) + 1;
Packit fcad23
    if ((dst = (char *) malloc(len)) == NULL)
Packit fcad23
        return (NULL);
Packit fcad23
    strcpy(dst, src);
Packit fcad23
    return (dst);
Packit fcad23
}
Packit fcad23
#endif                          /* HAVE_STRDUP */
Packit fcad23
Packit fcad23
#ifndef HAVE_SETENV
Packit fcad23
int
Packit fcad23
setenv(const char *name, const char *value, int overwrite)
Packit fcad23
{
Packit fcad23
    char           *cp;
Packit fcad23
    int             ret;
Packit fcad23
Packit fcad23
    if (overwrite == 0) {
Packit fcad23
        if (getenv(name))
Packit fcad23
            return 0;
Packit fcad23
    }
Packit fcad23
    cp = (char *) malloc(strlen(name) + strlen(value) + 2);
Packit fcad23
    if (cp == NULL)
Packit fcad23
        return -1;
Packit fcad23
    sprintf(cp, "%s=%s", name, value);
Packit fcad23
    ret = putenv(cp);
Packit fcad23
#ifdef WIN32
Packit fcad23
    free(cp);
Packit fcad23
#endif
Packit fcad23
    return ret;
Packit fcad23
}
Packit fcad23
#endif                          /* HAVE_SETENV */
Packit fcad23
Packit fcad23
netsnmp_feature_child_of(calculate_time_diff, netsnmp_unused)
Packit fcad23
#ifndef NETSNMP_FEATURE_REMOVE_CALCULATE_TIME_DIFF
Packit fcad23
/**
Packit fcad23
 * Compute (*now - *then) in centiseconds.
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
calculate_time_diff(const struct timeval *now, const struct timeval *then)
Packit fcad23
{
Packit fcad23
    struct timeval  diff;
Packit fcad23
Packit fcad23
    NETSNMP_TIMERSUB(now, then, &diff);
Packit fcad23
    return (int)(diff.tv_sec * 100 + diff.tv_usec / 10000);
Packit fcad23
}
Packit fcad23
#endif /* NETSNMP_FEATURE_REMOVE_CALCULATE_TIME_DIFF */
Packit fcad23
Packit fcad23
#ifndef NETSNMP_FEATURE_REMOVE_CALCULATE_SECTIME_DIFF
Packit fcad23
/** Compute rounded (*now - *then) in seconds. */
Packit fcad23
u_int
Packit fcad23
calculate_sectime_diff(const struct timeval *now, const struct timeval *then)
Packit fcad23
{
Packit fcad23
    struct timeval  diff;
Packit fcad23
Packit fcad23
    NETSNMP_TIMERSUB(now, then, &diff);
Packit fcad23
    return (u_int)(diff.tv_sec + (diff.tv_usec >= 500000L));
Packit fcad23
}
Packit fcad23
#endif /* NETSNMP_FEATURE_REMOVE_CALCULATE_SECTIME_DIFF */
Packit fcad23
Packit fcad23
#ifndef HAVE_STRCASESTR
Packit fcad23
/*
Packit fcad23
 * only glibc2 has this.
Packit fcad23
 */
Packit fcad23
char           *
Packit fcad23
strcasestr(const char *haystack, const char *needle)
Packit fcad23
{
Packit fcad23
    const char     *cp1 = haystack, *cp2 = needle;
Packit fcad23
    const char     *cx;
Packit fcad23
    int             tstch1, tstch2;
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * printf("looking for '%s' in '%s'\n", needle, haystack); 
Packit fcad23
     */
Packit fcad23
    if (cp1 && cp2 && *cp1 && *cp2)
Packit fcad23
        for (cp1 = haystack, cp2 = needle; *cp1;) {
Packit fcad23
            cx = cp1;
Packit fcad23
            cp2 = needle;
Packit fcad23
            do {
Packit fcad23
                /*
Packit fcad23
                 * printf("T'%c' ", *cp1); 
Packit fcad23
                 */
Packit fcad23
                if (!*cp2) {    /* found the needle */
Packit fcad23
                    /*
Packit fcad23
                     * printf("\nfound '%s' in '%s'\n", needle, cx); 
Packit fcad23
                     */
Packit fcad23
                    return NETSNMP_REMOVE_CONST(char *, cx);
Packit fcad23
                }
Packit fcad23
                if (!*cp1)
Packit fcad23
                    break;
Packit fcad23
Packit fcad23
                tstch1 = toupper(*cp1);
Packit fcad23
                tstch2 = toupper(*cp2);
Packit fcad23
                if (tstch1 != tstch2)
Packit fcad23
                    break;
Packit fcad23
                /*
Packit fcad23
                 * printf("M'%c' ", *cp1); 
Packit fcad23
                 */
Packit fcad23
                cp1++;
Packit fcad23
                cp2++;
Packit fcad23
            }
Packit fcad23
            while (1);
Packit fcad23
            if (*cp1)
Packit fcad23
                cp1++;
Packit fcad23
        }
Packit fcad23
    /*
Packit fcad23
     * printf("\n"); 
Packit fcad23
     */
Packit fcad23
    if (cp1 && *cp1)
Packit fcad23
        return NETSNMP_REMOVE_CONST(char *, cp1);
Packit fcad23
Packit fcad23
    return NULL;
Packit fcad23
}
Packit fcad23
#endif
Packit fcad23
Packit fcad23
int
Packit fcad23
mkdirhier(const char *pathname, mode_t mode, int skiplast)
Packit fcad23
{
Packit fcad23
    struct stat     sbuf;
Packit fcad23
    char           *ourcopy = strdup(pathname);
Packit fcad23
    char           *entry;
Packit fcad23
    char           *buf = NULL;
Packit fcad23
    char           *st = NULL;
Packit fcad23
    int             res;
Packit fcad23
Packit fcad23
    res = SNMPERR_GENERR;
Packit fcad23
    if (!ourcopy)
Packit fcad23
        goto out;
Packit fcad23
Packit fcad23
    buf = malloc(strlen(pathname) + 2);
Packit fcad23
    if (!buf)
Packit fcad23
        goto out;
Packit fcad23
Packit fcad23
#if defined (WIN32) || defined (cygwin)
Packit fcad23
    /* convert backslash to forward slash */
Packit fcad23
    for (entry = ourcopy; *entry; entry++)
Packit fcad23
        if (*entry == '\\')
Packit fcad23
            *entry = '/';
Packit fcad23
#endif
Packit fcad23
Packit fcad23
    entry = strtok_r(ourcopy, "/", &st);
Packit fcad23
Packit fcad23
    buf[0] = '\0';
Packit fcad23
Packit fcad23
#if defined (WIN32) || defined (cygwin)
Packit fcad23
    /*
Packit fcad23
     * Check if first entry contains a drive-letter
Packit fcad23
     *   e.g  "c:/path"
Packit fcad23
     */
Packit fcad23
    if ((entry) && (':' == entry[1]) &&
Packit fcad23
        (('\0' == entry[2]) || ('/' == entry[2]))) {
Packit fcad23
        strcat(buf, entry);
Packit fcad23
        entry = strtok_r(NULL, "/", &st);
Packit fcad23
    }
Packit fcad23
#endif
Packit fcad23
Packit fcad23
    /*
Packit fcad23
     * check to see if filename is a directory 
Packit fcad23
     */
Packit fcad23
    while (entry) {
Packit fcad23
        strcat(buf, "/");
Packit fcad23
        strcat(buf, entry);
Packit fcad23
        entry = strtok_r(NULL, "/", &st);
Packit fcad23
        if (entry == NULL && skiplast)
Packit fcad23
            break;
Packit fcad23
        if (stat(buf, &sbuf) < 0) {
Packit fcad23
            /*
Packit fcad23
             * DNE, make it 
Packit fcad23
             */
Packit fcad23
#ifdef WIN32
Packit fcad23
            if (CreateDirectory(buf, NULL) == 0)
Packit fcad23
#else
Packit fcad23
            if (mkdir(buf, mode) == -1)
Packit fcad23
#endif
Packit fcad23
                goto out;
Packit fcad23
            else
Packit fcad23
                snmp_log(LOG_INFO, "Created directory: %s\n", buf);
Packit fcad23
        } else {
Packit fcad23
            /*
Packit fcad23
             * exists, is it a file? 
Packit fcad23
             */
Packit fcad23
            if ((sbuf.st_mode & S_IFDIR) == 0) {
Packit fcad23
                /*
Packit fcad23
                 * ack! can't make a directory on top of a file 
Packit fcad23
                 */
Packit fcad23
                goto out;
Packit fcad23
            }
Packit fcad23
        }
Packit fcad23
    }
Packit fcad23
    res = SNMPERR_SUCCESS;
Packit fcad23
out:
Packit fcad23
    free(buf);
Packit fcad23
    free(ourcopy);
Packit fcad23
    return res;
Packit fcad23
}
Packit fcad23
Packit fcad23
/**
Packit fcad23
 * netsnmp_mktemp creates a temporary file based on the
Packit fcad23
 *                 configured tempFilePattern
Packit fcad23
 *
Packit fcad23
 * @return file descriptor
Packit fcad23
 */
Packit fcad23
const char     *
Packit fcad23
netsnmp_mktemp(void)
Packit fcad23
{
Packit fcad23
#ifdef PATH_MAX
Packit fcad23
    static char     name[PATH_MAX];
Packit fcad23
#else
Packit fcad23
    static char     name[256];
Packit fcad23
#endif
Packit fcad23
    int             fd = -1;
Packit fcad23
Packit fcad23
    strlcpy(name, get_temp_file_pattern(), sizeof(name));
Packit fcad23
#ifdef HAVE_MKSTEMP
Packit fcad23
    {
Packit fcad23
        mode_t oldmask = umask(~(S_IRUSR | S_IWUSR));
Packit fcad23
        netsnmp_assert(oldmask != (mode_t)(-1));
Packit fcad23
        fd = mkstemp(name);
Packit fcad23
        umask(oldmask);
Packit fcad23
    }
Packit fcad23
#else
Packit fcad23
    if (mktemp(name)) {
Packit fcad23
# ifndef WIN32
Packit fcad23
        fd = open(name, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
Packit fcad23
# else
Packit fcad23
        /*
Packit fcad23
         * Win32 needs _S_IREAD | _S_IWRITE to set permissions on file
Packit fcad23
         * after closing
Packit fcad23
         */
Packit fcad23
        fd = _open(name, _O_CREAT | _O_EXCL | _O_WRONLY, _S_IREAD | _S_IWRITE);
Packit fcad23
# endif
Packit fcad23
    }
Packit fcad23
#endif
Packit fcad23
    if (fd >= 0) {
Packit fcad23
        close(fd);
Packit fcad23
        DEBUGMSGTL(("netsnmp_mktemp", "temp file created: %s\n",
Packit fcad23
                    name));
Packit fcad23
        return name;
Packit fcad23
    }
Packit fcad23
    snmp_log(LOG_ERR, "netsnmp_mktemp: error creating file %s\n",
Packit fcad23
             name);
Packit fcad23
    return NULL;
Packit fcad23
}
Packit fcad23
Packit fcad23
/*
Packit fcad23
 * This function was created to differentiate actions
Packit fcad23
 * that are appropriate for Linux 2.4 kernels, but not later kernels.
Packit fcad23
 *
Packit fcad23
 * This function can be used to test kernels on any platform that supports uname().
Packit fcad23
 *
Packit fcad23
 * If not running a platform that supports uname(), return -1.
Packit fcad23
 *
Packit fcad23
 * If ospname matches, and the release matches up through the prefix,
Packit fcad23
 *  return 0.
Packit fcad23
 * If the release is ordered higher, return 1.
Packit fcad23
 * Be aware that "ordered higher" is not a guarantee of correctness.
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
netsnmp_os_prematch(const char *ospmname,
Packit fcad23
                    const char *ospmrelprefix)
Packit fcad23
{
Packit fcad23
#if HAVE_SYS_UTSNAME_H
Packit fcad23
  static int printOSonce = 1;
Packit fcad23
  struct utsname utsbuf;
Packit fcad23
  if ( 0 > uname(&utsbuf))
Packit fcad23
    return -1;
Packit fcad23
Packit fcad23
  if (printOSonce) {
Packit fcad23
    printOSonce = 0;
Packit fcad23
    /* show the four elements that the kernel can be sure of */
Packit fcad23
  DEBUGMSGT(("daemonize","sysname '%s',\nrelease '%s',\nversion '%s',\nmachine '%s'\n",
Packit fcad23
      utsbuf.sysname, utsbuf.release, utsbuf.version, utsbuf.machine));
Packit fcad23
  }
Packit fcad23
  if (0 != strcasecmp(utsbuf.sysname, ospmname)) return -1;
Packit fcad23
Packit fcad23
  /* Required to match only the leading characters */
Packit fcad23
  return strncasecmp(utsbuf.release, ospmrelprefix, strlen(ospmrelprefix));
Packit fcad23
Packit fcad23
#else
Packit fcad23
Packit fcad23
  return -1;
Packit fcad23
Packit fcad23
#endif /* HAVE_SYS_UTSNAME_H */
Packit fcad23
}
Packit fcad23
Packit fcad23
/**
Packit fcad23
 * netsnmp_os_kernel_width determines kernel width at runtime
Packit fcad23
 * Currently implemented for IRIX, AIX and Tru64 Unix
Packit fcad23
 *
Packit fcad23
 * @return kernel width (usually 32 or 64) on success, -1 on error
Packit fcad23
 */
Packit fcad23
int
Packit fcad23
netsnmp_os_kernel_width(void)
Packit fcad23
{
Packit fcad23
#ifdef irix6
Packit fcad23
  char buf[8];
Packit fcad23
  sysinfo(_MIPS_SI_OS_NAME, buf, 7);
Packit fcad23
  if (strncmp("IRIX64", buf, 6) == 0) {
Packit fcad23
    return 64;
Packit fcad23
  } else if (strncmp("IRIX", buf, 4) == 0) {
Packit fcad23
    return 32;
Packit fcad23
  } else {
Packit fcad23
    return -1;
Packit fcad23
  }
Packit fcad23
#elif defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
Packit fcad23
  return (__KERNEL_32() ? 32 : (__KERNEL_64() ? 64 : -1));
Packit fcad23
#elif defined(osf4) || defined(osf5) || defined(__alpha)
Packit fcad23
  return 64; /* Alpha is always 64bit */
Packit fcad23
#else
Packit fcad23
  /* kernel width detection not implemented */
Packit fcad23
  return -1;
Packit fcad23
#endif
Packit fcad23
}
Packit fcad23
Packit fcad23
netsnmp_feature_child_of(str_to_uid, user_information)
Packit fcad23
#ifndef NETSNMP_FEATURE_REMOVE_STR_TO_UID
Packit fcad23
/**
Packit fcad23
 * Convert a user name or number into numeric form.
Packit fcad23
 *
Packit fcad23
 * @param[in] useroruid Either a Unix user name or the ASCII representation
Packit fcad23
 *   of a user number.
Packit fcad23
 *
Packit fcad23
 * @return Either a user number > 0 or 0 if useroruid is not a valid user
Packit fcad23
 *   name, not a valid user number or the name of the root user.
Packit fcad23
 */
Packit fcad23
int netsnmp_str_to_uid(const char *useroruid) {
Packit fcad23
    int uid;
Packit fcad23
#if HAVE_GETPWNAM && HAVE_PWD_H
Packit fcad23
    struct passwd *pwd;
Packit fcad23
#endif
Packit fcad23
Packit fcad23
    uid = atoi(useroruid);
Packit fcad23
Packit fcad23
    if (uid == 0) {
Packit fcad23
#if HAVE_GETPWNAM && HAVE_PWD_H
Packit fcad23
        pwd = getpwnam(useroruid);
Packit fcad23
        uid = pwd ? pwd->pw_uid : 0;
Packit fcad23
        endpwent();
Packit fcad23
#endif
Packit fcad23
        if (uid == 0)
Packit fcad23
            snmp_log(LOG_WARNING, "Can't identify user (%s).\n", useroruid);
Packit fcad23
    }
Packit fcad23
    return uid;
Packit fcad23
    
Packit fcad23
}
Packit fcad23
#endif /* NETSNMP_FEATURE_REMOVE_STR_TO_UID */
Packit fcad23
Packit fcad23
netsnmp_feature_child_of(str_to_gid, user_information)
Packit fcad23
#ifndef NETSNMP_FEATURE_REMOVE_STR_TO_GID
Packit fcad23
/**
Packit fcad23
 * Convert a group name or number into numeric form.
Packit fcad23
 *
Packit fcad23
 * @param[in] grouporgid Either a Unix group name or the ASCII representation
Packit fcad23
 *   of a group number.
Packit fcad23
 *
Packit fcad23
 * @return Either a group number > 0 or 0 if grouporgid is not a valid group
Packit fcad23
 *   name, not a valid group number or the root group.
Packit fcad23
 */
Packit fcad23
int netsnmp_str_to_gid(const char *grouporgid)
Packit fcad23
{
Packit fcad23
    int gid;
Packit fcad23
Packit fcad23
    gid = atoi(grouporgid);
Packit fcad23
Packit fcad23
    if (gid == 0) {
Packit fcad23
#if HAVE_GETGRNAM && HAVE_GRP_H
Packit fcad23
        struct group  *grp;
Packit fcad23
Packit fcad23
        grp = getgrnam(grouporgid);
Packit fcad23
        gid = grp ? grp->gr_gid : 0;
Packit fcad23
        endgrent();
Packit fcad23
#endif
Packit fcad23
        if (gid == 0)
Packit fcad23
            snmp_log(LOG_WARNING, "Can't identify group (%s).\n", grouporgid);
Packit fcad23
    }
Packit fcad23
Packit fcad23
    return gid;
Packit fcad23
}
Packit fcad23
#endif /* NETSNMP_FEATURE_REMOVE_STR_TO_GID */