2
0

proc.c 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898
  1. /* Licensed to the Apache Software Foundation (ASF) under one or more
  2. * contributor license agreements. See the NOTICE file distributed with
  3. * this work for additional information regarding copyright ownership.
  4. * The ASF licenses this file to You under the Apache License, Version 2.0
  5. * (the "License"); you may not use this file except in compliance with
  6. * the License. You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #include "win32/fspr_arch_threadproc.h"
  17. #include "win32/fspr_arch_file_io.h"
  18. #include "fspr_thread_proc.h"
  19. #include "fspr_file_io.h"
  20. #include "fspr_general.h"
  21. #include "fspr_strings.h"
  22. #include "fspr_portable.h"
  23. #include "fspr_lib.h"
  24. #include <stdlib.h>
  25. #if APR_HAVE_SIGNAL_H
  26. #include <signal.h>
  27. #endif
  28. #include <string.h>
  29. #if APR_HAVE_PROCESS_H
  30. #include <process.h>
  31. #endif
  32. #ifdef _WIN32_WCE
  33. #ifndef DETACHED_PROCESS
  34. #define DETACHED_PROCESS 0
  35. #endif
  36. #ifndef CREATE_UNICODE_ENVIRONMENT
  37. #define CREATE_UNICODE_ENVIRONMENT 0
  38. #endif
  39. #ifndef STARTF_USESHOWWINDOW
  40. #define STARTF_USESHOWWINDOW 0
  41. #endif
  42. #ifndef SW_HIDE
  43. #define SW_HIDE 0
  44. #endif
  45. #endif
  46. /*
  47. * some of the ideas expressed herein are based off of Microsoft
  48. * Knowledge Base article: Q190351
  49. *
  50. */
  51. APR_DECLARE(fspr_status_t) fspr_procattr_create(fspr_procattr_t **new,
  52. fspr_pool_t *pool)
  53. {
  54. (*new) = (fspr_procattr_t *)fspr_pcalloc(pool, sizeof(fspr_procattr_t));
  55. (*new)->pool = pool;
  56. (*new)->cmdtype = APR_PROGRAM;
  57. return APR_SUCCESS;
  58. }
  59. APR_DECLARE(fspr_status_t) fspr_procattr_io_set(fspr_procattr_t *attr,
  60. fspr_int32_t in,
  61. fspr_int32_t out,
  62. fspr_int32_t err)
  63. {
  64. fspr_status_t stat = APR_SUCCESS;
  65. if (in) {
  66. /* APR_CHILD_BLOCK maps to APR_WRITE_BLOCK, while
  67. * APR_PARENT_BLOCK maps to APR_READ_BLOCK, so we
  68. * must transpose the CHILD/PARENT blocking flags
  69. * only for the stdin pipe. stdout/stderr naturally
  70. * map to the correct mode.
  71. */
  72. if (in == APR_CHILD_BLOCK)
  73. in = APR_READ_BLOCK;
  74. else if (in == APR_PARENT_BLOCK)
  75. in = APR_WRITE_BLOCK;
  76. stat = fspr_create_nt_pipe(&attr->child_in, &attr->parent_in, in,
  77. attr->pool);
  78. if (stat == APR_SUCCESS)
  79. stat = fspr_file_inherit_unset(attr->parent_in);
  80. }
  81. if (out && stat == APR_SUCCESS) {
  82. stat = fspr_create_nt_pipe(&attr->parent_out, &attr->child_out, out,
  83. attr->pool);
  84. if (stat == APR_SUCCESS)
  85. stat = fspr_file_inherit_unset(attr->parent_out);
  86. }
  87. if (err && stat == APR_SUCCESS) {
  88. stat = fspr_create_nt_pipe(&attr->parent_err, &attr->child_err, err,
  89. attr->pool);
  90. if (stat == APR_SUCCESS)
  91. stat = fspr_file_inherit_unset(attr->parent_err);
  92. }
  93. return stat;
  94. }
  95. APR_DECLARE(fspr_status_t) fspr_procattr_child_in_set(fspr_procattr_t *attr,
  96. fspr_file_t *child_in,
  97. fspr_file_t *parent_in)
  98. {
  99. fspr_status_t rv = APR_SUCCESS;
  100. if (child_in) {
  101. if (attr->child_in == NULL)
  102. rv = fspr_file_dup(&attr->child_in, child_in, attr->pool);
  103. else
  104. rv = fspr_file_dup2(attr->child_in, child_in, attr->pool);
  105. if (rv == APR_SUCCESS)
  106. rv = fspr_file_inherit_set(attr->child_in);
  107. }
  108. if (parent_in && rv == APR_SUCCESS) {
  109. if (attr->parent_in == NULL)
  110. rv = fspr_file_dup(&attr->parent_in, parent_in, attr->pool);
  111. else
  112. rv = fspr_file_dup2(attr->parent_in, parent_in, attr->pool);
  113. }
  114. return rv;
  115. }
  116. APR_DECLARE(fspr_status_t) fspr_procattr_child_out_set(fspr_procattr_t *attr,
  117. fspr_file_t *child_out,
  118. fspr_file_t *parent_out)
  119. {
  120. fspr_status_t rv = APR_SUCCESS;
  121. if (child_out) {
  122. if (attr->child_out == NULL)
  123. rv = fspr_file_dup(&attr->child_out, child_out, attr->pool);
  124. else
  125. rv = fspr_file_dup2(attr->child_out, child_out, attr->pool);
  126. if (rv == APR_SUCCESS)
  127. rv = fspr_file_inherit_set(attr->child_out);
  128. }
  129. if (parent_out && rv == APR_SUCCESS) {
  130. if (attr->parent_out == NULL)
  131. rv = fspr_file_dup(&attr->parent_out, parent_out, attr->pool);
  132. else
  133. rv = fspr_file_dup2(attr->parent_out, parent_out, attr->pool);
  134. }
  135. return rv;
  136. }
  137. APR_DECLARE(fspr_status_t) fspr_procattr_child_err_set(fspr_procattr_t *attr,
  138. fspr_file_t *child_err,
  139. fspr_file_t *parent_err)
  140. {
  141. fspr_status_t rv = APR_SUCCESS;
  142. if (child_err) {
  143. if (attr->child_err == NULL)
  144. rv = fspr_file_dup(&attr->child_err, child_err, attr->pool);
  145. else
  146. rv = fspr_file_dup2(attr->child_err, child_err, attr->pool);
  147. if (rv == APR_SUCCESS)
  148. rv = fspr_file_inherit_set(attr->child_err);
  149. }
  150. if (parent_err && rv == APR_SUCCESS) {
  151. if (attr->parent_err == NULL)
  152. rv = fspr_file_dup(&attr->parent_err, parent_err, attr->pool);
  153. else
  154. rv = fspr_file_dup2(attr->parent_err, parent_err, attr->pool);
  155. }
  156. return rv;
  157. }
  158. APR_DECLARE(fspr_status_t) fspr_procattr_dir_set(fspr_procattr_t *attr,
  159. const char *dir)
  160. {
  161. /* curr dir must be in native format, there are all sorts of bugs in
  162. * the NT library loading code that flunk the '/' parsing test.
  163. */
  164. return fspr_filepath_merge(&attr->currdir, NULL, dir,
  165. APR_FILEPATH_NATIVE, attr->pool);
  166. }
  167. APR_DECLARE(fspr_status_t) fspr_procattr_cmdtype_set(fspr_procattr_t *attr,
  168. fspr_cmdtype_e cmd)
  169. {
  170. attr->cmdtype = cmd;
  171. return APR_SUCCESS;
  172. }
  173. APR_DECLARE(fspr_status_t) fspr_procattr_detach_set(fspr_procattr_t *attr,
  174. fspr_int32_t det)
  175. {
  176. attr->detached = det;
  177. return APR_SUCCESS;
  178. }
  179. static fspr_status_t attr_cleanup(void *theattr)
  180. {
  181. fspr_procattr_t *attr = (fspr_procattr_t *)theattr;
  182. if (attr->user_token)
  183. CloseHandle(attr->user_token);
  184. attr->user_token = NULL;
  185. return APR_SUCCESS;
  186. }
  187. APR_DECLARE(fspr_status_t) fspr_procattr_user_set(fspr_procattr_t *attr,
  188. const char *username,
  189. const char *password)
  190. {
  191. #ifdef _WIN32_WCE
  192. return APR_ENOTIMPL;
  193. #else
  194. HANDLE user;
  195. fspr_wchar_t *wusername = NULL;
  196. fspr_wchar_t *wpassword = NULL;
  197. fspr_status_t rv;
  198. fspr_size_t len, wlen;
  199. if (fspr_os_level >= APR_WIN_NT_4)
  200. {
  201. if (attr->user_token) {
  202. /* Cannot set that twice */
  203. if (attr->errfn) {
  204. attr->errfn(attr->pool, 0,
  205. fspr_pstrcat(attr->pool,
  206. "function called twice"
  207. " on username: ", username, NULL));
  208. }
  209. return APR_EINVAL;
  210. }
  211. len = strlen(username) + 1;
  212. wlen = len;
  213. wusername = fspr_palloc(attr->pool, wlen * sizeof(fspr_wchar_t));
  214. if ((rv = fspr_conv_utf8_to_ucs2(username, &len, wusername, &wlen))
  215. != APR_SUCCESS) {
  216. if (attr->errfn) {
  217. attr->errfn(attr->pool, rv,
  218. fspr_pstrcat(attr->pool,
  219. "utf8 to ucs2 conversion failed"
  220. " on username: ", username, NULL));
  221. }
  222. return rv;
  223. }
  224. if (password) {
  225. len = strlen(password) + 1;
  226. wlen = len;
  227. wpassword = fspr_palloc(attr->pool, wlen * sizeof(fspr_wchar_t));
  228. if ((rv = fspr_conv_utf8_to_ucs2(password, &len, wpassword, &wlen))
  229. != APR_SUCCESS) {
  230. if (attr->errfn) {
  231. attr->errfn(attr->pool, rv,
  232. fspr_pstrcat(attr->pool,
  233. "utf8 to ucs2 conversion failed"
  234. " on password: ", password, NULL));
  235. }
  236. return rv;
  237. }
  238. }
  239. if (!LogonUserW(wusername,
  240. NULL,
  241. wpassword ? wpassword : L"",
  242. LOGON32_LOGON_NETWORK,
  243. LOGON32_PROVIDER_DEFAULT,
  244. &user)) {
  245. /* Logon Failed */
  246. return fspr_get_os_error();
  247. }
  248. if (wpassword)
  249. memset(wpassword, 0, wlen * sizeof(fspr_wchar_t));
  250. /* Get the primary token for user */
  251. if (!DuplicateTokenEx(user,
  252. TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY,
  253. NULL,
  254. SecurityImpersonation,
  255. TokenPrimary,
  256. &(attr->user_token))) {
  257. /* Failed to duplicate the user token */
  258. rv = fspr_get_os_error();
  259. CloseHandle(user);
  260. return rv;
  261. }
  262. CloseHandle(user);
  263. attr->sd = fspr_pcalloc(attr->pool, SECURITY_DESCRIPTOR_MIN_LENGTH);
  264. InitializeSecurityDescriptor(attr->sd, SECURITY_DESCRIPTOR_REVISION);
  265. SetSecurityDescriptorDacl(attr->sd, -1, 0, 0);
  266. attr->sa = fspr_palloc(attr->pool, sizeof(SECURITY_ATTRIBUTES));
  267. attr->sa->nLength = sizeof (SECURITY_ATTRIBUTES);
  268. attr->sa->lpSecurityDescriptor = attr->sd;
  269. attr->sa->bInheritHandle = TRUE;
  270. /* register the cleanup */
  271. fspr_pool_cleanup_register(attr->pool, (void *)attr,
  272. attr_cleanup,
  273. fspr_pool_cleanup_null);
  274. return APR_SUCCESS;
  275. }
  276. else
  277. return APR_ENOTIMPL;
  278. #endif
  279. }
  280. APR_DECLARE(fspr_status_t) fspr_procattr_group_set(fspr_procattr_t *attr,
  281. const char *groupname)
  282. {
  283. /* Always return SUCCESS cause groups are irrelevant */
  284. return APR_SUCCESS;
  285. }
  286. static const char* has_space(const char *str)
  287. {
  288. const char *ch;
  289. for (ch = str; *ch; ++ch) {
  290. if (fspr_isspace(*ch)) {
  291. return ch;
  292. }
  293. }
  294. return NULL;
  295. }
  296. static char *fspr_caret_escape_args(fspr_pool_t *p, const char *str)
  297. {
  298. char *cmd;
  299. unsigned char *d;
  300. const unsigned char *s;
  301. cmd = fspr_palloc(p, 2 * strlen(str) + 1); /* Be safe */
  302. d = (unsigned char *)cmd;
  303. s = (const unsigned char *)str;
  304. for (; *s; ++s) {
  305. /*
  306. * Newlines to Win32/OS2 CreateProcess() are ill advised.
  307. * Convert them to spaces since they are effectively white
  308. * space to most applications
  309. */
  310. if (*s == '\r' || *s == '\n') {
  311. *d++ = ' ';
  312. continue;
  313. }
  314. if (IS_SHCHAR(*s)) {
  315. *d++ = '^';
  316. }
  317. *d++ = *s;
  318. }
  319. *d = '\0';
  320. return cmd;
  321. }
  322. APR_DECLARE(fspr_status_t) fspr_procattr_child_errfn_set(fspr_procattr_t *attr,
  323. fspr_child_errfn_t *errfn)
  324. {
  325. attr->errfn = errfn;
  326. return APR_SUCCESS;
  327. }
  328. APR_DECLARE(fspr_status_t) fspr_procattr_error_check_set(fspr_procattr_t *attr,
  329. fspr_int32_t chk)
  330. {
  331. attr->errchk = chk;
  332. return APR_SUCCESS;
  333. }
  334. APR_DECLARE(fspr_status_t) fspr_procattr_addrspace_set(fspr_procattr_t *attr,
  335. fspr_int32_t addrspace)
  336. {
  337. /* won't ever be used on this platform, so don't save the flag */
  338. return APR_SUCCESS;
  339. }
  340. APR_DECLARE(fspr_status_t) fspr_proc_create(fspr_proc_t *new,
  341. const char *progname,
  342. const char * const *args,
  343. const char * const *env,
  344. fspr_procattr_t *attr,
  345. fspr_pool_t *pool)
  346. {
  347. fspr_status_t rv;
  348. fspr_size_t i;
  349. const char *argv0;
  350. char *cmdline;
  351. char *pEnvBlock;
  352. PROCESS_INFORMATION pi;
  353. DWORD dwCreationFlags = 0;
  354. new->in = attr->parent_in;
  355. new->out = attr->parent_out;
  356. new->err = attr->parent_err;
  357. if (attr->detached) {
  358. /* If we are creating ourselves detached, Then we should hide the
  359. * window we are starting in. And we had better redfine our
  360. * handles for STDIN, STDOUT, and STDERR. Do not set the
  361. * detached attribute for Win9x. We have found that Win9x does
  362. * not manage the stdio handles properly when running old 16
  363. * bit executables if the detached attribute is set.
  364. */
  365. if (fspr_os_level >= APR_WIN_NT) {
  366. /*
  367. * XXX DETACHED_PROCESS won't on Win9x at all; on NT/W2K
  368. * 16 bit executables fail (MS KB: Q150956)
  369. */
  370. dwCreationFlags |= DETACHED_PROCESS;
  371. }
  372. }
  373. /* progname must be unquoted, in native format, as there are all sorts
  374. * of bugs in the NT library loader code that fault when parsing '/'.
  375. * XXX progname must be NULL if this is a 16 bit app running in WOW
  376. */
  377. if (progname[0] == '\"') {
  378. progname = fspr_pstrndup(pool, progname + 1, strlen(progname) - 2);
  379. }
  380. if (attr->cmdtype == APR_PROGRAM || attr->cmdtype == APR_PROGRAM_ENV) {
  381. char *fullpath = NULL;
  382. if ((rv = fspr_filepath_merge(&fullpath, attr->currdir, progname,
  383. APR_FILEPATH_NATIVE, pool)) != APR_SUCCESS) {
  384. if (attr->errfn) {
  385. attr->errfn(pool, rv,
  386. fspr_pstrcat(pool, "filepath_merge failed.",
  387. " currdir: ", attr->currdir,
  388. " progname: ", progname, NULL));
  389. }
  390. return rv;
  391. }
  392. progname = fullpath;
  393. }
  394. else {
  395. /* Do not fail if the path isn't parseable for APR_PROGRAM_PATH
  396. * or APR_SHELLCMD. We only invoke fspr_filepath_merge (with no
  397. * left hand side expression) in order to correct the path slash
  398. * delimiters. But the filename doesn't need to be in the CWD,
  399. * nor does it need to be a filename at all (it could be a
  400. * built-in shell command.)
  401. */
  402. char *fullpath = NULL;
  403. if ((rv = fspr_filepath_merge(&fullpath, "", progname,
  404. APR_FILEPATH_NATIVE, pool)) == APR_SUCCESS) {
  405. progname = fullpath;
  406. }
  407. }
  408. if (has_space(progname)) {
  409. argv0 = fspr_pstrcat(pool, "\"", progname, "\"", NULL);
  410. }
  411. else {
  412. argv0 = progname;
  413. }
  414. /* Handle the args, seperate from argv0 */
  415. cmdline = "";
  416. for (i = 1; args && args[i]; ++i) {
  417. if (has_space(args[i]) || !args[i][0]) {
  418. cmdline = fspr_pstrcat(pool, cmdline, " \"", args[i], "\"", NULL);
  419. }
  420. else {
  421. cmdline = fspr_pstrcat(pool, cmdline, " ", args[i], NULL);
  422. }
  423. }
  424. #ifndef _WIN32_WCE
  425. if (attr->cmdtype == APR_SHELLCMD || attr->cmdtype == APR_SHELLCMD_ENV) {
  426. char *shellcmd = getenv("COMSPEC");
  427. if (!shellcmd) {
  428. if (attr->errfn) {
  429. attr->errfn(pool, APR_EINVAL, "COMSPEC envar is not set");
  430. }
  431. return APR_EINVAL;
  432. }
  433. if (shellcmd[0] == '"') {
  434. progname = fspr_pstrndup(pool, shellcmd + 1, strlen(shellcmd) - 2);
  435. }
  436. else {
  437. progname = shellcmd;
  438. if (has_space(shellcmd)) {
  439. shellcmd = fspr_pstrcat(pool, "\"", shellcmd, "\"", NULL);
  440. }
  441. }
  442. /* Command.com does not support a quoted command, while cmd.exe demands one.
  443. */
  444. i = strlen(progname);
  445. if (i >= 11 && strcasecmp(progname + i - 11, "command.com") == 0) {
  446. cmdline = fspr_pstrcat(pool, shellcmd, " /C ", argv0, cmdline, NULL);
  447. }
  448. else {
  449. cmdline = fspr_pstrcat(pool, shellcmd, " /C \"", argv0, cmdline, "\"", NULL);
  450. }
  451. }
  452. else
  453. #endif
  454. {
  455. /* Win32 is _different_ than unix. While unix will find the given
  456. * program since it's already chdir'ed, Win32 cannot since the parent
  457. * attempts to open the program with it's own path.
  458. * ###: This solution isn't much better - it may defeat path searching
  459. * when the path search was desired. Open to further discussion.
  460. */
  461. i = strlen(progname);
  462. if (i >= 4 && (strcasecmp(progname + i - 4, ".bat") == 0
  463. || strcasecmp(progname + i - 4, ".cmd") == 0))
  464. {
  465. char *shellcmd = getenv("COMSPEC");
  466. if (!shellcmd) {
  467. if (attr->errfn) {
  468. attr->errfn(pool, APR_EINVAL, "COMSPEC envar is not set");
  469. }
  470. return APR_EINVAL;
  471. }
  472. if (shellcmd[0] == '"') {
  473. progname = fspr_pstrndup(pool, shellcmd + 1, strlen(shellcmd) - 2);
  474. }
  475. else {
  476. progname = shellcmd;
  477. if (has_space(shellcmd)) {
  478. shellcmd = fspr_pstrcat(pool, "\"", shellcmd, "\"", NULL);
  479. }
  480. }
  481. i = strlen(progname);
  482. if (i >= 11 && strcasecmp(progname + i - 11, "command.com") == 0) {
  483. /* XXX: Still insecure - need doubled-quotes on each individual
  484. * arg of cmdline. Suspect we need to postpone cmdline parsing
  485. * until this moment in all four code paths, with some flags
  486. * to toggle 'which flavor' is needed.
  487. */
  488. cmdline = fspr_pstrcat(pool, shellcmd, " /C ", argv0, cmdline, NULL);
  489. }
  490. else {
  491. /* We must protect the cmdline args from any interpolation - this
  492. * is not a shellcmd, and the source of argv[] is untrusted.
  493. * Notice we escape ALL the cmdline args, including the quotes
  494. * around the individual args themselves. No sense in allowing
  495. * the shift-state to be toggled, and the application will
  496. * not see the caret escapes.
  497. */
  498. cmdline = fspr_caret_escape_args(pool, cmdline);
  499. /*
  500. * Our app name must always be quoted so the quotes surrounding
  501. * the entire /c "command args" are unambigious.
  502. */
  503. if (*argv0 != '"') {
  504. cmdline = fspr_pstrcat(pool, shellcmd, " /C \"\"", argv0, "\"", cmdline, "\"", NULL);
  505. }
  506. else {
  507. cmdline = fspr_pstrcat(pool, shellcmd, " /C \"", argv0, cmdline, "\"", NULL);
  508. }
  509. }
  510. }
  511. else {
  512. /* A simple command we are directly invoking. Do not pass
  513. * the first arg to CreateProc() for APR_PROGRAM_PATH
  514. * invocation, since it would need to be a literal and
  515. * complete file path. That is; "c:\bin\aprtest.exe"
  516. * would succeed, but "c:\bin\aprtest" or "aprtest.exe"
  517. * can fail.
  518. */
  519. cmdline = fspr_pstrcat(pool, argv0, cmdline, NULL);
  520. if (attr->cmdtype == APR_PROGRAM_PATH) {
  521. progname = NULL;
  522. }
  523. }
  524. }
  525. if (!env || attr->cmdtype == APR_PROGRAM_ENV ||
  526. attr->cmdtype == APR_SHELLCMD_ENV) {
  527. pEnvBlock = NULL;
  528. }
  529. else {
  530. fspr_size_t iEnvBlockLen;
  531. /*
  532. * Win32's CreateProcess call requires that the environment
  533. * be passed in an environment block, a null terminated block of
  534. * null terminated strings.
  535. */
  536. i = 0;
  537. iEnvBlockLen = 1;
  538. while (env[i]) {
  539. iEnvBlockLen += strlen(env[i]) + 1;
  540. i++;
  541. }
  542. if (!i)
  543. ++iEnvBlockLen;
  544. #if APR_HAS_UNICODE_FS
  545. IF_WIN_OS_IS_UNICODE
  546. {
  547. fspr_wchar_t *pNext;
  548. pEnvBlock = (char *)fspr_palloc(pool, iEnvBlockLen * 2);
  549. dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
  550. i = 0;
  551. pNext = (fspr_wchar_t*)pEnvBlock;
  552. while (env[i]) {
  553. fspr_size_t in = strlen(env[i]) + 1;
  554. if ((rv = fspr_conv_utf8_to_ucs2(env[i], &in,
  555. pNext, &iEnvBlockLen))
  556. != APR_SUCCESS) {
  557. if (attr->errfn) {
  558. attr->errfn(pool, rv,
  559. fspr_pstrcat(pool,
  560. "utf8 to ucs2 conversion failed"
  561. " on this string: ", env[i], NULL));
  562. }
  563. return rv;
  564. }
  565. pNext = wcschr(pNext, L'\0') + 1;
  566. i++;
  567. }
  568. if (!i)
  569. *(pNext++) = L'\0';
  570. *pNext = L'\0';
  571. }
  572. #endif /* APR_HAS_UNICODE_FS */
  573. #if APR_HAS_ANSI_FS
  574. ELSE_WIN_OS_IS_ANSI
  575. {
  576. char *pNext;
  577. pEnvBlock = (char *)fspr_palloc(pool, iEnvBlockLen);
  578. i = 0;
  579. pNext = pEnvBlock;
  580. while (env[i]) {
  581. strcpy(pNext, env[i]);
  582. pNext = strchr(pNext, '\0') + 1;
  583. i++;
  584. }
  585. if (!i)
  586. *(pNext++) = '\0';
  587. *pNext = '\0';
  588. }
  589. #endif /* APR_HAS_ANSI_FS */
  590. }
  591. new->invoked = cmdline;
  592. #if APR_HAS_UNICODE_FS
  593. IF_WIN_OS_IS_UNICODE
  594. {
  595. STARTUPINFOW si;
  596. fspr_wchar_t *wprg = NULL;
  597. fspr_wchar_t *wcmd = NULL;
  598. fspr_wchar_t *wcwd = NULL;
  599. if (progname) {
  600. fspr_size_t nprg = strlen(progname) + 1;
  601. fspr_size_t nwprg = nprg + 6;
  602. wprg = fspr_palloc(pool, nwprg * sizeof(wprg[0]));
  603. if ((rv = fspr_conv_utf8_to_ucs2(progname, &nprg, wprg, &nwprg))
  604. != APR_SUCCESS) {
  605. if (attr->errfn) {
  606. attr->errfn(pool, rv,
  607. fspr_pstrcat(pool,
  608. "utf8 to ucs2 conversion failed"
  609. " on progname: ", progname, NULL));
  610. }
  611. return rv;
  612. }
  613. }
  614. if (cmdline) {
  615. fspr_size_t ncmd = strlen(cmdline) + 1;
  616. fspr_size_t nwcmd = ncmd;
  617. wcmd = fspr_palloc(pool, nwcmd * sizeof(wcmd[0]));
  618. if ((rv = fspr_conv_utf8_to_ucs2(cmdline, &ncmd, wcmd, &nwcmd))
  619. != APR_SUCCESS) {
  620. if (attr->errfn) {
  621. attr->errfn(pool, rv,
  622. fspr_pstrcat(pool,
  623. "utf8 to ucs2 conversion failed"
  624. " on cmdline: ", cmdline, NULL));
  625. }
  626. return rv;
  627. }
  628. }
  629. if (attr->currdir)
  630. {
  631. fspr_size_t ncwd = strlen(attr->currdir) + 1;
  632. fspr_size_t nwcwd = ncwd;
  633. wcwd = fspr_palloc(pool, ncwd * sizeof(wcwd[0]));
  634. if ((rv = fspr_conv_utf8_to_ucs2(attr->currdir, &ncwd,
  635. wcwd, &nwcwd))
  636. != APR_SUCCESS) {
  637. if (attr->errfn) {
  638. attr->errfn(pool, rv,
  639. fspr_pstrcat(pool,
  640. "utf8 to ucs2 conversion failed"
  641. " on currdir: ", attr->currdir, NULL));
  642. }
  643. return rv;
  644. }
  645. }
  646. memset(&si, 0, sizeof(si));
  647. si.cb = sizeof(si);
  648. if (attr->detached) {
  649. si.dwFlags |= STARTF_USESHOWWINDOW;
  650. si.wShowWindow = SW_HIDE;
  651. }
  652. #ifndef _WIN32_WCE
  653. if ((attr->child_in && attr->child_in->filehand)
  654. || (attr->child_out && attr->child_out->filehand)
  655. || (attr->child_err && attr->child_err->filehand))
  656. {
  657. si.dwFlags |= STARTF_USESTDHANDLES;
  658. si.hStdInput = (attr->child_in)
  659. ? attr->child_in->filehand
  660. : INVALID_HANDLE_VALUE;
  661. si.hStdOutput = (attr->child_out)
  662. ? attr->child_out->filehand
  663. : INVALID_HANDLE_VALUE;
  664. si.hStdError = (attr->child_err)
  665. ? attr->child_err->filehand
  666. : INVALID_HANDLE_VALUE;
  667. }
  668. if (attr->user_token) {
  669. si.lpDesktop = L"Winsta0\\Default";
  670. if (!ImpersonateLoggedOnUser(attr->user_token)) {
  671. /* failed to impersonate the logged user */
  672. rv = fspr_get_os_error();
  673. CloseHandle(attr->user_token);
  674. attr->user_token = NULL;
  675. return rv;
  676. }
  677. rv = CreateProcessAsUserW(attr->user_token,
  678. wprg, wcmd,
  679. attr->sa,
  680. NULL,
  681. TRUE,
  682. dwCreationFlags,
  683. pEnvBlock,
  684. wcwd,
  685. &si, &pi);
  686. RevertToSelf();
  687. }
  688. else {
  689. rv = CreateProcessW(wprg, wcmd, /* Executable & Command line */
  690. NULL, NULL, /* Proc & thread security attributes */
  691. TRUE, /* Inherit handles */
  692. dwCreationFlags, /* Creation flags */
  693. pEnvBlock, /* Environment block */
  694. wcwd, /* Current directory name */
  695. &si, &pi);
  696. }
  697. #else
  698. rv = CreateProcessW(wprg, wcmd, /* Executable & Command line */
  699. NULL, NULL, /* Proc & thread security attributes */
  700. FALSE, /* must be 0 */
  701. dwCreationFlags, /* Creation flags */
  702. NULL, /* Environment block must be NULL */
  703. NULL, /* Current directory name must be NULL*/
  704. NULL, /* STARTUPINFO not supported */
  705. &pi);
  706. #endif
  707. }
  708. #endif /* APR_HAS_UNICODE_FS */
  709. #if APR_HAS_ANSI_FS
  710. ELSE_WIN_OS_IS_ANSI
  711. {
  712. STARTUPINFOA si;
  713. memset(&si, 0, sizeof(si));
  714. si.cb = sizeof(si);
  715. if (attr->detached) {
  716. si.dwFlags |= STARTF_USESHOWWINDOW;
  717. si.wShowWindow = SW_HIDE;
  718. }
  719. if ((attr->child_in && attr->child_in->filehand)
  720. || (attr->child_out && attr->child_out->filehand)
  721. || (attr->child_err && attr->child_err->filehand))
  722. {
  723. si.dwFlags |= STARTF_USESTDHANDLES;
  724. si.hStdInput = (attr->child_in)
  725. ? attr->child_in->filehand
  726. : INVALID_HANDLE_VALUE;
  727. si.hStdOutput = (attr->child_out)
  728. ? attr->child_out->filehand
  729. : INVALID_HANDLE_VALUE;
  730. si.hStdError = (attr->child_err)
  731. ? attr->child_err->filehand
  732. : INVALID_HANDLE_VALUE;
  733. }
  734. rv = CreateProcessA(progname, cmdline, /* Command line */
  735. NULL, NULL, /* Proc & thread security attributes */
  736. TRUE, /* Inherit handles */
  737. dwCreationFlags, /* Creation flags */
  738. pEnvBlock, /* Environment block */
  739. attr->currdir, /* Current directory name */
  740. &si, &pi);
  741. }
  742. #endif /* APR_HAS_ANSI_FS */
  743. /* Check CreateProcess result
  744. */
  745. if (!rv)
  746. return fspr_get_os_error();
  747. /* XXX Orphaned handle warning - no fix due to broken fspr_proc_t api.
  748. */
  749. new->hproc = pi.hProcess;
  750. new->pid = pi.dwProcessId;
  751. if (attr->child_in) {
  752. fspr_file_close(attr->child_in);
  753. }
  754. if (attr->child_out) {
  755. fspr_file_close(attr->child_out);
  756. }
  757. if (attr->child_err) {
  758. fspr_file_close(attr->child_err);
  759. }
  760. CloseHandle(pi.hThread);
  761. return APR_SUCCESS;
  762. }
  763. APR_DECLARE(fspr_status_t) fspr_proc_wait_all_procs(fspr_proc_t *proc,
  764. int *exitcode,
  765. fspr_exit_why_e *exitwhy,
  766. fspr_wait_how_e waithow,
  767. fspr_pool_t *p)
  768. {
  769. /* Unix does fspr_proc_wait(proc(-1), exitcode, exitwhy, waithow)
  770. * but Win32's fspr_proc_wait won't work that way. We can either
  771. * register all APR created processes in some sort of AsyncWait
  772. * thread, or simply walk from the global process pool for all
  773. * fspr_pool_note_subprocess()es registered with APR.
  774. */
  775. return APR_ENOTIMPL;
  776. }
  777. static fspr_exit_why_e why_from_exit_code(DWORD exit) {
  778. /* See WinNT.h STATUS_ACCESS_VIOLATION and family for how
  779. * this class of failures was determined
  780. */
  781. if (((exit & 0xC0000000) == 0xC0000000)
  782. && !(exit & 0x3FFF0000))
  783. return APR_PROC_SIGNAL;
  784. else
  785. return APR_PROC_EXIT;
  786. /* ### No way to tell if Dr Watson grabbed a core, AFAICT. */
  787. }
  788. APR_DECLARE(fspr_status_t) fspr_proc_wait(fspr_proc_t *proc,
  789. int *exitcode, fspr_exit_why_e *exitwhy,
  790. fspr_wait_how_e waithow)
  791. {
  792. DWORD stat;
  793. DWORD time;
  794. if (waithow == APR_WAIT)
  795. time = INFINITE;
  796. else
  797. time = 0;
  798. if ((stat = WaitForSingleObject(proc->hproc, time)) == WAIT_OBJECT_0) {
  799. if (GetExitCodeProcess(proc->hproc, &stat)) {
  800. if (exitcode)
  801. *exitcode = stat;
  802. if (exitwhy)
  803. *exitwhy = why_from_exit_code(stat);
  804. CloseHandle(proc->hproc);
  805. proc->hproc = NULL;
  806. return APR_CHILD_DONE;
  807. }
  808. }
  809. else if (stat == WAIT_TIMEOUT) {
  810. return APR_CHILD_NOTDONE;
  811. }
  812. return fspr_get_os_error();
  813. }
  814. APR_DECLARE(fspr_status_t) fspr_proc_detach(int daemonize)
  815. {
  816. return APR_ENOTIMPL;
  817. }