1 /*- 2 * Copyright (c) 2010 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Pawel Jakub Dawidek under sponsorship from 6 * the FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <sys/types.h> 34 #include <sys/wait.h> 35 36 #include <assert.h> 37 #include <fcntl.h> 38 #include <stdio.h> 39 #include <stdlib.h> 40 #include <unistd.h> 41 #include <string.h> 42 #include <syslog.h> 43 #include <libgen.h> 44 #include <paths.h> 45 46 #include <pjdlog.h> 47 48 #include "hooks.h" 49 50 static void 51 descriptors(void) 52 { 53 long maxfd; 54 int fd; 55 56 /* 57 * Close all descriptors. 58 */ 59 maxfd = sysconf(_SC_OPEN_MAX); 60 if (maxfd < 0) { 61 pjdlog_errno(LOG_WARNING, "sysconf(_SC_OPEN_MAX) failed"); 62 maxfd = 1024; 63 } 64 for (fd = 0; fd <= maxfd; fd++) 65 close(fd); 66 /* 67 * Redirect stdin, stdout and stderr to /dev/null. 68 */ 69 fd = open(_PATH_DEVNULL, O_RDONLY); 70 if (fd < 0) { 71 pjdlog_errno(LOG_WARNING, "Unable to open %s for reading", 72 _PATH_DEVNULL); 73 } else if (fd != STDIN_FILENO) { 74 if (dup2(fd, STDIN_FILENO) < 0) { 75 pjdlog_errno(LOG_WARNING, 76 "Unable to duplicate descriptor for stdin"); 77 } 78 close(fd); 79 } 80 fd = open(_PATH_DEVNULL, O_WRONLY); 81 if (fd < 0) { 82 pjdlog_errno(LOG_WARNING, "Unable to open %s for writing", 83 _PATH_DEVNULL); 84 } else { 85 if (fd != STDOUT_FILENO && dup2(fd, STDOUT_FILENO) < 0) { 86 pjdlog_errno(LOG_WARNING, 87 "Unable to duplicate descriptor for stdout"); 88 } 89 if (fd != STDERR_FILENO && dup2(fd, STDERR_FILENO) < 0) { 90 pjdlog_errno(LOG_WARNING, 91 "Unable to duplicate descriptor for stderr"); 92 } 93 if (fd != STDOUT_FILENO && fd != STDERR_FILENO) 94 close(fd); 95 } 96 } 97 98 int 99 hook_exec(const char *path, ...) 100 { 101 va_list ap; 102 int ret; 103 104 va_start(ap, path); 105 ret = hook_execv(path, ap); 106 va_end(ap); 107 return (ret); 108 } 109 110 int 111 hook_execv(const char *path, va_list ap) 112 { 113 char *args[64]; 114 unsigned int ii; 115 pid_t pid, wpid; 116 int status; 117 118 if (path == NULL || path[0] == '\0') 119 return (0); 120 121 memset(args, 0, sizeof(args)); 122 args[0] = basename(path); 123 for (ii = 1; ii < sizeof(args) / sizeof(args[0]); ii++) { 124 args[ii] = va_arg(ap, char *); 125 if (args[ii] == NULL) 126 break; 127 } 128 assert(ii < sizeof(args) / sizeof(args[0])); 129 130 pid = fork(); 131 switch (pid) { 132 case -1: /* Error. */ 133 pjdlog_errno(LOG_ERR, "Unable to fork %s", path); 134 return (-1); 135 case 0: /* Child. */ 136 descriptors(); 137 execv(path, args); 138 pjdlog_errno(LOG_ERR, "Unable to execute %s", path); 139 exit(EX_SOFTWARE); 140 default: /* Parent. */ 141 break; 142 } 143 144 wpid = waitpid(pid, &status, 0); 145 assert(wpid == pid); 146 147 return (WEXITSTATUS(status)); 148 } 149