about summary refs log tree commit diff stats
path: root/src/LYExtern.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/LYExtern.c')
-rw-r--r--src/LYExtern.c178
1 files changed, 127 insertions, 51 deletions
diff --git a/src/LYExtern.c b/src/LYExtern.c
index e042820c..9f5471db 100644
--- a/src/LYExtern.c
+++ b/src/LYExtern.c
@@ -66,16 +66,88 @@ static char *decode_string(char *s)
 #ifdef WIN_EX
 /*
  * Quote the path to make it safe for shell command processing.
+ *  We always quote it not only includes spaces in it.
+ *  At least we should quote paths which include "&".
  */
 char *quote_pathname(char *pathname)
 {
     char *result = NULL;
 
-    if (strchr(pathname, ' ') != NULL) {
-	HTSprintf0(&result, "\"%s\"", pathname);
-    } else {
-	StrAllocCopy(result, pathname);
+    HTSprintf0(&result, "\"%s\"", pathname);
+    return result;
+}
+
+/*
+ *  Delete dangerous characters as local path.
+ *  We delete '<>|' and also '%"'.
+ *  '%' should be deleted because it's difficut to escape for all cases.
+ *  So we can't treat paths which include '%'.
+ *  '"' should be deleted because it's a obstacle to quote whole path.
+ */
+static void delete_danger_characters(char *src)
+{
+    char *dst;
+
+    for (dst = src; *src != '\0'; src++) {
+	if (strchr("<>|%\"", *src) == NULL) {
+	    *dst = *src;
+	    dst++;
+	}
     }
+    *dst = '\0';
+}
+
+static char *escapeParameter(CONST char *parameter)
+{
+    size_t i;
+    size_t last = strlen(parameter);
+    size_t n = 0;
+    size_t encoded = 0;
+    size_t escaped = 0;
+    char *result;
+    char *needs_encoded = "<>|";
+    char *needs_escaped = "%";
+    char *needs_escaped_NT = "%&^";
+
+    for (i = 0; i < last; ++i) {
+	if (strchr(needs_encoded, parameter[i]) != NULL) {
+	    ++encoded;
+	}
+	if (system_is_NT) {
+	    if (strchr(needs_escaped_NT, parameter[i]) != NULL) {
+		++escaped;
+	    }
+	} else if (strchr(needs_escaped, parameter[i]) != NULL) {
+	    ++escaped;
+	}
+    }
+
+    result = (char *) malloc(last + encoded * 2 + escaped + 1);
+    if (result == NULL)
+	outofmem(__FILE__, "escapeParameter");
+
+    n = 0;
+    for (i = 0; i < last; i++) {
+	if (strchr(needs_encoded, parameter[i]) != NULL) {
+	    sprintf(result + n, "%%%02X", (unsigned char) parameter[i]);
+	    n += 3;
+	    continue;
+	}
+	if (system_is_NT) {
+	    if (strchr(needs_escaped_NT, parameter[i]) != NULL) {
+		result[n++] = '^';
+		result[n++] = parameter[i];
+		continue;
+	    }
+	} else if (strchr(needs_escaped, parameter[i]) != NULL) {
+	    result[n++] = '%';	/* parameter[i] is '%' */
+	    result[n++] = parameter[i];
+	    continue;
+	}
+	result[n++] = parameter[i];
+    }
+    result[n] = '\0';
+
     return result;
 }
 #endif /* WIN_EX */
@@ -103,62 +175,66 @@ static char *format_command(char *command,
     char *cmdbuf = NULL;
 
 #if defined(WIN_EX)
-    if (*param != '"' && strchr(param, ' ') != NULL) {
-	char *cp = quote_pathname(param);
-
-	format(&cmdbuf, command, cp);
-	FREE(cp);
-    } else {
-	char pram_string[LY_MAXPATH];
+    char pram_string[LY_MAXPATH];
+    char *escaped = NULL;
 
+    if (strnicmp("file://localhost/", param, 17) == 0) {
+	/* decode local path parameter for programs to be
+	   able to interpret - TH */
 	LYstrncpy(pram_string, param, sizeof(pram_string) - 1);
 	decode_string(pram_string);
 	param = pram_string;
+    } else {
+	/* encode or escape URL parameter - TH */
+	escaped = escapeParameter(param);
+	param = escaped;
+    }
 
-	if (isMAILTO_URL(param)) {
-	    format(&cmdbuf, command, param + 7);
-	} else if (strnicmp("telnet://", param, 9) == 0) {
-	    char host[sizeof(pram_string)];
-	    int last_pos;
-
-	    strcpy(host, param + 9);
-	    last_pos = strlen(host) - 1;
-	    if (last_pos > 1 && host[last_pos] == '/')
-		host[last_pos] = '\0';
-
-	    format(&cmdbuf, command, host);
-	} else if (strnicmp("file://localhost/", param, 17) == 0) {
-	    char e_buff[LY_MAXPATH], *p;
-
-	    p = param + 17;
-	    *e_buff = 0;
-	    if (strchr(p, ':') == NULL) {
-		sprintf(e_buff, "%.3s/", windows_drive);
-	    }
-	    strncat(e_buff, p, sizeof(e_buff) - strlen(e_buff) - 1);
-	    p = strrchr(e_buff, '.');
-	    if (p) {
-		trimPoundSelector(p);
-	    }
+    if (isMAILTO_URL(param)) {
+	format(&cmdbuf, command, param + 7);
+    } else if (strnicmp("telnet://", param, 9) == 0) {
+	char host[sizeof(pram_string)];
+	int last_pos;
+
+	LYstrncpy(host, param + 9, sizeof(host));
+	last_pos = strlen(host) - 1;
+	if (last_pos > 1 && host[last_pos] == '/')
+	    host[last_pos] = '\0';
+
+	format(&cmdbuf, command, host);
+    } else if (strnicmp("file://localhost/", param, 17) == 0) {
+	char e_buff[LY_MAXPATH], *p;
+
+	p = param + 17;
+	delete_danger_characters(p);
+	*e_buff = 0;
+	if (strchr(p, ':') == NULL) {
+	    sprintf(e_buff, "%.3s/", windows_drive);
+	}
+	strncat(e_buff, p, sizeof(e_buff) - strlen(e_buff) - 1);
+	p = strrchr(e_buff, '.');
+	if (p) {
+	    trimPoundSelector(p);
+	}
 
-	    /* Less ==> short filename with backslashes,
-	     * less ==> long filename with forward slashes, may be quoted
-	     */
-	    if (ISUPPER(command[0])) {
-		format(&cmdbuf,
-		       command, HTDOS_short_name(e_buff));
-	    } else {
-		if (*e_buff != '"' && strchr(e_buff, ' ') != NULL) {
-		    p = quote_pathname(e_buff);
-		    LYstrncpy(e_buff, p, sizeof(e_buff) - 1);
-		    FREE(p);
-		}
-		format(&cmdbuf, command, e_buff);
-	    }
+	/* Less ==> short filename with backslashes,
+	 * less ==> long filename with forward slashes, may be quoted
+	 */
+	if (ISUPPER(command[0])) {
+	    char *short_name = HTDOS_short_name(e_buff);
+
+	    p = quote_pathname(short_name);
+	    format(&cmdbuf, command, p);
+	    FREE(p);
 	} else {
-	    format(&cmdbuf, command, param);
+	    p = quote_pathname(e_buff);
+	    format(&cmdbuf, command, p);
+	    FREE(p);
 	}
+    } else {
+	format(&cmdbuf, command, param);
     }
+    FREE(escaped);
 #else
     format(&cmdbuf, command, param);
 #endif