1d74d50a8SDag-Erling Smørgrav /* 2761efaa7SDag-Erling Smørgrav * Copyright (c) 2004-2005 Todd C. Miller <Todd.Miller@courtesan.com> 3d74d50a8SDag-Erling Smørgrav * 4d74d50a8SDag-Erling Smørgrav * Permission to use, copy, modify, and distribute this software for any 5d74d50a8SDag-Erling Smørgrav * purpose with or without fee is hereby granted, provided that the above 6d74d50a8SDag-Erling Smørgrav * copyright notice and this permission notice appear in all copies. 7d74d50a8SDag-Erling Smørgrav * 8d74d50a8SDag-Erling Smørgrav * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9d74d50a8SDag-Erling Smørgrav * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10d74d50a8SDag-Erling Smørgrav * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11d74d50a8SDag-Erling Smørgrav * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12d74d50a8SDag-Erling Smørgrav * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13d74d50a8SDag-Erling Smørgrav * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14d74d50a8SDag-Erling Smørgrav * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15d74d50a8SDag-Erling Smørgrav */ 16d74d50a8SDag-Erling Smørgrav 17d74d50a8SDag-Erling Smørgrav #include "includes.h" 18d74d50a8SDag-Erling Smørgrav 19*1323ec57SEd Maste #if !defined(HAVE_CLOSEFROM) || defined(BROKEN_CLOSEFROM) 20d74d50a8SDag-Erling Smørgrav 21d74d50a8SDag-Erling Smørgrav #include <sys/types.h> 22d74d50a8SDag-Erling Smørgrav #include <unistd.h> 23d74d50a8SDag-Erling Smørgrav #include <stdio.h> 24761efaa7SDag-Erling Smørgrav #ifdef HAVE_FCNTL_H 25761efaa7SDag-Erling Smørgrav # include <fcntl.h> 26761efaa7SDag-Erling Smørgrav #endif 27d74d50a8SDag-Erling Smørgrav #include <limits.h> 28d74d50a8SDag-Erling Smørgrav #include <stdlib.h> 29d74d50a8SDag-Erling Smørgrav #include <stddef.h> 30761efaa7SDag-Erling Smørgrav #include <string.h> 31761efaa7SDag-Erling Smørgrav #include <unistd.h> 32d74d50a8SDag-Erling Smørgrav #ifdef HAVE_DIRENT_H 33d74d50a8SDag-Erling Smørgrav # include <dirent.h> 34d74d50a8SDag-Erling Smørgrav # define NAMLEN(dirent) strlen((dirent)->d_name) 35d74d50a8SDag-Erling Smørgrav #else 36d74d50a8SDag-Erling Smørgrav # define dirent direct 37d74d50a8SDag-Erling Smørgrav # define NAMLEN(dirent) (dirent)->d_namlen 38d74d50a8SDag-Erling Smørgrav # ifdef HAVE_SYS_NDIR_H 39d74d50a8SDag-Erling Smørgrav # include <sys/ndir.h> 40d74d50a8SDag-Erling Smørgrav # endif 41d74d50a8SDag-Erling Smørgrav # ifdef HAVE_SYS_DIR_H 42d74d50a8SDag-Erling Smørgrav # include <sys/dir.h> 43d74d50a8SDag-Erling Smørgrav # endif 44d74d50a8SDag-Erling Smørgrav # ifdef HAVE_NDIR_H 45d74d50a8SDag-Erling Smørgrav # include <ndir.h> 46d74d50a8SDag-Erling Smørgrav # endif 47d74d50a8SDag-Erling Smørgrav #endif 4819261079SEd Maste #if defined(HAVE_LIBPROC_H) 4919261079SEd Maste # include <libproc.h> 5019261079SEd Maste #endif 51d74d50a8SDag-Erling Smørgrav 52d74d50a8SDag-Erling Smørgrav #ifndef OPEN_MAX 53d74d50a8SDag-Erling Smørgrav # define OPEN_MAX 256 54d74d50a8SDag-Erling Smørgrav #endif 55d74d50a8SDag-Erling Smørgrav 56761efaa7SDag-Erling Smørgrav #if 0 57761efaa7SDag-Erling Smørgrav __unused static const char rcsid[] = "$Sudo: closefrom.c,v 1.11 2006/08/17 15:26:54 millert Exp $"; 58d74d50a8SDag-Erling Smørgrav #endif /* lint */ 59d74d50a8SDag-Erling Smørgrav 6019261079SEd Maste #ifndef HAVE_FCNTL_CLOSEM 61d74d50a8SDag-Erling Smørgrav /* 62d74d50a8SDag-Erling Smørgrav * Close all file descriptors greater than or equal to lowfd. 63d74d50a8SDag-Erling Smørgrav */ 6419261079SEd Maste static void 6519261079SEd Maste closefrom_fallback(int lowfd) 66d74d50a8SDag-Erling Smørgrav { 67d74d50a8SDag-Erling Smørgrav long fd, maxfd; 68d74d50a8SDag-Erling Smørgrav 69d74d50a8SDag-Erling Smørgrav /* 70d74d50a8SDag-Erling Smørgrav * Fall back on sysconf() or getdtablesize(). We avoid checking 71d74d50a8SDag-Erling Smørgrav * resource limits since it is possible to open a file descriptor 72d74d50a8SDag-Erling Smørgrav * and then drop the rlimit such that it is below the open fd. 73d74d50a8SDag-Erling Smørgrav */ 74d74d50a8SDag-Erling Smørgrav #ifdef HAVE_SYSCONF 75d74d50a8SDag-Erling Smørgrav maxfd = sysconf(_SC_OPEN_MAX); 76d74d50a8SDag-Erling Smørgrav #else 77d74d50a8SDag-Erling Smørgrav maxfd = getdtablesize(); 78d74d50a8SDag-Erling Smørgrav #endif /* HAVE_SYSCONF */ 79d74d50a8SDag-Erling Smørgrav if (maxfd < 0) 80d74d50a8SDag-Erling Smørgrav maxfd = OPEN_MAX; 81d74d50a8SDag-Erling Smørgrav 82d74d50a8SDag-Erling Smørgrav for (fd = lowfd; fd < maxfd; fd++) 83d74d50a8SDag-Erling Smørgrav (void) close((int) fd); 84d74d50a8SDag-Erling Smørgrav } 8519261079SEd Maste #endif /* HAVE_FCNTL_CLOSEM */ 8619261079SEd Maste 8719261079SEd Maste #ifdef HAVE_FCNTL_CLOSEM 8819261079SEd Maste void 8919261079SEd Maste closefrom(int lowfd) 9019261079SEd Maste { 9119261079SEd Maste (void) fcntl(lowfd, F_CLOSEM, 0); 9219261079SEd Maste } 9319261079SEd Maste #elif defined(HAVE_LIBPROC_H) && defined(HAVE_PROC_PIDINFO) 9419261079SEd Maste void 9519261079SEd Maste closefrom(int lowfd) 9619261079SEd Maste { 9719261079SEd Maste int i, r, sz; 9819261079SEd Maste pid_t pid = getpid(); 9919261079SEd Maste struct proc_fdinfo *fdinfo_buf = NULL; 10019261079SEd Maste 10119261079SEd Maste sz = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, NULL, 0); 10219261079SEd Maste if (sz == 0) 10319261079SEd Maste return; /* no fds, really? */ 10419261079SEd Maste else if (sz == -1) 10519261079SEd Maste goto fallback; 10619261079SEd Maste if ((fdinfo_buf = malloc(sz)) == NULL) 10719261079SEd Maste goto fallback; 10819261079SEd Maste r = proc_pidinfo(pid, PROC_PIDLISTFDS, 0, fdinfo_buf, sz); 10919261079SEd Maste if (r < 0 || r > sz) 11019261079SEd Maste goto fallback; 11119261079SEd Maste for (i = 0; i < r / (int)PROC_PIDLISTFD_SIZE; i++) { 11219261079SEd Maste if (fdinfo_buf[i].proc_fd >= lowfd) 11319261079SEd Maste close(fdinfo_buf[i].proc_fd); 11419261079SEd Maste } 11519261079SEd Maste free(fdinfo_buf); 11619261079SEd Maste return; 11719261079SEd Maste fallback: 11819261079SEd Maste free(fdinfo_buf); 11919261079SEd Maste closefrom_fallback(lowfd); 12019261079SEd Maste return; 12119261079SEd Maste } 12219261079SEd Maste #elif defined(HAVE_DIRFD) && defined(HAVE_PROC_PID) 12319261079SEd Maste void 12419261079SEd Maste closefrom(int lowfd) 12519261079SEd Maste { 12619261079SEd Maste long fd; 12719261079SEd Maste char fdpath[PATH_MAX], *endp; 12819261079SEd Maste struct dirent *dent; 12919261079SEd Maste DIR *dirp; 13019261079SEd Maste int len; 13119261079SEd Maste 132*1323ec57SEd Maste #ifdef HAVE_CLOSE_RANGE 133*1323ec57SEd Maste if (close_range(lowfd, INT_MAX, 0) == 0) 134*1323ec57SEd Maste return; 135*1323ec57SEd Maste #endif 136*1323ec57SEd Maste 13719261079SEd Maste /* Check for a /proc/$$/fd directory. */ 13819261079SEd Maste len = snprintf(fdpath, sizeof(fdpath), "/proc/%ld/fd", (long)getpid()); 13919261079SEd Maste if (len > 0 && (size_t)len < sizeof(fdpath) && (dirp = opendir(fdpath))) { 14019261079SEd Maste while ((dent = readdir(dirp)) != NULL) { 14119261079SEd Maste fd = strtol(dent->d_name, &endp, 10); 14219261079SEd Maste if (dent->d_name != endp && *endp == '\0' && 14319261079SEd Maste fd >= 0 && fd < INT_MAX && fd >= lowfd && fd != dirfd(dirp)) 14419261079SEd Maste (void) close((int) fd); 14519261079SEd Maste } 14619261079SEd Maste (void) closedir(dirp); 14719261079SEd Maste return; 14819261079SEd Maste } 14919261079SEd Maste /* /proc/$$/fd strategy failed, fall back to brute force closure */ 15019261079SEd Maste closefrom_fallback(lowfd); 15119261079SEd Maste } 15219261079SEd Maste #else 15319261079SEd Maste void 15419261079SEd Maste closefrom(int lowfd) 15519261079SEd Maste { 15619261079SEd Maste closefrom_fallback(lowfd); 157d74d50a8SDag-Erling Smørgrav } 158761efaa7SDag-Erling Smørgrav #endif /* !HAVE_FCNTL_CLOSEM */ 159d74d50a8SDag-Erling Smørgrav #endif /* HAVE_CLOSEFROM */ 160