1 /* $OpenBSD: misc.c,v 1.9 2024/07/01 18:43:50 deraadt 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 int save_errno = errno; 83 84 if (child != -1) { 85 /* Forcibly kill the child, no excuse... */ 86 kill(child, SIGKILL); 87 } 88 errno = save_errno; 89 } 90 91 int 92 lg_exec(const char *file, char **new_argv) 93 { 94 int status = 0, ret = 0; 95 sig_t save_quit, save_int, save_chld; 96 struct itimerval it; 97 98 if (new_argv == NULL) 99 return (EFAULT); 100 101 save_quit = signal(SIGQUIT, SIG_IGN); 102 save_int = signal(SIGINT, SIG_IGN); 103 save_chld = signal(SIGCHLD, SIG_DFL); 104 105 switch (child = fork()) { 106 case -1: 107 ret = errno; 108 goto done; 109 case 0: 110 signal(SIGQUIT, SIG_DFL); 111 signal(SIGINT, SIG_DFL); 112 signal(SIGCHLD, SIG_DFL); 113 114 execvp(file, new_argv); 115 _exit(127); 116 break; 117 default: 118 /* Kill the process after a timeout */ 119 signal(SIGALRM, lg_sig_alarm); 120 bzero(&it, sizeof(it)); 121 it.it_value.tv_sec = BGPLG_TIMEOUT; 122 setitimer(ITIMER_REAL, &it, NULL); 123 124 waitpid(child, &status, 0); 125 break; 126 } 127 128 switch (ret) { 129 case -1: 130 ret = ECHILD; 131 break; 132 default: 133 if (WIFEXITED(status)) 134 ret = WEXITSTATUS(status); 135 else 136 ret = ECHILD; 137 } 138 139 done: 140 /* Disable the process timeout timer */ 141 bzero(&it, sizeof(it)); 142 setitimer(ITIMER_REAL, &it, NULL); 143 child = -1; 144 145 signal(SIGQUIT, save_quit); 146 signal(SIGINT, save_int); 147 signal(SIGCHLD, save_chld); 148 signal(SIGALRM, SIG_DFL); 149 150 return (ret); 151 } 152 153 ssize_t 154 lg_strip(char *str) 155 { 156 size_t len; 157 158 if ((len = strlen(str)) < 1) 159 return (0); /* XXX EINVAL? */ 160 161 if (isspace((unsigned char)str[len - 1])) { 162 str[len - 1] = '\0'; 163 return (lg_strip(str)); 164 } 165 166 return (strlen(str)); 167 } 168