• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/cgi-io/util.c

  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