Thu, 04 Oct 2012 20:30:05 +0200
Correct out of date build configuration, porting to Solaris 11 network
link infrastructure and new libpcap logic. This additionally allows for
device drivers in subdirectories of /dev. Correct packaged nmap
personalities and signatures to work out of the box. Finally, hack
arpd logic to properly close sockets and quit on TERM by repeating
signaling in the run command script. Sadly, all this fails to correct
the run time behaviour of honeyd which fails to bind to the IP layer.
michael@428 | 1 | /* |
michael@428 | 2 | ** mutex.c -- OpenPKG Mutex Utility |
michael@428 | 3 | ** Copyright (c) 2008-2012 OpenPKG GmbH <http://openpkg.com/> |
michael@428 | 4 | ** |
michael@428 | 5 | ** This software is property of the OpenPKG GmbH, DE MUC HRB 160208. |
michael@428 | 6 | ** All rights reserved. Licenses which grant limited permission to use, |
michael@428 | 7 | ** copy, modify and distribute this software are available from the |
michael@428 | 8 | ** OpenPKG GmbH. |
michael@428 | 9 | ** |
michael@428 | 10 | ** THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED |
michael@428 | 11 | ** WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
michael@428 | 12 | ** MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. |
michael@428 | 13 | ** IN NO EVENT SHALL THE AUTHORS AND COPYRIGHT HOLDERS AND THEIR |
michael@428 | 14 | ** CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
michael@428 | 15 | ** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
michael@428 | 16 | ** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF |
michael@428 | 17 | ** USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND |
michael@428 | 18 | ** ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, |
michael@428 | 19 | ** OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT |
michael@428 | 20 | ** OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
michael@428 | 21 | ** SUCH DAMAGE. |
michael@428 | 22 | */ |
michael@428 | 23 | |
michael@428 | 24 | /* standard system headers */ |
michael@428 | 25 | #include <stdio.h> |
michael@428 | 26 | #include <stdlib.h> |
michael@428 | 27 | #include <stdarg.h> |
michael@428 | 28 | #include <string.h> |
michael@428 | 29 | #include <unistd.h> |
michael@428 | 30 | #include <errno.h> |
michael@428 | 31 | #include <fcntl.h> |
michael@428 | 32 | #include <signal.h> |
michael@428 | 33 | #include <sys/types.h> |
michael@428 | 34 | #include <sys/wait.h> |
michael@428 | 35 | |
michael@428 | 36 | /* non-standard add-on headers */ |
michael@428 | 37 | #include "popt.h" |
michael@428 | 38 | |
michael@428 | 39 | /* program information */ |
michael@428 | 40 | #define PROGRAM_NAME "mutex" |
michael@428 | 41 | |
michael@428 | 42 | /* error handling constants */ |
michael@428 | 43 | #define EXITCODE_NONE 00 |
michael@428 | 44 | #define EXITCODE_USAGE 64 |
michael@428 | 45 | #define EXITCODE_OSERR 71 |
michael@428 | 46 | #define EXITCODE_CANTCREAT 73 |
michael@428 | 47 | #define EXITCODE_TEMPFAIL 75 |
michael@428 | 48 | #define ERRORCODE_NONE 0 |
michael@428 | 49 | #define ERRORCODE_SYSTEM 1 |
michael@428 | 50 | |
michael@428 | 51 | /* global variables */ |
michael@428 | 52 | static const char *mutex_filename = NULL; |
michael@428 | 53 | static int mutex_fd = -1; |
michael@428 | 54 | static int mutex_keep = 0; |
michael@428 | 55 | static int mutex_timeout = -1; |
michael@428 | 56 | static volatile int mutex_timed_out = 0; |
michael@428 | 57 | |
michael@428 | 58 | /* display warning and continue or display error and exit */ |
michael@428 | 59 | static void |
michael@428 | 60 | error( |
michael@428 | 61 | int exitcode, |
michael@428 | 62 | int errorcode, |
michael@428 | 63 | const char *fmt, ...) |
michael@428 | 64 | { |
michael@428 | 65 | va_list ap; |
michael@428 | 66 | int errno_safed = errno; |
michael@428 | 67 | |
michael@428 | 68 | va_start(ap, fmt); |
michael@428 | 69 | if (exitcode != 0) |
michael@428 | 70 | fprintf(stderr, PROGRAM_NAME ":ERROR: "); |
michael@428 | 71 | else |
michael@428 | 72 | fprintf(stderr, PROGRAM_NAME ":WARNING: "); |
michael@428 | 73 | vfprintf(stderr, fmt, ap); |
michael@428 | 74 | if (errorcode) |
michael@428 | 75 | fprintf(stderr, ": %s", strerror(errno_safed)); |
michael@428 | 76 | fprintf(stderr, "\n"); |
michael@428 | 77 | va_end(ap); |
michael@428 | 78 | if (exitcode != 0) |
michael@428 | 79 | exit(exitcode); |
michael@428 | 80 | return; |
michael@428 | 81 | } |
michael@428 | 82 | |
michael@428 | 83 | /* acquire mutex */ |
michael@428 | 84 | static int |
michael@428 | 85 | mutex_acquire(int nonblock) |
michael@428 | 86 | { |
michael@428 | 87 | static struct flock lock; |
michael@428 | 88 | int flags; |
michael@428 | 89 | |
michael@428 | 90 | /* open mutex file (and optionally create it) */ |
michael@428 | 91 | flags = O_RDWR|O_CREAT; |
michael@428 | 92 | if (nonblock) |
michael@428 | 93 | flags |= O_NONBLOCK; |
michael@428 | 94 | if ((mutex_fd = open(mutex_filename, flags, 0600)) == -1) { |
michael@428 | 95 | if (errno == EAGAIN || errno == EINTR) |
michael@428 | 96 | return 0; |
michael@428 | 97 | error(EXITCODE_CANTCREAT, ERRORCODE_SYSTEM, "cannot open mutex file \"%s\"", |
michael@428 | 98 | mutex_filename); |
michael@428 | 99 | } |
michael@428 | 100 | |
michael@428 | 101 | /* acquire exclusive lock on the mutex file */ |
michael@428 | 102 | lock.l_whence = SEEK_SET; /* from current point */ |
michael@428 | 103 | lock.l_start = 0; /* -"- */ |
michael@428 | 104 | lock.l_len = 0; /* until end of file */ |
michael@428 | 105 | lock.l_type = F_WRLCK; /* set exclusive/read-write lock */ |
michael@428 | 106 | lock.l_pid = 0; /* pid not actually interesting */ |
michael@428 | 107 | if (fcntl(mutex_fd, nonblock ? F_SETLK : F_SETLKW, &lock) == -1) { |
michael@428 | 108 | close(mutex_fd); |
michael@428 | 109 | mutex_fd = -1; |
michael@428 | 110 | return 0; |
michael@428 | 111 | } |
michael@428 | 112 | |
michael@428 | 113 | return 1; |
michael@428 | 114 | } |
michael@428 | 115 | |
michael@428 | 116 | /* release mutex */ |
michael@428 | 117 | static void |
michael@428 | 118 | mutex_release(void) |
michael@428 | 119 | { |
michael@428 | 120 | static struct flock unlock; |
michael@428 | 121 | |
michael@428 | 122 | if (mutex_fd != -1) { |
michael@428 | 123 | /* release lock on the mutex file */ |
michael@428 | 124 | unlock.l_whence = SEEK_SET; /* from current point */ |
michael@428 | 125 | unlock.l_start = 0; /* -"- */ |
michael@428 | 126 | unlock.l_len = 0; /* until end of file */ |
michael@428 | 127 | unlock.l_type = F_UNLCK; /* unlock */ |
michael@428 | 128 | unlock.l_pid = 0; /* pid not actually interesting */ |
michael@428 | 129 | fcntl(mutex_fd, F_SETLK, &unlock); |
michael@428 | 130 | |
michael@428 | 131 | /* close mutex file */ |
michael@428 | 132 | close(mutex_fd); |
michael@428 | 133 | mutex_fd = -1; |
michael@428 | 134 | } |
michael@428 | 135 | return; |
michael@428 | 136 | } |
michael@428 | 137 | |
michael@428 | 138 | /* destroy the mutex */ |
michael@428 | 139 | static void |
michael@428 | 140 | mutex_destroy( |
michael@428 | 141 | void) |
michael@428 | 142 | { |
michael@428 | 143 | /* release lock on mutex file */ |
michael@428 | 144 | mutex_release(); |
michael@428 | 145 | |
michael@428 | 146 | /* optionally remove mutex file */ |
michael@428 | 147 | if (!mutex_keep) |
michael@428 | 148 | unlink(mutex_filename); |
michael@428 | 149 | |
michael@428 | 150 | return; |
michael@428 | 151 | } |
michael@428 | 152 | |
michael@428 | 153 | /* signal handler for SIGTERM */ |
michael@428 | 154 | static void |
michael@428 | 155 | handler_killed( |
michael@428 | 156 | int sig) |
michael@428 | 157 | { |
michael@428 | 158 | /* destroy mutex */ |
michael@428 | 159 | mutex_destroy(); |
michael@428 | 160 | |
michael@428 | 161 | /* re-raise the signal */ |
michael@428 | 162 | signal(sig, SIG_DFL); |
michael@428 | 163 | if (kill(getpid(), sig) == -1) |
michael@428 | 164 | error(EXITCODE_OSERR, ERRORCODE_SYSTEM, "kill(2) failed"); |
michael@428 | 165 | |
michael@428 | 166 | return; |
michael@428 | 167 | } |
michael@428 | 168 | |
michael@428 | 169 | /* signal handler for SIGALRM */ |
michael@428 | 170 | static void |
michael@428 | 171 | handler_timeout( |
michael@428 | 172 | int sig) |
michael@428 | 173 | { |
michael@428 | 174 | mutex_timed_out = 1; |
michael@428 | 175 | return; |
michael@428 | 176 | } |
michael@428 | 177 | |
michael@428 | 178 | /* command line options */ |
michael@428 | 179 | static struct poptOption options_tab[] = { |
michael@428 | 180 | { "keep", 'k', POPT_ARG_NONE, &mutex_keep, 0, NULL, NULL }, |
michael@428 | 181 | { "timeout", 't', POPT_ARG_INT, &mutex_timeout, 0, NULL, NULL }, |
michael@428 | 182 | POPT_TABLEEND |
michael@428 | 183 | }; |
michael@428 | 184 | |
michael@428 | 185 | /* main program procedure */ |
michael@428 | 186 | int |
michael@428 | 187 | main( |
michael@428 | 188 | int argc, |
michael@428 | 189 | char *argv[]) |
michael@428 | 190 | { |
michael@428 | 191 | int status; |
michael@428 | 192 | pid_t child; |
michael@428 | 193 | int locked; |
michael@428 | 194 | char c; |
michael@428 | 195 | const char **args; |
michael@428 | 196 | poptContext options_ctx; |
michael@428 | 197 | |
michael@428 | 198 | /* process command line arguments */ |
michael@428 | 199 | options_ctx = poptGetContext(argv[0], argc, (const char **)argv, |
michael@428 | 200 | options_tab, POPT_CONTEXT_NO_EXEC|POPT_CONTEXT_POSIXMEHARDER); |
michael@428 | 201 | while ((c = poptGetNextOpt(options_ctx)) > 0) |
michael@428 | 202 | ; |
michael@428 | 203 | if (c < -1) |
michael@428 | 204 | error(EXITCODE_USAGE, ERRORCODE_NONE, "command line option \"%s\": %s", |
michael@428 | 205 | poptBadOption(options_ctx, POPT_BADOPTION_NOALIAS), poptStrerror(c)); |
michael@428 | 206 | mutex_filename = poptGetArg(options_ctx); |
michael@428 | 207 | if (mutex_filename == NULL) { |
michael@428 | 208 | fprintf(stderr, |
michael@428 | 209 | "usage: %s [--keep|-k] [--timeout|-t <seconds>] <mutex-file> <command> [<arguments>]\n", |
michael@428 | 210 | PROGRAM_NAME); |
michael@428 | 211 | exit(EXITCODE_USAGE); |
michael@428 | 212 | } |
michael@428 | 213 | args = poptGetArgs(options_ctx); |
michael@428 | 214 | |
michael@428 | 215 | /* optionally set up a timeout */ |
michael@428 | 216 | if (mutex_timeout > 0) { |
michael@428 | 217 | struct sigaction act; |
michael@428 | 218 | act.sa_handler = handler_timeout; |
michael@428 | 219 | act.sa_flags = 0; |
michael@428 | 220 | sigemptyset(&act.sa_mask); |
michael@428 | 221 | sigaction(SIGALRM, &act, NULL); |
michael@428 | 222 | alarm(mutex_timeout); |
michael@428 | 223 | } |
michael@428 | 224 | |
michael@428 | 225 | /* try to acquire the mutex lock */ |
michael@428 | 226 | locked = mutex_acquire(1 /* non-blocking */); |
michael@428 | 227 | while (!locked && !mutex_timed_out && mutex_timeout != 0) |
michael@428 | 228 | locked = mutex_acquire(0 /* blocking */); |
michael@428 | 229 | |
michael@428 | 230 | /* optionally destroy timeout */ |
michael@428 | 231 | if (mutex_timeout > 0) |
michael@428 | 232 | alarm(0); |
michael@428 | 233 | |
michael@428 | 234 | /* exit in case we failed to acquire the mutex lock */ |
michael@428 | 235 | if (!locked) |
michael@428 | 236 | error(EXITCODE_TEMPFAIL, ERRORCODE_NONE, "%s: already locked", mutex_filename); |
michael@428 | 237 | |
michael@428 | 238 | /* execute the command */ |
michael@428 | 239 | if (atexit(mutex_destroy) == -1) |
michael@428 | 240 | error(EXITCODE_OSERR, ERRORCODE_SYSTEM, "atexit(3) failed"); |
michael@428 | 241 | if ((child = fork()) == -1) |
michael@428 | 242 | error(EXITCODE_OSERR, ERRORCODE_SYSTEM, "fork(2) failed"); |
michael@428 | 243 | if (child == 0) { |
michael@428 | 244 | /* the child process */ |
michael@428 | 245 | mutex_release(); |
michael@428 | 246 | execvp((char *)args[0], (char **)args); |
michael@428 | 247 | error(EXITCODE_NONE, ERRORCODE_SYSTEM, "execvp(2) failed: %s", args[0]); |
michael@428 | 248 | exit(1); |
michael@428 | 249 | } |
michael@428 | 250 | poptFreeContext(options_ctx); |
michael@428 | 251 | |
michael@428 | 252 | /* wait for child process and return its exit status */ |
michael@428 | 253 | signal(SIGINT, SIG_IGN); |
michael@428 | 254 | signal(SIGQUIT, SIG_IGN); |
michael@428 | 255 | signal(SIGTERM, handler_killed); |
michael@428 | 256 | if (waitpid(child, &status, 0) == -1) |
michael@428 | 257 | error(EXITCODE_OSERR, ERRORCODE_SYSTEM, "waitpid(2) failed"); |
michael@428 | 258 | return (WIFEXITED(status) ? WEXITSTATUS(status) : 1); |
michael@428 | 259 | } |
michael@428 | 260 |