1. Shambhala 0.6.1 ignores any QUERY_STRING after a NULL character which
making the argv vector for a CGI script.
e.g. script?text%00word
sets argv to text
instead it should set it to text\000word
A patch is supplied.
2. Shambhala applies different shell-escaping from Apache & NCSA 1.3 for
<!-- #exec cmd--> commands.
Consider test.shtml which contains <!-- #exec cmd="env" -->
Calling test.shtml/aa{b?c%7bd gives
PATH_INFO=/aa\{b
PATH_TRANSLATED=/opt/httpd/htdocs/aa{b
QUERY_STRING=c%7bd
QUERY_STRING_UNESCAPED=c\{d
whereas NCSA and apache give
PATH_INFO=/aa\{b
PATH_TRANSLATED=/opt/httpd/htdocs/aa\{b
QUERY_STRING=c%7bd
QUERY_STRING_UNESCAPED=c\{d
Both of these behaviours a wrong, in my opinion; if escaped
strings are to be provided, they should be called PATH_INFO_ESCAPED
and PATH_TRANSLATED_ESCAPED.
At the very least, the documentation is wrong; it does not mention
that PATH_INFO and PATH_TRANSLATED are escaped strings.
David.
--------------- Patch for null characters in QUERY_STRING -------------------
*** httpd.h.orig Fri Jul 14 11:21:19 1995
--- httpd.h Mon Jul 17 11:27:26 1995
***************
*** 388,394 ****
char *escape_uri (pool *p, char *s);
char *construct_url (pool *p, char *path, server_rec *s);
char *escape_shell_cmd (pool *p, char *s);
!
int count_dirs(char *path);
char *make_dirstr(pool *a, char *s, int n);
char *make_full_path(pool *a, char *dir, char *f);
--- 388,395 ----
char *escape_uri (pool *p, char *s);
char *construct_url (pool *p, char *path, server_rec *s);
char *escape_shell_cmd (pool *p, char *s);
! extern char *url2shell_escape(pool *p, const char *s);
!
int count_dirs(char *path);
char *make_dirstr(pool *a, char *s, int n);
char *make_full_path(pool *a, char *dir, char *f);
*** util.c.orig Sun Jul 9 18:52:43 1995
--- util.c Mon Jul 17 11:51:10 1995
***************
*** 65,70 ****
--- 65,74 ----
#include "httpd.h"
#include "http_conf_globals.h" /* for user_id & group_id */
+
+ /* prototypes */
+ static int x2c(const char *what);
+
#ifdef NOTDEF
extern char** environ;
***************
*** 413,418 ****
--- 417,461 ----
return cmd;
}
+ /*
+ * Converts a URL-encoded string to a shell-encoded string.
+ * This way we are careful with NULL characters in the URL.
+ * We skip bad escape sequences in the URL.
+ */
+ char *
+ url2shell_escape(pool *p, const char *s)
+ {
+ register int x, y, ch;
+ char *cmd;
+
+ cmd = palloc(p, 2*strlen(s)+1); /* Be safe. */
+ for (x=0, y=0; s[x] != '\0'; x++, y++)
+ {
+ ch = s[x];
+ if (ch == '%' && isxdigit(s[x+1]) && isxdigit(s[x+2]))
+ {
+ ch = x2c(&s[x+1]);
+ x += 2;
+ }
+ if (ch == 0) /* and other control characters, or 0x80-ff? */
+ {
+ cmd[y++] = '\\';
+ cmd[y++] = '0';
+ cmd[y++] = '0';
+ cmd[y] = '0';
+ } else if (ind("&;`'\"|*?~<>^()[]{}$\\", ch) != -1)
+ {
+ cmd[y++] = '\\';
+ cmd[y] = ch;
+ }
+ else cmd[y] = ch;
+ }
+ cmd[y] = '\0';
+
+ return cmd;
+ }
+
+
void plustospace(char *str) {
register int x;
***************
*** 425,431 ****
for(x=0;str[x];x++) if(str[x] == ' ') str[x] = '+';
}
! char x2c(char *what) {
register char digit;
digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
--- 468,475 ----
for(x=0;str[x];x++) if(str[x] == ' ') str[x] = '+';
}
! static int
! x2c(const char *what) {
register char digit;
digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
*** util_script.c.orig Sun Jul 9 17:30:32 1995
--- util_script.c Mon Jul 17 11:32:34 1995
***************
*** 80,87 ****
for(x=1;x<n;x++) {
w = getword(p, &args, '+');
! unescape_url(w);
! av[x] = escape_shell_cmd(p, w);
}
av[n] = NULL;
return av;
--- 80,86 ----
for(x=1;x<n;x++) {
w = getword(p, &args, '+');
! av[x] = url2shell_escape(p, w);
}
av[n] = NULL;
return av;
*** mod_include.c.orig Tue Jul 11 23:58:08 1995
--- mod_include.c Mon Jul 17 11:31:36 1995
***************
*** 417,425 ****
if (r->args) {
table_set (env, "QUERY_STRING", r->args);
- unescape_url (r->args);
table_set (env, "QUERY_STRING_UNESCAPED",
! escape_shell_cmd (r->pool, r->args));
}
error_log2stderr (r->server);
--- 417,424 ----
if (r->args) {
table_set (env, "QUERY_STRING", r->args);
table_set (env, "QUERY_STRING_UNESCAPED",
! url2shell_escape (r->pool, r->args));
}
error_log2stderr (r->server);
----------------------------- End of file ---------------------------------
making the argv vector for a CGI script.
e.g. script?text%00word
sets argv to text
instead it should set it to text\000word
A patch is supplied.
2. Shambhala applies different shell-escaping from Apache & NCSA 1.3 for
<!-- #exec cmd--> commands.
Consider test.shtml which contains <!-- #exec cmd="env" -->
Calling test.shtml/aa{b?c%7bd gives
PATH_INFO=/aa\{b
PATH_TRANSLATED=/opt/httpd/htdocs/aa{b
QUERY_STRING=c%7bd
QUERY_STRING_UNESCAPED=c\{d
whereas NCSA and apache give
PATH_INFO=/aa\{b
PATH_TRANSLATED=/opt/httpd/htdocs/aa\{b
QUERY_STRING=c%7bd
QUERY_STRING_UNESCAPED=c\{d
Both of these behaviours a wrong, in my opinion; if escaped
strings are to be provided, they should be called PATH_INFO_ESCAPED
and PATH_TRANSLATED_ESCAPED.
At the very least, the documentation is wrong; it does not mention
that PATH_INFO and PATH_TRANSLATED are escaped strings.
David.
--------------- Patch for null characters in QUERY_STRING -------------------
*** httpd.h.orig Fri Jul 14 11:21:19 1995
--- httpd.h Mon Jul 17 11:27:26 1995
***************
*** 388,394 ****
char *escape_uri (pool *p, char *s);
char *construct_url (pool *p, char *path, server_rec *s);
char *escape_shell_cmd (pool *p, char *s);
!
int count_dirs(char *path);
char *make_dirstr(pool *a, char *s, int n);
char *make_full_path(pool *a, char *dir, char *f);
--- 388,395 ----
char *escape_uri (pool *p, char *s);
char *construct_url (pool *p, char *path, server_rec *s);
char *escape_shell_cmd (pool *p, char *s);
! extern char *url2shell_escape(pool *p, const char *s);
!
int count_dirs(char *path);
char *make_dirstr(pool *a, char *s, int n);
char *make_full_path(pool *a, char *dir, char *f);
*** util.c.orig Sun Jul 9 18:52:43 1995
--- util.c Mon Jul 17 11:51:10 1995
***************
*** 65,70 ****
--- 65,74 ----
#include "httpd.h"
#include "http_conf_globals.h" /* for user_id & group_id */
+
+ /* prototypes */
+ static int x2c(const char *what);
+
#ifdef NOTDEF
extern char** environ;
***************
*** 413,418 ****
--- 417,461 ----
return cmd;
}
+ /*
+ * Converts a URL-encoded string to a shell-encoded string.
+ * This way we are careful with NULL characters in the URL.
+ * We skip bad escape sequences in the URL.
+ */
+ char *
+ url2shell_escape(pool *p, const char *s)
+ {
+ register int x, y, ch;
+ char *cmd;
+
+ cmd = palloc(p, 2*strlen(s)+1); /* Be safe. */
+ for (x=0, y=0; s[x] != '\0'; x++, y++)
+ {
+ ch = s[x];
+ if (ch == '%' && isxdigit(s[x+1]) && isxdigit(s[x+2]))
+ {
+ ch = x2c(&s[x+1]);
+ x += 2;
+ }
+ if (ch == 0) /* and other control characters, or 0x80-ff? */
+ {
+ cmd[y++] = '\\';
+ cmd[y++] = '0';
+ cmd[y++] = '0';
+ cmd[y] = '0';
+ } else if (ind("&;`'\"|*?~<>^()[]{}$\\", ch) != -1)
+ {
+ cmd[y++] = '\\';
+ cmd[y] = ch;
+ }
+ else cmd[y] = ch;
+ }
+ cmd[y] = '\0';
+
+ return cmd;
+ }
+
+
void plustospace(char *str) {
register int x;
***************
*** 425,431 ****
for(x=0;str[x];x++) if(str[x] == ' ') str[x] = '+';
}
! char x2c(char *what) {
register char digit;
digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
--- 468,475 ----
for(x=0;str[x];x++) if(str[x] == ' ') str[x] = '+';
}
! static int
! x2c(const char *what) {
register char digit;
digit = ((what[0] >= 'A') ? ((what[0] & 0xdf) - 'A')+10 : (what[0] - '0'));
*** util_script.c.orig Sun Jul 9 17:30:32 1995
--- util_script.c Mon Jul 17 11:32:34 1995
***************
*** 80,87 ****
for(x=1;x<n;x++) {
w = getword(p, &args, '+');
! unescape_url(w);
! av[x] = escape_shell_cmd(p, w);
}
av[n] = NULL;
return av;
--- 80,86 ----
for(x=1;x<n;x++) {
w = getword(p, &args, '+');
! av[x] = url2shell_escape(p, w);
}
av[n] = NULL;
return av;
*** mod_include.c.orig Tue Jul 11 23:58:08 1995
--- mod_include.c Mon Jul 17 11:31:36 1995
***************
*** 417,425 ****
if (r->args) {
table_set (env, "QUERY_STRING", r->args);
- unescape_url (r->args);
table_set (env, "QUERY_STRING_UNESCAPED",
! escape_shell_cmd (r->pool, r->args));
}
error_log2stderr (r->server);
--- 417,424 ----
if (r->args) {
table_set (env, "QUERY_STRING", r->args);
table_set (env, "QUERY_STRING_UNESCAPED",
! url2shell_escape (r->pool, r->args));
}
error_log2stderr (r->server);
----------------------------- End of file ---------------------------------