Coverage Report

Created: 2023-06-07 06:42

/src/net-snmp/snmplib/system.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * system.c
3
 */
4
/* Portions of this file are subject to the following copyright(s).  See
5
 * the Net-SNMP's COPYING file for more details and other copyrights
6
 * that may apply:
7
 */
8
/***********************************************************
9
        Copyright 1992 by Carnegie Mellon University
10
11
                      All Rights Reserved
12
13
Permission to use, copy, modify, and distribute this software and its
14
documentation for any purpose and without fee is hereby granted,
15
provided that the above copyright notice appear in all copies and that
16
both that copyright notice and this permission notice appear in
17
supporting documentation, and that the name of CMU not be
18
used in advertising or publicity pertaining to distribution of the
19
software without specific, written prior permission.
20
21
CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
22
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
23
CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
24
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
25
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
26
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
27
SOFTWARE.
28
******************************************************************/
29
/*
30
 * Portions of this file are copyrighted by:
31
 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
32
 * Use is subject to license terms specified in the COPYING file
33
 * distributed with the Net-SNMP package.
34
 */
35
/*
36
 * Portions of this file are copyrighted by:
37
 * Copyright (C) 2007 Apple, Inc. All rights reserved.
38
 * Use is subject to license terms specified in the COPYING file
39
 * distributed with the Net-SNMP package.
40
 *
41
 * Portions of this file are copyrighted by:
42
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
43
 * Use is subject to license terms specified in the COPYING file
44
 * distributed with the Net-SNMP package.
45
 */
46
/*
47
 * System dependent routines go here
48
 */
49
#include <net-snmp/net-snmp-config.h>
50
#include <net-snmp/net-snmp-features.h>
51
#include <stdio.h>
52
#include <ctype.h>
53
#include <errno.h>
54
55
#ifdef HAVE_INTTYPES_H
56
#include <inttypes.h>
57
#endif
58
#ifdef HAVE_IO_H
59
#include <io.h>
60
#endif
61
#ifdef HAVE_DIRECT_H
62
#include <direct.h>
63
#endif
64
#ifdef HAVE_UNISTD_H
65
#include <unistd.h>
66
#endif
67
#ifdef HAVE_STDLIB_H
68
#include <stdlib.h>
69
#endif
70
71
#ifdef TIME_WITH_SYS_TIME
72
# include <sys/time.h>
73
# include <time.h>
74
#else
75
# ifdef HAVE_SYS_TIME_H
76
#  include <sys/time.h>
77
# else
78
#  include <time.h>
79
# endif
80
#endif
81
82
#include <sys/types.h>
83
84
#ifdef HAVE_NETINET_IN_H
85
#include <netinet/in.h>
86
#endif
87
88
#ifdef HAVE_SYS_SOCKET_H
89
#include <sys/socket.h>
90
#endif
91
#ifdef HAVE_NET_IF_H
92
#include <net/if.h>
93
#endif
94
#ifdef HAVE_NETDB_H
95
#include <netdb.h>
96
#endif
97
98
99
#ifdef HAVE_SYS_SOCKIO_H
100
#include <sys/sockio.h>
101
#endif
102
103
#ifdef HAVE_SYS_IOCTL_H
104
#include <sys/ioctl.h>
105
#endif
106
107
#ifdef HAVE_NLIST_H
108
#include <nlist.h>
109
#endif
110
111
#ifdef HAVE_SYS_FILE_H
112
#include <sys/file.h>
113
#endif
114
115
#ifdef HAVE_KSTAT_H
116
#include <kstat.h>
117
#endif
118
119
#ifdef HAVE_SYS_PARAM_H
120
#include <sys/param.h>
121
#endif
122
#ifdef HAVE_SYS_SYSCTL_H
123
#include <sys/sysctl.h>
124
#endif
125
126
#ifdef HAVE_STRING_H
127
#include <string.h>
128
#else
129
#include <strings.h>
130
#endif
131
132
#ifdef WIN32
133
#include <wchar.h>   /* wcsncmp() */
134
#include <winperf.h> /* PERF_DATA_BLOCK */
135
#endif
136
137
#ifdef HAVE_SYS_STAT_H
138
#include <sys/stat.h>
139
#endif
140
#ifdef HAVE_FCNTL_H
141
#include <fcntl.h>
142
#endif
143
144
#if defined(hpux10) || defined(hpux11)
145
#include <sys/pstat.h>
146
#endif
147
148
#ifdef HAVE_SYS_UTSNAME_H
149
#include <sys/utsname.h>
150
#endif
151
152
#ifdef HAVE_SYS_SYSTEMCFG_H
153
#include <sys/systemcfg.h>
154
#endif
155
156
#ifdef HAVE_SYS_SYSTEMINFO_H
157
#include <sys/systeminfo.h>
158
#endif
159
160
#ifdef HAVE_CRT_EXTERNS_H
161
#include <crt_externs.h>        /* for _NSGetArgv() */
162
#endif
163
164
#ifdef HAVE_MACH_O_DYLD_H
165
#include <mach-o/dyld.h>
166
#endif
167
168
#ifdef HAVE_PWD_H
169
#include <pwd.h>
170
#endif
171
#ifdef HAVE_GRP_H
172
#include <grp.h>
173
#endif
174
175
#ifdef HAVE_LIMITS_H
176
#include <limits.h>
177
#endif
178
179
#ifdef HAVE_ARPA_INET_H
180
#include <arpa/inet.h>
181
#endif
182
183
#ifdef DNSSEC_LOCAL_VALIDATION
184
#if 1 /*HAVE_ARPA_NAMESER_H*/
185
#include <arpa/nameser.h>
186
#endif
187
#include <validator/validator.h>
188
/* NetSNMP and DNSSEC-Tools both define FREE. We'll not use either here. */
189
#undef FREE
190
#endif
191
192
#include <net-snmp/types.h>
193
#include <net-snmp/output_api.h>
194
#include <net-snmp/utilities.h>
195
#include <net-snmp/library/system.h>    /* for "internal" definitions */
196
197
#include <net-snmp/library/snmp_api.h>
198
#include <net-snmp/library/read_config.h> /* for get_temp_file_pattern() */
199
200
#include "inet_ntop.h"
201
202
/* NetSNMP and DNSSEC-Tools both define FREE. We'll not use either here. */
203
#undef FREE
204
205
netsnmp_feature_child_of(system_all, libnetsnmp);
206
207
netsnmp_feature_child_of(user_information, system_all);
208
netsnmp_feature_child_of(calculate_sectime_diff, system_all);
209
210
#ifndef IFF_LOOPBACK
211
# define IFF_LOOPBACK 0
212
#endif
213
214
#ifdef  INADDR_LOOPBACK
215
0
# define LOOPBACK    INADDR_LOOPBACK
216
#else
217
# define LOOPBACK    0x7f000001
218
#endif
219
220
#ifndef EAI_FAIL
221
# define EAI_FAIL    -4    /* Non-recoverable failure in name res.  */
222
#endif
223
224
#if defined(HAVE_FORK)
225
static void
226
_daemon_prep(int stderr_log)
227
0
{
228
0
    int fd;
229
230
    /* Avoid keeping any directory in use. */
231
0
    NETSNMP_IGNORE_RESULT(chdir("/"));
232
233
0
    if (stderr_log)
234
0
        return;
235
236
0
    fd = open("/dev/null", O_RDWR);
237
    
238
    /*
239
     * Close inherited file descriptors to avoid
240
     * keeping unnecessary references.
241
     */
242
0
    close(STDIN_FILENO);
243
0
    close(STDOUT_FILENO);
244
0
    close(STDERR_FILENO);
245
246
    /*
247
     * Redirect std{in,out,err} to /dev/null, just in case.
248
     */
249
0
    if (fd >= 0) {
250
0
        dup2(fd, STDIN_FILENO);
251
0
        dup2(fd, STDOUT_FILENO);
252
0
        dup2(fd, STDERR_FILENO);
253
0
        close(fd);
254
0
    }
255
0
}
256
#endif
257
258
/**
259
 * fork current process into the background.
260
 *
261
 * This function forks a process into the background, in order to
262
 * become a daemon process. It does a few things along the way:
263
 *
264
 * - becoming a process/session group leader, and  forking a second time so
265
 *   that process/session group leader can exit.
266
 *
267
 * - changing the working directory to /
268
 *
269
 * - closing stdin, stdout and stderr (unless stderr_log is set) and
270
 *   redirecting them to /dev/null
271
 *
272
 * @param quit_immediately : indicates if the parent process should
273
 *                           exit after a successful fork.
274
 * @param stderr_log       : indicates if stderr is being used for
275
 *                           logging and shouldn't be closed
276
 * @returns -1 : fork error
277
 *           0 : child process returning
278
 *          >0 : parent process returning. returned value is the child PID.
279
 */
280
int
281
netsnmp_daemonize(int quit_immediately, int stderr_log)
282
0
{
283
0
    int i = 0;
284
0
    DEBUGMSGT(("daemonize","deamonizing...\n"));
285
0
#ifdef HAVE_FORK
286
#ifdef HAVE__NSGETEXECUTABLEPATH
287
     char            path [PATH_MAX] = "";
288
     uint32_t        size = sizeof (path);
289
290
     /*
291
      * if we are already launched in a "daemonized state", just
292
      * close & redirect the file descriptors
293
      */
294
     if(getppid() <= 2) {
295
         _daemon_prep(stderr_log);
296
         return 0;
297
     }
298
299
     if (_NSGetExecutablePath (path, &size))
300
         return -1;
301
#endif
302
    /*
303
     * Fork to return control to the invoking process and to
304
     * guarantee that we aren't a process group leader.
305
     */
306
#ifdef HAVE_FORKALL
307
    i = forkall();
308
#else
309
0
    i = fork();
310
0
#endif
311
0
    if (i != 0) {
312
        /* Parent. */
313
0
        DEBUGMSGT(("daemonize","first fork returned %d.\n", i));
314
0
        if(i == -1) {
315
0
            snmp_log(LOG_ERR,"first fork failed (errno %d) in "
316
0
                     "netsnmp_daemonize()\n", errno);
317
0
            return -1;
318
0
        }
319
0
        if (quit_immediately) {
320
0
            DEBUGMSGT(("daemonize","parent exiting\n"));
321
0
            exit(0);
322
0
        }
323
0
    } else {
324
        /* Child. */
325
0
#ifdef HAVE_SETSID
326
        /* Become a process/session group leader. */
327
0
        setsid();
328
0
#endif
329
        /*
330
         * Fork to let the process/session group leader exit.
331
         */
332
#ifdef HAVE_FORKALL
333
  i = forkall();
334
#else
335
0
  i = fork();
336
0
#endif
337
0
        if (i != 0) {
338
0
            DEBUGMSGT(("daemonize","second fork returned %d.\n", i));
339
0
            if(i == -1) {
340
0
                snmp_log(LOG_ERR,"second fork failed (errno %d) in "
341
0
                         "netsnmp_daemonize()\n", errno);
342
0
            }
343
            /* Parent. */
344
0
            exit(0);
345
0
        }
346
0
#ifndef WIN32
347
0
        else {
348
            /* Child. */
349
            
350
0
            DEBUGMSGT(("daemonize","child continuing\n"));
351
352
0
#if !defined(HAVE__NSGETARGV)
353
0
            _daemon_prep(stderr_log);
354
#else
355
             /*
356
              * Some darwin calls (using mach ports) don't work after
357
              * a fork. So, now that we've forked, we re-exec ourself
358
              * to ensure that the child's mach ports are all set up correctly,
359
              * the getppid call above will prevent the exec child from
360
              * forking...
361
              */
362
             char * const *argv = *_NSGetArgv ();
363
             DEBUGMSGT(("daemonize","re-execing forked child\n"));
364
             execv (path, argv);
365
             snmp_log(LOG_ERR,"Forked child unable to re-exec - %s.\n", strerror (errno));
366
             exit (0);
367
#endif
368
0
        }
369
0
#endif /* !WIN32 */
370
0
    }
371
0
#endif /* HAVE_FORK */
372
0
    return i;
373
0
}
374
375
/*
376
 * ********************************************* 
377
 */
378
#ifdef              WIN32
379
in_addr_t
380
get_myaddr(void)
381
{
382
    char            local_host[130];
383
    int             result;
384
    LPHOSTENT       lpstHostent;
385
    SOCKADDR_IN     in_addr, remote_in_addr;
386
    SOCKET          hSock;
387
    int             nAddrSize = sizeof(SOCKADDR);
388
389
    in_addr.sin_addr.s_addr = INADDR_ANY;
390
391
    result = gethostname(local_host, sizeof(local_host));
392
    if (result == 0) {
393
        lpstHostent = gethostbyname((LPSTR) local_host);
394
        if (lpstHostent) {
395
            in_addr.sin_addr.s_addr =
396
                *((u_long FAR *) (lpstHostent->h_addr));
397
            return ((in_addr_t) in_addr.sin_addr.s_addr);
398
        }
399
    }
400
401
    /*
402
     * if we are here, than we don't have host addr 
403
     */
404
    hSock = socket(AF_INET, SOCK_DGRAM, 0);
405
    if (hSock != INVALID_SOCKET) {
406
        /*
407
         * connect to any port and address 
408
         */
409
        remote_in_addr.sin_family = AF_INET;
410
        remote_in_addr.sin_port = htons(IPPORT_ECHO);
411
        remote_in_addr.sin_addr.s_addr = inet_addr("0.0.0.0");
412
        result =
413
            connect(hSock, (LPSOCKADDR) & remote_in_addr,
414
                    sizeof(SOCKADDR));
415
        if (result != SOCKET_ERROR) {
416
            /*
417
             * get local ip address 
418
             */
419
            getsockname(hSock, (LPSOCKADDR) & in_addr,
420
                        (int FAR *) &nAddrSize);
421
        }
422
        closesocket(hSock);
423
    }
424
    return ((in_addr_t) in_addr.sin_addr.s_addr);
425
}
426
427
long
428
get_uptime(void)
429
{
430
    long            return_value = 0;
431
    DWORD           buffersize = (sizeof(PERF_DATA_BLOCK) +
432
                                  sizeof(PERF_OBJECT_TYPE)),
433
        type = REG_EXPAND_SZ;
434
    PPERF_DATA_BLOCK perfdata = NULL;
435
436
    /*
437
     * min requirement is one PERF_DATA_BLOCK plus one PERF_OBJECT_TYPE 
438
     */
439
    perfdata = (PPERF_DATA_BLOCK) malloc(buffersize);
440
    if (!perfdata)
441
        return 0;
442
443
    memset(perfdata, 0, buffersize);
444
445
    RegQueryValueEx(HKEY_PERFORMANCE_DATA,
446
                    "Global", NULL, &type, (LPBYTE) perfdata, &buffersize);
447
448
    /*
449
     * we can not rely on the return value since there is always more so
450
     * we check the signature 
451
     */
452
453
    if (wcsncmp(perfdata->Signature, L"PERF", 4) == 0) {
454
        /*
455
         * signature ok, and all we need is in the in the PERF_DATA_BLOCK 
456
         */
457
        return_value = (long) ((perfdata->PerfTime100nSec.QuadPart /
458
                                (LONGLONG) 100000));
459
    } else
460
        return_value = GetTickCount() / 10;
461
462
    RegCloseKey(HKEY_PERFORMANCE_DATA);
463
    free(perfdata);
464
465
    return return_value;
466
}
467
468
char           *
469
winsock_startup(void)
470
{
471
    WORD            VersionRequested;
472
    WSADATA         stWSAData;
473
    int             i;
474
    static char     errmsg[100];
475
476
  /* winsock 1: use MAKEWORD(1,1) */
477
  /* winsock 2: use MAKEWORD(2,2) */
478
479
    VersionRequested = MAKEWORD(2,2);
480
    i = WSAStartup(VersionRequested, &stWSAData);
481
    if (i != 0) {
482
        if (i == WSAVERNOTSUPPORTED)
483
            sprintf(errmsg,
484
                    "Unable to init. socket lib, does not support 1.1");
485
        else {
486
            sprintf(errmsg, "Socket Startup error %d", i);
487
        }
488
        return (errmsg);
489
    }
490
    return (NULL);
491
}
492
493
void
494
winsock_cleanup(void)
495
{
496
    WSACleanup();
497
}
498
499
#else                           /* ! WIN32 */
500
/*******************************************************************/
501
502
/*
503
 * XXX  What if we have multiple addresses?  Or no addresses for that matter?
504
 * XXX  Could it be computed once then cached?  Probably not worth it (not
505
 *                                                           used very often).
506
 */
507
in_addr_t
508
get_myaddr(void)
509
0
{
510
0
    int             sd, i, lastlen = 0;
511
0
    struct ifconf   ifc;
512
0
    struct ifreq   *ifrp = NULL;
513
0
    in_addr_t       addr;
514
0
    char           *buf = NULL;
515
516
0
    if ((sd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
517
0
        return 0;
518
0
    }
519
520
    /*
521
     * Cope with lots of interfaces and brokenness of ioctl SIOCGIFCONF on
522
     * some platforms; see W. R. Stevens, ``Unix Network Programming Volume
523
     * I'', p.435.  
524
     */
525
526
0
    for (i = 8;; i += 8) {
527
0
        buf = calloc(i, sizeof(struct ifreq));
528
0
        if (buf == NULL) {
529
0
            close(sd);
530
0
            return 0;
531
0
        }
532
0
        ifc.ifc_len = i * sizeof(struct ifreq);
533
0
        ifc.ifc_buf = (caddr_t) buf;
534
535
0
        if (ioctl(sd, SIOCGIFCONF, (char *) &ifc) < 0) {
536
0
            if (errno != EINVAL || lastlen != 0) {
537
                /*
538
                 * Something has gone genuinely wrong.  
539
                 */
540
0
                free(buf);
541
0
                close(sd);
542
0
                return 0;
543
0
            }
544
            /*
545
             * Otherwise, it could just be that the buffer is too small.  
546
             */
547
0
        } else {
548
0
            if (ifc.ifc_len == lastlen) {
549
                /*
550
                 * The length is the same as the last time; we're done.  
551
                 */
552
0
                break;
553
0
            }
554
0
            lastlen = ifc.ifc_len;
555
0
        }
556
0
        free(buf);
557
0
    }
558
559
0
    for (ifrp = ifc.ifc_req;
560
0
        (char *)ifrp < (char *)ifc.ifc_req + ifc.ifc_len;
561
#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
562
        ifrp = (struct ifreq *)(((char *) ifrp) +
563
                                sizeof(ifrp->ifr_name) +
564
                                ifrp->ifr_addr.sa_len)
565
#else
566
0
        ifrp++
567
0
#endif
568
0
        ) {
569
0
        if (ifrp->ifr_addr.sa_family != AF_INET) {
570
0
            continue;
571
0
        }
572
0
        addr = ((struct sockaddr_in *) &(ifrp->ifr_addr))->sin_addr.s_addr;
573
574
0
        if (ioctl(sd, SIOCGIFFLAGS, (char *) ifrp) < 0) {
575
0
            continue;
576
0
        }
577
0
        if ((ifrp->ifr_flags & IFF_UP)
578
0
#ifdef IFF_RUNNING
579
0
            && (ifrp->ifr_flags & IFF_RUNNING)
580
0
#endif                          /* IFF_RUNNING */
581
0
            && !(ifrp->ifr_flags & IFF_LOOPBACK)
582
0
            && addr != LOOPBACK) {
583
            /*
584
             * I *really* don't understand why this is necessary.  Perhaps for
585
             * some broken platform?  Leave it for now.  JBPN  
586
             */
587
0
#ifdef SYS_IOCTL_H_HAS_SIOCGIFADDR
588
0
            if (ioctl(sd, SIOCGIFADDR, (char *) ifrp) < 0) {
589
0
                continue;
590
0
            }
591
0
            addr =
592
0
                ((struct sockaddr_in *) &(ifrp->ifr_addr))->sin_addr.
593
0
                s_addr;
594
0
#endif
595
0
            free(buf);
596
0
            close(sd);
597
0
            return addr;
598
0
        }
599
0
    }
600
0
    free(buf);
601
0
    close(sd);
602
0
    return 0;
603
0
}
604
605
606
#if !defined(solaris2) && !defined(linux) && !defined(cygwin)
607
/*
608
 * Returns boottime in centiseconds(!).
609
 *      Caches this for future use.
610
 */
611
long
612
get_boottime(void)
613
{
614
    static long     boottime_csecs = 0;
615
#if defined(hpux10) || defined(hpux11)
616
    struct pst_static pst_buf;
617
#else
618
    struct timeval  boottime;
619
#ifdef  NETSNMP_CAN_USE_SYSCTL
620
    int             mib[2];
621
    size_t          len;
622
#elif defined(NETSNMP_CAN_USE_NLIST)
623
    int             kmem;
624
#if !defined(hpux)
625
    static char boottime_name[] = "_boottime";
626
#else
627
    static char boottime_name[] = "boottime";
628
#endif
629
    static char empty_name[] = "";
630
    struct nlist nl[2];
631
632
    memset(nl, 0, sizeof(nl));
633
    nl[0].n_name = boottime_name;
634
    nl[1].n_name = empty_name;
635
#endif                          /* NETSNMP_CAN_USE_SYSCTL */
636
#endif                          /* hpux10 || hpux 11 */
637
638
639
    if (boottime_csecs != 0)
640
        return (boottime_csecs);
641
642
#if defined(hpux10) || defined(hpux11)
643
    pstat_getstatic(&pst_buf, sizeof(struct pst_static), 1, 0);
644
    boottime_csecs = pst_buf.boot_time * 100;
645
#elif defined(NETSNMP_CAN_USE_SYSCTL)
646
    mib[0] = CTL_KERN;
647
    mib[1] = KERN_BOOTTIME;
648
649
    len = sizeof(boottime);
650
651
    sysctl(mib, 2, &boottime, &len, NULL, 0);
652
    boottime_csecs = (boottime.tv_sec * 100) + (boottime.tv_usec / 10000);
653
#elif defined(NETSNMP_CAN_USE_NLIST)
654
    if ((kmem = open("/dev/kmem", 0)) < 0)
655
        return 0;
656
    nlist(KERNEL_LOC, nl);
657
    if (nl[0].n_type == 0) {
658
        close(kmem);
659
        return 0;
660
    }
661
662
    lseek(kmem, (long) nl[0].n_value, L_SET);
663
    read(kmem, &boottime, sizeof(boottime));
664
    close(kmem);
665
    boottime_csecs = (boottime.tv_sec * 100) + (boottime.tv_usec / 10000);
666
#else
667
    return 0;
668
#endif                          /* hpux10 || hpux 11 */
669
670
    return (boottime_csecs);
671
}
672
#endif
673
674
/**
675
 * Returns the system uptime in centiseconds.
676
 *
677
 * @note The value returned by this function is not identical to sysUpTime
678
 *   defined in RFC 1213. get_uptime() returns the system uptime while
679
 *   sysUpTime represents the time that has elapsed since the most recent
680
 *   restart of the network manager (snmpd).
681
 *
682
 * @see See also netsnmp_get_agent_uptime().
683
 */
684
long
685
get_uptime(void)
686
0
{
687
#if defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
688
    static char lbolt_name[] = "lbolt";
689
    struct nlist nl;
690
    int kmem;
691
    time_t lbolt;
692
    nl.n_name = lbolt_name;
693
    if(knlist(&nl, 1, sizeof(struct nlist)) != 0) return(0);
694
    if(nl.n_type == 0 || nl.n_value == 0) return(0);
695
    if((kmem = open("/dev/mem", 0)) < 0) return 0;
696
    lseek(kmem, (long) nl.n_value, L_SET);
697
    read(kmem, &lbolt, sizeof(lbolt));
698
    close(kmem);
699
    return(lbolt);
700
#elif defined(solaris2)
701
    kstat_ctl_t    *ksc = kstat_open();
702
    kstat_t        *ks;
703
    kid_t           kid;
704
    kstat_named_t  *named;
705
    u_long          lbolt = 0;
706
707
    if (ksc) {
708
        ks = kstat_lookup(ksc, NETSNMP_REMOVE_CONST(char *, "unix"), -1,
709
                          NETSNMP_REMOVE_CONST(char *, "system_misc"));
710
        if (ks) {
711
            kid = kstat_read(ksc, ks, NULL);
712
            if (kid != -1) {
713
                named = kstat_data_lookup(ks, NETSNMP_REMOVE_CONST(char *, "lbolt"));
714
                if (named) {
715
#ifdef KSTAT_DATA_UINT32
716
                    lbolt = named->value.ui32;
717
#else
718
                    lbolt = named->value.ul;
719
#endif
720
                }
721
            }
722
        }
723
        kstat_close(ksc);
724
    }
725
    return lbolt;
726
#elif defined(linux) || defined(cygwin)
727
0
    FILE           *in = fopen("/proc/uptime", "r");
728
0
    long            uptim = 0, a, b;
729
0
    if (in) {
730
0
        if (2 == fscanf(in, "%ld.%ld", &a, &b))
731
0
            uptim = a * 100 + b;
732
0
        fclose(in);
733
0
    }
734
0
    return uptim;
735
#else
736
    struct timeval  now;
737
    long            boottime_csecs, nowtime_csecs;
738
739
    boottime_csecs = get_boottime();
740
    if (boottime_csecs == 0)
741
        return 0;
742
    gettimeofday(&now, (struct timezone *) 0);
743
    nowtime_csecs = (now.tv_sec * 100) + (now.tv_usec / 10000);
744
745
    return (nowtime_csecs - boottime_csecs);
746
#endif
747
0
}
748
749
#endif                          /* ! WIN32 */
750
/*******************************************************************/
751
752
#ifdef DNSSEC_LOCAL_VALIDATION
753
static val_context_t *_val_context = NULL;
754
755
static val_context_t *
756
netsnmp_validator_context(void)
757
{
758
    if (NULL == _val_context) {
759
        int rc;
760
        char *apptype = netsnmp_ds_get_string(NETSNMP_DS_LIBRARY_ID, 
761
                                              NETSNMP_DS_LIB_APPTYPE);
762
        DEBUGMSGTL(("dns:sec:context", "creating dnssec context for %s\n",
763
                    apptype));
764
        rc = val_create_context(apptype, &_val_context);
765
    }
766
767
    return _val_context;
768
}
769
#endif /* DNSSEC_LOCAL_VALIDATION */
770
771
int
772
netsnmp_gethostbyname_v4(const char* name, in_addr_t *addr_out)
773
0
{
774
0
#ifdef HAVE_GETADDRINFO
775
0
    struct addrinfo *addrs = NULL;
776
0
    struct addrinfo hint;
777
0
    int             err;
778
779
0
    memset(&hint, 0, sizeof hint);
780
0
    hint.ai_flags = 0;
781
0
    hint.ai_family = PF_INET;
782
0
    hint.ai_socktype = SOCK_DGRAM;
783
0
    hint.ai_protocol = 0;
784
785
0
    err = netsnmp_getaddrinfo(name, NULL, &hint, &addrs);
786
0
    if (err != 0) {
787
0
        return -1;
788
0
    }
789
790
0
    if (addrs != NULL) {
791
0
        memcpy(addr_out,
792
0
               &((struct sockaddr_in *) addrs->ai_addr)->sin_addr,
793
0
               sizeof(in_addr_t));
794
0
        freeaddrinfo(addrs);
795
0
    } else {
796
0
        DEBUGMSGTL(("get_thisaddr",
797
0
                    "Failed to resolve IPv4 hostname\n"));
798
0
    }
799
0
    return 0;
800
801
#elif defined(HAVE_GETHOSTBYNAME)
802
    struct hostent *hp = NULL;
803
804
    hp = netsnmp_gethostbyname(name);
805
    if (hp == NULL) {
806
        DEBUGMSGTL(("get_thisaddr",
807
                    "hostname (couldn't resolve)\n"));
808
        return -1;
809
    } else if (hp->h_addrtype != AF_INET) {
810
        DEBUGMSGTL(("get_thisaddr",
811
                    "hostname (not AF_INET!)\n"));
812
        return -1;
813
    } else {
814
        DEBUGMSGTL(("get_thisaddr",
815
                    "hostname (resolved okay)\n"));
816
        memcpy(addr_out, hp->h_addr, sizeof(in_addr_t));
817
    }
818
    return 0;
819
820
#elif defined(HAVE_GETIPNODEBYNAME)
821
    struct hostent *hp = NULL;
822
    int             err;
823
824
    hp = getipnodebyname(peername, AF_INET, 0, &err);
825
    if (hp == NULL) {
826
        DEBUGMSGTL(("get_thisaddr",
827
                    "hostname (couldn't resolve = %d)\n", err));
828
        return -1;
829
    }
830
    DEBUGMSGTL(("get_thisaddr",
831
                "hostname (resolved okay)\n"));
832
    memcpy(addr_out, hp->h_addr, sizeof(in_addr_t));
833
    return 0;
834
835
#else /* HAVE_GETIPNODEBYNAME */
836
    return -1;
837
#endif
838
0
}
839
840
int
841
netsnmp_getaddrinfo(const char *name, const char *service,
842
                    const struct addrinfo *hints, struct addrinfo **res)
843
0
{
844
0
#ifdef HAVE_GETADDRINFO
845
0
    struct addrinfo *addrs = NULL;
846
0
    struct addrinfo hint;
847
0
    int             err;
848
#ifdef DNSSEC_LOCAL_VALIDATION
849
    val_status_t    val_status;
850
#endif
851
852
0
    DEBUGMSGTL(("dns:getaddrinfo", "looking up "));
853
0
    if (name)
854
0
        DEBUGMSG(("dns:getaddrinfo", "\"%s\"", name));
855
0
    else
856
0
        DEBUGMSG(("dns:getaddrinfo", "<NULL>"));
857
858
0
    if (service)
859
0
  DEBUGMSG(("dns:getaddrinfo", ":\"%s\"", service));
860
861
0
    if (hints)
862
0
  DEBUGMSG(("dns:getaddrinfo",
863
0
                  " with hints ({.ai_flags = %#x, .ai_family = %s})",
864
0
                  hints->ai_flags, hints->ai_family == 0 ? "0" :
865
0
                  hints->ai_family == AF_INET ? "AF_INET" :
866
0
                  hints->ai_family == AF_INET6 ? "AF_INET6" : "?"));
867
0
    else
868
0
  DEBUGMSG(("dns:getaddrinfo", " with no hint"));
869
870
0
    DEBUGMSG(("dns:getaddrinfo", "\n"));
871
872
0
    if (NULL == hints) {
873
0
        memset(&hint, 0, sizeof hint);
874
0
        hint.ai_flags = 0;
875
0
        hint.ai_family = PF_INET;
876
0
        hint.ai_socktype = SOCK_DGRAM;
877
0
        hint.ai_protocol = 0;
878
0
        hints = &hint;
879
0
    } else {
880
0
        memcpy(&hint, hints, sizeof hint);
881
0
    }
882
883
0
#ifndef DNSSEC_LOCAL_VALIDATION
884
0
    err = getaddrinfo(name, NULL, &hint, &addrs);
885
#else /* DNSSEC_LOCAL_VALIDATION */
886
    err = val_getaddrinfo(netsnmp_validator_context(), name, NULL, &hint,
887
                          &addrs, &val_status);
888
    DEBUGMSGTL(("dns:sec:val", "err %d, val_status %d / %s; trusted: %d\n",
889
                err, val_status, p_val_status(val_status),
890
                val_istrusted(val_status)));
891
    if (! val_istrusted(val_status)) {
892
        int rc;
893
        if ((err != 0) && VAL_GETADDRINFO_HAS_STATUS(err)) {
894
            snmp_log(LOG_WARNING,
895
                     "WARNING: UNTRUSTED error in DNS resolution for %s!\n",
896
                     name);
897
            rc = EAI_FAIL;
898
        } else {
899
            snmp_log(LOG_WARNING,
900
                     "The authenticity of DNS response is not trusted (%s)\n",
901
                     p_val_status(val_status));
902
            rc = EAI_NONAME;
903
        }
904
        /** continue anyways if DNSSEC_WARN_ONLY is set */
905
        if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
906
                                    NETSNMP_DS_LIB_DNSSEC_WARN_ONLY))
907
            return rc;
908
    }
909
910
911
#endif /* DNSSEC_LOCAL_VALIDATION */
912
0
    *res = addrs;
913
0
    DEBUGIF("dns:getaddrinfo") {
914
0
        if (err == 0 && addrs && addrs->ai_addr) {
915
0
            const char *fam = "?";
916
0
            char dst[64] = "?";
917
0
            uint16_t port = 0;
918
919
0
            switch (addrs->ai_addr->sa_family) {
920
0
            case AF_INET: {
921
0
                struct sockaddr_in *sin = (struct sockaddr_in *)addrs->ai_addr;
922
923
0
                fam = "AF_INET";
924
0
                inet_ntop(AF_INET, &sin->sin_addr, dst, sizeof(dst));
925
0
                port = ntohs(sin->sin_port);
926
0
                break;
927
0
            }
928
0
            case AF_INET6: {
929
0
                struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)
930
0
                    addrs->ai_addr;
931
932
0
                fam = "AF_INET6";
933
0
                inet_ntop(AF_INET6, &sin6->sin6_addr, dst, sizeof(dst));
934
0
                port = ntohs(sin6->sin6_port);
935
0
                break;
936
0
            }
937
0
            }
938
0
            DEBUGMSGTL(("dns:getaddrinfo", "answer { %s, %s:%hu }\n", fam, dst,
939
0
                        port));
940
0
        }
941
0
    }
942
0
    return err;
943
#else
944
    NETSNMP_LOGONCE((LOG_ERR, "getaddrinfo not available"));
945
    return EAI_FAIL;
946
#endif /* getaddrinfo */
947
0
}
948
949
struct hostent *
950
netsnmp_gethostbyname(const char *name)
951
0
{
952
0
#ifdef HAVE_GETHOSTBYNAME
953
#ifdef DNSSEC_LOCAL_VALIDATION
954
    val_status_t val_status;
955
#endif
956
0
    struct hostent *hp = NULL;
957
958
0
    if (NULL == name)
959
0
        return NULL;
960
961
0
    DEBUGMSGTL(("dns:gethostbyname", "looking up %s\n", name));
962
963
#ifdef DNSSEC_LOCAL_VALIDATION
964
    hp  = val_gethostbyname(netsnmp_validator_context(), name, &val_status);
965
    DEBUGMSGTL(("dns:sec:val", "val_status %d / %s; trusted: %d\n",
966
                val_status, p_val_status(val_status),
967
                val_istrusted(val_status)));
968
    if (!val_istrusted(val_status)) {
969
        snmp_log(LOG_WARNING,
970
                 "The authenticity of DNS response is not trusted (%s)\n",
971
                 p_val_status(val_status));
972
        /** continue anyways if DNSSEC_WARN_ONLY is set */
973
        if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
974
                                    NETSNMP_DS_LIB_DNSSEC_WARN_ONLY))
975
            hp = NULL;
976
    }
977
    else if (val_does_not_exist(val_status) && hp)
978
        hp = NULL;
979
#else
980
0
    hp = gethostbyname(name);
981
0
#endif
982
0
    if (hp == NULL) {
983
0
        DEBUGMSGTL(("dns:gethostbyname",
984
0
                    "couldn't resolve %s\n", name));
985
0
    } else if (hp->h_addrtype != AF_INET
986
0
#ifdef AF_INET6
987
0
               && hp->h_addrtype != AF_INET6
988
0
#endif
989
0
        ) {
990
0
#ifdef AF_INET6
991
0
        DEBUGMSGTL(("dns:gethostbyname",
992
0
                    "warning: response for %s not AF_INET/AF_INET6!\n", name));
993
#else
994
        DEBUGMSGTL(("dns:gethostbyname",
995
                    "warning: response for %s not AF_INET!\n", name));
996
#endif
997
0
    } else {
998
0
        DEBUGMSGTL(("dns:gethostbyname",
999
0
                    "%s resolved okay\n", name));
1000
0
    }
1001
0
    return hp;
1002
#else
1003
    NETSNMP_LOGONCE((LOG_ERR, "gethostbyname not available"));
1004
    return NULL;
1005
#endif /* HAVE_GETHOSTBYNAME */
1006
0
}
1007
1008
/**
1009
 * Look up the host name via DNS.
1010
 *
1011
 * @param[in] addr Pointer to the address to resolve. This argument points e.g.
1012
 *   to a struct in_addr for AF_INET or to a struct in6_addr for AF_INET6.
1013
 * @param[in] len  Length in bytes of *addr.
1014
 * @param[in] type Address family, e.g. AF_INET or AF_INET6.
1015
 *
1016
 * @return Pointer to a hostent structure if address lookup succeeded or NULL
1017
 *   if the lookup failed.
1018
 *
1019
 * @see See also the gethostbyaddr() man page.
1020
 */
1021
struct hostent *
1022
netsnmp_gethostbyaddr(const void *addr, socklen_t len, int type)
1023
0
{
1024
0
#ifdef HAVE_GETHOSTBYADDR
1025
0
    struct hostent *hp = NULL;
1026
0
    char buf[64];
1027
1028
0
    DEBUGMSGTL(("dns:gethostbyaddr", "resolving %s\n",
1029
0
                inet_ntop(type, addr, buf, sizeof(buf))));
1030
1031
#ifdef DNSSEC_LOCAL_VALIDATION
1032
    val_status_t val_status;
1033
    hp = val_gethostbyaddr(netsnmp_validator_context(), addr, len, type,
1034
                           &val_status);
1035
    DEBUGMSGTL(("dns:sec:val", "val_status %d / %s; trusted: %d\n",
1036
                val_status, p_val_status(val_status),
1037
                val_istrusted(val_status)));
1038
    if (!val_istrusted(val_status)) {
1039
        snmp_log(LOG_WARNING,
1040
                 "The authenticity of DNS response is not trusted (%s)\n",
1041
                 p_val_status(val_status));
1042
        /** continue anyways if DNSSEC_WARN_ONLY is set */
1043
        if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
1044
                                    NETSNMP_DS_LIB_DNSSEC_WARN_ONLY))
1045
            hp = NULL;
1046
    }
1047
    else if (val_does_not_exist(val_status) && hp)
1048
        hp = NULL;
1049
#else
1050
0
    hp = gethostbyaddr(addr, len, type);
1051
0
#endif
1052
0
    if (hp == NULL) {
1053
0
        DEBUGMSGTL(("dns:gethostbyaddr", "couldn't resolve addr\n"));
1054
0
    } else if (hp->h_addrtype != AF_INET) {
1055
0
        DEBUGMSGTL(("dns:gethostbyaddr",
1056
0
                    "warning: response for addr not AF_INET!\n"));
1057
0
    } else {
1058
0
        DEBUGMSGTL(("dns:gethostbyaddr", "addr resolved okay\n"));
1059
0
    }
1060
0
    return hp;
1061
#else
1062
    NETSNMP_LOGONCE((LOG_ERR, "gethostbyaddr not available"));
1063
    return NULL;
1064
#endif
1065
0
}
1066
1067
/*******************************************************************/
1068
1069
#if !defined(HAVE_STRNCASECMP) && !defined(strncasecmp)
1070
1071
/*
1072
 * test for NULL pointers before and NULL characters after
1073
 * * comparing possibly non-NULL strings.
1074
 * * WARNING: This function does NOT check for array overflow.
1075
 */
1076
int
1077
strncasecmp(const char *s1, const char *s2, size_t nch)
1078
{
1079
    size_t          ii;
1080
    int             res = -1;
1081
1082
    if (!s1) {
1083
        if (!s2)
1084
            return 0;
1085
        return (-1);
1086
    }
1087
    if (!s2)
1088
        return (1);
1089
1090
    for (ii = 0; (ii < nch) && *s1 && *s2; ii++, s1++, s2++) {
1091
        res = (int) (tolower(*s1) - tolower(*s2));
1092
        if (res != 0)
1093
            break;
1094
    }
1095
1096
    if (ii == nch) {
1097
        s1--;
1098
        s2--;
1099
    }
1100
1101
    if (!*s1) {
1102
        if (!*s2)
1103
            return 0;
1104
        return (-1);
1105
    }
1106
    if (!*s2)
1107
        return (1);
1108
1109
    return (res);
1110
}
1111
1112
int
1113
strcasecmp(const char *s1, const char *s2)
1114
{
1115
    return strncasecmp(s1, s2, 1000000);
1116
}
1117
1118
#endif                /* !defined(HAVE_STRNCASECMP) && !defined(strncasecmp) */
1119
1120
1121
#ifndef HAVE_STRDUP
1122
char           *
1123
strdup(const char *src)
1124
{
1125
    int             len;
1126
    char           *dst;
1127
1128
    len = strlen(src) + 1;
1129
    if ((dst = (char *) malloc(len)) == NULL)
1130
        return (NULL);
1131
    strcpy(dst, src);
1132
    return (dst);
1133
}
1134
#endif                          /* HAVE_STRDUP */
1135
1136
#ifndef HAVE_SETENV
1137
int
1138
setenv(const char *name, const char *value, int overwrite)
1139
{
1140
    char           *cp;
1141
    int             ret;
1142
1143
    if (overwrite == 0) {
1144
        if (getenv(name))
1145
            return 0;
1146
    }
1147
    if (asprintf(&cp, "%s=%s", name, value) < 0)
1148
        return -1;
1149
    ret = putenv(cp);
1150
#ifdef WIN32
1151
    free(cp);
1152
#endif
1153
    return ret;
1154
}
1155
#endif                          /* HAVE_SETENV */
1156
1157
netsnmp_feature_child_of(calculate_time_diff, netsnmp_unused);
1158
#ifndef NETSNMP_FEATURE_REMOVE_CALCULATE_TIME_DIFF
1159
/**
1160
 * Compute (*now - *then) in centiseconds.
1161
 */
1162
int
1163
calculate_time_diff(const struct timeval *now, const struct timeval *then)
1164
0
{
1165
0
    struct timeval  diff;
1166
1167
0
    NETSNMP_TIMERSUB(now, then, &diff);
1168
0
    return (int)(diff.tv_sec * 100 + diff.tv_usec / 10000);
1169
0
}
1170
#endif /* NETSNMP_FEATURE_REMOVE_CALCULATE_TIME_DIFF */
1171
1172
#ifndef NETSNMP_FEATURE_REMOVE_CALCULATE_SECTIME_DIFF
1173
/** Compute rounded (*now - *then) in seconds. */
1174
u_int
1175
calculate_sectime_diff(const struct timeval *now, const struct timeval *then)
1176
5.97k
{
1177
5.97k
    struct timeval  diff;
1178
1179
5.97k
    NETSNMP_TIMERSUB(now, then, &diff);
1180
5.97k
    return (u_int)(diff.tv_sec + (diff.tv_usec >= 500000L));
1181
5.97k
}
1182
#endif /* NETSNMP_FEATURE_REMOVE_CALCULATE_SECTIME_DIFF */
1183
1184
#ifndef HAVE_STRCASESTR
1185
/*
1186
 * only glibc2 has this.
1187
 */
1188
char           *
1189
strcasestr(const char *haystack, const char *needle)
1190
{
1191
    const char     *cp1 = haystack, *cp2 = needle;
1192
    const char     *cx;
1193
    int             tstch1, tstch2;
1194
1195
    /*
1196
     * printf("looking for '%s' in '%s'\n", needle, haystack); 
1197
     */
1198
    if (cp1 && cp2 && *cp1 && *cp2)
1199
        for (cp1 = haystack, cp2 = needle; *cp1;) {
1200
            cx = cp1;
1201
            cp2 = needle;
1202
            do {
1203
                /*
1204
                 * printf("T'%c' ", *cp1); 
1205
                 */
1206
                if (!*cp2) {    /* found the needle */
1207
                    /*
1208
                     * printf("\nfound '%s' in '%s'\n", needle, cx); 
1209
                     */
1210
                    return NETSNMP_REMOVE_CONST(char *, cx);
1211
                }
1212
                if (!*cp1)
1213
                    break;
1214
1215
                tstch1 = toupper(*cp1);
1216
                tstch2 = toupper(*cp2);
1217
                if (tstch1 != tstch2)
1218
                    break;
1219
                /*
1220
                 * printf("M'%c' ", *cp1); 
1221
                 */
1222
                cp1++;
1223
                cp2++;
1224
            }
1225
            while (1);
1226
            if (*cp1)
1227
                cp1++;
1228
        }
1229
    /*
1230
     * printf("\n"); 
1231
     */
1232
    if (cp1 && *cp1)
1233
        return NETSNMP_REMOVE_CONST(char *, cp1);
1234
1235
    return NULL;
1236
}
1237
#endif
1238
1239
int
1240
mkdirhier(const char *pathname, mode_t mode, int skiplast)
1241
8.96k
{
1242
8.96k
    struct stat     sbuf;
1243
8.96k
    char           *ourcopy = strdup(pathname);
1244
8.96k
    char           *entry;
1245
8.96k
    char           *buf = NULL;
1246
8.96k
    char           *st = NULL;
1247
8.96k
    int             res;
1248
1249
8.96k
    res = SNMPERR_GENERR;
1250
8.96k
    if (!ourcopy)
1251
0
        goto out;
1252
1253
8.96k
    buf = malloc(strlen(pathname) + 2);
1254
8.96k
    if (!buf)
1255
0
        goto out;
1256
1257
#if defined (WIN32) || defined (cygwin)
1258
    /* convert backslash to forward slash */
1259
    for (entry = ourcopy; *entry; entry++)
1260
        if (*entry == '\\')
1261
            *entry = '/';
1262
#endif
1263
1264
8.96k
    entry = strtok_r(ourcopy, "/", &st);
1265
1266
8.96k
    buf[0] = '\0';
1267
1268
#if defined (WIN32) || defined (cygwin)
1269
    /*
1270
     * Check if first entry contains a drive-letter
1271
     *   e.g  "c:/path"
1272
     */
1273
    if ((entry) && (':' == entry[1]) &&
1274
        (('\0' == entry[2]) || ('/' == entry[2]))) {
1275
        strcat(buf, entry);
1276
        entry = strtok_r(NULL, "/", &st);
1277
    }
1278
#endif
1279
1280
    /*
1281
     * check to see if filename is a directory 
1282
     */
1283
26.9k
    while (entry) {
1284
26.9k
        strcat(buf, "/");
1285
26.9k
        strcat(buf, entry);
1286
26.9k
        entry = strtok_r(NULL, "/", &st);
1287
26.9k
        if (entry == NULL && skiplast)
1288
8.96k
            break;
1289
17.9k
        if (stat(buf, &sbuf) < 0) {
1290
            /*
1291
             * DNE, make it 
1292
             */
1293
#ifdef WIN32
1294
            if (CreateDirectory(buf, NULL) == 0)
1295
#else
1296
0
            if (mkdir(buf, mode) == -1)
1297
0
#endif
1298
0
                goto out;
1299
0
            else
1300
0
                snmp_log(LOG_INFO, "Created directory: %s\n", buf);
1301
17.9k
        } else {
1302
            /*
1303
             * exists, is it a file? 
1304
             */
1305
17.9k
            if ((sbuf.st_mode & S_IFDIR) == 0) {
1306
                /*
1307
                 * ack! can't make a directory on top of a file 
1308
                 */
1309
0
                goto out;
1310
0
            }
1311
17.9k
        }
1312
17.9k
    }
1313
8.96k
    res = SNMPERR_SUCCESS;
1314
8.96k
out:
1315
8.96k
    free(buf);
1316
8.96k
    free(ourcopy);
1317
8.96k
    return res;
1318
8.96k
}
1319
1320
/**
1321
 * netsnmp_mktemp creates a temporary file based on the
1322
 *                 configured tempFilePattern
1323
 *
1324
 * @return file descriptor
1325
 */
1326
const char     *
1327
netsnmp_mktemp(void)
1328
0
{
1329
0
#ifdef PATH_MAX
1330
0
    static char     name[PATH_MAX];
1331
#else
1332
    static char     name[256];
1333
#endif
1334
0
    int             fd = -1;
1335
1336
0
    strlcpy(name, get_temp_file_pattern(), sizeof(name));
1337
0
#ifdef HAVE_MKSTEMP
1338
0
    {
1339
0
        mode_t oldmask = umask(~(S_IRUSR | S_IWUSR));
1340
0
        netsnmp_assert(oldmask != (mode_t)(-1));
1341
0
        fd = mkstemp(name);
1342
0
        umask(oldmask);
1343
0
    }
1344
#else
1345
    if (mktemp(name)) {
1346
# ifndef WIN32
1347
        fd = open(name, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
1348
# else
1349
        /*
1350
         * Win32 needs _S_IREAD | _S_IWRITE to set permissions on file
1351
         * after closing
1352
         */
1353
        fd = _open(name, _O_CREAT | _O_EXCL | _O_WRONLY, _S_IREAD | _S_IWRITE);
1354
# endif
1355
    }
1356
#endif
1357
0
    if (fd >= 0) {
1358
0
        close(fd);
1359
0
        DEBUGMSGTL(("netsnmp_mktemp", "temp file created: %s\n",
1360
0
                    name));
1361
0
        return name;
1362
0
    }
1363
0
    snmp_log(LOG_ERR, "netsnmp_mktemp: error creating file %s\n",
1364
0
             name);
1365
0
    return NULL;
1366
0
}
1367
1368
/*
1369
 * This function was created to differentiate actions
1370
 * that are appropriate for Linux 2.4 kernels, but not later kernels.
1371
 *
1372
 * This function can be used to test kernels on any platform that supports uname().
1373
 *
1374
 * If not running a platform that supports uname(), return -1.
1375
 *
1376
 * If ospname matches, and the release matches up through the prefix,
1377
 *  return 0.
1378
 * If the release is ordered higher, return 1.
1379
 * Be aware that "ordered higher" is not a guarantee of correctness.
1380
 */
1381
int
1382
netsnmp_os_prematch(const char *ospmname,
1383
                    const char *ospmrelprefix)
1384
2.98k
{
1385
2.98k
#ifdef HAVE_SYS_UTSNAME_H
1386
2.98k
  static int printOSonce = 1;
1387
2.98k
  struct utsname utsbuf;
1388
2.98k
  if ( 0 > uname(&utsbuf))
1389
0
    return -1;
1390
1391
2.98k
  if (printOSonce) {
1392
1
    printOSonce = 0;
1393
    /* show the four elements that the kernel can be sure of */
1394
1
  DEBUGMSGT(("daemonize","sysname '%s',\nrelease '%s',\nversion '%s',\nmachine '%s'\n",
1395
1
      utsbuf.sysname, utsbuf.release, utsbuf.version, utsbuf.machine));
1396
1
  }
1397
2.98k
  if (0 != strcasecmp(utsbuf.sysname, ospmname)) return -1;
1398
1399
  /* Required to match only the leading characters */
1400
2.98k
  return strncasecmp(utsbuf.release, ospmrelprefix, strlen(ospmrelprefix));
1401
1402
#else
1403
1404
  return -1;
1405
1406
#endif /* HAVE_SYS_UTSNAME_H */
1407
2.98k
}
1408
1409
/**
1410
 * netsnmp_os_kernel_width determines kernel width at runtime
1411
 * Currently implemented for IRIX, AIX and Tru64 Unix
1412
 *
1413
 * @return kernel width (usually 32 or 64) on success, -1 on error
1414
 */
1415
int
1416
netsnmp_os_kernel_width(void)
1417
0
{
1418
#ifdef irix6
1419
  char buf[8];
1420
  sysinfo(_MIPS_SI_OS_NAME, buf, 7);
1421
  if (strncmp("IRIX64", buf, 6) == 0) {
1422
    return 64;
1423
  } else if (strncmp("IRIX", buf, 4) == 0) {
1424
    return 32;
1425
  } else {
1426
    return -1;
1427
  }
1428
#elif defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
1429
  return (__KERNEL_32() ? 32 : (__KERNEL_64() ? 64 : -1));
1430
#elif defined(osf4) || defined(osf5) || defined(__alpha)
1431
  return 64; /* Alpha is always 64bit */
1432
#else
1433
  /* kernel width detection not implemented */
1434
0
  return -1;
1435
0
#endif
1436
0
}
1437
1438
netsnmp_feature_child_of(str_to_uid, user_information);
1439
#ifndef NETSNMP_FEATURE_REMOVE_STR_TO_UID
1440
/**
1441
 * Convert a user name or number into numeric form.
1442
 *
1443
 * @param[in] useroruid Either a Unix user name or the ASCII representation
1444
 *   of a user number.
1445
 *
1446
 * @return Either a user number > 0 or 0 if useroruid is not a valid user
1447
 *   name, not a valid user number or the name of the root user.
1448
 */
1449
0
int netsnmp_str_to_uid(const char *useroruid) {
1450
0
    int uid;
1451
0
#if defined(HAVE_GETPWNAM) && defined(HAVE_PWD_H)
1452
0
    struct passwd *pwd;
1453
0
#endif
1454
1455
0
    uid = atoi(useroruid);
1456
1457
0
    if (uid == 0) {
1458
0
#if defined(HAVE_GETPWNAM) && defined(HAVE_PWD_H)
1459
0
        pwd = getpwnam(useroruid);
1460
0
        uid = pwd ? pwd->pw_uid : 0;
1461
0
        endpwent();
1462
0
#endif
1463
0
        if (uid == 0)
1464
0
            snmp_log(LOG_WARNING, "Can't identify user (%s).\n", useroruid);
1465
0
    }
1466
0
    return uid;
1467
    
1468
0
}
1469
#endif /* NETSNMP_FEATURE_REMOVE_STR_TO_UID */
1470
1471
netsnmp_feature_child_of(str_to_gid, user_information);
1472
#ifndef NETSNMP_FEATURE_REMOVE_STR_TO_GID
1473
/**
1474
 * Convert a group name or number into numeric form.
1475
 *
1476
 * @param[in] grouporgid Either a Unix group name or the ASCII representation
1477
 *   of a group number.
1478
 *
1479
 * @return Either a group number > 0 or 0 if grouporgid is not a valid group
1480
 *   name, not a valid group number or the root group.
1481
 */
1482
int netsnmp_str_to_gid(const char *grouporgid)
1483
0
{
1484
0
    int gid;
1485
1486
0
    gid = atoi(grouporgid);
1487
1488
0
    if (gid == 0) {
1489
0
#if defined(HAVE_GETGRNAM) && defined(HAVE_GRP_H)
1490
0
        struct group  *grp;
1491
1492
0
        grp = getgrnam(grouporgid);
1493
0
        gid = grp ? grp->gr_gid : 0;
1494
0
        endgrent();
1495
0
#endif
1496
0
        if (gid == 0)
1497
0
            snmp_log(LOG_WARNING, "Can't identify group (%s).\n", grouporgid);
1498
0
    }
1499
1500
0
    return gid;
1501
0
}
1502
#endif /* NETSNMP_FEATURE_REMOVE_STR_TO_GID */