@@ -136,6 +136,44 @@ static const char *set_interpreter_source(cmd_parms *cmd, void *dv,
136136 return NULL ;
137137}
138138
139+ /* XXX: prep_string should translate the string into unicode,
140+ * such that it is compatible with whatever codepage the client
141+ * will read characters 80-ff. For the moment, use the unicode
142+ * values 0080-00ff. This isn't trivial, since the code page
143+ * varies between msdos and Windows applications.
144+ */
145+ static void prep_string (const char * * str , apr_pool_t * p )
146+ {
147+ const char * ch = * str ;
148+ char * ch2 ;
149+ int widen = 0 ;
150+ if (!ch ) {
151+ return ;
152+ }
153+ while (* ch ) {
154+ if (* (ch ++ ) & 0x80 ) {
155+ ++ widen ;
156+ }
157+ }
158+ if (!widen ) {
159+ return ;
160+ }
161+ widen += (ch - * str ) + 1 ;
162+ ch = * str ;
163+ * str = ch2 = apr_palloc (p , widen );
164+ while (* ch ) {
165+ if (* ch & 0x80 ) {
166+ /* sign extension won't hurt us here */
167+ * (ch2 ++ ) = 0xC0 | ((* ch >> 6 ) & 0x03 );
168+ * (ch2 ++ ) = 0x80 | (* (ch ++ ) & 0x3f );
169+ }
170+ else {
171+ * (ch2 ++ ) = * (ch ++ );
172+ }
173+ }
174+ * (ch2 ++ ) = '\0' ;
175+ }
176+
139177/* Pretty unexciting ... yank a registry value, and explode any envvars
140178 * that the system has configured (e.g. %SystemRoot%/someapp.exe)
141179 *
@@ -294,7 +332,7 @@ static apr_array_header_t *split_argv(apr_pool_t *p, const char *interp,
294332
295333 while (* ch ) {
296334 /* Skip on through Deep Space */
297- if (isspace (* ch )) {
335+ if (apr_isspace (* ch )) {
298336 ++ ch ; continue ;
299337 }
300338 /* One Arg */
@@ -307,6 +345,7 @@ static apr_array_header_t *split_argv(apr_pool_t *p, const char *interp,
307345 break ;
308346 }
309347 ap_unescape_url (w );
348+ prep_string (& w , p );
310349 arg = (const char * * )apr_array_push (args );
311350 * arg = ap_escape_shell_cmd (p , w );
312351 }
@@ -352,7 +391,7 @@ static apr_array_header_t *split_argv(apr_pool_t *p, const char *interp,
352391 * arg = d ;
353392 inquo = 0 ;
354393 while (* ch ) {
355- if (isspace (* ch ) && !inquo ) {
394+ if (apr_isspace (* ch ) && !inquo ) {
356395 ++ ch ; break ;
357396 }
358397 /* Get 'em backslashes */
@@ -373,7 +412,7 @@ static apr_array_header_t *split_argv(apr_pool_t *p, const char *interp,
373412 }
374413 /* Flip quote state */
375414 inquo = !inquo ;
376- if (isspace (* ch ) && !inquo ) {
415+ if (apr_isspace (* ch ) && !inquo ) {
377416 ++ ch ; break ;
378417 }
379418 /* All other '"'s are Munched */
@@ -399,6 +438,7 @@ static apr_array_header_t *split_argv(apr_pool_t *p, const char *interp,
399438 break ;
400439 }
401440 ap_unescape_url (w );
441+ prep_string (& w , p );
402442 arg = (const char * * )apr_array_push (args );
403443 * arg = ap_escape_shell_cmd (p , w );
404444 }
@@ -415,28 +455,33 @@ static apr_status_t ap_cgi_build_command(const char **cmd, const char ***argv,
415455 request_rec * r , apr_pool_t * p ,
416456 cgi_exec_info_t * e_info )
417457{
458+ const apr_table_entry_t * elts = (apr_table_entry_t * )r -> subprocess_env -> a .elts ;
418459 const char * ext = NULL ;
419460 const char * interpreter = NULL ;
420461 win32_dir_conf * d ;
421462 apr_file_t * fh ;
422463 const char * args = "" ;
464+ int i ;
423465
424466 d = (win32_dir_conf * )ap_get_module_config (r -> per_dir_config ,
425467 & win32_module );
426468
427469 if (e_info -> cmd_type ) {
428- /* Handle the complete file name, we DON'T want to follow suexec, since
429- * an unrooted command is as predictable as shooting craps in Win32.
430- *
431- * Notice that unlike most mime extension parsing, we have to use the
432- * win32 parsing here, therefore the final extension is the only one
433- * we will consider
470+ /* We have to consider that the client gets any QUERY_ARGS
471+ * without any charset interpretation, use prep_string to
472+ * create a string of the literal QUERY_ARGS bytes.
434473 */
435474 * cmd = r -> filename ;
436475 if (r -> args && r -> args [0 ] && !ap_strchr_c (r -> args , '=' )) {
437476 args = r -> args ;
438477 }
439478 }
479+ /* Handle the complete file name, we DON'T want to follow suexec, since
480+ * an unrooted command is as predictable as shooting craps in Win32.
481+ * Notice that unlike most mime extension parsing, we have to use the
482+ * win32 parsing here, therefore the final extension is the only one
483+ * we will consider.
484+ */
440485 ext = strrchr (apr_filename_of_pathname (* cmd ), '.' );
441486
442487 /* If the file has an extension and it is not .com and not .exe and
@@ -496,7 +541,7 @@ static apr_status_t ap_cgi_build_command(const char **cmd, const char ***argv,
496541 }
497542 if (i < sizeof (buffer )) {
498543 interpreter = buffer + 2 ;
499- while (isspace (* interpreter )) {
544+ while (apr_isspace (* interpreter )) {
500545 ++ interpreter ;
501546 }
502547 if (e_info -> cmd_type != APR_SHELLCMD ) {
@@ -532,6 +577,21 @@ static apr_status_t ap_cgi_build_command(const char **cmd, const char ***argv,
532577
533578 e_info -> detached = 1 ;
534579
580+ /* XXX: Must fix r->subprocess_env to follow utf-8 conventions from
581+ * the client's octets so that win32 apr_proc_create is happy.
582+ * The -best- way is to determine if the .exe is unicode aware
583+ * (using 0x0080-0x00ff) or is linked as a command or windows
584+ * application (following the OEM or Ansi code page in effect.)
585+ */
586+ for (i = 0 ; i < r -> subprocess_env -> a .nelts ; ++ i ) {
587+ if (elts [i ].key && * elts [i ].key
588+ && (strncmp (elts [i ].key , "HTTP_" , 5 ) == 0
589+ || strncmp (elts [i ].key , "SERVER_" , 7 ) == 0
590+ || strncmp (elts [i ].key , "REQUEST_" , 8 ) == 0
591+ || strcmp (elts [i ].key , "QUERY_STRING" ) == 0 )) {
592+ prep_string ((const char * * ) & elts [i ].val , r -> pool );
593+ }
594+ }
535595 return APR_SUCCESS ;
536596}
537597
0 commit comments