1 /*- 2 * Copyright (c) 2002 Tim J. Robbins. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include "namespace.h" 28 #include <sys/cdefs.h> 29 #include <sys/types.h> 30 #include <sys/wait.h> 31 #include <errno.h> 32 #include <fcntl.h> 33 #include <paths.h> 34 #include <signal.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <string.h> 38 #include <unistd.h> 39 #include <wordexp.h> 40 #include "un-namespace.h" 41 42 __FBSDID("$FreeBSD$"); 43 44 static int we_askshell(const char *, wordexp_t *, int); 45 static int we_check(const char *, int); 46 47 /* 48 * wordexp -- 49 * Perform shell word expansion on `words' and place the resulting list 50 * of words in `we'. See wordexp(3). 51 * 52 * Specified by IEEE Std. 1003.1-2001. 53 */ 54 int 55 wordexp(const char * __restrict words, wordexp_t * __restrict we, int flags) 56 { 57 int error; 58 59 if (flags & WRDE_REUSE) 60 wordfree(we); 61 if ((flags & WRDE_APPEND) == 0) { 62 we->we_wordc = 0; 63 we->we_wordv = NULL; 64 we->we_strings = NULL; 65 we->we_nbytes = 0; 66 } 67 if ((error = we_check(words, flags)) != 0) { 68 wordfree(we); 69 return (error); 70 } 71 if ((error = we_askshell(words, we, flags)) != 0) { 72 wordfree(we); 73 return (error); 74 } 75 return (0); 76 } 77 78 static size_t 79 we_read_fully(int fd, char *buffer, size_t len) 80 { 81 size_t done; 82 ssize_t nread; 83 84 done = 0; 85 do { 86 nread = _read(fd, buffer + done, len - done); 87 if (nread == -1 && errno == EINTR) 88 continue; 89 if (nread <= 0) 90 break; 91 done += nread; 92 } while (done != len); 93 return done; 94 } 95 96 /* 97 * we_askshell -- 98 * Use the `wordexp' /bin/sh builtin function to do most of the work 99 * in expanding the word string. This function is complicated by 100 * memory management. 101 */ 102 static int 103 we_askshell(const char *words, wordexp_t *we, int flags) 104 { 105 int pdes[2]; /* Pipe to child */ 106 char buf[18]; /* Buffer for byte and word count */ 107 long nwords, nbytes; /* Number of words, bytes from child */ 108 long i; /* Handy integer */ 109 size_t sofs; /* Offset into we->we_strings */ 110 size_t vofs; /* Offset into we->we_wordv */ 111 pid_t pid; /* Process ID of child */ 112 pid_t wpid; /* waitpid return value */ 113 int status; /* Child exit status */ 114 int error; /* Our return value */ 115 int serrno; /* errno to return */ 116 char *np, *p; /* Handy pointers */ 117 char *nstrings; /* Temporary for realloc() */ 118 char **nwv; /* Temporary for realloc() */ 119 sigset_t newsigblock, oldsigblock; 120 const char *ifs; 121 char save; 122 123 serrno = errno; 124 ifs = getenv("IFS"); 125 126 if (pipe2(pdes, O_CLOEXEC) < 0) 127 return (WRDE_NOSPACE); /* XXX */ 128 (void)sigemptyset(&newsigblock); 129 (void)sigaddset(&newsigblock, SIGCHLD); 130 (void)_sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock); 131 if ((pid = fork()) < 0) { 132 serrno = errno; 133 _close(pdes[0]); 134 _close(pdes[1]); 135 (void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); 136 errno = serrno; 137 return (WRDE_NOSPACE); /* XXX */ 138 } 139 else if (pid == 0) { 140 /* 141 * We are the child; make /bin/sh expand `words'. 142 */ 143 (void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); 144 if ((pdes[1] != STDOUT_FILENO ? 145 _dup2(pdes[1], STDOUT_FILENO) : 146 _fcntl(pdes[1], F_SETFD, 0)) < 0) 147 _exit(1); 148 execl(_PATH_BSHELL, "sh", flags & WRDE_UNDEF ? "-u" : "+u", 149 "-c", "IFS=$1;eval \"$2\";eval \"echo;set -- $3\";" 150 "IFS=;a=\"$*\";printf '%08x' \"$#\" \"${#a}\";" 151 "printf '%s\\0' \"$@\"", 152 "", 153 ifs != NULL ? ifs : " \t\n", 154 flags & WRDE_SHOWERR ? "" : "exec 2>/dev/null", words, 155 (char *)NULL); 156 _exit(1); 157 } 158 159 /* 160 * We are the parent; read the output of the shell wordexp function, 161 * which is a byte indicating that the words were parsed successfully, 162 * a 32-bit hexadecimal word count, a 32-bit hexadecimal byte count 163 * (not including terminating null bytes), followed by the expanded 164 * words separated by nulls. 165 */ 166 _close(pdes[1]); 167 switch (we_read_fully(pdes[0], buf, 17)) { 168 case 1: 169 error = WRDE_BADVAL; 170 serrno = errno; 171 goto cleanup; 172 case 17: 173 break; 174 default: 175 error = WRDE_SYNTAX; 176 serrno = errno; 177 goto cleanup; 178 } 179 save = buf[9]; 180 buf[9] = '\0'; 181 nwords = strtol(buf + 1, NULL, 16); 182 buf[9] = save; 183 buf[17] = '\0'; 184 nbytes = strtol(buf + 9, NULL, 16) + nwords; 185 186 /* 187 * Allocate or reallocate (when flags & WRDE_APPEND) the word vector 188 * and string storage buffers for the expanded words we're about to 189 * read from the child. 190 */ 191 sofs = we->we_nbytes; 192 vofs = we->we_wordc; 193 if ((flags & (WRDE_DOOFFS|WRDE_APPEND)) == (WRDE_DOOFFS|WRDE_APPEND)) 194 vofs += we->we_offs; 195 we->we_wordc += nwords; 196 we->we_nbytes += nbytes; 197 if ((nwv = realloc(we->we_wordv, (we->we_wordc + 1 + 198 (flags & WRDE_DOOFFS ? we->we_offs : 0)) * 199 sizeof(char *))) == NULL) { 200 error = WRDE_NOSPACE; 201 goto cleanup; 202 } 203 we->we_wordv = nwv; 204 if ((nstrings = realloc(we->we_strings, we->we_nbytes)) == NULL) { 205 error = WRDE_NOSPACE; 206 goto cleanup; 207 } 208 for (i = 0; i < vofs; i++) 209 if (we->we_wordv[i] != NULL) 210 we->we_wordv[i] += nstrings - we->we_strings; 211 we->we_strings = nstrings; 212 213 if (we_read_fully(pdes[0], we->we_strings + sofs, nbytes) != nbytes) { 214 error = WRDE_NOSPACE; /* abort for unknown reason */ 215 serrno = errno; 216 goto cleanup; 217 } 218 219 error = 0; 220 cleanup: 221 _close(pdes[0]); 222 do 223 wpid = _waitpid(pid, &status, 0); 224 while (wpid < 0 && errno == EINTR); 225 (void)_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); 226 if (error != 0) { 227 errno = serrno; 228 return (error); 229 } 230 if (wpid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) 231 return (WRDE_NOSPACE); /* abort for unknown reason */ 232 233 /* 234 * Break the null-terminated expanded word strings out into 235 * the vector. 236 */ 237 if (vofs == 0 && flags & WRDE_DOOFFS) 238 while (vofs < we->we_offs) 239 we->we_wordv[vofs++] = NULL; 240 p = we->we_strings + sofs; 241 while (nwords-- != 0) { 242 we->we_wordv[vofs++] = p; 243 if ((np = memchr(p, '\0', nbytes)) == NULL) 244 return (WRDE_NOSPACE); /* XXX */ 245 nbytes -= np - p + 1; 246 p = np + 1; 247 } 248 we->we_wordv[vofs] = NULL; 249 250 return (0); 251 } 252 253 /* 254 * we_check -- 255 * Check that the string contains none of the following unquoted 256 * special characters: <newline> |&;<>(){} 257 * or command substitutions when WRDE_NOCMD is set in flags. 258 */ 259 static int 260 we_check(const char *words, int flags) 261 { 262 char c; 263 int dquote, level, quote, squote; 264 265 quote = squote = dquote = 0; 266 while ((c = *words++) != '\0') { 267 switch (c) { 268 case '\\': 269 if (squote == 0) 270 quote ^= 1; 271 continue; 272 case '\'': 273 if (quote + dquote == 0) 274 squote ^= 1; 275 break; 276 case '"': 277 if (quote + squote == 0) 278 dquote ^= 1; 279 break; 280 case '`': 281 if (quote + squote == 0 && flags & WRDE_NOCMD) 282 return (WRDE_CMDSUB); 283 while ((c = *words++) != '\0' && c != '`') 284 if (c == '\\' && (c = *words++) == '\0') 285 break; 286 if (c == '\0') 287 return (WRDE_SYNTAX); 288 break; 289 case '|': case '&': case ';': case '<': case '>': 290 case '{': case '}': case '(': case ')': case '\n': 291 if (quote + squote + dquote == 0) 292 return (WRDE_BADCHAR); 293 break; 294 case '$': 295 if ((c = *words++) == '\0') 296 break; 297 else if (quote + squote == 0 && c == '(') { 298 if (flags & WRDE_NOCMD && *words != '(') 299 return (WRDE_CMDSUB); 300 level = 1; 301 while ((c = *words++) != '\0') { 302 if (c == '\\') { 303 if ((c = *words++) == '\0') 304 break; 305 } else if (c == '(') 306 level++; 307 else if (c == ')' && --level == 0) 308 break; 309 } 310 if (c == '\0' || level != 0) 311 return (WRDE_SYNTAX); 312 } else if (quote + squote == 0 && c == '{') { 313 level = 1; 314 while ((c = *words++) != '\0') { 315 if (c == '\\') { 316 if ((c = *words++) == '\0') 317 break; 318 } else if (c == '{') 319 level++; 320 else if (c == '}' && --level == 0) 321 break; 322 } 323 if (c == '\0' || level != 0) 324 return (WRDE_SYNTAX); 325 } else 326 --words; 327 break; 328 default: 329 break; 330 } 331 quote = 0; 332 } 333 if (quote + squote + dquote != 0) 334 return (WRDE_SYNTAX); 335 336 return (0); 337 } 338 339 /* 340 * wordfree -- 341 * Free the result of wordexp(). See wordexp(3). 342 * 343 * Specified by IEEE Std. 1003.1-2001. 344 */ 345 void 346 wordfree(wordexp_t *we) 347 { 348 349 if (we == NULL) 350 return; 351 free(we->we_wordv); 352 free(we->we_strings); 353 we->we_wordv = NULL; 354 we->we_strings = NULL; 355 we->we_nbytes = 0; 356 we->we_wordc = 0; 357 } 358