net-snmp 5.7
system.c
00001 /*
00002  * system.c
00003  */
00004 /* Portions of this file are subject to the following copyright(s).  See
00005  * the Net-SNMP's COPYING file for more details and other copyrights
00006  * that may apply:
00007  */
00008 /***********************************************************
00009         Copyright 1992 by Carnegie Mellon University
00010 
00011                       All Rights Reserved
00012 
00013 Permission to use, copy, modify, and distribute this software and its
00014 documentation for any purpose and without fee is hereby granted,
00015 provided that the above copyright notice appear in all copies and that
00016 both that copyright notice and this permission notice appear in
00017 supporting documentation, and that the name of CMU not be
00018 used in advertising or publicity pertaining to distribution of the
00019 software without specific, written prior permission.
00020 
00021 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
00022 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
00023 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
00024 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
00025 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
00026 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
00027 SOFTWARE.
00028 ******************************************************************/
00029 /*
00030  * Portions of this file are copyrighted by:
00031  * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
00032  * Use is subject to license terms specified in the COPYING file
00033  * distributed with the Net-SNMP package.
00034  */
00035 /*
00036  * Portions of this file are copyrighted by:
00037  * Copyright (C) 2007 Apple, Inc. All rights reserved.
00038  * Use is subject to license terms specified in the COPYING file
00039  * distributed with the Net-SNMP package.
00040  */
00041 /*
00042  * System dependent routines go here
00043  */
00044 #include <net-snmp/net-snmp-config.h>
00045 #include <net-snmp/net-snmp-features.h>
00046 #include <stdio.h>
00047 #include <ctype.h>
00048 #include <errno.h>
00049 
00050 #if HAVE_IO_H
00051 #include <io.h>
00052 #endif
00053 #if HAVE_DIRECT_H
00054 #include <direct.h>
00055 #endif
00056 #if HAVE_UNISTD_H
00057 #include <unistd.h>
00058 #endif
00059 #if HAVE_STDLIB_H
00060 #include <stdlib.h>
00061 #endif
00062 
00063 #if TIME_WITH_SYS_TIME
00064 # include <sys/time.h>
00065 # include <time.h>
00066 #else
00067 # if HAVE_SYS_TIME_H
00068 #  include <sys/time.h>
00069 # else
00070 #  include <time.h>
00071 # endif
00072 #endif
00073 
00074 #include <sys/types.h>
00075 
00076 #if HAVE_NETINET_IN_H
00077 #include <netinet/in.h>
00078 #endif
00079 
00080 #if HAVE_SYS_SOCKET_H
00081 #include <sys/socket.h>
00082 #endif
00083 #if HAVE_NET_IF_H
00084 #include <net/if.h>
00085 #endif
00086 #if HAVE_NETDB_H
00087 #include <netdb.h>
00088 #endif
00089 
00090 
00091 #if HAVE_SYS_SOCKIO_H
00092 #include <sys/sockio.h>
00093 #endif
00094 
00095 #if HAVE_SYS_IOCTL_H
00096 #include <sys/ioctl.h>
00097 #endif
00098 
00099 #ifdef HAVE_NLIST_H
00100 #include <nlist.h>
00101 #endif
00102 
00103 #if HAVE_SYS_FILE_H
00104 #include <sys/file.h>
00105 #endif
00106 
00107 #if HAVE_KSTAT_H
00108 #include <kstat.h>
00109 #endif
00110 
00111 #if HAVE_SYS_PARAM_H
00112 #include <sys/param.h>
00113 #endif
00114 #if HAVE_SYS_SYSCTL_H
00115 #include <sys/sysctl.h>
00116 #endif
00117 
00118 #if HAVE_STRING_H
00119 #include <string.h>
00120 #else
00121 #include <strings.h>
00122 #endif
00123 
00124 #if HAVE_DMALLOC_H
00125 #include <dmalloc.h>
00126 #endif
00127 
00128 #ifdef HAVE_SYS_STAT_H
00129 #include <sys/stat.h>
00130 #endif
00131 #if HAVE_FCNTL_H
00132 #include <fcntl.h>
00133 #endif
00134 
00135 #if defined(hpux10) || defined(hpux11)
00136 #include <sys/pstat.h>
00137 #endif
00138 
00139 #if HAVE_SYS_UTSNAME_H
00140 #include <sys/utsname.h>
00141 #endif
00142 
00143 #if HAVE_SYS_SYSTEMCFG_H
00144 #include <sys/systemcfg.h>
00145 #endif
00146 
00147 #if HAVE_SYS_SYSTEMINFO_H
00148 #include <sys/systeminfo.h>
00149 #endif
00150 
00151 #if defined(darwin9)
00152 #include <crt_externs.h>        /* for _NSGetArgv() */
00153 #endif
00154 
00155 #if HAVE_PWD_H
00156 #include <pwd.h>
00157 #endif
00158 #if HAVE_GRP_H
00159 #include <grp.h>
00160 #endif
00161 
00162 #if HAVE_LIMITS_H
00163 #include <limits.h>
00164 #endif
00165 
00166 #if HAVE_ARPA_INET_H
00167 #include <arpa/inet.h>
00168 #endif
00169 
00170 #ifdef DNSSEC_LOCAL_VALIDATION
00171 #if 1 /*HAVE_ARPA_NAMESER_H*/
00172 #include <arpa/nameser.h>
00173 #endif
00174 #include <validator/validator.h>
00175 /* NetSNMP and DNSSEC-Tools both define FREE. We'll not use either here. */
00176 #undef FREE
00177 #endif
00178 
00179 #include <net-snmp/types.h>
00180 #include <net-snmp/output_api.h>
00181 #include <net-snmp/utilities.h>
00182 #include <net-snmp/library/system.h>    /* for "internal" definitions */
00183 
00184 #include <net-snmp/library/snmp_api.h>
00185 #include <net-snmp/library/read_config.h> /* for get_temp_file_pattern() */
00186 
00187 /* NetSNMP and DNSSEC-Tools both define FREE. We'll not use either here. */
00188 #undef FREE
00189 
00190 netsnmp_feature_child_of(system_all, libnetsnmp)
00191 
00192 netsnmp_feature_child_of(user_information, system_all)
00193 netsnmp_feature_child_of(calculate_sectime_diff, system_all)
00194 
00195 #ifndef IFF_LOOPBACK
00196 #       define IFF_LOOPBACK 0
00197 #endif
00198 
00199 #ifdef  INADDR_LOOPBACK
00200 # define LOOPBACK    INADDR_LOOPBACK
00201 #else
00202 # define LOOPBACK    0x7f000001
00203 #endif
00204 
00205 #if defined(HAVE_FORK)
00206 static void
00207 _daemon_prep(int stderr_log)
00208 {
00209     /* Avoid keeping any directory in use. */
00210     chdir("/");
00211 
00212     if (stderr_log)
00213         return;
00214 
00215     /*
00216      * Close inherited file descriptors to avoid
00217      * keeping unnecessary references.
00218      */
00219     close(0);
00220     close(1);
00221     close(2);
00222 
00223     /*
00224      * Redirect std{in,out,err} to /dev/null, just in case.
00225      */
00226     open("/dev/null", O_RDWR);
00227     dup(0);
00228     dup(0);
00229 }
00230 #endif
00231 
00254 int
00255 netsnmp_daemonize(int quit_immediately, int stderr_log)
00256 {
00257     int i = 0;
00258     DEBUGMSGT(("daemonize","deamonizing...\n"));
00259 #if HAVE_FORK
00260 #if defined(darwin9)
00261      char            path [PATH_MAX] = "";
00262      uint32_t        size = sizeof (path);
00263 
00264      /*
00265       * if we are already launched in a "daemonized state", just
00266       * close & redirect the file descriptors
00267       */
00268      if(getppid() <= 2) {
00269          _daemon_prep(stderr_log);
00270          return 0;
00271      }
00272 
00273      if (_NSGetExecutablePath (path, &size))
00274          return -1;
00275 #endif
00276     /*
00277      * Fork to return control to the invoking process and to
00278      * guarantee that we aren't a process group leader.
00279      */
00280     i = fork();
00281     if (i != 0) {
00282         /* Parent. */
00283         DEBUGMSGT(("daemonize","first fork returned %d.\n", i));
00284         if(i == -1) {
00285             snmp_log(LOG_ERR,"first fork failed (errno %d) in "
00286                      "netsnmp_daemonize()\n", errno);
00287             return -1;
00288         }
00289         if (quit_immediately) {
00290             DEBUGMSGT(("daemonize","parent exiting\n"));
00291             exit(0);
00292         }
00293     } else {
00294         /* Child. */
00295 #ifdef HAVE_SETSID
00296         /* Become a process/session group leader. */
00297         setsid();
00298 #endif
00299         /*
00300          * Fork to let the process/session group leader exit.
00301          */
00302         if ((i = fork()) != 0) {
00303             DEBUGMSGT(("daemonize","second fork returned %d.\n", i));
00304             if(i == -1) {
00305                 snmp_log(LOG_ERR,"second fork failed (errno %d) in "
00306                          "netsnmp_daemonize()\n", errno);
00307             }
00308             /* Parent. */
00309             exit(0);
00310         }
00311 #ifndef WIN32
00312         else {
00313             /* Child. */
00314             
00315             DEBUGMSGT(("daemonize","child continuing\n"));
00316 
00317 #if ! defined(darwin9)
00318             _daemon_prep(stderr_log);
00319 #else
00320              /*
00321               * Some darwin calls (using mach ports) don't work after
00322               * a fork. So, now that we've forked, we re-exec ourself
00323               * to ensure that the child's mach ports are all set up correctly,
00324               * the getppid call above will prevent the exec child from
00325               * forking...
00326               */
00327              char * const *argv = *_NSGetArgv ();
00328              DEBUGMSGT(("daemonize","re-execing forked child\n"));
00329              execv (path, argv);
00330              snmp_log(LOG_ERR,"Forked child unable to re-exec - %s.\n", strerror (errno));
00331              exit (0);
00332 #endif
00333         }
00334 #endif /* !WIN32 */
00335     }
00336 #endif /* HAVE_FORK */
00337     return i;
00338 }
00339 
00340 /*
00341  * ********************************************* 
00342  */
00343 #ifdef                                                  WIN32
00344 in_addr_t
00345 get_myaddr(void)
00346 {
00347     char            local_host[130];
00348     int             result;
00349     LPHOSTENT       lpstHostent;
00350     SOCKADDR_IN     in_addr, remote_in_addr;
00351     SOCKET          hSock;
00352     int             nAddrSize = sizeof(SOCKADDR);
00353 
00354     in_addr.sin_addr.s_addr = INADDR_ANY;
00355 
00356     result = gethostname(local_host, sizeof(local_host));
00357     if (result == 0) {
00358         lpstHostent = gethostbyname((LPSTR) local_host);
00359         if (lpstHostent) {
00360             in_addr.sin_addr.s_addr =
00361                 *((u_long FAR *) (lpstHostent->h_addr));
00362             return ((in_addr_t) in_addr.sin_addr.s_addr);
00363         }
00364     }
00365 
00366     /*
00367      * if we are here, than we don't have host addr 
00368      */
00369     hSock = socket(AF_INET, SOCK_DGRAM, 0);
00370     if (hSock != INVALID_SOCKET) {
00371         /*
00372          * connect to any port and address 
00373          */
00374         remote_in_addr.sin_family = AF_INET;
00375         remote_in_addr.sin_port = htons(IPPORT_ECHO);
00376         remote_in_addr.sin_addr.s_addr = inet_addr("0.0.0.0");
00377         result =
00378             connect(hSock, (LPSOCKADDR) & remote_in_addr,
00379                     sizeof(SOCKADDR));
00380         if (result != SOCKET_ERROR) {
00381             /*
00382              * get local ip address 
00383              */
00384             getsockname(hSock, (LPSOCKADDR) & in_addr,
00385                         (int FAR *) &nAddrSize);
00386         }
00387         closesocket(hSock);
00388     }
00389     return ((in_addr_t) in_addr.sin_addr.s_addr);
00390 }
00391 
00392 long
00393 get_uptime(void)
00394 {
00395     long            return_value = 0;
00396     DWORD           buffersize = (sizeof(PERF_DATA_BLOCK) +
00397                                   sizeof(PERF_OBJECT_TYPE)),
00398         type = REG_EXPAND_SZ;
00399     PPERF_DATA_BLOCK perfdata = NULL;
00400 
00401     /*
00402      * min requirement is one PERF_DATA_BLOCK plus one PERF_OBJECT_TYPE 
00403      */
00404     perfdata = (PPERF_DATA_BLOCK) malloc(buffersize);
00405     if (!perfdata)
00406         return 0;
00407 
00408     memset(perfdata, 0, buffersize);
00409 
00410     RegQueryValueEx(HKEY_PERFORMANCE_DATA,
00411                     "Global", NULL, &type, (LPBYTE) perfdata, &buffersize);
00412 
00413     /*
00414      * we can not rely on the return value since there is always more so
00415      * we check the signature 
00416      */
00417 
00418     if (wcsncmp(perfdata->Signature, L"PERF", 4) == 0) {
00419         /*
00420          * signature ok, and all we need is in the in the PERF_DATA_BLOCK 
00421          */
00422         return_value = (long) ((perfdata->PerfTime100nSec.QuadPart /
00423                                 (LONGLONG) 100000));
00424     } else
00425         return_value = GetTickCount() / 10;
00426 
00427     RegCloseKey(HKEY_PERFORMANCE_DATA);
00428     free(perfdata);
00429 
00430     return return_value;
00431 }
00432 
00433 char           *
00434 winsock_startup(void)
00435 {
00436     WORD            VersionRequested;
00437     WSADATA         stWSAData;
00438     int             i;
00439     static char     errmsg[100];
00440 
00441         /* winsock 1: use MAKEWORD(1,1) */
00442         /* winsock 2: use MAKEWORD(2,2) */
00443 
00444     VersionRequested = MAKEWORD(2,2);
00445     i = WSAStartup(VersionRequested, &stWSAData);
00446     if (i != 0) {
00447         if (i == WSAVERNOTSUPPORTED)
00448             sprintf(errmsg,
00449                     "Unable to init. socket lib, does not support 1.1");
00450         else {
00451             sprintf(errmsg, "Socket Startup error %d", i);
00452         }
00453         return (errmsg);
00454     }
00455     return (NULL);
00456 }
00457 
00458 void
00459 winsock_cleanup(void)
00460 {
00461     WSACleanup();
00462 }
00463 
00464 #else                           /* ! WIN32 */
00465 /*******************************************************************/
00466 
00467 /*
00468  * XXX  What if we have multiple addresses?  Or no addresses for that matter?
00469  * XXX  Could it be computed once then cached?  Probably not worth it (not
00470  *                                                           used very often).
00471  */
00472 in_addr_t
00473 get_myaddr(void)
00474 {
00475     int             sd, i, lastlen = 0;
00476     struct ifconf   ifc;
00477     struct ifreq   *ifrp = NULL;
00478     in_addr_t       addr;
00479     char           *buf = NULL;
00480 
00481     if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
00482         return 0;
00483     }
00484 
00485     /*
00486      * Cope with lots of interfaces and brokenness of ioctl SIOCGIFCONF on
00487      * some platforms; see W. R. Stevens, ``Unix Network Programming Volume
00488      * I'', p.435.  
00489      */
00490 
00491     for (i = 8;; i += 8) {
00492         buf = (char *) calloc(i, sizeof(struct ifreq));
00493         if (buf == NULL) {
00494             close(sd);
00495             return 0;
00496         }
00497         ifc.ifc_len = i * sizeof(struct ifreq);
00498         ifc.ifc_buf = (caddr_t) buf;
00499 
00500         if (ioctl(sd, SIOCGIFCONF, (char *) &ifc) < 0) {
00501             if (errno != EINVAL || lastlen != 0) {
00502                 /*
00503                  * Something has gone genuinely wrong.  
00504                  */
00505                 free(buf);
00506                 close(sd);
00507                 return 0;
00508             }
00509             /*
00510              * Otherwise, it could just be that the buffer is too small.  
00511              */
00512         } else {
00513             if (ifc.ifc_len == lastlen) {
00514                 /*
00515                  * The length is the same as the last time; we're done.  
00516                  */
00517                 break;
00518             }
00519             lastlen = ifc.ifc_len;
00520         }
00521         free(buf);
00522     }
00523 
00524     for (ifrp = ifc.ifc_req;
00525         (char *)ifrp < (char *)ifc.ifc_req + ifc.ifc_len;
00526 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
00527         ifrp = (struct ifreq *)(((char *) ifrp) +
00528                                 sizeof(ifrp->ifr_name) +
00529                                 ifrp->ifr_addr.sa_len)
00530 #else
00531         ifrp++
00532 #endif
00533         ) {
00534         if (ifrp->ifr_addr.sa_family != AF_INET) {
00535             continue;
00536         }
00537         addr = ((struct sockaddr_in *) &(ifrp->ifr_addr))->sin_addr.s_addr;
00538 
00539         if (ioctl(sd, SIOCGIFFLAGS, (char *) ifrp) < 0) {
00540             continue;
00541         }
00542         if ((ifrp->ifr_flags & IFF_UP)
00543 #ifdef IFF_RUNNING
00544             && (ifrp->ifr_flags & IFF_RUNNING)
00545 #endif                          /* IFF_RUNNING */
00546             && !(ifrp->ifr_flags & IFF_LOOPBACK)
00547             && addr != LOOPBACK) {
00548             /*
00549              * I *really* don't understand why this is necessary.  Perhaps for
00550              * some broken platform?  Leave it for now.  JBPN  
00551              */
00552 #ifdef SYS_IOCTL_H_HAS_SIOCGIFADDR
00553             if (ioctl(sd, SIOCGIFADDR, (char *) ifrp) < 0) {
00554                 continue;
00555             }
00556             addr =
00557                 ((struct sockaddr_in *) &(ifrp->ifr_addr))->sin_addr.
00558                 s_addr;
00559 #endif
00560             free(buf);
00561             close(sd);
00562             return addr;
00563         }
00564     }
00565     free(buf);
00566     close(sd);
00567     return 0;
00568 }
00569 
00570 
00571 #if !defined(solaris2) && !defined(linux) && !defined(cygwin)
00572 /*
00573  * Returns boottime in centiseconds(!).
00574  *      Caches this for future use.
00575  */
00576 long
00577 get_boottime(void)
00578 {
00579     static long     boottime_csecs = 0;
00580 #if defined(hpux10) || defined(hpux11)
00581     struct pst_static pst_buf;
00582 #else
00583     struct timeval  boottime;
00584 #ifdef  NETSNMP_CAN_USE_SYSCTL
00585     int             mib[2];
00586     size_t          len;
00587 #elif defined(NETSNMP_CAN_USE_NLIST)
00588     int             kmem;
00589     static struct nlist nl[] = {
00590 #if !defined(hpux)
00591         {(char *) "_boottime"},
00592 #else
00593         {(char *) "boottime"},
00594 #endif
00595         {(char *) ""}
00596     };
00597 #endif                          /* NETSNMP_CAN_USE_SYSCTL */
00598 #endif                          /* hpux10 || hpux 11 */
00599 
00600 
00601     if (boottime_csecs != 0)
00602         return (boottime_csecs);
00603 
00604 #if defined(hpux10) || defined(hpux11)
00605     pstat_getstatic(&pst_buf, sizeof(struct pst_static), 1, 0);
00606     boottime_csecs = pst_buf.boot_time * 100;
00607 #elif NETSNMP_CAN_USE_SYSCTL
00608     mib[0] = CTL_KERN;
00609     mib[1] = KERN_BOOTTIME;
00610 
00611     len = sizeof(boottime);
00612 
00613     sysctl(mib, 2, &boottime, &len, NULL, 0);
00614     boottime_csecs = (boottime.tv_sec * 100) + (boottime.tv_usec / 10000);
00615 #elif defined(NETSNMP_CAN_USE_NLIST)
00616     if ((kmem = open("/dev/kmem", 0)) < 0)
00617         return 0;
00618     nlist(KERNEL_LOC, nl);
00619     if (nl[0].n_type == 0) {
00620         close(kmem);
00621         return 0;
00622     }
00623 
00624     lseek(kmem, (long) nl[0].n_value, L_SET);
00625     read(kmem, &boottime, sizeof(boottime));
00626     close(kmem);
00627     boottime_csecs = (boottime.tv_sec * 100) + (boottime.tv_usec / 10000);
00628 #else
00629     return 0;
00630 #endif                          /* hpux10 || hpux 11 */
00631 
00632     return (boottime_csecs);
00633 }
00634 #endif
00635 
00636 /*
00637  * Returns uptime in centiseconds(!).
00638  */
00639 long
00640 get_uptime(void)
00641 {
00642 #if !defined(solaris2) && !defined(linux) && !defined(cygwin) && !defined(aix4) && !defined(aix5) && !defined(aix6) && !defined(aix7)
00643     struct timeval  now;
00644     long            boottime_csecs, nowtime_csecs;
00645 
00646     boottime_csecs = get_boottime();
00647     if (boottime_csecs == 0)
00648         return 0;
00649     gettimeofday(&now, (struct timezone *) 0);
00650     nowtime_csecs = (now.tv_sec * 100) + (now.tv_usec / 10000);
00651 
00652     return (nowtime_csecs - boottime_csecs);
00653 #endif
00654 
00655 #if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
00656     struct nlist nl;
00657     int kmem;
00658     time_t lbolt;
00659     nl.n_name = "lbolt";
00660     if(knlist(&nl, 1, sizeof(struct nlist)) != 0) return(0);
00661     if(nl.n_type == 0 || nl.n_value == 0) return(0);
00662     if((kmem = open("/dev/mem", 0)) < 0) return 0;
00663     lseek(kmem, (long) nl.n_value, L_SET);
00664     read(kmem, &lbolt, sizeof(lbolt));
00665     close(kmem);
00666     return(lbolt);
00667 #endif
00668 
00669 #ifdef solaris2
00670     kstat_ctl_t    *ksc = kstat_open();
00671     kstat_t        *ks;
00672     kid_t           kid;
00673     kstat_named_t  *named;
00674     u_long          lbolt = 0;
00675 
00676     if (ksc) {
00677         ks = kstat_lookup(ksc, "unix", -1, "system_misc");
00678         if (ks) {
00679             kid = kstat_read(ksc, ks, NULL);
00680             if (kid != -1) {
00681                 named = kstat_data_lookup(ks, "lbolt");
00682                 if (named) {
00683 #ifdef KSTAT_DATA_UINT32
00684                     lbolt = named->value.ui32;
00685 #else
00686                     lbolt = named->value.ul;
00687 #endif
00688                 }
00689             }
00690         }
00691         kstat_close(ksc);
00692     }
00693     return lbolt;
00694 #endif                          /* solaris2 */
00695 
00696 #ifdef linux
00697     FILE           *in = fopen("/proc/uptime", "r");
00698     long            uptim = 0, a, b;
00699     if (in) {
00700         if (2 == fscanf(in, "%ld.%ld", &a, &b))
00701             uptim = a * 100 + b;
00702         fclose(in);
00703     }
00704     return uptim;
00705 #endif                          /* linux */
00706 
00707 #ifdef cygwin
00708     return (0);                 /* not implemented */
00709 #endif
00710 }
00711 
00712 #endif                          /* ! WIN32 */
00713 /*******************************************************************/
00714 
00715 #ifdef DNSSEC_LOCAL_VALIDATION
00716 static val_context_t *_val_context = NULL;
00717 
00718 static val_context_t *
00719 netsnmp_validator_context(void)
00720 {
00721     if (NULL == _val_context) {
00722         int rc;
00723         char *apptype = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
00724                                               NETSNMP_DS_LIB_APPTYPE);
00725         DEBUGMSGTL(("dns:sec:context", "creating dnssec context for %s\n",
00726                     apptype));
00727         rc = val_create_context(apptype, &_val_context);
00728     }
00729 
00730     return _val_context;
00731 }
00732 #endif /* DNSSEC_LOCAL_VALIDATION */
00733 
00734 int
00735 netsnmp_gethostbyname_v4(const char* name, in_addr_t *addr_out)
00736 {
00737 #if HAVE_GETADDRINFO
00738     struct addrinfo *addrs = NULL;
00739     struct addrinfo hint;
00740     int             err;
00741 
00742     memset(&hint, 0, sizeof hint);
00743     hint.ai_flags = 0;
00744     hint.ai_family = PF_INET;
00745     hint.ai_socktype = SOCK_DGRAM;
00746     hint.ai_protocol = 0;
00747 
00748     err = netsnmp_getaddrinfo(name, NULL, &hint, &addrs);
00749     if (err != 0) {
00750 #if HAVE_GAI_STRERROR
00751         snmp_log(LOG_ERR, "getaddrinfo: %s %s\n", name,
00752                  gai_strerror(err));
00753 #else
00754         snmp_log(LOG_ERR, "getaddrinfo: %s (error %d)\n", name,
00755                  err);
00756 #endif
00757         return -1;
00758     }
00759 
00760     if (addrs != NULL) {
00761         memcpy(addr_out,
00762                &((struct sockaddr_in *) addrs->ai_addr)->sin_addr,
00763                sizeof(in_addr_t));
00764         freeaddrinfo(addrs);
00765     } else {
00766         DEBUGMSGTL(("get_thisaddr",
00767                     "Failed to resolve IPv4 hostname\n"));
00768     }
00769     return 0;
00770 
00771 #elif HAVE_GETHOSTBYNAME
00772     struct hostent *hp = NULL;
00773 
00774     hp = netsnmp_gethostbyname(name);
00775     if (hp == NULL) {
00776         DEBUGMSGTL(("get_thisaddr",
00777                     "hostname (couldn't resolve)\n"));
00778         return -1;
00779     } else if (hp->h_addrtype != AF_INET) {
00780         DEBUGMSGTL(("get_thisaddr",
00781                     "hostname (not AF_INET!)\n"));
00782         return -1;
00783     } else {
00784         DEBUGMSGTL(("get_thisaddr",
00785                     "hostname (resolved okay)\n"));
00786         memcpy(addr_out, hp->h_addr, sizeof(in_addr_t));
00787     }
00788     return 0;
00789 
00790 #elif HAVE_GETIPNODEBYNAME
00791     struct hostent *hp = NULL;
00792     int             err;
00793 
00794     hp = getipnodebyname(peername, AF_INET, 0, &err);
00795     if (hp == NULL) {
00796         DEBUGMSGTL(("get_thisaddr",
00797                     "hostname (couldn't resolve = %d)\n", err));
00798         return -1;
00799     }
00800     DEBUGMSGTL(("get_thisaddr",
00801                 "hostname (resolved okay)\n"));
00802     memcpy(addr_out, hp->h_addr, sizeof(in_addr_t));
00803     return 0;
00804 
00805 #else /* HAVE_GETIPNODEBYNAME */
00806     return -1;
00807 #endif
00808 }
00809 
00810 int
00811 netsnmp_getaddrinfo(const char *name, const char *service,
00812                     const struct addrinfo *hints, struct addrinfo **res)
00813 {
00814 #if HAVE_GETADDRINFO
00815     struct addrinfo *addrs = NULL;
00816     struct addrinfo hint;
00817     int             err;
00818 #ifdef DNSSEC_LOCAL_VALIDATION
00819     val_status_t    val_status;
00820 #endif
00821 
00822     DEBUGMSGTL(("dns:getaddrinfo", "looking up %s:%s\n", name, service));
00823 
00824     if (NULL == hints) {
00825         memset(&hint, 0, sizeof hint);
00826         hint.ai_flags = 0;
00827         hint.ai_family = PF_INET;
00828         hint.ai_socktype = SOCK_DGRAM;
00829         hint.ai_protocol = 0;
00830         hints = &hint;
00831     } else {
00832         memcpy(&hint, hints, sizeof hint);
00833     }
00834 
00835 #ifndef DNSSEC_LOCAL_VALIDATION
00836     err = getaddrinfo(name, NULL, &hint, &addrs);
00837 #else /* DNSSEC_LOCAL_VALIDATION */
00838     err = val_getaddrinfo(netsnmp_validator_context(), name, NULL, &hint,
00839                           &addrs, &val_status);
00840     DEBUGMSGTL(("dns:sec:val", "err %d, val_status %d / %s; trusted: %d\n",
00841                 err, val_status, p_val_status(val_status),
00842                 val_istrusted(val_status)));
00843     if (! val_istrusted(val_status)) {
00844         int rc;
00845         if ((err != 0) && VAL_GETADDRINFO_HAS_STATUS(err)) {
00846             snmp_log(LOG_WARNING,
00847                      "WARNING: UNTRUSTED error in DNS resolution for %s!\n",
00848                      name);
00849             rc = EAI_FAIL;
00850         } else {
00851             snmp_log(LOG_WARNING,
00852                      "The authenticity of DNS response is not trusted (%s)\n",
00853                      p_val_status(val_status));
00854             rc = EAI_NONAME;
00855         }
00857         if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
00858                                     NETSNMP_DS_LIB_DNSSEC_WARN_ONLY))
00859             return rc;
00860     }
00861 
00862 
00863 #endif /* DNSSEC_LOCAL_VALIDATION */
00864     *res = addrs;
00865     if ((0 == err) && addrs && addrs->ai_addr) {
00866         DEBUGMSGTL(("dns:getaddrinfo", "answer { AF_INET, %s:%hu }\n",
00867                     inet_ntoa(((struct sockaddr_in*)addrs->ai_addr)->sin_addr),
00868                     ntohs(((struct sockaddr_in*)addrs->ai_addr)->sin_port)));
00869     }
00870     return err;
00871 #else
00872     NETSNMP_LOGONCE((LOG_ERR, "getaddrinfo not available"));
00873     return EAI_FAIL;
00874 #endif /* getaddrinfo */
00875 }
00876 
00877 struct hostent *
00878 netsnmp_gethostbyname(const char *name)
00879 {
00880 #if HAVE_GETHOSTBYNAME
00881 #ifdef DNSSEC_LOCAL_VALIDATION
00882     val_status_t val_status;
00883 #endif
00884     struct hostent *hp = NULL;
00885 
00886     if (NULL == name)
00887         return NULL;
00888 
00889     DEBUGMSGTL(("dns:gethostbyname", "looking up %s\n", name));
00890 
00891 #ifdef DNSSEC_LOCAL_VALIDATION
00892     hp  = val_gethostbyname(netsnmp_validator_context(), name, &val_status);
00893     DEBUGMSGTL(("dns:sec:val", "val_status %d / %s; trusted: %d\n",
00894                 val_status, p_val_status(val_status),
00895                 val_istrusted(val_status)));
00896     if (!val_istrusted(val_status)) {
00897         snmp_log(LOG_WARNING,
00898                  "The authenticity of DNS response is not trusted (%s)\n",
00899                  p_val_status(val_status));
00901         if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
00902                                     NETSNMP_DS_LIB_DNSSEC_WARN_ONLY))
00903             hp = NULL;
00904     }
00905     else if (val_does_not_exist(val_status) && hp)
00906         hp = NULL;
00907 #else
00908     hp = gethostbyname(name);
00909 #endif
00910     if (hp == NULL) {
00911         DEBUGMSGTL(("dns:gethostbyname",
00912                     "couldn't resolve %s\n", name));
00913     } else if (hp->h_addrtype != AF_INET) {
00914         DEBUGMSGTL(("dns:gethostbyname",
00915                     "warning: response for %s not AF_INET!\n", name));
00916     } else {
00917         DEBUGMSGTL(("dns:gethostbyname",
00918                     "%s resolved okay\n", name));
00919     }
00920     return hp;
00921 #else
00922     NETSNMP_LOGONCE((LOG_ERR, "gethostbyname not available"));
00923     return NULL;
00924 #endif /* HAVE_GETHOSTBYNAME */
00925 }
00926 
00927 struct hostent *
00928 netsnmp_gethostbyaddr(const void *addr, socklen_t len, int type)
00929 {
00930 #if HAVE_GETHOSTBYADDR
00931     struct hostent *hp = NULL;
00932     struct sockaddr_in *saddr_in =
00933         NETSNMP_REMOVE_CONST(struct sockaddr_in *,addr);
00934 
00935     DEBUGMSGTL(("dns:gethostbyaddr", "resolving { AF_INET, %s:%hu }\n",
00936                 inet_ntoa(saddr_in->sin_addr), ntohs(saddr_in->sin_port)));
00937 
00938 #ifdef DNSSEC_LOCAL_VALIDATION
00939     val_status_t val_status;
00940     hp = val_gethostbyaddr(netsnmp_validator_context(),
00941                            (const void*)&saddr_in->sin_addr,
00942                            sizeof(struct in_addr), AF_INET, &val_status);
00943     DEBUGMSGTL(("dns:sec:val", "val_status %d / %s; trusted: %d\n",
00944                 val_status, p_val_status(val_status),
00945                 val_istrusted(val_status)));
00946     if (!val_istrusted(val_status)) {
00947         snmp_log(LOG_WARNING,
00948                  "The authenticity of DNS response is not trusted (%s)\n",
00949                  p_val_status(val_status));
00951         if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
00952                                     NETSNMP_DS_LIB_DNSSEC_WARN_ONLY))
00953             hp = NULL;
00954     }
00955     else if (val_does_not_exist(val_status) && hp)
00956         hp = NULL;
00957 #else
00958     hp = gethostbyaddr((const void*) &saddr_in->sin_addr,
00959                        sizeof(struct in_addr), AF_INET);
00960 #endif
00961     if (hp == NULL) {
00962         DEBUGMSGTL(("dns:gethostbyaddr", "couldn't resolve addr\n"));
00963     } else if (hp->h_addrtype != AF_INET) {
00964         DEBUGMSGTL(("dns:gethostbyaddr",
00965                     "warning: response for addr not AF_INET!\n"));
00966     } else {
00967         DEBUGMSGTL(("dns:gethostbyaddr", "addr resolved okay\n"));
00968     }
00969     return hp;
00970 #else
00971     NETSNMP_LOGONCE((LOG_ERR, "gethostbyname not available"));
00972     return NULL;
00973 #endif
00974 }
00975 
00976 /*******************************************************************/
00977 
00978 #ifndef HAVE_STRNCASECMP
00979 
00980 /*
00981  * test for NULL pointers before and NULL characters after
00982  * * comparing possibly non-NULL strings.
00983  * * WARNING: This function does NOT check for array overflow.
00984  */
00985 int
00986 strncasecmp(const char *s1, const char *s2, size_t nch)
00987 {
00988     size_t          ii;
00989     int             res = -1;
00990 
00991     if (!s1) {
00992         if (!s2)
00993             return 0;
00994         return (-1);
00995     }
00996     if (!s2)
00997         return (1);
00998 
00999     for (ii = 0; (ii < nch) && *s1 && *s2; ii++, s1++, s2++) {
01000         res = (int) (tolower(*s1) - tolower(*s2));
01001         if (res != 0)
01002             break;
01003     }
01004 
01005     if (ii == nch) {
01006         s1--;
01007         s2--;
01008     }
01009 
01010     if (!*s1) {
01011         if (!*s2)
01012             return 0;
01013         return (-1);
01014     }
01015     if (!*s2)
01016         return (1);
01017 
01018     return (res);
01019 }
01020 
01021 int
01022 strcasecmp(const char *s1, const char *s2)
01023 {
01024     return strncasecmp(s1, s2, 1000000);
01025 }
01026 
01027 #endif                          /* HAVE_STRNCASECMP */
01028 
01029 
01030 #ifndef HAVE_STRDUP
01031 char           *
01032 strdup(const char *src)
01033 {
01034     int             len;
01035     char           *dst;
01036 
01037     len = strlen(src) + 1;
01038     if ((dst = (char *) malloc(len)) == NULL)
01039         return (NULL);
01040     strcpy(dst, src);
01041     return (dst);
01042 }
01043 #endif                          /* HAVE_STRDUP */
01044 
01045 #ifndef HAVE_SETENV
01046 int
01047 setenv(const char *name, const char *value, int overwrite)
01048 {
01049     char           *cp;
01050     int             ret;
01051 
01052     if (overwrite == 0) {
01053         if (getenv(name))
01054             return 0;
01055     }
01056     cp = (char *) malloc(strlen(name) + strlen(value) + 2);
01057     if (cp == NULL)
01058         return -1;
01059     sprintf(cp, "%s=%s", name, value);
01060     ret = putenv(cp);
01061 #ifdef WIN32
01062     free(cp);
01063 #endif
01064     return ret;
01065 }
01066 #endif                          /* HAVE_SETENV */
01067 
01068 /* returns centiseconds */
01069 netsnmp_feature_child_of(calculate_time_diff, netsnmp_unused)
01070 #ifndef NETSNMP_FEATURE_REMOVE_CALCULATE_TIME_DIFF
01071 int
01072 calculate_time_diff(const struct timeval *now, const struct timeval *then)
01073 {
01074     struct timeval  tmp, diff;
01075     memcpy(&tmp, now, sizeof(struct timeval));
01076     tmp.tv_sec--;
01077     tmp.tv_usec += 1000000L;
01078     diff.tv_sec = tmp.tv_sec - then->tv_sec;
01079     diff.tv_usec = tmp.tv_usec - then->tv_usec;
01080     if (diff.tv_usec > 1000000L) {
01081         diff.tv_usec -= 1000000L;
01082         diff.tv_sec++;
01083     }
01084     return (int)(diff.tv_sec * 100 + diff.tv_usec / 10000);
01085 }
01086 #endif /* NETSNMP_FEATURE_REMOVE_CALCULATE_TIME_DIFF */
01087 
01088 #ifndef NETSNMP_FEATURE_REMOVE_CALCULATE_SECTIME_DIFF
01089 /* returns diff in rounded seconds */
01090 u_int
01091 calculate_sectime_diff(const struct timeval *now, const struct timeval *then)
01092 {
01093     struct timeval  tmp, diff;
01094     memcpy(&tmp, now, sizeof(struct timeval));
01095     tmp.tv_sec--;
01096     tmp.tv_usec += 1000000L;
01097     diff.tv_sec = tmp.tv_sec - then->tv_sec;
01098     diff.tv_usec = tmp.tv_usec - then->tv_usec;
01099     if (diff.tv_usec >= 1000000L) {
01100         diff.tv_usec -= 1000000L;
01101         diff.tv_sec++;
01102     }
01103     if (diff.tv_usec >= 500000L)
01104         return (u_int)(diff.tv_sec + 1);
01105     return (u_int)(diff.tv_sec);
01106 }
01107 #endif /* NETSNMP_FEATURE_REMOVE_CALCULATE_SECTIME_DIFF */
01108 
01109 #ifndef HAVE_STRCASESTR
01110 /*
01111  * only glibc2 has this.
01112  */
01113 char           *
01114 strcasestr(const char *haystack, const char *needle)
01115 {
01116     const char     *cp1 = haystack, *cp2 = needle;
01117     const char     *cx;
01118     int             tstch1, tstch2;
01119 
01120     /*
01121      * printf("looking for '%s' in '%s'\n", needle, haystack); 
01122      */
01123     if (cp1 && cp2 && *cp1 && *cp2)
01124         for (cp1 = haystack, cp2 = needle; *cp1;) {
01125             cx = cp1;
01126             cp2 = needle;
01127             do {
01128                 /*
01129                  * printf("T'%c' ", *cp1); 
01130                  */
01131                 if (!*cp2) {    /* found the needle */
01132                     /*
01133                      * printf("\nfound '%s' in '%s'\n", needle, cx); 
01134                      */
01135                     return NETSNMP_REMOVE_CONST(char *, cx);
01136                 }
01137                 if (!*cp1)
01138                     break;
01139 
01140                 tstch1 = toupper(*cp1);
01141                 tstch2 = toupper(*cp2);
01142                 if (tstch1 != tstch2)
01143                     break;
01144                 /*
01145                  * printf("M'%c' ", *cp1); 
01146                  */
01147                 cp1++;
01148                 cp2++;
01149             }
01150             while (1);
01151             if (*cp1)
01152                 cp1++;
01153         }
01154     /*
01155      * printf("\n"); 
01156      */
01157     if (cp1 && *cp1)
01158         return NETSNMP_REMOVE_CONST(char *, cp1);
01159 
01160     return NULL;
01161 }
01162 #endif
01163 
01164 int
01165 mkdirhier(const char *pathname, mode_t mode, int skiplast)
01166 {
01167     struct stat     sbuf;
01168     char           *ourcopy = strdup(pathname);
01169     char           *entry;
01170     char            buf[SNMP_MAXPATH];
01171     char           *st = NULL;
01172 
01173 #if defined (WIN32) || defined (cygwin)
01174     /* convert backslash to forward slash */
01175     for (entry = ourcopy; *entry; entry++)
01176         if (*entry == '\\')
01177             *entry = '/';
01178 #endif
01179 
01180     entry = strtok_r(ourcopy, "/", &st);
01181 
01182     buf[0] = '\0';
01183 
01184 #if defined (WIN32) || defined (cygwin)
01185     /*
01186      * Check if first entry contains a drive-letter
01187      *   e.g  "c:/path"
01188      */
01189     if ((entry) && (':' == entry[1]) &&
01190         (('\0' == entry[2]) || ('/' == entry[2]))) {
01191         strcat(buf, entry);
01192         entry = strtok_r(NULL, "/", &st);
01193     }
01194 #endif
01195 
01196     /*
01197      * check to see if filename is a directory 
01198      */
01199     while (entry) {
01200         strcat(buf, "/");
01201         strcat(buf, entry);
01202         entry = strtok_r(NULL, "/", &st);
01203         if (entry == NULL && skiplast)
01204             break;
01205         if (stat(buf, &sbuf) < 0) {
01206             /*
01207              * DNE, make it 
01208              */
01209 #ifdef WIN32
01210             if (CreateDirectory(buf, NULL) == 0)
01211 #else
01212             if (mkdir(buf, mode) == -1)
01213 #endif
01214             {
01215                 free(ourcopy);
01216                 return SNMPERR_GENERR;
01217             } else {
01218                 snmp_log(LOG_INFO, "Created directory: %s\n", buf);
01219             }
01220         } else {
01221             /*
01222              * exists, is it a file? 
01223              */
01224             if ((sbuf.st_mode & S_IFDIR) == 0) {
01225                 /*
01226                  * ack! can't make a directory on top of a file 
01227                  */
01228                 free(ourcopy);
01229                 return SNMPERR_GENERR;
01230             }
01231         }
01232     }
01233     free(ourcopy);
01234     return SNMPERR_SUCCESS;
01235 }
01236 
01243 const char     *
01244 netsnmp_mktemp(void)
01245 {
01246 #ifdef PATH_MAX
01247     static char     name[PATH_MAX];
01248 #else
01249     static char     name[256];
01250 #endif
01251     int             fd = -1;
01252 
01253     strcpy(name, get_temp_file_pattern());
01254 #ifdef HAVE_MKSTEMP
01255     fd = mkstemp(name);
01256 #else
01257     if (mktemp(name)) {
01258 # ifndef WIN32
01259         fd = open(name, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
01260 # else
01261         /*
01262          * Win32 needs _S_IREAD | _S_IWRITE to set permissions on file
01263          * after closing
01264          */
01265         fd = _open(name, _O_CREAT | _O_EXCL | _O_WRONLY, _S_IREAD | _S_IWRITE);
01266 # endif
01267     }
01268 #endif
01269     if (fd >= 0) {
01270         close(fd);
01271         DEBUGMSGTL(("netsnmp_mktemp", "temp file created: %s\n",
01272                     name));
01273         return name;
01274     }
01275     snmp_log(LOG_ERR, "netsnmp_mktemp: error creating file %s\n",
01276              name);
01277     return NULL;
01278 }
01279 
01280 /*
01281  * This function was created to differentiate actions
01282  * that are appropriate for Linux 2.4 kernels, but not later kernels.
01283  *
01284  * This function can be used to test kernels on any platform that supports uname().
01285  *
01286  * If not running a platform that supports uname(), return -1.
01287  *
01288  * If ospname matches, and the release matches up through the prefix,
01289  *  return 0.
01290  * If the release is ordered higher, return 1.
01291  * Be aware that "ordered higher" is not a guarantee of correctness.
01292  */
01293 int
01294 netsnmp_os_prematch(const char *ospmname,
01295                     const char *ospmrelprefix)
01296 {
01297 #if HAVE_SYS_UTSNAME_H
01298 static int printOSonce = 1;
01299   struct utsname utsbuf;
01300   if ( 0 != uname(&utsbuf))
01301     return -1;
01302 
01303   if (printOSonce) {
01304     printOSonce = 0;
01305     /* show the four elements that the kernel can be sure of */
01306   DEBUGMSGT(("daemonize","sysname '%s',\nrelease '%s',\nversion '%s',\nmachine '%s'\n",
01307       utsbuf.sysname, utsbuf.release, utsbuf.version, utsbuf.machine));
01308   }
01309   if (0 != strcasecmp(utsbuf.sysname, ospmname)) return -1;
01310 
01311   /* Required to match only the leading characters */
01312   return strncasecmp(utsbuf.release, ospmrelprefix, strlen(ospmrelprefix));
01313 
01314 #else
01315 
01316   return -1;
01317 
01318 #endif /* HAVE_SYS_UTSNAME_H */
01319 }
01320 
01327 int
01328 netsnmp_os_kernel_width(void)
01329 {
01330 #ifdef irix6
01331   char buf[8];
01332   sysinfo(_MIPS_SI_OS_NAME, buf, 7);
01333   if (strncmp("IRIX64", buf, 6) == 0) {
01334     return 64;
01335   } else if (strncmp("IRIX", buf, 4) == 0) {
01336     return 32;
01337   } else {
01338     return -1;
01339   }
01340 #elif defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
01341   return (__KERNEL_32() ? 32 : (__KERNEL_64() ? 64 : -1));
01342 #elif defined(osf4) || defined(osf5) || defined(__alpha)
01343   return 64; /* Alpha is always 64bit */
01344 #else
01345   /* kernel width detection not implemented */
01346   return -1;
01347 #endif
01348 }
01349 
01350 netsnmp_feature_child_of(str_to_uid, user_information)
01351 #ifndef NETSNMP_FEATURE_REMOVE_STR_TO_UID
01352 int netsnmp_str_to_uid(const char *useroruid) {
01353     int uid;
01354 #if HAVE_GETPWNAM && HAVE_PWD_H
01355     struct passwd *pwd;
01356 #endif
01357 
01358     uid = atoi(useroruid);
01359 
01360     if ( uid == 0 ) {
01361 #if HAVE_GETPWNAM && HAVE_PWD_H
01362         pwd = getpwnam( useroruid );
01363         if (pwd)
01364             uid = pwd->pw_uid;
01365         else
01366 #endif
01367             snmp_log(LOG_WARNING, "Can't identify user (%s).\n", useroruid);
01368     }
01369     return uid;
01370     
01371 }
01372 #endif /* NETSNMP_FEATURE_REMOVE_STR_TO_UID */
01373 
01374 netsnmp_feature_child_of(str_to_gid, user_information)
01375 #ifndef NETSNMP_FEATURE_REMOVE_STR_TO_GID
01376 int netsnmp_str_to_gid(const char *grouporgid) {
01377     int gid;
01378 #if HAVE_GETGRNAM && HAVE_GRP_H
01379     struct group  *grp;
01380 #endif
01381 
01382     gid = atoi(grouporgid);
01383 
01384     if ( gid == 0 ) {
01385 #if HAVE_GETGRNAM && HAVE_GRP_H
01386         grp = getgrnam( grouporgid );
01387         if (grp)
01388             gid = grp->gr_gid;
01389         else
01390 #endif
01391             snmp_log(LOG_WARNING, "Can't identify group (%s).\n",
01392                      grouporgid);
01393     }
01394 
01395     return gid;
01396 }
01397 #endif /* NETSNMP_FEATURE_REMOVE_STR_TO_GID */