1 /* $OpenBSD: misc.c,v 1.8 2017/12/18 09:12:49 job Exp $ */ 2 3 /* 4 * Copyright (c) 2005, 2006 Reyk Floeter <reyk@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/stat.h> 20 #include <sys/types.h> 21 #include <sys/utsname.h> 22 #include <sys/wait.h> 23 #include <sys/time.h> 24 25 #include <stdio.h> 26 #include <stdlib.h> 27 #include <signal.h> 28 #include <string.h> 29 #include <unistd.h> 30 #include <ctype.h> 31 #include <errno.h> 32 #include <fcntl.h> 33 34 #include "bgplg.h" 35 36 static volatile pid_t child = -1; 37 38 int 39 lg_checkperm(struct cmd *cmd) 40 { 41 struct stat stbuf; 42 43 /* No external command to execute, this is always valid */ 44 if (cmd->earg[0] == NULL) 45 return (1); 46 47 /* 48 * Skip commands if the executable is missing or 49 * the permission mode has been set to zero (the default 50 * in a CGI environment). 51 */ 52 if (stat(cmd->earg[0], &stbuf) != 0 || 53 (stbuf.st_mode & ~S_IFMT) == 0) 54 return (0); 55 56 return (1); 57 } 58 59 int 60 lg_help(struct cmd *cmds, char **argv) 61 { 62 u_int i; 63 64 printf("valid commands:\n"); 65 for (i = 0; cmds[i].name != NULL; i++) { 66 if (!lg_checkperm(&cmds[i])) 67 continue; 68 69 printf(" %s", cmds[i].name); 70 if (cmds[i].minargs > 0) 71 printf(" { arg }"); 72 else if (cmds[i].maxargs > 0) 73 printf(" [ arg ]"); 74 printf("\n"); 75 } 76 return (0); 77 } 78 79 void 80 lg_sig_alarm(int sig) 81 { 82 if (child != -1) { 83 /* Forcibly kill the child, no excuse... */ 84 kill(child, SIGKILL); 85 } 86 } 87 88 int 89 lg_exec(const char *file, char **new_argv) 90 { 91 int status = 0, ret = 0; 92 sig_t save_quit, save_int, save_chld; 93 struct itimerval it; 94 95 if (new_argv == NULL) 96 return (EFAULT); 97 98 save_quit = signal(SIGQUIT, SIG_IGN); 99 save_int = signal(SIGINT, SIG_IGN); 100 save_chld = signal(SIGCHLD, SIG_DFL); 101 102 switch (child = fork()) { 103 case -1: 104 ret = errno; 105 goto done; 106 case 0: 107 signal(SIGQUIT, SIG_DFL); 108 signal(SIGINT, SIG_DFL); 109 signal(SIGCHLD, SIG_DFL); 110 111 execvp(file, new_argv); 112 _exit(127); 113 break; 114 default: 115 /* Kill the process after a timeout */ 116 signal(SIGALRM, lg_sig_alarm); 117 bzero(&it, sizeof(it)); 118 it.it_value.tv_sec = BGPLG_TIMEOUT; 119 setitimer(ITIMER_REAL, &it, NULL); 120 121 waitpid(child, &status, 0); 122 break; 123 } 124 125 switch (ret) { 126 case -1: 127 ret = ECHILD; 128 break; 129 default: 130 if (WIFEXITED(status)) 131 ret = WEXITSTATUS(status); 132 else 133 ret = ECHILD; 134 } 135 136 done: 137 /* Disable the process timeout timer */ 138 bzero(&it, sizeof(it)); 139 setitimer(ITIMER_REAL, &it, NULL); 140 child = -1; 141 142 signal(SIGQUIT, save_quit); 143 signal(SIGINT, save_int); 144 signal(SIGCHLD, save_chld); 145 signal(SIGALRM, SIG_DFL); 146 147 return (ret); 148 } 149 150 ssize_t 151 lg_strip(char *str) 152 { 153 size_t len; 154 155 if ((len = strlen(str)) < 1) 156 return (0); /* XXX EINVAL? */ 157 158 if (isspace((unsigned char)str[len - 1])) { 159 str[len - 1] = '\0'; 160 return (lg_strip(str)); 161 } 162 163 return (strlen(str)); 164 } 165