Faster, simpler, not yet completely correct reimplementation of

make_safe_uri().  It still has a lot of debugging cruft inside.
This commit is contained in:
Emil Mikulic 2003-11-22 12:09:56 +00:00
parent b2f504f975
commit b082fa213f

View File

@ -438,93 +438,85 @@ static void consolidate_slashes(char *s)
*/ */
static char *make_safe_uri(char *uri) static char *make_safe_uri(char *uri)
{ {
char **elements, **reassembly, *out; char **elem, *out;
unsigned int slashes, elem, reasm, urilen, i, j; unsigned int slashes = 0, elements = 0;
size_t urilen, i, j, pos;
assert(uri != NULL); assert(uri != NULL);
debugf("make_safe_uri(`%s')\n", uri);
if (uri[0] != '/') return NULL; if (uri[0] != '/') return NULL;
consolidate_slashes(uri); consolidate_slashes(uri);
urilen = (unsigned int)strlen(uri); urilen = strlen(uri);
/* count the slashes */ /* count the slashes */
for (i=0, slashes=0; i<urilen; i++) for (i=0, slashes=0; i<urilen; i++)
if (uri[i] == '/') slashes++; if (uri[i] == '/') slashes++;
/* make an array for the URI elements */ /* make an array for the URI elements */
elements = xmalloc(sizeof(char*) * slashes); elem = xmalloc(sizeof(char*) * slashes);
for (i=0; i<slashes; i++) elements[i] = NULL; for (i=0; i<slashes; i++) elem[i] = NULL;
/* split by slash */ /* split by slashes and build elem[] array */
elem = i = 0; for (i=1; i<urilen;)
while (i < urilen) /* i is the left bound */
{ {
/* look for a non-slash */
for (; uri[i] == '/'; i++)
;
/* look for the next slash */ /* look for the next slash */
for (j=i+1; j < urilen && uri[j] != '/'; j++) for (j=i; j<urilen && uri[j] != '/'; j++)
; ;
if (j <= urilen) /* process uri[i,j) */
elements[elem++] = split_string(uri, i, j); if ((j == i+1) && (uri[i] == '.'))
{
i = j; /* iterate */ /* "." */
debugf("got `.'\n");
} }
else if ((j == i+2) && (uri[i] == '.') && (uri[i+1] == '.'))
{
/* ".." */
debugf("got `..'\n");
reassembly = xmalloc(sizeof(char*) * slashes); if (elements == 0)
for (i=0; i<slashes; i++) reassembly[i] = NULL;
reasm = 0;
/* process */
for (i=0; i<elem; i++)
{ {
if (strcmp(elements[i], ".") == 0) /* unsafe string so free elem[]; all its elements are free at
{ /* do nothing */ } * this point.
else if (strcmp(elements[i], "..") == 0) */
{ free(elem);
/* try to backstep */
if (reasm == 0)
{
/* user walked out of wwwroot! unsafe uri! */
for (j=0; j<elem; j++)
if (elements[j] != NULL) free(elements[j]);
free(elements);
free(reassembly);
return NULL; return NULL;
} }
/* else */ else
reasm--; {
reassembly[reasm] = NULL; elements--;
free(elem[elements]);
elem[elements] = NULL; /* FIXME: not needed */
}
} }
else else
{ {
/* plain copy */ /* token */
reassembly[reasm++] = elements[i]; debugf("splitting [%d,%d): ", i, j);
} elem[elements++] = split_string(uri, i, j);
debugf("splitting [%d,%d): element %d: `%s'\n",
i,j,elements,elem[elements-1]);
} }
if (reasm == 0) i = j + 1; /* uri[j] is a slash - move along one */
{
out = xstrdup("/");
} }
else
{
/* reassemble */ /* reassemble */
size_t pos = 0;
out = xmalloc(urilen+1); /* it won't expand */ out = xmalloc(urilen+1); /* it won't expand */
pos = 0;
for (i=0; i<reasm; i++) for (i=0; i<elements; i++)
{ {
size_t delta = strlen(reassembly[i]); size_t delta = strlen(elem[i]);
assert(pos <= urilen); assert(pos <= urilen);
out[pos++] = '/'; out[pos++] = '/';
assert(pos+delta <= urilen); assert(pos+delta <= urilen);
memcpy(out+pos, reassembly[i], delta); memcpy(out+pos, elem[i], delta);
free(elem[i]);
pos += delta; pos += delta;
} }
free(elem);
if (uri[urilen-1] == '/') out[pos++] = '/'; if (uri[urilen-1] == '/') out[pos++] = '/';
assert(pos <= urilen); assert(pos <= urilen);
@ -532,13 +524,8 @@ static char *make_safe_uri(char *uri)
if (pos != urilen) if (pos != urilen)
out = xrealloc(out, strlen(out)+1); /* shorten buffer */ out = xrealloc(out, strlen(out)+1); /* shorten buffer */
}
debugf("`%s' -safe-> `%s'\n", uri, out); debugf("`%s' -safe-> `%s'\n", uri, out);
for (j=0; j<elem; j++)
if (elements[j] != NULL) free(elements[j]);
free(elements);
free(reassembly);
return out; return out;
} }
@ -548,7 +535,9 @@ static char *make_safe_uri(char *uri)
static void test_make_safe_uri(void) static void test_make_safe_uri(void)
{ {
#define SAFE(from,to) do { char *uri = xstrdup(from), *tmp;\ #define SAFE(from,to) do { char *uri = xstrdup(from), *tmp;\
tmp = make_safe_uri(uri); if (strcmp(tmp, to) != 0) \ tmp = make_safe_uri(uri); if (tmp == NULL) \
debugf("FAIL: `%s' unsafe, expecting `%s'\n", from, to); \
else if (strcmp(tmp, to) != 0) \
debugf("FAIL: `%s' -> `%s', expecting `%s'\n", from, tmp, to); \ debugf("FAIL: `%s' -> `%s', expecting `%s'\n", from, tmp, to); \
free(tmp); free(uri); } while(0) free(tmp); free(uri); } while(0)
@ -574,6 +563,7 @@ static void test_make_safe_uri(void)
SAFE("/foo/bar/../moo/", "/foo/moo/"); SAFE("/foo/bar/../moo/", "/foo/moo/");
SAFE("/./moo/./../a/b/c/../.././d/../..", "/"); SAFE("/./moo/./../a/b/c/../.././d/../..", "/");
SAFE("/./moo/./../a/b/c/../.././d/../../", "/"); SAFE("/./moo/./../a/b/c/../.././d/../../", "/");
SAFE("/./moo/./../a/b/c/../.././d/../../xyzzy/", "/xyzzy/");
#undef SAFE #undef SAFE