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 #include "libc_private.h" 42 43 __FBSDID("$FreeBSD$"); 44 45 static int we_askshell(const char *, wordexp_t *, int); 46 static int we_check(const char *, int); 47 48 /* 49 * wordexp -- 50 * Perform shell word expansion on `words' and place the resulting list 51 * of words in `we'. See wordexp(3). 52 * 53 * Specified by IEEE Std. 1003.1-2001. 54 */ 55 int 56 wordexp(const char * __restrict words, wordexp_t * __restrict we, int flags) 57 { 58 int error; 59 60 if (flags & WRDE_REUSE) 61 wordfree(we); 62 if ((flags & WRDE_APPEND) == 0) { 63 we->we_wordc = 0; 64 we->we_wordv = NULL; 65 we->we_strings = NULL; 66 we->we_nbytes = 0; 67 } 68 if ((error = we_check(words, flags)) != 0) { 69 wordfree(we); 70 return (error); 71 } 72 if ((error = we_askshell(words, we, flags)) != 0) { 73 wordfree(we); 74 return (error); 75 } 76 return (0); 77 } 78 79 static size_t 80 we_read_fully(int fd, char *buffer, size_t len) 81 { 82 size_t done; 83 ssize_t nread; 84 85 done = 0; 86 do { 87 nread = _read(fd, buffer + done, len - done); 88 if (nread == -1 && errno == EINTR) 89 continue; 90 if (nread <= 0) 91 break; 92 done += nread; 93 } while (done != len); 94 return done; 95 } 96 97 /* 98 * we_askshell -- 99 * Use the `wordexp' /bin/sh builtin function to do most of the work 100 * in expanding the word string. This function is complicated by 101 * memory management. 102 */ 103 static int 104 we_askshell(const char *words, wordexp_t *we, int flags) 105 { 106 int pdes[2]; /* Pipe to child */ 107 char buf[18]; /* Buffer for byte and word count */ 108 long nwords, nbytes; /* Number of words, bytes from child */ 109 long i; /* Handy integer */ 110 size_t sofs; /* Offset into we->we_strings */ 111 size_t vofs; /* Offset into we->we_wordv */ 112 pid_t pid; /* Process ID of child */ 113 pid_t wpid; /* waitpid return value */ 114 int status; /* Child exit status */ 115 int error; /* Our return value */ 116 int serrno; /* errno to return */ 117 char *np, *p; /* Handy pointers */ 118 char *nstrings; /* Temporary for realloc() */ 119 char **nwv; /* Temporary for realloc() */ 120 sigset_t newsigblock, oldsigblock; 121 const char *ifs; 122 char save; 123 124 serrno = errno; 125 ifs = getenv("IFS"); 126 127 if (pipe2(pdes, O_CLOEXEC) < 0) 128 return (WRDE_NOSPACE); /* XXX */ 129 (void)sigemptyset(&newsigblock); 130 (void)sigaddset(&newsigblock, SIGCHLD); 131 (void)__libc_sigprocmask(SIG_BLOCK, &newsigblock, &oldsigblock); 132 if ((pid = fork()) < 0) { 133 serrno = errno; 134 _close(pdes[0]); 135 _close(pdes[1]); 136 (void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); 137 errno = serrno; 138 return (WRDE_NOSPACE); /* XXX */ 139 } 140 else if (pid == 0) { 141 /* 142 * We are the child; make /bin/sh expand `words'. 143 */ 144 (void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); 145 if ((pdes[1] != STDOUT_FILENO ? 146 _dup2(pdes[1], STDOUT_FILENO) : 147 _fcntl(pdes[1], F_SETFD, 0)) < 0) 148 _exit(1); 149 execl(_PATH_BSHELL, "sh", flags & WRDE_UNDEF ? "-u" : "+u", 150 "-c", "IFS=$1;eval \"$2\";eval \"echo;set -- $3\";" 151 "IFS=;a=\"$*\";printf '%08x' \"$#\" \"${#a}\";" 152 "printf '%s\\0' \"$@\"", 153 "", 154 ifs != NULL ? ifs : " \t\n", 155 flags & WRDE_SHOWERR ? "" : "exec 2>/dev/null", words, 156 (char *)NULL); 157 _exit(1); 158 } 159 160 /* 161 * We are the parent; read the output of the shell wordexp function, 162 * which is a byte indicating that the words were parsed successfully, 163 * a 32-bit hexadecimal word count, a 32-bit hexadecimal byte count 164 * (not including terminating null bytes), followed by the expanded 165 * words separated by nulls. 166 */ 167 _close(pdes[1]); 168 switch (we_read_fully(pdes[0], buf, 17)) { 169 case 1: 170 error = WRDE_BADVAL; 171 serrno = errno; 172 goto cleanup; 173 case 17: 174 break; 175 default: 176 error = WRDE_SYNTAX; 177 serrno = errno; 178 goto cleanup; 179 } 180 save = buf[9]; 181 buf[9] = '\0'; 182 nwords = strtol(buf + 1, NULL, 16); 183 buf[9] = save; 184 buf[17] = '\0'; 185 nbytes = strtol(buf + 9, NULL, 16) + nwords; 186 187 /* 188 * Allocate or reallocate (when flags & WRDE_APPEND) the word vector 189 * and string storage buffers for the expanded words we're about to 190 * read from the child. 191 */ 192 sofs = we->we_nbytes; 193 vofs = we->we_wordc; 194 if ((flags & (WRDE_DOOFFS|WRDE_APPEND)) == (WRDE_DOOFFS|WRDE_APPEND)) 195 vofs += we->we_offs; 196 we->we_wordc += nwords; 197 we->we_nbytes += nbytes; 198 if ((nwv = realloc(we->we_wordv, (we->we_wordc + 1 + 199 (flags & WRDE_DOOFFS ? we->we_offs : 0)) * 200 sizeof(char *))) == NULL) { 201 error = WRDE_NOSPACE; 202 goto cleanup; 203 } 204 we->we_wordv = nwv; 205 if ((nstrings = realloc(we->we_strings, we->we_nbytes)) == NULL) { 206 error = WRDE_NOSPACE; 207 goto cleanup; 208 } 209 for (i = 0; i < vofs; i++) 210 if (we->we_wordv[i] != NULL) 211 we->we_wordv[i] += nstrings - we->we_strings; 212 we->we_strings = nstrings; 213 214 if (we_read_fully(pdes[0], we->we_strings + sofs, nbytes) != nbytes) { 215 error = WRDE_NOSPACE; /* abort for unknown reason */ 216 serrno = errno; 217 goto cleanup; 218 } 219 220 error = 0; 221 cleanup: 222 _close(pdes[0]); 223 do 224 wpid = _waitpid(pid, &status, 0); 225 while (wpid < 0 && errno == EINTR); 226 (void)__libc_sigprocmask(SIG_SETMASK, &oldsigblock, NULL); 227 if (error != 0) { 228 errno = serrno; 229 return (error); 230 } 231 if (wpid < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0) 232 return (WRDE_NOSPACE); /* abort for unknown reason */ 233 234 /* 235 * Break the null-terminated expanded word strings out into 236 * the vector. 237 */ 238 if (vofs == 0 && flags & WRDE_DOOFFS) 239 while (vofs < we->we_offs) 240 we->we_wordv[vofs++] = NULL; 241 p = we->we_strings + sofs; 242 while (nwords-- != 0) { 243 we->we_wordv[vofs++] = p; 244 if ((np = memchr(p, '\0', nbytes)) == NULL) 245 return (WRDE_NOSPACE); /* XXX */ 246 nbytes -= np - p + 1; 247 p = np + 1; 248 } 249 we->we_wordv[vofs] = NULL; 250 251 return (0); 252 } 253 254 /* 255 * we_check -- 256 * Check that the string contains none of the following unquoted 257 * special characters: <newline> |&;<>(){} 258 * or command substitutions when WRDE_NOCMD is set in flags. 259 */ 260 static int 261 we_check(const char *words, int flags) 262 { 263 char c; 264 int dquote, level, quote, squote; 265 266 quote = squote = dquote = 0; 267 while ((c = *words++) != '\0') { 268 switch (c) { 269 case '\\': 270 if (squote == 0) 271 quote ^= 1; 272 continue; 273 case '\'': 274 if (quote + dquote == 0) 275 squote ^= 1; 276 break; 277 case '"': 278 if (quote + squote == 0) 279 dquote ^= 1; 280 break; 281 case '`': 282 if (quote + squote == 0 && flags & WRDE_NOCMD) 283 return (WRDE_CMDSUB); 284 while ((c = *words++) != '\0' && c != '`') 285 if (c == '\\' && (c = *words++) == '\0') 286 break; 287 if (c == '\0') 288 return (WRDE_SYNTAX); 289 break; 290 case '|': case '&': case ';': case '<': case '>': 291 case '{': case '}': case '(': case ')': case '\n': 292 if (quote + squote + dquote == 0) 293 return (WRDE_BADCHAR); 294 break; 295 case '$': 296 if ((c = *words++) == '\0') 297 break; 298 else if (quote + squote == 0 && c == '(') { 299 if (flags & WRDE_NOCMD && *words != '(') 300 return (WRDE_CMDSUB); 301 level = 1; 302 while ((c = *words++) != '\0') { 303 if (c == '\\') { 304 if ((c = *words++) == '\0') 305 break; 306 } else if (c == '(') 307 level++; 308 else if (c == ')' && --level == 0) 309 break; 310 } 311 if (c == '\0' || level != 0) 312 return (WRDE_SYNTAX); 313 } else if (quote + squote == 0 && c == '{') { 314 level = 1; 315 while ((c = *words++) != '\0') { 316 if (c == '\\') { 317 if ((c = *words++) == '\0') 318 break; 319 } else if (c == '{') 320 level++; 321 else if (c == '}' && --level == 0) 322 break; 323 } 324 if (c == '\0' || level != 0) 325 return (WRDE_SYNTAX); 326 } else 327 --words; 328 break; 329 default: 330 break; 331 } 332 quote = 0; 333 } 334 if (quote + squote + dquote != 0) 335 return (WRDE_SYNTAX); 336 337 return (0); 338 } 339 340 /* 341 * wordfree -- 342 * Free the result of wordexp(). See wordexp(3). 343 * 344 * Specified by IEEE Std. 1003.1-2001. 345 */ 346 void 347 wordfree(wordexp_t *we) 348 { 349 350 if (we == NULL) 351 return; 352 free(we->we_wordv); 353 free(we->we_strings); 354 we->we_wordv = NULL; 355 we->we_strings = NULL; 356 we->we_nbytes = 0; 357 we->we_wordc = 0; 358 } 359