diff options
| author | Lars Hjemli | 2011-06-12 20:49:35 +0000 |
|---|---|---|
| committer | Lars Hjemli | 2011-06-12 21:21:30 +0000 |
| commit | 7f88d20823ad9d375900657334bc27793860f6ee (patch) | |
| tree | c9f9a0048cae2d94e97138e9ea82e2a103b215ad /ui-plain.c | |
| parent | 2a8f553163d642e60092ced20631e1020581273b (diff) | |
| download | cgit-7f88d20823ad9d375900657334bc27793860f6ee.tar.gz cgit-7f88d20823ad9d375900657334bc27793860f6ee.tar.bz2 cgit-7f88d20823ad9d375900657334bc27793860f6ee.zip | |
ui-plain.c: fix html and links generated by print_dir() and print_dir_entry()
This patch fixes the following issues:
* the base argument usually isn't zero-terminated, so printing base
without considering baselen will usually generate random garbage
* when the current url represents a directory but doesn't end in a slash,
relative urls would be incorrect
* using unescaped paths allows XSS
Signed-off-by: Lars Hjemli <hjemli@gmail.com>
Diffstat (limited to 'ui-plain.c')
| -rw-r--r-- | ui-plain.c | 65 |
1 files changed, 46 insertions, 19 deletions
| @@ -52,30 +52,57 @@ static void print_object(const unsigned char *sha1, const char *path) | |||
| 52 | match = 1; | 52 | match = 1; |
| 53 | } | 53 | } |
| 54 | 54 | ||
| 55 | static void print_dir(const unsigned char *sha1, const char *path, | 55 | static char *buildpath(const char *base, int baselen, const char *path) |
| 56 | const char *base) | ||
| 57 | { | 56 | { |
| 58 | char *fullpath; | 57 | if (path[0]) |
| 59 | if (path[0] || base[0]) | 58 | return fmt("%.*s%s/", baselen, base, path); |
| 60 | fullpath = fmt("/%s%s/", base, path); | ||
| 61 | else | 59 | else |
| 62 | fullpath = "/"; | 60 | return fmt("%.*s/", baselen, base); |
| 61 | } | ||
| 62 | |||
| 63 | static void print_dir(const unsigned char *sha1, const char *base, | ||
| 64 | int baselen, const char *path) | ||
| 65 | { | ||
| 66 | char *fullpath, *slash; | ||
| 67 | size_t len; | ||
| 68 | |||
| 69 | fullpath = buildpath(base, baselen, path); | ||
| 70 | slash = (fullpath[0] == '/' ? "" : "/"); | ||
| 63 | ctx.page.etag = sha1_to_hex(sha1); | 71 | ctx.page.etag = sha1_to_hex(sha1); |
| 64 | cgit_print_http_headers(&ctx); | 72 | cgit_print_http_headers(&ctx); |
| 65 | htmlf("<html><head><title>%s</title></head>\n<body>\n" | 73 | htmlf("<html><head><title>%s", slash); |
| 66 | " <h2>%s</h2>\n <ul>\n", fullpath, fullpath); | 74 | html_txt(fullpath); |
| 67 | if (path[0] || base[0]) | 75 | htmlf("</title></head>\n<body>\n<h2>%s", slash); |
| 68 | html(" <li><a href=\"../\">../</a></li>\n"); | 76 | html_txt(fullpath); |
| 77 | html("</h2>\n<ul>\n"); | ||
| 78 | len = strlen(fullpath); | ||
| 79 | if (len > 1) { | ||
| 80 | fullpath[len - 1] = 0; | ||
| 81 | slash = strrchr(fullpath, '/'); | ||
| 82 | if (slash) | ||
| 83 | *(slash + 1) = 0; | ||
| 84 | else | ||
| 85 | fullpath = NULL; | ||
| 86 | html("<li>"); | ||
| 87 | cgit_plain_link("../", NULL, NULL, ctx.qry.head, ctx.qry.sha1, | ||
| 88 | fullpath); | ||
| 89 | html("</li>\n"); | ||
| 90 | } | ||
| 69 | match = 2; | 91 | match = 2; |
| 70 | } | 92 | } |
| 71 | 93 | ||
| 72 | static void print_dir_entry(const unsigned char *sha1, const char *path, | 94 | static void print_dir_entry(const unsigned char *sha1, const char *base, |
| 73 | unsigned mode) | 95 | int baselen, const char *path, unsigned mode) |
| 74 | { | 96 | { |
| 75 | const char *sep = ""; | 97 | char *fullpath; |
| 76 | if (S_ISDIR(mode)) | 98 | |
| 77 | sep = "/"; | 99 | fullpath = buildpath(base, baselen, path); |
| 78 | htmlf(" <li><a href=\"%s%s\">%s%s</a></li>\n", path, sep, path, sep); | 100 | if (!S_ISDIR(mode)) |
| 101 | fullpath[strlen(fullpath) - 1] = 0; | ||
| 102 | html(" <li>"); | ||
| 103 | cgit_plain_link(path, NULL, NULL, ctx.qry.head, ctx.qry.sha1, | ||
| 104 | fullpath); | ||
| 105 | html("</li>\n"); | ||
| 79 | match = 2; | 106 | match = 2; |
| 80 | } | 107 | } |
| 81 | 108 | ||
| @@ -92,12 +119,12 @@ static int walk_tree(const unsigned char *sha1, const char *base, int baselen, | |||
| 92 | if (S_ISREG(mode)) | 119 | if (S_ISREG(mode)) |
| 93 | print_object(sha1, pathname); | 120 | print_object(sha1, pathname); |
| 94 | else if (S_ISDIR(mode)) { | 121 | else if (S_ISDIR(mode)) { |
| 95 | print_dir(sha1, pathname, base); | 122 | print_dir(sha1, base, baselen, pathname); |
| 96 | return READ_TREE_RECURSIVE; | 123 | return READ_TREE_RECURSIVE; |
| 97 | } | 124 | } |
| 98 | } | 125 | } |
| 99 | else if (baselen > match_baselen) | 126 | else if (baselen > match_baselen) |
| 100 | print_dir_entry(sha1, pathname, mode); | 127 | print_dir_entry(sha1, base, baselen, pathname, mode); |
| 101 | else if (S_ISDIR(mode)) | 128 | else if (S_ISDIR(mode)) |
| 102 | return READ_TREE_RECURSIVE; | 129 | return READ_TREE_RECURSIVE; |
| 103 | 130 | ||
| @@ -134,7 +161,7 @@ void cgit_print_plain(struct cgit_context *ctx) | |||
| 134 | if (!paths[0]) { | 161 | if (!paths[0]) { |
| 135 | paths[0] = ""; | 162 | paths[0] = ""; |
| 136 | match_baselen = -1; | 163 | match_baselen = -1; |
| 137 | print_dir(commit->tree->object.sha1, "", ""); | 164 | print_dir(commit->tree->object.sha1, "", 0, ""); |
| 138 | } | 165 | } |
| 139 | else | 166 | else |
| 140 | match_baselen = basedir_len(paths[0]); | 167 | match_baselen = basedir_len(paths[0]); |
