]> git.armaanb.net Git - opendoas.git/blob - libopenbsd/closefrom.c
libopenbsd/closefrom.c: sync with sudo
[opendoas.git] / libopenbsd / closefrom.c
1 /*
2  * SPDX-License-Identifier: ISC
3  *
4  * Copyright (c) 2004-2005, 2007, 2010, 2012-2015, 2017-2018
5  *      Todd C. Miller <Todd.Miller@sudo.ws>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19
20 /*
21  * This is an open source non-commercial project. Dear PVS-Studio, please check it.
22  * PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com
23  */
24
25 #include <config.h>
26
27 #ifndef HAVE_CLOSEFROM
28
29 #include <sys/types.h>
30 #include <unistd.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <fcntl.h>
34 #include <limits.h>
35 #ifdef HAVE_PSTAT_GETPROC
36 # include <sys/pstat.h>
37 #else
38 # include <dirent.h>
39 #endif
40
41 #include "openbsd.h"
42
43 #ifndef _POSIX_OPEN_MAX
44 # define _POSIX_OPEN_MAX        20
45 #endif
46
47 /*
48  * Close all file descriptors greater than or equal to lowfd.
49  * This is the expensive (fallback) method.
50  */
51 static void
52 closefrom_fallback(int lowfd)
53 {
54     long fd, maxfd;
55
56     /*
57      * Fall back on sysconf(_SC_OPEN_MAX).  We avoid checking
58      * resource limits since it is possible to open a file descriptor
59      * and then drop the rlimit such that it is below the open fd.
60      */
61     maxfd = sysconf(_SC_OPEN_MAX);
62     if (maxfd < 0)
63         maxfd = _POSIX_OPEN_MAX;
64
65     for (fd = lowfd; fd < maxfd; fd++) {
66 #ifdef __APPLE__
67         /* Avoid potential libdispatch crash when we close its fds. */
68         (void) fcntl((int) fd, F_SETFD, FD_CLOEXEC);
69 #else
70         (void) close((int) fd);
71 #endif
72     }
73 }
74
75 /*
76  * Close all file descriptors greater than or equal to lowfd.
77  * We try the fast way first, falling back on the slow method.
78  */
79 void
80 closefrom(int lowfd)
81 {
82 #if defined(HAVE_PSTAT_GETPROC)
83     struct pst_status pstat;
84 #elif defined(HAVE_DIRFD)
85     const char *path;
86     DIR *dirp;
87 #endif
88
89     /* Try the fast method first, if possible. */
90 #if defined(HAVE_FCNTL_CLOSEM)
91     if (fcntl(lowfd, F_CLOSEM, 0) != -1)
92         return;
93 #endif
94 #if defined(HAVE_PSTAT_GETPROC)
95     /*
96      * EOVERFLOW is not a fatal error for the fields we use.
97      * See the "EOVERFLOW Error" section of pstat_getvminfo(3).
98      */
99     if (pstat_getproc(&pstat, sizeof(pstat), 0, getpid()) != -1 ||
100         errno == EOVERFLOW) {
101         int fd;
102
103         for (fd = lowfd; fd <= pstat.pst_highestfd; fd++)
104             (void) close(fd);
105         return;
106     }
107 #elif defined(HAVE_DIRFD)
108     /* Use /proc/self/fd (or /dev/fd on macOS) if it exists. */
109 # ifdef __APPLE__
110     path = _PATH_DEV "fd";
111 # else
112     path = "/proc/self/fd";
113 # endif
114     if ((dirp = opendir(path)) != NULL) {
115         struct dirent *dent;
116         while ((dent = readdir(dirp)) != NULL) {
117             const char *errstr;
118             int fd = strtonum(dent->d_name, lowfd, INT_MAX, &errstr);
119             if (errstr == NULL && fd != dirfd(dirp)) {
120 # ifdef __APPLE__
121                 /* Avoid potential libdispatch crash when we close its fds. */
122                 (void) fcntl(fd, F_SETFD, FD_CLOEXEC);
123 # else
124                 (void) close(fd);
125 # endif
126             }
127         }
128         (void) closedir(dirp);
129         return;
130     }
131 #endif /* HAVE_DIRFD */
132
133     /* Do things the slow way. */
134     closefrom_fallback(lowfd);
135 }
136
137 #endif /* HAVE_CLOSEFROM */