net-snmp 5.7
|
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 */