summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko2006-11-29 15:58:50 +0000
committerDenis Vlasenko2006-11-29 15:58:50 +0000
commita35c9e91ba53073ff797d1d68d0d4e1836d934f0 (patch)
treea19543c721a5a98f9b96522303ca250b58d1bcca
parent2425bdce34cd142b29eabad00927a9c473b05ecb (diff)
downloadbusybox-a35c9e91ba53073ff797d1d68d0d4e1836d934f0.zip
busybox-a35c9e91ba53073ff797d1d68d0d4e1836d934f0.tar.gz
httpd: fix decode of '/' when called via -d
-rw-r--r--networking/httpd.c66
1 files changed, 34 insertions, 32 deletions
diff --git a/networking/httpd.c b/networking/httpd.c
index f95e0c0..49c2c76 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -671,43 +671,47 @@ static char *encodeString(const char *string)
*
* $Parameters:
* (char *) string . . . The first string to decode.
- * (int) flag . . . 1 if need to decode '+' as ' ' for CGI
+ * (int) option_d . . 1 if called for httpd -d
*
* $Return: (char *) . . . . A pointer to the decoded string (same as input).
*
* $Errors: None
*
****************************************************************************/
-static char *decodeString(char *orig, int flag_plus_to_space)
+static char *decodeString(char *orig, int option_d)
{
/* note that decoded string is always shorter than original */
char *string = orig;
char *ptr = string;
+ char c;
- while (*ptr) {
- if (*ptr == '+' && flag_plus_to_space) {
+ while ((c = *ptr++) != '\0') {
+ unsigned value1, value2;
+
+ if (option_d && c == '+') {
*string++ = ' ';
- ptr++;
- } else if (*ptr != '%') {
- *string++ = *ptr++;
- } else {
- unsigned int value1, value2;
-
- ptr++;
- if (sscanf(ptr, "%1X", &value1) != 1
- || sscanf(ptr+1, "%1X", &value2) != 1
- ) {
- if (!flag_plus_to_space)
- return NULL;
- *string++ = '%';
- } else {
- value1 = value1 * 16 + value2;
- if (value1 == '/' || value1 == 0)
- return orig+1;
- *string++ = value1;
- ptr += 2;
- }
+ continue;
+ }
+ if (c != '%') {
+ *string++ = c;
+ continue;
+ }
+ if (sscanf(ptr, "%1X", &value1) != 1
+ || sscanf(ptr+1, "%1X", &value2) != 1
+ ) {
+ if (!option_d)
+ return NULL;
+ *string++ = '%';
+ continue;
+ }
+ value1 = value1 * 16 + value2;
+ if (!option_d && (value1 == '/' || value1 == '\0')) {
+ /* caller takes it as indication of invalid
+ * (dangerous wrt exploits) chars */
+ return orig + 1;
}
+ *string++ = value1;
+ ptr += 2;
}
*string = '\0';
return orig;
@@ -1510,8 +1514,8 @@ static void handleIncoming(void)
test = decodeString(url, 0);
if (test == NULL)
goto BAD_REQUEST;
- /* FIXME: bug? should be "url+1"? */
- if (test == (buf+1)) {
+ if (test == url+1) {
+ /* '/' or NUL is encoded */
sendHeaders(HTTP_NOT_FOUND);
break;
}
@@ -1909,12 +1913,12 @@ int httpd_main(int argc, char *argv[])
char *e;
// FIXME: what the default group should be?
ugid.gid = -1;
- ugid.uid = strtoul(s_ugid, &e, 0);
+ ugid.uid = bb_strtoul(s_ugid, &e, 0);
if (*e == ':') {
e++;
- ugid.gid = strtoul(e, &e, 0);
+ ugid.gid = bb_strtoul(e, NULL, 0);
}
- if (*e != '\0') {
+ if (errno) {
/* not integer */
if (!uidgid_get(&ugid, s_ugid))
bb_error_msg_and_die("unrecognized user[:group] "
@@ -1942,9 +1946,7 @@ int httpd_main(int argc, char *argv[])
#if ENABLE_FEATURE_HTTPD_CGI
{
char *p = getenv("PATH");
- if (p) {
- p = xstrdup(p);
- }
+ p = xstrdup(p); /* if gets NULL, returns NULL */
clearenv();
if (p)
setenv1("PATH", p);