author | Lars Hjemli <hjemli@gmail.com> | 2011-06-12 20:49:35 (UTC) |
---|---|---|
committer | Lars Hjemli <hjemli@gmail.com> | 2011-06-12 21:21:30 (UTC) |
commit | 7f88d20823ad9d375900657334bc27793860f6ee (patch) (unidiff) | |
tree | c9f9a0048cae2d94e97138e9ea82e2a103b215ad | |
parent | 2a8f553163d642e60092ced20631e1020581273b (diff) | |
download | cgit-7f88d20823ad9d375900657334bc27793860f6ee.zip cgit-7f88d20823ad9d375900657334bc27793860f6ee.tar.gz cgit-7f88d20823ad9d375900657334bc27793860f6ee.tar.bz2 |
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>
-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]); |