Coverage Report

Created: 2026-10-17 06:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/net-snmp/snmplib/system.c
Line
Count
Source
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
            snprintf(errmsg, sizeof(errmsg),
484
                    "Unable to init. socket lib, does not support 1.1");
485
        else {
486
            snprintf(errmsg, sizeof(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
    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
        return -1;
799
0
    }
800
0
    return 0;
801
802
#elif defined(HAVE_GETHOSTBYNAME)
803
    struct hostent *hp = NULL;
804
805
    hp = netsnmp_gethostbyname(name);
806
    if (hp == NULL) {
807
        DEBUGMSGTL(("get_thisaddr",
808
                    "hostname (couldn't resolve)\n"));
809
        return -1;
810
    } else if (hp->h_addrtype != AF_INET) {
811
        DEBUGMSGTL(("get_thisaddr",
812
                    "hostname (not AF_INET!)\n"));
813
        return -1;
814
    } else {
815
        DEBUGMSGTL(("get_thisaddr",
816
                    "hostname (resolved okay)\n"));
817
        memcpy(addr_out, hp->h_addr, sizeof(in_addr_t));
818
    }
819
    return 0;
820
821
#elif defined(HAVE_GETIPNODEBYNAME)
822
    struct hostent *hp = NULL;
823
    int             err;
824
825
    hp = getipnodebyname(peername, AF_INET, 0, &err);
826
    if (hp == NULL) {
827
        DEBUGMSGTL(("get_thisaddr",
828
                    "hostname (couldn't resolve = %d)\n", err));
829
        return -1;
830
    }
831
    DEBUGMSGTL(("get_thisaddr",
832
                "hostname (resolved okay)\n"));
833
    memcpy(addr_out, hp->h_addr, sizeof(in_addr_t));
834
    return 0;
835
836
#else /* HAVE_GETIPNODEBYNAME */
837
    return -1;
838
#endif
839
0
}
840
841
int
842
netsnmp_getaddrinfo(const char *name, const char *service,
843
                    const struct addrinfo *hints, struct addrinfo **res)
844
0
{
845
0
#ifdef HAVE_GETADDRINFO
846
0
    struct addrinfo *addrs = NULL;
847
0
    struct addrinfo hint;
848
0
    int             err;
849
#ifdef DNSSEC_LOCAL_VALIDATION
850
    val_status_t    val_status;
851
#endif
852
853
0
    DEBUGMSGTL(("dns:getaddrinfo", "looking up "));
854
0
    if (name)
855
0
        DEBUGMSG(("dns:getaddrinfo", "\"%s\"", name));
856
0
    else
857
0
        DEBUGMSG(("dns:getaddrinfo", "<NULL>"));
858
859
0
    if (service)
860
0
  DEBUGMSG(("dns:getaddrinfo", ":\"%s\"", service));
861
862
0
    if (hints)
863
0
  DEBUGMSG(("dns:getaddrinfo",
864
0
                  " with hints ({.ai_flags = %#x, .ai_family = %s})",
865
0
                  hints->ai_flags, hints->ai_family == 0 ? "0" :
866
0
                  hints->ai_family == AF_INET ? "AF_INET" :
867
0
                  hints->ai_family == AF_INET6 ? "AF_INET6" : "?"));
868
0
    else
869
0
  DEBUGMSG(("dns:getaddrinfo", " with no hint"));
870
871
0
    DEBUGMSG(("dns:getaddrinfo", "\n"));
872
873
0
    if (NULL == hints) {
874
0
        memset(&hint, 0, sizeof hint);
875
0
        hint.ai_flags = 0;
876
0
        hint.ai_family = PF_INET;
877
0
        hint.ai_socktype = SOCK_DGRAM;
878
0
        hint.ai_protocol = 0;
879
0
        hints = &hint;
880
0
    } else {
881
0
        memcpy(&hint, hints, sizeof hint);
882
0
    }
883
884
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
885
    /*
886
     * Fuzz targets must not perform network I/O. Without network access,
887
     * DNS queries block until they time out. Hence, only allow lookups
888
     * that can be resolved without querying a DNS server.
889
     */
890
0
    if (name && strcmp(name, "localhost") != 0)
891
0
        hint.ai_flags |= AI_NUMERICHOST;
892
0
#endif
893
894
0
#ifndef DNSSEC_LOCAL_VALIDATION
895
0
    err = getaddrinfo(name, NULL, &hint, &addrs);
896
#else /* DNSSEC_LOCAL_VALIDATION */
897
    err = val_getaddrinfo(netsnmp_validator_context(), name, NULL, &hint,
898
                          &addrs, &val_status);
899
    DEBUGMSGTL(("dns:sec:val", "err %d, val_status %d / %s; trusted: %d\n",
900
                err, val_status, p_val_status(val_status),
901
                val_istrusted(val_status)));
902
    if (! val_istrusted(val_status)) {
903
        int rc;
904
        if ((err != 0) && VAL_GETADDRINFO_HAS_STATUS(err)) {
905
            snmp_log(LOG_WARNING,
906
                     "WARNING: UNTRUSTED error in DNS resolution for %s!\n",
907
                     name);
908
            rc = EAI_FAIL;
909
        } else {
910
            snmp_log(LOG_WARNING,
911
                     "The authenticity of DNS response is not trusted (%s)\n",
912
                     p_val_status(val_status));
913
            rc = EAI_NONAME;
914
        }
915
        /** continue anyways if DNSSEC_WARN_ONLY is set */
916
        if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
917
                                    NETSNMP_DS_LIB_DNSSEC_WARN_ONLY))
918
            return rc;
919
    }
920
921
922
#endif /* DNSSEC_LOCAL_VALIDATION */
923
0
    *res = addrs;
924
0
    DEBUGIF("dns:getaddrinfo") {
925
0
        if (err == 0 && addrs && addrs->ai_addr) {
926
0
            const char *fam = "?";
927
0
            char dst[64] = "?";
928
0
            uint16_t port = 0;
929
930
0
            switch (addrs->ai_addr->sa_family) {
931
0
            case AF_INET: {
932
0
                struct sockaddr_in *sin = (struct sockaddr_in *)addrs->ai_addr;
933
934
0
                fam = "AF_INET";
935
0
                inet_ntop(AF_INET, &sin->sin_addr, dst, sizeof(dst));
936
0
                port = ntohs(sin->sin_port);
937
0
                break;
938
0
            }
939
0
            case AF_INET6: {
940
0
                struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)
941
0
                    addrs->ai_addr;
942
943
0
                fam = "AF_INET6";
944
0
                inet_ntop(AF_INET6, &sin6->sin6_addr, dst, sizeof(dst));
945
0
                port = ntohs(sin6->sin6_port);
946
0
                break;
947
0
            }
948
0
            }
949
0
            DEBUGMSGTL(("dns:getaddrinfo", "answer { %s, %s:%hu }\n", fam, dst,
950
0
                        port));
951
0
        }
952
0
    }
953
0
    return err;
954
#else
955
    NETSNMP_LOGONCE((LOG_ERR, "getaddrinfo not available"));
956
    return EAI_FAIL;
957
#endif /* getaddrinfo */
958
0
}
959
960
struct hostent *
961
netsnmp_gethostbyname(const char *name)
962
0
{
963
0
#ifdef HAVE_GETHOSTBYNAME
964
#ifdef DNSSEC_LOCAL_VALIDATION
965
    val_status_t val_status;
966
#endif
967
0
    struct hostent *hp = NULL;
968
969
0
    if (NULL == name)
970
0
        return NULL;
971
972
0
    DEBUGMSGTL(("dns:gethostbyname", "looking up %s\n", name));
973
974
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
975
    /* See also netsnmp_getaddrinfo(). */
976
0
    {
977
0
        struct in_addr  a4;
978
0
#ifdef AF_INET6
979
0
        struct in6_addr a6;
980
0
#endif
981
982
0
        if (strcmp(name, "localhost") != 0 &&
983
0
            inet_pton(AF_INET, name, &a4) != 1
984
0
#ifdef AF_INET6
985
0
            && inet_pton(AF_INET6, name, &a6) != 1
986
0
#endif
987
0
            )
988
0
            return NULL;
989
0
    }
990
0
#endif
991
992
#ifdef DNSSEC_LOCAL_VALIDATION
993
    hp  = val_gethostbyname(netsnmp_validator_context(), name, &val_status);
994
    DEBUGMSGTL(("dns:sec:val", "val_status %d / %s; trusted: %d\n",
995
                val_status, p_val_status(val_status),
996
                val_istrusted(val_status)));
997
    if (!val_istrusted(val_status)) {
998
        snmp_log(LOG_WARNING,
999
                 "The authenticity of DNS response is not trusted (%s)\n",
1000
                 p_val_status(val_status));
1001
        /** continue anyways if DNSSEC_WARN_ONLY is set */
1002
        if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
1003
                                    NETSNMP_DS_LIB_DNSSEC_WARN_ONLY))
1004
            hp = NULL;
1005
    }
1006
    else if (val_does_not_exist(val_status) && hp)
1007
        hp = NULL;
1008
#else
1009
0
    hp = gethostbyname(name);
1010
0
#endif
1011
0
    if (hp == NULL) {
1012
0
        DEBUGMSGTL(("dns:gethostbyname",
1013
0
                    "couldn't resolve %s\n", name));
1014
0
    } else if (hp->h_addrtype != AF_INET
1015
0
#ifdef AF_INET6
1016
0
               && hp->h_addrtype != AF_INET6
1017
0
#endif
1018
0
        ) {
1019
0
#ifdef AF_INET6
1020
0
        DEBUGMSGTL(("dns:gethostbyname",
1021
0
                    "warning: response for %s not AF_INET/AF_INET6!\n", name));
1022
#else
1023
        DEBUGMSGTL(("dns:gethostbyname",
1024
                    "warning: response for %s not AF_INET!\n", name));
1025
#endif
1026
0
    } else {
1027
0
        DEBUGMSGTL(("dns:gethostbyname",
1028
0
                    "%s resolved okay\n", name));
1029
0
    }
1030
0
    return hp;
1031
#else
1032
    NETSNMP_LOGONCE((LOG_ERR, "gethostbyname not available"));
1033
    return NULL;
1034
#endif /* HAVE_GETHOSTBYNAME */
1035
0
}
1036
1037
/**
1038
 * Look up the host name via DNS.
1039
 *
1040
 * @param[in] addr Pointer to the address to resolve. This argument points e.g.
1041
 *   to a struct in_addr for AF_INET or to a struct in6_addr for AF_INET6.
1042
 * @param[in] len  Length in bytes of *addr.
1043
 * @param[in] type Address family, e.g. AF_INET or AF_INET6.
1044
 *
1045
 * @return Pointer to a hostent structure if address lookup succeeded or NULL
1046
 *   if the lookup failed.
1047
 *
1048
 * @see See also the gethostbyaddr() man page.
1049
 */
1050
struct hostent *
1051
netsnmp_gethostbyaddr(const void *addr, socklen_t len, int type)
1052
0
{
1053
0
#ifdef HAVE_GETHOSTBYADDR
1054
0
    struct hostent *hp = NULL;
1055
0
    char buf[64];
1056
1057
0
    DEBUGMSGTL(("dns:gethostbyaddr", "resolving %s\n",
1058
0
                inet_ntop(type, addr, buf, sizeof(buf))));
1059
1060
0
#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
1061
    /* Reverse DNS lookups require network access. */
1062
0
    return NULL;
1063
0
#endif
1064
1065
#ifdef DNSSEC_LOCAL_VALIDATION
1066
    val_status_t val_status;
1067
    hp = val_gethostbyaddr(netsnmp_validator_context(), addr, len, type,
1068
                           &val_status);
1069
    DEBUGMSGTL(("dns:sec:val", "val_status %d / %s; trusted: %d\n",
1070
                val_status, p_val_status(val_status),
1071
                val_istrusted(val_status)));
1072
    if (!val_istrusted(val_status)) {
1073
        snmp_log(LOG_WARNING,
1074
                 "The authenticity of DNS response is not trusted (%s)\n",
1075
                 p_val_status(val_status));
1076
        /** continue anyways if DNSSEC_WARN_ONLY is set */
1077
        if (!netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 
1078
                                    NETSNMP_DS_LIB_DNSSEC_WARN_ONLY))
1079
            hp = NULL;
1080
    }
1081
    else if (val_does_not_exist(val_status) && hp)
1082
        hp = NULL;
1083
#else
1084
0
    hp = gethostbyaddr(addr, len, type);
1085
0
#endif
1086
0
    if (hp == NULL) {
1087
0
        DEBUGMSGTL(("dns:gethostbyaddr", "couldn't resolve addr\n"));
1088
0
    } else if (hp->h_addrtype != AF_INET) {
1089
0
        DEBUGMSGTL(("dns:gethostbyaddr",
1090
0
                    "warning: response for addr not AF_INET!\n"));
1091
0
    } else {
1092
0
        DEBUGMSGTL(("dns:gethostbyaddr", "addr resolved okay\n"));
1093
0
    }
1094
0
    return hp;
1095
#else
1096
    NETSNMP_LOGONCE((LOG_ERR, "gethostbyaddr not available"));
1097
    return NULL;
1098
#endif
1099
0
}
1100
1101
/*******************************************************************/
1102
1103
#if !defined(HAVE_STRNCASECMP) && !defined(strncasecmp)
1104
1105
/*
1106
 * test for NULL pointers before and NULL characters after
1107
 * * comparing possibly non-NULL strings.
1108
 * * WARNING: This function does NOT check for array overflow.
1109
 */
1110
int
1111
strncasecmp(const char *s1, const char *s2, size_t nch)
1112
{
1113
    size_t          ii;
1114
    int             res = -1;
1115
1116
    if (!s1) {
1117
        if (!s2)
1118
            return 0;
1119
        return (-1);
1120
    }
1121
    if (!s2)
1122
        return (1);
1123
1124
    for (ii = 0; (ii < nch) && *s1 && *s2; ii++, s1++, s2++) {
1125
        res = (int) (tolower(*s1) - tolower(*s2));
1126
        if (res != 0)
1127
            break;
1128
    }
1129
1130
    if (ii == nch) {
1131
        s1--;
1132
        s2--;
1133
    }
1134
1135
    if (!*s1) {
1136
        if (!*s2)
1137
            return 0;
1138
        return (-1);
1139
    }
1140
    if (!*s2)
1141
        return (1);
1142
1143
    return (res);
1144
}
1145
1146
int
1147
strcasecmp(const char *s1, const char *s2)
1148
{
1149
    return strncasecmp(s1, s2, 1000000);
1150
}
1151
1152
#endif                /* !defined(HAVE_STRNCASECMP) && !defined(strncasecmp) */
1153
1154
1155
#ifndef HAVE_STRDUP
1156
char           *
1157
strdup(const char *src)
1158
{
1159
    int             len;
1160
    char           *dst;
1161
1162
    len = strlen(src) + 1;
1163
    if ((dst = (char *) malloc(len)) == NULL)
1164
        return (NULL);
1165
    strcpy(dst, src);
1166
    return (dst);
1167
}
1168
#endif                          /* HAVE_STRDUP */
1169
1170
#ifndef HAVE_SETENV
1171
int
1172
setenv(const char *name, const char *value, int overwrite)
1173
{
1174
    char           *cp;
1175
    int             ret;
1176
1177
    if (overwrite == 0) {
1178
        if (getenv(name))
1179
            return 0;
1180
    }
1181
    if (asprintf(&cp, "%s=%s", name, value) < 0)
1182
        return -1;
1183
    ret = putenv(cp);
1184
#ifdef WIN32
1185
    free(cp);
1186
#endif
1187
    return ret;
1188
}
1189
#endif                          /* HAVE_SETENV */
1190
1191
netsnmp_feature_child_of(calculate_time_diff, netsnmp_unused);
1192
#ifndef NETSNMP_FEATURE_REMOVE_CALCULATE_TIME_DIFF
1193
/**
1194
 * Compute (*now - *then) in centiseconds.
1195
 */
1196
int
1197
calculate_time_diff(const struct timeval *now, const struct timeval *then)
1198
0
{
1199
0
    struct timeval  diff;
1200
1201
0
    NETSNMP_TIMERSUB(now, then, &diff);
1202
0
    return (int)(diff.tv_sec * 100 + diff.tv_usec / 10000);
1203
0
}
1204
#endif /* NETSNMP_FEATURE_REMOVE_CALCULATE_TIME_DIFF */
1205
1206
#ifndef NETSNMP_FEATURE_REMOVE_CALCULATE_SECTIME_DIFF
1207
/** Compute rounded (*now - *then) in seconds. */
1208
u_int
1209
calculate_sectime_diff(const struct timeval *now, const struct timeval *then)
1210
2
{
1211
2
    struct timeval  diff;
1212
1213
2
    NETSNMP_TIMERSUB(now, then, &diff);
1214
2
    return (u_int)(diff.tv_sec + (diff.tv_usec >= 500000L));
1215
2
}
1216
#endif /* NETSNMP_FEATURE_REMOVE_CALCULATE_SECTIME_DIFF */
1217
1218
#ifndef HAVE_STRCASESTR
1219
/*
1220
 * only glibc2 has this.
1221
 */
1222
char           *
1223
strcasestr(const char *haystack, const char *needle)
1224
{
1225
    const char     *cp1 = haystack, *cp2 = needle;
1226
    const char     *cx;
1227
    int             tstch1, tstch2;
1228
1229
    /*
1230
     * printf("looking for '%s' in '%s'\n", needle, haystack); 
1231
     */
1232
    if (cp1 && cp2 && *cp1 && *cp2)
1233
        for (cp1 = haystack, cp2 = needle; *cp1;) {
1234
            cx = cp1;
1235
            cp2 = needle;
1236
            do {
1237
                /*
1238
                 * printf("T'%c' ", *cp1); 
1239
                 */
1240
                if (!*cp2) {    /* found the needle */
1241
                    /*
1242
                     * printf("\nfound '%s' in '%s'\n", needle, cx); 
1243
                     */
1244
                    return NETSNMP_REMOVE_CONST(char *, cx);
1245
                }
1246
                if (!*cp1)
1247
                    break;
1248
1249
                tstch1 = toupper(*cp1);
1250
                tstch2 = toupper(*cp2);
1251
                if (tstch1 != tstch2)
1252
                    break;
1253
                /*
1254
                 * printf("M'%c' ", *cp1); 
1255
                 */
1256
                cp1++;
1257
                cp2++;
1258
            }
1259
            while (1);
1260
            cp1 = cx + 1;
1261
        }
1262
    /*
1263
     * printf("\n"); 
1264
     */
1265
    if (cp1 && *cp1)
1266
        return NETSNMP_REMOVE_CONST(char *, cp1);
1267
1268
    return NULL;
1269
}
1270
#endif
1271
1272
int
1273
mkdirhier(const char *pathname, mode_t mode, int skiplast)
1274
0
{
1275
0
    struct stat     sbuf;
1276
0
    char           *ourcopy = strdup(pathname);
1277
0
    char           *entry;
1278
0
    char           *buf = NULL;
1279
0
    char           *st = NULL;
1280
0
    int             res;
1281
1282
0
    res = SNMPERR_GENERR;
1283
0
    if (!ourcopy)
1284
0
        goto out;
1285
1286
0
    buf = malloc(strlen(pathname) + 2);
1287
0
    if (!buf)
1288
0
        goto out;
1289
1290
#if defined (WIN32) || defined (cygwin)
1291
    /* convert backslash to forward slash */
1292
    for (entry = ourcopy; *entry; entry++)
1293
        if (*entry == '\\')
1294
            *entry = '/';
1295
#endif
1296
1297
0
    entry = strtok_r(ourcopy, "/", &st);
1298
1299
0
    buf[0] = '\0';
1300
1301
#if defined (WIN32) || defined (cygwin)
1302
    /*
1303
     * Check if first entry contains a drive-letter
1304
     *   e.g  "c:/path"
1305
     */
1306
    if ((entry) && (':' == entry[1]) &&
1307
        (('\0' == entry[2]) || ('/' == entry[2]))) {
1308
        strcat(buf, entry);
1309
        entry = strtok_r(NULL, "/", &st);
1310
    }
1311
#endif
1312
1313
    /*
1314
     * check to see if filename is a directory 
1315
     */
1316
0
    while (entry) {
1317
0
        strcat(buf, "/");
1318
0
        strcat(buf, entry);
1319
0
        entry = strtok_r(NULL, "/", &st);
1320
0
        if (entry == NULL && skiplast)
1321
0
            break;
1322
0
        if (stat(buf, &sbuf) < 0) {
1323
            /*
1324
             * DNE, make it 
1325
             */
1326
#ifdef WIN32
1327
            if (CreateDirectory(buf, NULL) == 0)
1328
#else
1329
0
            if (mkdir(buf, mode) == -1)
1330
0
#endif
1331
0
                goto out;
1332
0
            else
1333
0
                snmp_log(LOG_INFO, "Created directory: %s\n", buf);
1334
0
        } else {
1335
            /*
1336
             * exists, is it a file? 
1337
             */
1338
0
            if ((sbuf.st_mode & S_IFDIR) == 0) {
1339
                /*
1340
                 * ack! can't make a directory on top of a file 
1341
                 */
1342
0
                goto out;
1343
0
            }
1344
0
        }
1345
0
    }
1346
0
    res = SNMPERR_SUCCESS;
1347
0
out:
1348
0
    free(buf);
1349
0
    free(ourcopy);
1350
0
    return res;
1351
0
}
1352
1353
/**
1354
 * netsnmp_mktemp creates a temporary file based on the
1355
 *                 configured tempFilePattern
1356
 *
1357
 * @return file descriptor
1358
 */
1359
const char     *
1360
netsnmp_mktemp(void)
1361
0
{
1362
0
#ifdef PATH_MAX
1363
0
    static char     name[PATH_MAX];
1364
#else
1365
    static char     name[256];
1366
#endif
1367
0
    int             fd = -1;
1368
1369
0
    strlcpy(name, get_temp_file_pattern(), sizeof(name));
1370
0
#ifdef HAVE_MKSTEMP
1371
0
    {
1372
0
        mode_t oldmask = umask(0177);
1373
0
        netsnmp_assert(oldmask != (mode_t)(-1));
1374
0
        fd = mkstemp(name);
1375
0
        umask(oldmask);
1376
0
    }
1377
#else
1378
    if (mktemp(name)) {
1379
# ifndef WIN32
1380
        fd = open(name, O_CREAT | O_EXCL | O_WRONLY, S_IRUSR | S_IWUSR);
1381
# else
1382
        /*
1383
         * Win32 needs _S_IREAD | _S_IWRITE to set permissions on file
1384
         * after closing
1385
         */
1386
        fd = _open(name, _O_CREAT | _O_EXCL | _O_WRONLY, _S_IREAD | _S_IWRITE);
1387
# endif
1388
    }
1389
#endif
1390
0
    if (fd >= 0) {
1391
0
        close(fd);
1392
0
        DEBUGMSGTL(("netsnmp_mktemp", "temp file created: %s\n",
1393
0
                    name));
1394
0
        return name;
1395
0
    }
1396
0
    snmp_log(LOG_ERR, "netsnmp_mktemp: error creating file %s\n",
1397
0
             name);
1398
0
    return NULL;
1399
0
}
1400
1401
/*
1402
 * This function was created to differentiate actions
1403
 * that are appropriate for Linux 2.4 kernels, but not later kernels.
1404
 *
1405
 * This function can be used to test kernels on any platform that supports uname().
1406
 *
1407
 * If not running a platform that supports uname(), return -1.
1408
 *
1409
 * If ospname matches, and the release matches up through the prefix,
1410
 *  return 0.
1411
 * If the release is ordered higher, return 1.
1412
 * Be aware that "ordered higher" is not a guarantee of correctness.
1413
 */
1414
int
1415
netsnmp_os_prematch(const char *ospmname,
1416
                    const char *ospmrelprefix)
1417
0
{
1418
0
#ifdef HAVE_SYS_UTSNAME_H
1419
0
  static int printOSonce = 1;
1420
0
  struct utsname utsbuf;
1421
0
  if ( 0 > uname(&utsbuf))
1422
0
    return -1;
1423
1424
0
  if (printOSonce) {
1425
0
    printOSonce = 0;
1426
    /* show the four elements that the kernel can be sure of */
1427
0
  DEBUGMSGT(("daemonize","sysname '%s',\nrelease '%s',\nversion '%s',\nmachine '%s'\n",
1428
0
      utsbuf.sysname, utsbuf.release, utsbuf.version, utsbuf.machine));
1429
0
  }
1430
0
  if (0 != strcasecmp(utsbuf.sysname, ospmname)) return -1;
1431
1432
  /* Required to match only the leading characters */
1433
0
  return strncasecmp(utsbuf.release, ospmrelprefix, strlen(ospmrelprefix));
1434
1435
#else
1436
1437
  return -1;
1438
1439
#endif /* HAVE_SYS_UTSNAME_H */
1440
0
}
1441
1442
/**
1443
 * netsnmp_os_kernel_width determines kernel width at runtime
1444
 * Currently implemented for IRIX, AIX and Tru64 Unix
1445
 *
1446
 * @return kernel width (usually 32 or 64) on success, -1 on error
1447
 */
1448
int
1449
netsnmp_os_kernel_width(void)
1450
0
{
1451
#ifdef irix6
1452
  char buf[8];
1453
  sysinfo(_MIPS_SI_OS_NAME, buf, 7);
1454
  if (strncmp("IRIX64", buf, 6) == 0) {
1455
    return 64;
1456
  } else if (strncmp("IRIX", buf, 4) == 0) {
1457
    return 32;
1458
  } else {
1459
    return -1;
1460
  }
1461
#elif defined(aix4) || defined(aix5) || defined(aix6) || defined(aix7)
1462
  return (__KERNEL_32() ? 32 : (__KERNEL_64() ? 64 : -1));
1463
#elif defined(osf4) || defined(osf5) || defined(__alpha)
1464
  return 64; /* Alpha is always 64bit */
1465
#else
1466
  /* kernel width detection not implemented */
1467
0
  return -1;
1468
0
#endif
1469
0
}
1470
1471
netsnmp_feature_child_of(str_to_uid, user_information);
1472
#ifndef NETSNMP_FEATURE_REMOVE_STR_TO_UID
1473
/**
1474
 * Convert a user name or number into numeric form.
1475
 *
1476
 * @param[in] useroruid Either a Unix user name or the ASCII representation
1477
 *   of a user number.
1478
 *
1479
 * @return Either a user number > 0 or 0 if useroruid is not a valid user
1480
 *   name, not a valid user number or the name of the root user.
1481
 */
1482
0
int netsnmp_str_to_uid(const char *useroruid) {
1483
0
    int uid;
1484
0
#if defined(HAVE_GETPWNAM) && defined(HAVE_PWD_H)
1485
0
    struct passwd *pwd;
1486
0
#endif
1487
1488
0
    uid = atoi(useroruid);
1489
1490
0
    if (uid == 0) {
1491
0
#if defined(HAVE_GETPWNAM) && defined(HAVE_PWD_H)
1492
0
        pwd = getpwnam(useroruid);
1493
0
        uid = pwd ? pwd->pw_uid : 0;
1494
0
        endpwent();
1495
0
#endif
1496
0
        if (uid == 0)
1497
0
            snmp_log(LOG_WARNING, "Can't identify user (%s).\n", useroruid);
1498
0
    }
1499
0
    return uid;
1500
    
1501
0
}
1502
#endif /* NETSNMP_FEATURE_REMOVE_STR_TO_UID */
1503
1504
netsnmp_feature_child_of(str_to_gid, user_information);
1505
#ifndef NETSNMP_FEATURE_REMOVE_STR_TO_GID
1506
/**
1507
 * Convert a group name or number into numeric form.
1508
 *
1509
 * @param[in] grouporgid Either a Unix group name or the ASCII representation
1510
 *   of a group number.
1511
 *
1512
 * @return Either a group number > 0 or 0 if grouporgid is not a valid group
1513
 *   name, not a valid group number or the root group.
1514
 */
1515
int netsnmp_str_to_gid(const char *grouporgid)
1516
0
{
1517
0
    int gid;
1518
1519
0
    gid = atoi(grouporgid);
1520
1521
0
    if (gid == 0) {
1522
0
#if defined(HAVE_GETGRNAM) && defined(HAVE_GRP_H)
1523
0
        struct group  *grp;
1524
1525
0
        grp = getgrnam(grouporgid);
1526
0
        gid = grp ? grp->gr_gid : 0;
1527
0
        endgrent();
1528
0
#endif
1529
0
        if (gid == 0)
1530
0
            snmp_log(LOG_WARNING, "Can't identify group (%s).\n", grouporgid);
1531
0
    }
1532
1533
0
    return gid;
1534
0
}
1535
#endif /* NETSNMP_FEATURE_REMOVE_STR_TO_GID */