source: trunk/oscam-http-helpers.c@ 4149

Last change on this file since 4149 was 4137, checked in by _network, 13 years ago

WebIf: add POST support

File size: 14.3 KB
Line 
1//FIXME Not checked on threadsafety yet; after checking please remove this line
2#include "globals.h"
3#ifdef WEBIF
4#include "oscam-http.h"
5
6/* Adds a name->value-mapping or appends to it. You will get a reference back which you may freely
7 use (but you should not call free/realloc on this!)*/
8char *tpl_addVar(struct templatevars *vars, int append, char *name, char *value){
9 int i;
10 char *tmp,*result = NULL;
11 for(i = (*vars).varscnt-1; i >= 0; --i){
12 if(strcmp((*vars).names[i], name) == 0){
13 result = (*vars).values[i];
14 break;
15 }
16 }
17 if(result == NULL){
18 if((*vars).varsalloc <= (*vars).varscnt){
19 (*vars).varsalloc = (*vars).varscnt * 2;
20 (*vars).names = (char**) realloc ((*vars).names, (*vars).varsalloc * sizeof(char**));
21 (*vars).values = (char**) realloc ((*vars).values, (*vars).varsalloc * sizeof(char**));
22 }
23 tmp = (char *) malloc((strlen(name) + 1) * sizeof(char));
24 strcpy(tmp, name);
25 (*vars).names[(*vars).varscnt] = tmp;
26 tmp = (char *) malloc((strlen(value) + 1) * sizeof(char));
27 strcpy(tmp, value);
28 (*vars).values[(*vars).varscnt] = tmp;
29 (*vars).varscnt = (*vars).varscnt + 1;
30 } else {
31 int newlen = strlen(value);
32 if(append == 1){
33 int oldlen = strlen((*vars).values[i]);
34 tmp = (char*) malloc ((oldlen + newlen + 1) * sizeof(char));
35 memcpy(tmp, (*vars).values[i], oldlen);
36 strcpy(tmp + oldlen, value);
37 } else {
38 tmp = (char*) malloc ((newlen + 1) * sizeof(char));
39 strcpy(tmp, value);
40 }
41 free((*vars).values[i]);
42 (*vars).values[i] = tmp;
43 }
44 return tmp;
45}
46
47/* Allows to add a char array which has been allocated by malloc. It will automatically get
48 freed when calling tpl_clear(). Please do NOT free the memory yourself or realloc
49 it after having added the array here! */
50char *tpl_addTmp(struct templatevars *vars, char *value){
51 if((*vars).tmpalloc <= (*vars).tmpcnt){
52 (*vars).tmpalloc = (*vars).tmpcnt * 2;
53 (*vars).tmp = (char**) realloc ((*vars).tmp, (*vars).tmpalloc * sizeof(char**));
54 }
55 (*vars).tmp[(*vars).tmpcnt] = value;
56 (*vars).tmpcnt = (*vars).tmpcnt + 1;
57 return value;
58}
59
60/* Allows to do a dynamic printf without knowing and defining the needed memory size. If you specify
61 varname, the printf-result will be added/appended to the varlist. You will always get a reference
62 back which you may freely use (but you should not call free/realloc on this!)*/
63char *tpl_printf(struct templatevars *vars, int append, char *varname, char *fmtstring, ...){
64 unsigned int allocated = strlen(fmtstring) - (strlen(fmtstring)%16) + 16;
65 char *result, *tmp = (char *) malloc(allocated * sizeof(char));
66 va_list argptr;
67
68 va_start(argptr,fmtstring);
69 vsnprintf(tmp ,allocated, fmtstring, argptr);
70 va_end(argptr);
71 while (strlen(tmp) + 1 == allocated){
72 allocated += 16;
73 tmp = (char *) realloc(tmp, allocated * sizeof(char));
74 va_start(argptr,fmtstring);
75 vsnprintf(tmp, allocated, fmtstring, argptr);
76 va_end(argptr);
77 }
78 result = (char *) malloc(strlen(tmp) + 1 * sizeof(char));
79 strcpy(result, tmp);
80 free(tmp);
81 if(varname == NULL) tpl_addTmp(vars, result);
82 else {
83 char *tmp = tpl_addVar(vars, append, varname, result);
84 free(result);
85 result = tmp;
86 }
87 return result;
88}
89
90/* Returns the value for a name or an empty string if nothing was found. */
91char *tpl_getVar(struct templatevars *vars, char *name){
92 int i;
93 char *result = NULL;
94 for(i = (*vars).varscnt-1; i >= 0; --i){
95 if(strcmp((*vars).names[i], name) == 0){
96 result = (*vars).values[i];
97 break;
98 }
99 }
100 if(result == NULL) return "";
101 else return result;
102}
103
104/* Initializes all variables vor a templatevar-structure and returns a pointer to it. Make
105 sure to call tpl_clear() when you are finished or you'll run into a memory leak! */
106struct templatevars *tpl_create(){
107 struct templatevars *vars = (struct templatevars *) malloc(sizeof(struct templatevars));
108 (*vars).varsalloc = 16;
109 (*vars).varscnt = 0;
110 (*vars).tmpalloc = 16;
111 (*vars).tmpcnt = 0;
112 (*vars).names = (char**) malloc ((*vars).varsalloc * sizeof(char**));
113 (*vars).values = (char**) malloc ((*vars).varsalloc * sizeof(char**));
114 (*vars).tmp = (char**) malloc ((*vars).tmpalloc * sizeof(char**));
115 return vars;
116}
117
118/* Clears all allocated memory for the specified templatevar-structure. */
119void tpl_clear(struct templatevars *vars){
120 int i;
121 for(i = (*vars).varscnt-1; i >= 0; --i){
122 free((*vars).names[i]);
123 free((*vars).values[i]);
124 }
125 free((*vars).names);
126 free((*vars).values);
127 for(i = (*vars).tmpcnt-1; i >= 0; --i){
128 free((*vars).tmp[i]);
129 }
130 free((*vars).tmp);
131 free(vars);
132}
133
134/* Creates a path to a template file. You need to set the resultsize to the correct size of result. */
135char *tpl_getTplPath(const char *name, const char *path, char *result, unsigned int resultsize){
136 char *pch;
137 if((strlen(path) + strlen(name) + 6) <= resultsize){
138 strcpy(result, path);
139 strcat(result, name);
140 strcat(result, ".tpl");
141 result[resultsize - 1] = '\0';
142 for(pch = result + strlen(path); pch[0] != '\0'; ++pch){
143 if(pch[0] == '/' || pch[0] == '\\') pch[0] = ' ';
144 }
145 } else result[0] = '\0';
146 return result;
147}
148
149/* Returns an unparsed template either from disk or from internal templates.
150 Note: You must free() the result after using it!*/
151char *tpl_getUnparsedTpl(const char* name){
152 int i;
153 int tplcnt = sizeof(tpl)/sizeof(char *);
154 int tplmapcnt = sizeof(tplmap)/sizeof(char *);
155 char *result;
156
157 for(i = 0; i < tplcnt; ++i){
158 if(strcmp(name, tpl[i]) == 0) break;
159 }
160
161 if(strlen(cfg->http_tpl) > 0){
162 char path[200];
163 if(strlen(tpl_getTplPath(name, cfg->http_tpl, path, 200)) > 0 && file_exists(path)){
164 FILE *fp;
165 char buffer[1024];
166 int read, allocated = 1025, size = 0;
167 result = (char *) malloc(allocated * sizeof(char));
168 if((fp = fopen(path,"r"))!=NULL){
169 while((read = fread(&buffer,sizeof(char),1024,fp)) > 0){
170 if(allocated < size + read + 1) {
171 allocated += size + 1024;
172 result = (char *) realloc(result, allocated * sizeof(char));
173 }
174 memcpy(result + size, buffer, read);
175 size += read;
176 }
177 result[size] = '\0';
178 fclose (fp);
179 return result;
180 }
181 }
182 }
183 if(i >= 0 && i < tplmapcnt){
184 int len = (strlen(tplmap[i])) + 1;
185 result = (char *) malloc(len * sizeof(char));
186 memcpy(result, tplmap[i], len);
187 } else {
188 result = (char *) malloc(1 * sizeof(char));
189 result[0] = '\0';
190 }
191 return result;
192}
193
194/* Returns the specified template with all variables/other templates replaced or an
195 empty string if the template doesn't exist*/
196char *tpl_getTpl(struct templatevars *vars, const char* name){
197 char *tplorg = tpl_getUnparsedTpl(name);
198 char *tplend = tplorg + strlen(tplorg);
199 char *pch, *pch2, *tpl=tplorg;
200 char varname[33];
201
202 int tmp,respos = 0;
203 int allocated = 2 * strlen(tpl) + 1;
204 char *result = (char *) malloc(allocated * sizeof(char));
205
206 while(tpl < tplend){
207 if(tpl[0] == '#' && tpl[1] == '#' && tpl[2] != '#'){
208 pch2 = tpl;
209 pch = tpl + 2;
210 while(pch[0] != '\0' && (pch[0] != '#' || pch[1] != '#')) ++pch;
211 if(pch - pch2 < 32 && pch[0] == '#' && pch[1] == '#'){
212 memcpy(varname, pch2 + 2, pch - pch2 - 2);
213 varname[pch - pch2 - 2] = '\0';
214 if(strncmp(varname, "TPL", 3) == 0){
215 pch2 = tpl_getTpl(vars, varname + 3);
216 } else {
217 pch2 = tpl_getVar(vars, varname);
218 }
219 tmp = strlen(pch2);
220 if(tmp + respos + 2 >= allocated){
221 allocated = tmp + respos + 256;
222 result = (char *) realloc(result, allocated * sizeof(char));
223 }
224 memcpy(result + respos, pch2, tmp);
225 respos += tmp;
226 tpl = pch + 2;
227 }
228 } else {
229 if(respos + 2 >= allocated){
230 allocated = respos + 256;
231 result = (char *) realloc(result, allocated * sizeof(char));
232 }
233 result[respos] = tpl[0];
234 ++respos;
235 ++tpl;
236 }
237 }
238 free(tplorg);
239 result[respos] = '\0';
240 tpl_addTmp(vars, result);
241 return result;
242}
243
244/* Saves all templates to the specified paths. Existing files will be overwritten! */
245int tpl_saveIncludedTpls(const char *path){
246 int tplcnt = sizeof(tpl)/sizeof(char *);
247 int tplmapcnt = sizeof(tplmap)/sizeof(char *);
248 int i, cnt = 0;
249 char tmp[200];
250 FILE *fp;
251 for(i = 0; i < tplcnt && i < tplmapcnt; ++i){
252 if(strlen(tpl_getTplPath(tpl[i], path, tmp, 200)) > 0 && (fp = fopen(tmp,"w")) != NULL){
253 fwrite(tplmap[i], sizeof(char), strlen(tplmap[i]), fp);
254 fclose (fp);
255 ++cnt;
256 }
257 }
258 return cnt;
259}
260
261/* Parses a value in an authentication string by removing all quotes/whitespace. Note that the original array is modified*/
262char *parse_auth_value(char *value){
263 char *pch = value;
264 char *pch2;
265 value = strstr(value, "=");
266 if(value != NULL){
267 do{
268 ++value;
269 } while (value[0] == ' ' || value[0] == '"');
270 pch = value;
271 for(pch2 = value + strlen(value) - 1; pch2 >= value && (pch2[0] == ' ' || pch2[0] == '"' || pch2[0] == '\r' || pch2[0] == '\n'); --pch2) pch2[0] = '\0';
272 }
273 return pch;
274}
275
276/* Calculates the currently valid nonce value and copies it to result*/
277void calculate_nonce(char *result, int resultlen){
278 char *expectednonce, *noncetmp;
279 noncetmp = (char*) malloc (128*sizeof(char));
280 sprintf(noncetmp, "%d", (int)time(NULL)/AUTHNONCEVALIDSECS);
281 strcat(noncetmp, ":");
282 strcat(noncetmp, noncekey);
283 fflush(stdout);
284 expectednonce =char_to_hex(MD5((unsigned char*)noncetmp, strlen(noncetmp), NULL), MD5_DIGEST_LENGTH, hex2ascii);
285 cs_strncpy(result, expectednonce, resultlen);
286 free(noncetmp);
287 free(expectednonce);
288}
289
290/* Checks if authentication is correct. Returns -1 if not correct, 1 if correct and 2 if nonce isn't valid anymore */
291int check_auth(char *authstring, char *method, char *path, char *expectednonce){
292 int authok = 0, uriok = 0;
293 char *authnonce;
294 char *authnc;
295 char *authcnonce;
296 char *uri;
297 char *authresponse;
298 char *A1tmp, *A2tmp, *A3tmp;
299 char *A1, *A2, *A3;
300 char *pch, *pch2;
301
302 authnonce = "";
303 authnc = "";
304 authcnonce = "";
305 authresponse = "";
306 uri = "";
307 pch = authstring + 22;
308 pch = strtok (pch,",");
309 while (pch != NULL){
310 pch2 = pch;
311 while(pch2[0] == ' ' && pch2[0] != '\0') ++pch2;
312 if(strncmp(pch2, "nonce", 5) == 0){
313 authnonce=parse_auth_value(pch2);
314 } else if (strncmp(pch2, "nc", 2) == 0){
315 authnc=parse_auth_value(pch2);
316 } else if (strncmp(pch2, "cnonce", 6) == 0){
317 authcnonce=parse_auth_value(pch2);
318 } else if (strncmp(pch2, "response", 8) == 0){
319 authresponse=parse_auth_value(pch2);
320 } else if (strncmp(pch2, "uri", 3) == 0){
321 uri=parse_auth_value(pch2);
322 }
323 pch = strtok (NULL, ",");
324 }
325 if(strncmp(uri, path, strlen(path)) == 0) uriok = 1;
326 else {
327 pch2 = uri;
328 for(pch = uri; pch[0] != '\0'; ++pch) {
329 if(pch[0] == '/') pch2 = pch;
330 }
331 if(strncmp(pch2, path, strlen(path)) == 0) uriok = 1;
332 }
333 if(uriok == 1){
334 A1tmp = (char*) malloc ((3 + strlen(cfg->http_user) + strlen(AUTHREALM) + strlen(cfg->http_pwd))*sizeof(char));
335 strcpy(A1tmp, cfg->http_user);
336 strcat(A1tmp, ":");
337 strcat(A1tmp, AUTHREALM);
338 strcat(A1tmp, ":");
339 strcat(A1tmp, cfg->http_pwd);
340 A2tmp = (char*) malloc ((2 + strlen(method) + strlen(uri))*sizeof(char));
341 strcpy(A2tmp, method);
342 strcat(A2tmp, ":");
343 strcat(A2tmp, uri);
344 A1=char_to_hex(MD5((unsigned char*)A1tmp, strlen(A1tmp), NULL), MD5_DIGEST_LENGTH, hex2ascii);
345 A2=char_to_hex(MD5((unsigned char*)A2tmp, strlen(A2tmp), NULL), MD5_DIGEST_LENGTH, hex2ascii);
346 A3tmp = (char*) malloc ((10 + strlen(A1) + strlen(A2) + strlen(authnonce) + strlen(authnc) + strlen(authcnonce))*sizeof(char));
347 strcpy(A3tmp, A1);
348 strcat(A3tmp, ":");
349 strcat(A3tmp, authnonce);
350 strcat(A3tmp, ":");
351 strcat(A3tmp, authnc);
352 strcat(A3tmp, ":");
353 strcat(A3tmp, authcnonce);
354 strcat(A3tmp, ":auth:");
355 strcat(A3tmp, A2);
356 A3=char_to_hex(MD5((unsigned char*)A3tmp, strlen(A3tmp), NULL), MD5_DIGEST_LENGTH, hex2ascii);
357 if(strcmp(A3, authresponse) == 0) {
358 if(strcmp(expectednonce, authnonce) == 0) authok = 1;
359 else authok = 2;
360 }
361 free(A1tmp);
362 free(A2tmp);
363 free(A3tmp);
364 free(A1);
365 free(A2);
366 free(A3);
367 }
368 return authok;
369}
370
371#ifdef WITH_SSL
372#include <openssl/crypto.h>
373#include <openssl/ssl.h>
374#include <openssl/err.h>
375#endif
376
377int webif_write(char *buf, FILE* f) {
378#ifdef WITH_SSL
379 if (cfg->http_use_ssl) {
380 return SSL_write((SSL*)f, buf, strlen(buf));
381 } else
382#endif
383 return fwrite(buf, 1, strlen(buf), f);
384}
385
386int webif_read(char *buf, int num, FILE *f) {
387#ifdef WITH_SSL
388 if (cfg->http_use_ssl) {
389 return SSL_read((SSL*)f, buf, num);
390 } else
391#endif
392 return read(fileno(f), buf, num);
393}
394
395void send_headers(FILE *f, int status, char *title, char *extra, char *mime){
396
397 time_t now;
398 char timebuf[128];
399 char buf[1024];
400
401 sprintf(buf, "%s %d %s\r\n", PROTOCOL, status, title);
402 sprintf(buf+strlen(buf), "Server: %s\r\n", SERVER);
403
404 now = time(NULL);
405 strftime(timebuf, sizeof(timebuf), RFC1123FMT, gmtime(&now));
406 sprintf(buf+strlen(buf), "Date: %s\r\n", timebuf);
407
408 if (extra)
409 sprintf(buf+strlen(buf), "%s\r\n", extra);
410
411 if (mime)
412 sprintf(buf+strlen(buf), "Content-Type: %s\r\n", mime);
413
414 strftime(timebuf, sizeof(timebuf), RFC1123FMT, gmtime(&now));
415 sprintf(buf+strlen(buf), "Cache-Control: no-store, no-cache, must-revalidate\r\n");
416 sprintf(buf+strlen(buf), "Expires: Sat, 26 Jul 1997 05:00:00 GMT\r\n");
417 sprintf(buf+strlen(buf), "Last-Modified: %s\r\n", timebuf);
418 sprintf(buf+strlen(buf), "Connection: close\r\n");
419 sprintf(buf+strlen(buf), "\r\n");
420 webif_write(buf, f);
421}
422
423
424/*
425 * function for sending files. 1 = CSS, 2 = JS
426 */
427void send_file(FILE *f, int fileno){
428
429 char *filename;
430
431 if (fileno == 1)
432 filename = cfg->http_css;
433 else if (fileno == 2)
434 filename = cfg->http_jscript;
435 else
436 return;
437
438 if(strlen(filename) > 0 && file_exists(filename) == 1){
439 FILE *fp;
440 char buffer[1024];
441 int read;
442
443 if((fp = fopen(filename, "r"))==NULL) return;
444 while((read = fread(buffer,sizeof(char), 1023, fp)) > 0) {
445 buffer[read] = '\0';
446 webif_write(buffer, f);
447 }
448
449 fclose (fp);
450 } else {
451 webif_write(CSS, f);
452 }
453}
454
455void send_error(FILE *f, int status, char *title, char *extra, char *text){
456 char buf[1024];
457 send_headers(f, status, title, extra, "text/html");
458 sprintf(buf, "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\r\n", status, title);
459 sprintf(buf+strlen(buf), "<BODY><H4>%d %s</H4>\r\n", status, title);
460 sprintf(buf+strlen(buf), "%s\r\n", text);
461 sprintf(buf+strlen(buf), "</BODY></HTML>\r\n");
462 webif_write(buf, f);
463}
464
465char *getParam(struct uriparams *params, char *name){
466 int i;
467 for(i=(*params).paramcount-1; i>=0; --i){
468 if(strcmp((*params).params[i], name) == 0) return (*params).values[i];
469 }
470 return "";
471}
472
473char *getParamDef(struct uriparams *params, char *name, char* def){
474 int i;
475 for(i=(*params).paramcount-1; i>=0; --i){
476 if(strcmp((*params).params[i], name) == 0) return (*params).values[i];
477 }
478 return def;
479}
480
481#endif
Note: See TracBrowser for help on using the repository browser.