diff --git a/package/uhttpd/src/uhttpd-lua.c b/package/uhttpd/src/uhttpd-lua.c index c2efe3384..a140dc2f2 100644 --- a/package/uhttpd/src/uhttpd-lua.c +++ b/package/uhttpd/src/uhttpd-lua.c @@ -108,19 +108,34 @@ static int uh_lua_sendc(lua_State *L) return uh_lua_send_common(L, 1); } -static int uh_lua_urldecode(lua_State *L) +static int uh_lua_str2str(lua_State *L, int (*xlate_func) (char *, int, const char *, int)) { - size_t inlen, outlen; + size_t inlen; + int outlen; const char *inbuf; char outbuf[UH_LIMIT_MSGHEAD]; inbuf = luaL_checklstring(L, 1, &inlen); - outlen = uh_urldecode(outbuf, sizeof(outbuf), inbuf, inlen); + outlen = (* xlate_func)(outbuf, sizeof(outbuf), inbuf, inlen); + if( outlen < 0 ) + luaL_error( L, "%s on URL-encode codec", + (outlen==-1) ? "buffer overflow" : "malformed string" ); lua_pushlstring(L, outbuf, outlen); return 1; } +static int uh_lua_urldecode(lua_State *L) +{ + return uh_lua_str2str( L, uh_urldecode ); +} + + +static int uh_lua_urlencode(lua_State *L) +{ + return uh_lua_str2str( L, uh_urlencode ); +} + lua_State * uh_lua_init(const char *handler) { @@ -146,6 +161,9 @@ lua_State * uh_lua_init(const char *handler) lua_pushcfunction(L, uh_lua_urldecode); lua_setfield(L, -2, "urldecode"); + lua_pushcfunction(L, uh_lua_urlencode); + lua_setfield(L, -2, "urlencode"); + /* _G.uhttpd = { ... } */ lua_setfield(L, LUA_GLOBALSINDEX, "uhttpd"); diff --git a/package/uhttpd/src/uhttpd-utils.c b/package/uhttpd/src/uhttpd-utils.c index 1073f3bb3..1dac33db0 100644 --- a/package/uhttpd/src/uhttpd-utils.c +++ b/package/uhttpd/src/uhttpd-utils.c @@ -307,7 +307,7 @@ int uh_http_send( /* blen is the size of buf; slen is the length of src. The input-string need ** not be, and the output string will not be, null-terminated. Returns the -** length of the decoded string. */ +** length of the decoded string, -1 on buffer overflow, -2 on malformed string. */ int uh_urldecode(char *buf, int blen, const char *src, int slen) { int i; @@ -329,7 +329,15 @@ int uh_urldecode(char *buf, int blen, const char *src, int slen) } else { - buf[len++] = '%'; + /* Encoding error: it's hard to think of a + ** scenario in which returning an incorrect + ** 'decoding' of the malformed string is + ** preferable to signaling an error condition. */ + #if 0 /* WORSE_IS_BETTER */ + buf[len++] = '%'; + #else + return -2; + #endif } } else @@ -338,12 +346,12 @@ int uh_urldecode(char *buf, int blen, const char *src, int slen) } } - return len; + return (i == slen) ? len : -1; } /* blen is the size of buf; slen is the length of src. The input-string need ** not be, and the output string will not be, null-terminated. Returns the -** length of the encoded string. */ +** length of the encoded string, or -1 on error (buffer overflow) */ int uh_urlencode(char *buf, int blen, const char *src, int slen) { int i; @@ -365,11 +373,12 @@ int uh_urlencode(char *buf, int blen, const char *src, int slen) } else { + len = -1; break; } } - return len; + return (i == slen) ? len : -1; } int uh_b64decode(char *buf, int blen, const unsigned char *src, int slen) @@ -495,6 +504,9 @@ static char * canonpath(const char *path, char *path_resolved) return NULL; } +/* Returns NULL on error. +** NB: improperly encoded URL should give client 400 [Bad Syntax]; returning +** NULL here causes 404 [Not Found], but that's not too unreasonable. */ struct path_info * uh_path_lookup(struct client *cl, const char *url) { static char path_phys[PATH_MAX]; @@ -530,21 +542,21 @@ struct path_info * uh_path_lookup(struct client *cl, const char *url) /* urldecode component w/o query */ if( pathptr > url ) - uh_urldecode( - &buffer[strlen(docroot)], - sizeof(buffer) - strlen(docroot) - 1, - url, pathptr - url - ); + if ( uh_urldecode( + &buffer[strlen(docroot)], + sizeof(buffer) - strlen(docroot) - 1, + url, pathptr - url ) < 0 ) + return NULL; /* bad URL */ } /* no query string, decode all of url */ else { - uh_urldecode( - &buffer[strlen(docroot)], - sizeof(buffer) - strlen(docroot) - 1, - url, strlen(url) - ); + if ( uh_urldecode( + &buffer[strlen(docroot)], + sizeof(buffer) - strlen(docroot) - 1, + url, strlen(url) ) < 0 ) + return NULL; /* bad URL */ } /* create canon path */ diff --git a/package/uhttpd/src/uhttpd.c b/package/uhttpd/src/uhttpd.c index 9b9608628..5d66e23a5 100644 --- a/package/uhttpd/src/uhttpd.c +++ b/package/uhttpd/src/uhttpd.c @@ -948,9 +948,10 @@ int main (int argc, char **argv) for (opt = 0; optarg[opt]; opt++) if (optarg[opt] == '+') optarg[opt] = ' '; - - memset(port, 0, strlen(optarg)+1); - uh_urldecode(port, strlen(optarg), optarg, strlen(optarg)); + /* opt now contains strlen(optarg) -- no need to re-scan */ + memset(port, 0, opt+1); + if (uh_urldecode(port, opt, optarg, opt) < 0) + fprintf( stderr, "uhttpd: invalid encoding\n" ); printf("%s", port); free(port);