1 #include <ctype.h> 2 #include <stddef.h> 3 #include <stdbool.h> 4 #include <stdlib.h> 5 #include <string.h> 6 #include <unistd.h> 7 8 #include <stdio.h> 9 10 #include "util.h" 11 12 char ** 13 parse_command(const char *cmdline) 14 { 15 const char *p = cmdline, *s; 16 char **argv = NULL, *out; 17 size_t arglen = 0; 18 int argnum = 0; 19 bool esc; 20 21 while (isspace(*cmdline)) 22 cmdline++; 23 24 for (p = cmdline, s = p, esc = false; p; p++) { 25 if (esc) { 26 esc = false; 27 } 28 else if (*p == '\\' && p[1] != 0) { 29 esc = true; 30 } 31 else if (isspace(*p) || *p == 0) { 32 if (p > s) { 33 argnum += 1; 34 arglen += sizeof(char *) + (p - s) + 1; 35 } 36 37 s = p + 1; 38 } 39 40 if (*p == 0) 41 break; 42 } 43 44 if (arglen == 0) 45 return NULL; 46 47 argv = calloc(1, arglen + sizeof(char *)); 48 49 if (!argv) 50 return NULL; 51 52 out = (char *)argv + sizeof(char *) * (argnum + 1); 53 argv[0] = out; 54 55 for (p = cmdline, s = p, esc = false, argnum = 0; p; p++) { 56 if (esc) { 57 esc = false; 58 *out++ = *p; 59 } 60 else if (*p == '\\' && p[1] != 0) { 61 esc = true; 62 } 63 else if (isspace(*p) || *p == 0) { 64 if (p > s) { 65 *out++ = ' '; 66 argv[++argnum] = out; 67 } 68 69 s = p + 1; 70 } 71 else { 72 *out++ = *p; 73 } 74 75 if (*p == 0) 76 break; 77 } 78 79 argv[argnum] = NULL; 80 out[-1] = 0; 81 82 return argv; 83 } 84 85 char * 86 postdecode_fields(char *postbuf, ssize_t len, char **fields, int n_fields) 87 { 88 char *p; 89 int i, field, found = 0; 90 91 for (p = postbuf, i = 0; i < len; i++) 92 { 93 if (postbuf[i] == '=') 94 { 95 postbuf[i] = 0; 96 97 for (field = 0; field < (n_fields * 2); field += 2) 98 { 99 if (!strcmp(p, fields[field])) 100 { 101 fields[field + 1] = postbuf + i + 1; 102 found++; 103 } 104 } 105 } 106 else if (postbuf[i] == '&' || postbuf[i] == '\0') 107 { 108 postbuf[i] = 0; 109 110 if (found >= n_fields) 111 break; 112 113 p = postbuf + i + 1; 114 } 115 } 116 117 for (field = 0; field < (n_fields * 2); field += 2) 118 { 119 if (!urldecode(fields[field + 1])) 120 { 121 /* 122 * Clear all value pointers before releasing the shared 123 * buffer so that a caller which ignores the NULL return 124 * cannot dereference a dangling pointer into freed memory. 125 */ 126 for (i = 0; i < n_fields; i++) 127 fields[(i * 2) + 1] = NULL; 128 129 free(postbuf); 130 return NULL; 131 } 132 } 133 134 return postbuf; 135 } 136 137 char * 138 postdecode(char **fields, int n_fields) 139 { 140 const char *var; 141 char *p, *postbuf; 142 ssize_t len = 0, rlen = 0, content_length = 0; 143 144 var = getenv("CONTENT_TYPE"); 145 146 if (!var || strncmp(var, "application/x-www-form-urlencoded", 33)) 147 return NULL; 148 149 var = getenv("CONTENT_LENGTH"); 150 151 if (!var) 152 return NULL; 153 154 content_length = strtol(var, &p, 10); 155 156 if (p == var || content_length <= 0 || content_length >= POST_LIMIT) 157 return NULL; 158 159 postbuf = calloc(1, content_length + 1); 160 161 if (postbuf == NULL) 162 return NULL; 163 164 for (len = 0; len < content_length; ) 165 { 166 rlen = read(0, postbuf + len, content_length - len); 167 168 if (rlen <= 0) 169 break; 170 171 len += rlen; 172 } 173 174 if (len < content_length) 175 { 176 free(postbuf); 177 return NULL; 178 } 179 180 return postdecode_fields(postbuf, len, fields, n_fields); 181 } 182 183 char * 184 datadup(const void *in, size_t len) 185 { 186 char *out = malloc(len + 1); 187 188 if (!out) 189 return NULL; 190 191 memcpy(out, in, len); 192 193 *(out + len) = 0; 194 195 return out; 196 } 197 198 char * 199 canonicalize_path(const char *path, size_t len) 200 { 201 char *canonpath, *cp; 202 const char *p, *e; 203 204 if (path == NULL || *path == '\0') 205 return NULL; 206 207 canonpath = datadup(path, len); 208 209 if (canonpath == NULL) 210 return NULL; 211 212 /* normalize */ 213 for (cp = canonpath, p = path, e = path + len; p < e; ) { 214 if (*p != '/') 215 goto next; 216 217 /* skip repeating / */ 218 if ((p + 1 < e) && (p[1] == '/')) { 219 p++; 220 continue; 221 } 222 223 /* /./ or /../ */ 224 if ((p + 1 < e) && (p[1] == '.')) { 225 /* skip /./ */ 226 if ((p + 2 >= e) || (p[2] == '/')) { 227 p += 2; 228 continue; 229 } 230 231 /* collapse /x/../ */ 232 if ((p + 2 < e) && (p[2] == '.') && ((p + 3 >= e) || (p[3] == '/'))) { 233 while ((cp > canonpath) && (*--cp != '/')) 234 ; 235 236 p += 3; 237 continue; 238 } 239 } 240 241 next: 242 *cp++ = *p++; 243 } 244 245 /* remove trailing slash if not root / */ 246 if ((cp > canonpath + 1) && (cp[-1] == '/')) 247 cp--; 248 else if (cp == canonpath) 249 *cp++ = '/'; 250 251 *cp = '\0'; 252 253 return canonpath; 254 } 255 256 bool 257 urldecode(char *buf) 258 { 259 char *c, *p; 260 261 if (!buf || !*buf) 262 return true; 263 264 #define hex(x) \ 265 (((x) <= '9') ? ((x) - '') : \ 266 (((x) <= 'F') ? ((x) - 'A' + 10) : \ 267 ((x) - 'a' + 10))) 268 269 for (c = p = buf; *p; c++) 270 { 271 if (*p == '%') 272 { 273 if (!isxdigit(*(p + 1)) || !isxdigit(*(p + 2))) 274 return false; 275 276 *c = (char)(16 * hex(*(p + 1)) + hex(*(p + 2))); 277 278 p += 3; 279 } 280 else if (*p == '+') 281 { 282 *c = ' '; 283 p++; 284 } 285 else 286 { 287 *c = *p++; 288 } 289 } 290 291 *c = 0; 292 293 return true; 294 } 295
This page was automatically generated by LXR 0.3.1. • OpenWrt