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

Last change on this file since 5166 was 5166, checked in by Admin, 9 years ago

WebIf: Some bugfixes and better error handling.

File size: 25.9 KB
Line 
1//FIXME Not checked on threadsafety yet; after checking please remove this line
2#include "globals.h"
3#ifdef WEBIF
4#ifdef WITH_SSL
5#include <openssl/crypto.h>
6#include <openssl/ssl.h>
7#include <openssl/err.h>
8#endif
9#include "oscam-http.h"
10
11/* Adds a name->value-mapping or appends to it. You will get a reference back which you may freely
12 use (but you should not call free/realloc on this!)*/
13char *tpl_addVar(struct templatevars *vars, uint8_t addmode, char *name, char *value){
14 if(name == NULL || value == NULL) return "";
15 int32_t i;
16 char *tmp,*result = NULL;
17 for(i = (*vars).varscnt-1; i >= 0; --i){
18 if(strcmp((*vars).names[i], name) == 0){
19 result = (*vars).values[i];
20 break;
21 }
22 }
23 if(result == NULL){
24 if((*vars).varsalloc <= (*vars).varscnt){
25 if(!cs_realloc(&(*vars).names, (*vars).varsalloc * 2 * sizeof(char**), -1)) return "";
26 if(!cs_realloc(&(*vars).values, (*vars).varsalloc * 2 * sizeof(char**), -1)) return "";
27 if(!cs_realloc(&(*vars).vartypes, (*vars).varsalloc * 2 * sizeof(uint8_t*), -1)) return "";
28 (*vars).varsalloc = (*vars).varscnt * 2;
29 }
30 int32_t len = strlen(name) + 1;
31 if(!cs_malloc(&tmp, len * sizeof(char), -1)) return "";
32 memcpy(tmp, name, len);
33 (*vars).names[(*vars).varscnt] = tmp;
34
35 len = strlen(value) + 1;
36 if(!cs_malloc(&tmp, len * sizeof(char), -1)){
37 free((*vars).names[(*vars).varscnt]);
38 return "";
39 }
40 memcpy(tmp, value, len);
41 (*vars).values[(*vars).varscnt] = tmp;
42 (*vars).vartypes[(*vars).varscnt] = addmode;
43 (*vars).varscnt++;
44 } else {
45 int32_t oldlen = 0, newlen = strlen(value);
46 if(addmode == TPLAPPEND || addmode == TPLAPPENDONCE) oldlen = strlen((*vars).values[i]);
47 if(!cs_realloc(&((*vars).values[i]), (oldlen + newlen + 1) * sizeof(char), -1)) return value;
48 memcpy((*vars).values[i] + oldlen, value, newlen + 1);
49 (*vars).vartypes[i] = addmode;
50 }
51 return tmp;
52}
53
54/* Allows to add a char array which has been allocated by malloc. It will automatically get
55 freed when calling tpl_clear(). Please do NOT free the memory yourself or realloc
56 it after having added the array here! */
57char *tpl_addTmp(struct templatevars *vars, char *value){
58 if(value == NULL) return "";
59 if((*vars).tmpalloc <= (*vars).tmpcnt){
60 if(!cs_realloc (&(*vars).tmp, (*vars).tmpalloc * 2 * sizeof(char**), -1)) return value;
61 (*vars).tmpalloc = (*vars).tmpcnt * 2;
62 }
63 (*vars).tmp[(*vars).tmpcnt] = value;
64 (*vars).tmpcnt++;
65 return value;
66}
67
68/* Allows to do a dynamic printf without knowing and defining the needed memory size. If you specify
69 varname, the printf-result will be added/appended to the varlist, if varname=NULL it will only be returned.
70 In either case you will always get a reference back which you may freely use (but you should not call
71 free/realloc on this as it will be automatically cleaned!)*/
72char *tpl_printf(struct templatevars *vars, uint8_t addmode, char *varname, char *fmtstring, ...){
73 uint32_t needed;
74 char test[1];
75 va_list argptr;
76
77 va_start(argptr,fmtstring);
78 needed = vsnprintf(test, 1, fmtstring, argptr);
79 va_end(argptr);
80
81 char *result;
82 if(!cs_malloc(&result, (needed + 1) * sizeof(char), -1)) return "";
83 va_start(argptr,fmtstring);
84 vsnprintf(result, needed + 1, fmtstring, argptr);
85 va_end(argptr);
86
87 if(varname == NULL) tpl_addTmp(vars, result);
88 else {
89 char *tmp = tpl_addVar(vars, addmode, varname, result);
90 free(result);
91 result = tmp;
92 }
93 return result;
94}
95
96/* Returns the value for a name or an empty string if nothing was found. */
97char *tpl_getVar(struct templatevars *vars, char *name){
98 int32_t i;
99 char *result = NULL;
100 for(i = (*vars).varscnt-1; i >= 0; --i){
101 if(strcmp((*vars).names[i], name) == 0){
102 result = (*vars).values[i];
103 break;
104 }
105 }
106 if(result == NULL) return "";
107 else {
108 if((*vars).vartypes[i] == TPLADDONCE || (*vars).vartypes[i] == TPLAPPENDONCE){
109 // This is a one-time-use variable which gets cleaned up automatically after retrieving it
110 if(!cs_malloc(&(*vars).values[i], 1 * sizeof(char), -1)){
111 (*vars).values[i] = result;
112 result[0] = '\0';
113 return result;
114 } else {
115 (*vars).values[i][0] = '\0';
116 return tpl_addTmp(vars, result);
117 }
118 } else return result;
119 }
120}
121
122/* Initializes all variables for a templatevar-structure and returns a pointer to it. Make
123 sure to call tpl_clear() when you are finished or you'll run into a memory leak! */
124struct templatevars *tpl_create(){
125 struct templatevars *vars;
126 if(!cs_malloc(&vars, sizeof(struct templatevars), -1)) return NULL;
127 (*vars).varsalloc = 64;
128 (*vars).varscnt = 0;
129 (*vars).tmpalloc = 64;
130 (*vars).tmpcnt = 0;
131 if(!cs_malloc(&(*vars).names, (*vars).varsalloc * sizeof(char**), -1)){
132 free(vars);
133 return NULL;
134 }
135 if(!cs_malloc(&(*vars).values, (*vars).varsalloc * sizeof(char**), -1)){
136 free((*vars).names);
137 free(vars);
138 return NULL;
139 };
140 if(!cs_malloc(&(*vars).vartypes, (*vars).varsalloc * sizeof(uint8_t*), -1)){
141 free((*vars).names);
142 free((*vars).values);
143 free(vars);
144 return NULL;
145 };
146 if(!cs_malloc(&(*vars).tmp, (*vars).tmpalloc * sizeof(char**), -1)){
147 free((*vars).names);
148 free((*vars).values);
149 free((*vars).vartypes);
150 free(vars);
151 return NULL;
152 };
153 return vars;
154}
155
156/* Clears all allocated memory for the specified templatevar-structure. */
157void tpl_clear(struct templatevars *vars){
158 int32_t i;
159 for(i = (*vars).varscnt-1; i >= 0; --i){
160 free((*vars).names[i]);
161 free((*vars).values[i]);
162 }
163 free((*vars).names);
164 free((*vars).values);
165 free((*vars).vartypes);
166 for(i = (*vars).tmpcnt-1; i >= 0; --i){
167 free((*vars).tmp[i]);
168 }
169 free((*vars).tmp);
170 free(vars);
171}
172
173/* Creates a path to a template file. You need to set the resultsize to the correct size of result. */
174char *tpl_getTplPath(const char *name, const char *path, char *result, uint32_t resultsize){
175 char *pch;
176 if((strlen(path) + strlen(name) + 6) <= resultsize){
177 snprintf(result, resultsize, "%s%s.tpl", path, name);
178 for(pch = result + strlen(path); pch[0] != '\0'; ++pch){
179 if(pch[0] == '/' || pch[0] == '\\') pch[0] = ' ';
180 }
181 } else result[0] = '\0';
182 return result;
183}
184
185/* Returns an unparsed template either from disk or from internal templates.
186 Note: You must free() the result after using it and you may get NULL if an error occured!*/
187char *tpl_getUnparsedTpl(const char* name){
188 int32_t i;
189 int32_t tplcnt = sizeof(tpl)/sizeof(char *);
190 int32_t tplmapcnt = sizeof(tplmap)/sizeof(char *);
191 char *result;
192
193 for(i = 0; i < tplcnt; ++i){
194 if(strcmp(name, tpl[i]) == 0) break;
195 }
196
197 if(strlen(cfg.http_tpl) > 0){
198 char path[255];
199 if(strlen(tpl_getTplPath(name, cfg.http_tpl, path, 255)) > 0 && file_exists(path)){
200 FILE *fp;
201 char buffer[1024];
202 int32_t read, allocated = 1025, size = 0;
203 if(!cs_malloc(&result, allocated * sizeof(char), -1)) return NULL;
204 if((fp = fopen(path,"r"))!=NULL){
205 while((read = fread(&buffer,sizeof(char),1024,fp)) > 0){
206 if(allocated < size + read + 1) {
207 allocated += size + 1024;
208 if(!cs_realloc(&result, allocated * sizeof(char), -1)) return NULL;
209 }
210 memcpy(result + size, buffer, read);
211 size += read;
212 }
213 result[size] = '\0';
214 fclose (fp);
215 return result;
216 }
217 }
218 }
219 if(i >= 0 && i < tplmapcnt){
220 int32_t len = (strlen(tplmap[i])) + 1;
221 if(!cs_malloc(&result, len * sizeof(char), -1)) return NULL;
222 memcpy(result, tplmap[i], len);
223 } else {
224 if(!cs_malloc(&result, 1 * sizeof(char), -1)) return NULL;
225 result[0] = '\0';
226 }
227 return result;
228}
229
230/* Returns the specified template with all variables/other templates replaced or an
231 empty string if the template doesn't exist. Do not free the result yourself, it
232 will get automatically cleaned up! */
233char *tpl_getTpl(struct templatevars *vars, const char* name){
234 char *tplorg = tpl_getUnparsedTpl(name);
235 if(!tplorg) return "";
236 char *tplend = tplorg + strlen(tplorg);
237 char *pch, *pch2, *tpl=tplorg;
238 char varname[33];
239
240 int32_t tmp,respos = 0;
241 int32_t allocated = 2 * strlen(tpl) + 1;
242 char *result;
243 if(!cs_malloc(&result, allocated * sizeof(char), -1)) return "";
244
245 while(tpl < tplend){
246 if(tpl[0] == '#' && tpl[1] == '#' && tpl[2] != '#'){
247 pch2 = tpl;
248 pch = tpl + 2;
249 while(pch[0] != '\0' && (pch[0] != '#' || pch[1] != '#')) ++pch;
250 if(pch - pch2 < 32 && pch[0] == '#' && pch[1] == '#'){
251 memcpy(varname, pch2 + 2, pch - pch2 - 2);
252 varname[pch - pch2 - 2] = '\0';
253 if(strncmp(varname, "TPL", 3) == 0){
254 pch2 = tpl_getTpl(vars, varname + 3);
255 } else {
256 pch2 = tpl_getVar(vars, varname);
257 }
258 tmp = strlen(pch2);
259 if(tmp + respos + 2 >= allocated){
260 allocated = tmp + respos + 256;
261 if(!cs_realloc(&result, allocated * sizeof(char), -1)) return "";
262 }
263 memcpy(result + respos, pch2, tmp);
264 respos += tmp;
265 tpl = pch + 2;
266 }
267 } else {
268 if(respos + 2 >= allocated){
269 allocated = respos + 256;
270 if(!cs_realloc(&result, allocated * sizeof(char), -1)) return "";
271 }
272 result[respos] = tpl[0];
273 ++respos;
274 ++tpl;
275 }
276 }
277 free(tplorg);
278 result[respos] = '\0';
279 tpl_addTmp(vars, result);
280 return result;
281}
282
283/* Saves all templates to the specified paths. Existing files will be overwritten! */
284int32_t tpl_saveIncludedTpls(const char *path){
285 int32_t tplcnt = sizeof(tpl)/sizeof(char *);
286 int32_t tplmapcnt = sizeof(tplmap)/sizeof(char *);
287 int32_t i, cnt = 0;
288 char tmp[256];
289 FILE *fp;
290 for(i = 0; i < tplcnt && i < tplmapcnt; ++i){
291 if(strlen(tpl_getTplPath(tpl[i], path, tmp, 256)) > 0 && (fp = fopen(tmp,"w")) != NULL){
292 fwrite(tplmap[i], sizeof(char), strlen(tplmap[i]), fp);
293 fclose (fp);
294 ++cnt;
295 }
296 }
297 return cnt;
298}
299
300/* Parses a value in an authentication string by removing all quotes/whitespace. Note that the original array is modified. */
301char *parse_auth_value(char *value){
302 char *pch = value;
303 char *pch2;
304 value = strstr(value, "=");
305 if(value != NULL){
306 do{
307 ++value;
308 } while (value[0] == ' ' || value[0] == '"');
309 pch = value;
310 for(pch2 = value + strlen(value) - 1; pch2 >= value && (pch2[0] == ' ' || pch2[0] == '"' || pch2[0] == '\r' || pch2[0] == '\n'); --pch2) pch2[0] = '\0';
311 }
312 return pch;
313}
314
315/* Calculates the currently valid nonce value and copies it to result. Please note that result needs to be at least (MD5_DIGEST_LENGTH * 2) + 1 large. */
316void calculate_nonce(char *result){
317 char noncetmp[128];
318 unsigned char md5tmp[MD5_DIGEST_LENGTH];
319 snprintf(noncetmp, sizeof(noncetmp), "%d:%s", (int)time(NULL)/AUTHNONCEVALIDSECS, noncekey);
320 char_to_hex(MD5((unsigned char*)noncetmp, strlen(noncetmp), md5tmp), MD5_DIGEST_LENGTH, (unsigned char*)result);
321}
322
323/* Checks if authentication is correct. Returns -1 if not correct, 1 if correct and 2 if nonce isn't valid anymore.
324 Note that authstring will be modified. */
325int32_t check_auth(char *authstring, char *method, char *path, char *expectednonce){
326 int32_t authok = 0, uriok = 0;
327 char *authnonce = "";
328 char *authnc = "";
329 char *authcnonce = "";
330 char *authresponse = "";
331 char *uri = "";
332 char *username = "";
333 char *expectedPassword = cfg.http_pwd;
334 char *pch = authstring + 22;
335 char *pch2;
336
337 pch = strtok (pch,",");
338 while (pch != NULL){
339 pch2 = pch;
340 while(pch2[0] == ' ' && pch2[0] != '\0') ++pch2;
341 if(strncmp(pch2, "nonce", 5) == 0){
342 authnonce=parse_auth_value(pch2);
343 } else if (strncmp(pch2, "nc", 2) == 0){
344 authnc=parse_auth_value(pch2);
345 } else if (strncmp(pch2, "cnonce", 6) == 0){
346 authcnonce=parse_auth_value(pch2);
347 } else if (strncmp(pch2, "response", 8) == 0){
348 authresponse=parse_auth_value(pch2);
349 } else if (strncmp(pch2, "uri", 3) == 0){
350 uri=parse_auth_value(pch2);
351 } else if (strncmp(pch2, "username", 8) == 0){
352 username=parse_auth_value(pch2);
353 }
354 pch = strtok (NULL, ",");
355 }
356
357 if(strncmp(uri, path, strlen(path)) == 0) uriok = 1;
358 else {
359 pch2 = uri;
360 for(pch = uri; pch[0] != '\0'; ++pch) {
361 if(pch[0] == '/') pch2 = pch;
362 }
363 if(strncmp(pch2, path, strlen(path)) == 0) uriok = 1;
364 }
365 if(uriok == 1 && strcmp(username, cfg.http_user) == 0){
366 char A1tmp[3 + strlen(username) + strlen(AUTHREALM) + strlen(expectedPassword)];
367 char A1[(MD5_DIGEST_LENGTH * 2) + 1], A2[(MD5_DIGEST_LENGTH * 2) + 1], A3[(MD5_DIGEST_LENGTH * 2) + 1];
368 unsigned char md5tmp[MD5_DIGEST_LENGTH];
369 snprintf(A1tmp, sizeof(A1tmp), "%s:%s:%s", username, AUTHREALM, expectedPassword);
370 char_to_hex(MD5((unsigned char*)A1tmp, strlen(A1tmp), md5tmp), MD5_DIGEST_LENGTH, (unsigned char*)A1);
371
372 char A2tmp[2 + strlen(method) + strlen(uri)];
373 snprintf(A2tmp, sizeof(A2tmp), "%s:%s", method, uri);
374 char_to_hex(MD5((unsigned char*)A2tmp, strlen(A2tmp), md5tmp), MD5_DIGEST_LENGTH, (unsigned char*)A2);
375
376 char A3tmp[10 + strlen(A1) + strlen(A2) + strlen(authnonce) + strlen(authnc) + strlen(authcnonce)];
377 snprintf(A3tmp, sizeof(A3tmp), "%s:%s:%s:%s:auth:%s", A1, authnonce, authnc, authcnonce, A2);
378 char_to_hex(MD5((unsigned char*)A3tmp, strlen(A3tmp), md5tmp), MD5_DIGEST_LENGTH, (unsigned char*)A3);
379
380 if(strcmp(A3, authresponse) == 0) {
381 if(strcmp(expectednonce, authnonce) == 0) authok = 1;
382 else authok = 2;
383 }
384 }
385 return authok;
386}
387
388int32_t webif_write_raw(char *buf, FILE* f, int32_t len) {
389 errno=0;
390#ifdef WITH_SSL
391 if (ssl_active) {
392 return SSL_write((SSL*)f, buf, len);
393 } else
394#endif
395 return fwrite(buf, 1, len, f);
396}
397
398int32_t webif_write(char *buf, FILE* f) {
399 return webif_write_raw(buf, f, strlen(buf));
400}
401
402int32_t webif_read(char *buf, int32_t num, FILE *f) {
403 errno=0;
404#ifdef WITH_SSL
405 if (ssl_active) {
406 return SSL_read((SSL*)f, buf, num);
407 } else
408#endif
409 return read(fileno(f), buf, num);
410}
411
412void send_headers(FILE *f, int32_t status, char *title, char *extra, char *mime, int32_t cache, int32_t length, int8_t forcePlain){
413 time_t now;
414 char timebuf[32];
415 char buf[sizeof(PROTOCOL) + sizeof(SERVER) + strlen(title) + (extra == NULL?0:strlen(extra)+2) + (mime == NULL?0:strlen(mime)+2) + 300];
416 char *pos = buf;
417
418 pos += snprintf(pos, sizeof(buf)-(pos-buf), "%s %d %s\r\n", PROTOCOL, status, title);
419 pos += snprintf(pos, sizeof(buf)-(pos-buf), "Server: %s\r\n", SERVER);
420
421 now = time(NULL);
422 strftime(timebuf, sizeof(timebuf), RFC1123FMT, gmtime(&now));
423 pos += snprintf(pos, sizeof(buf)-(pos-buf), "Date: %s\r\n", timebuf);
424
425 if (extra)
426 pos += snprintf(pos, sizeof(buf)-(pos-buf),"%s\r\n", extra);
427
428 if (mime)
429 pos += snprintf(pos, sizeof(buf)-(pos-buf),"Content-Type: %s\r\n", mime);
430
431 if(!cache){
432 pos += snprintf(pos, sizeof(buf)-(pos-buf),"Cache-Control: no-store, no-cache, must-revalidate\r\n");
433 pos += snprintf(pos, sizeof(buf)-(pos-buf),"Expires: Sat, 26 Jul 1997 05:00:00 GMT\r\n");
434 } else {
435 pos += snprintf(pos, sizeof(buf)-(pos-buf),"Cache-Control: public, max-age=7200\r\n");
436 }
437 pos += snprintf(pos, sizeof(buf)-(pos-buf),"Content-Length: %d\r\n", length);
438 pos += snprintf(pos, sizeof(buf)-(pos-buf),"Last-Modified: %s\r\n", timebuf);
439 pos += snprintf(pos, sizeof(buf)-(pos-buf), "Connection: close\r\n");
440 pos += snprintf(pos, sizeof(buf)-(pos-buf),"\r\n");
441 if(forcePlain == 1) fwrite(buf, 1, strlen(buf), f);
442 else webif_write(buf, f);
443}
444
445/*
446 * function for sending files.
447 */
448void send_file(FILE *f, char *filename){
449 int32_t fileno = 0;
450 char* mimetype = "";
451
452 if (!strcmp(filename, "CSS")){
453 filename = cfg.http_css;
454 mimetype = "text/css";
455 fileno = 1;
456 } else if (!strcmp(filename, "JS")){
457 filename = cfg.http_jscript;
458 mimetype = "text/javascript";
459 fileno = 2;
460 }
461
462 if(strlen(filename) > 0 && file_exists(filename) == 1){
463 FILE *fp;
464 char buffer[1024];
465 int32_t read;
466 struct stat st;
467
468 stat(filename, &st);
469 if((fp = fopen(filename, "r"))==NULL) return;
470 send_headers(f, 200, "OK", NULL, mimetype, 1, st.st_size, 0);
471 while((read = fread(buffer,sizeof(char), 1023, fp)) > 0) {
472 buffer[read] = '\0';
473 webif_write(buffer, f);
474 }
475
476 fclose (fp);
477 } else {
478 if (fileno == 1){
479 send_headers(f, 200, "OK", NULL, mimetype, 1, strlen(CSS), 0);
480 webif_write(CSS, f);
481 } else if (fileno == 2){
482 send_headers(f, 200, "OK", NULL, mimetype, 1, strlen(JSCRIPT), 0);
483 webif_write(JSCRIPT, f);
484 }
485 }
486}
487
488void send_error(FILE *f, int32_t status, char *title, char *extra, char *text, int8_t forcePlain){
489 char buf[(2* strlen(title)) + strlen(text) + 128];
490 char *pos = buf;
491 send_headers(f, status, title, extra, "text/html", 0, strlen(buf), forcePlain);
492 pos += snprintf(pos, sizeof(buf)-(pos-buf), "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\r\n", status, title);
493 pos += snprintf(pos, sizeof(buf)-(pos-buf), "<BODY><H4>%d %s</H4>\r\n", status, title);
494 pos += snprintf(pos, sizeof(buf)-(pos-buf), "%s\r\n", text);
495 pos += snprintf(pos, sizeof(buf)-(pos-buf), "</BODY></HTML>\r\n");
496 if(forcePlain == 1) fwrite(buf, 1, strlen(buf), f);
497 else webif_write(buf, f);
498}
499
500void send_error500(FILE *f){
501 send_error(f, 500, "Internal Server Error", NULL, "The server encountered an internal error that prevented it from fulfilling this request.", 0);
502}
503
504/* Helper function for urldecode.*/
505int32_t x2i(int32_t i){
506 i=toupper(i);
507 i = i - '0';
508 if(i > 9) i = i - 'A' + '9' + 1;
509 return i;
510}
511
512/* Decodes values in a http url. Note: The original value is modified! */
513void urldecode(char *s){
514 int32_t c, c1, n;
515 char *s0,*t;
516 t = s0 = s;
517 n = strlen(s);
518 while(n >0){
519 c = *s++;
520 if(c == '+') c = ' ';
521 else if(c == '%' && n > 2){
522 c = *s++;
523 c1 = c;
524 c = *s++;
525 c = 16*x2i(c1) + x2i(c);
526 n -= 2;
527 }
528 *t++ = c;
529 n--;
530 }
531 *t = 0;
532}
533
534/* Encode values in a http url. Do not call free() or realloc on the returned reference or you will get memory corruption! */
535char *urlencode(struct templatevars *vars, char *str){
536 char buf[strlen(str) * 3 + 1];
537 char *pstr = str, *pbuf = buf;
538 while (*pstr) {
539 if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~') *pbuf++ = *pstr;
540 else if (*pstr == ' ') *pbuf++ = '+';
541 else {
542 *pbuf++ = '%';
543 *pbuf++ = to_hex(*pstr >> 4);
544 *pbuf++ = to_hex(*pstr & 15);
545 }
546 ++pstr;
547 }
548 *pbuf = '\0';
549 /* Allocate the needed memory size and store it in the templatevars */
550 if(!cs_malloc(&pbuf, strlen(buf) + 1, -1)) return "";
551 memcpy(pbuf, buf, strlen(buf) + 1);
552 return tpl_addTmp(vars, pbuf);
553}
554
555/* XML-Escapes a char array. The returned reference will be automatically cleaned through the templatevars-mechanism tpl_clear().
556 Do not call free() or realloc on the returned reference or you will get memory corruption! */
557char *xml_encode(struct templatevars *vars, char *chartoencode) {
558 int32_t i, pos = 0, len = strlen(chartoencode);
559 char *result;
560 /* In worst case, every character could get converted to 6 chars (we only support ASCII, for Unicode it would be 7)*/
561 char encoded[len * 6 + 1], buffer[7];
562 for (i = 0; i < len; ++i){
563 switch(chartoencode[i]) {
564 case '&': memcpy(encoded + pos, "&amp;", 5); pos+=5; break;
565 case '<': memcpy(encoded + pos, "&lt;", 4); pos+=4; break;
566 case '>': memcpy(encoded + pos, "&gt;", 4); pos+=4; break;
567 case '"': memcpy(encoded + pos, "&quot;", 6); pos+=6; break;
568 case '\'': memcpy(encoded + pos, "&apos;", 6); pos+=6; break;
569
570 default:
571 if ( (unsigned int)chartoencode[i] < 32 || (unsigned int)chartoencode[i] > 127 ) {
572 snprintf(buffer, 7, "&#%d;", chartoencode[i] + 256);
573 memcpy(encoded + pos, buffer, strlen(buffer));
574 pos+=strlen(buffer);
575
576 } else {
577 encoded[pos] = chartoencode[i];
578 ++pos;
579 }
580
581 }
582 }
583 /* Allocate the needed memory size and store it in the templatevars */
584 if(!cs_malloc(&result, pos + 1, -1)) return "";
585 memcpy(result, encoded, pos);
586 result[pos] = '\0';
587 return tpl_addTmp(vars, result);
588}
589
590int32_t b64decode(unsigned char *result){
591 char inalphabet[256], decoder[256];
592 unsigned char alphabet[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
593 int32_t i, len = strlen((char *)result), j = 0, bits = 0, char_count = 0;
594
595 for (i = sizeof(alphabet) - 1; i >= 0; --i) {
596 inalphabet[alphabet[i]] = 1;
597 decoder[alphabet[i]] = i;
598 }
599 for(i = 0; i < len; ++i){
600 if (result[i] == '=') break;
601 if (!inalphabet[result[i]]) continue;
602 bits += decoder[result[i]];
603 ++char_count;
604 if (char_count == 4) {
605 result[j++] = bits >> 16;
606 result[j++] = (bits >> 8) & 0xff;
607 result[j++] = bits & 0xff;
608 bits = 0;
609 char_count = 0;
610 } else {
611 bits <<= 6;
612 }
613 }
614 if (i == len) {
615 if (char_count) {
616 result[j] = '\0';
617 return 0;
618 }
619 } else {
620 switch (char_count) {
621 case 1:
622 result[j] = '\0';
623 return 0;
624 case 2:
625 result[j++] = bits >> 10;
626 result[j] = '\0';
627 break;
628 case 3:
629 result[j++] = bits >> 16;
630 result[j++] = (bits >> 8) & 0xff;
631 result[j] = '\0';
632 break;
633 }
634 }
635 return j;
636}
637
638/* Format a seconds integer to hh:mm:ss or dd hh:mm:ss depending hrs >24 */
639char *sec2timeformat(struct templatevars *vars, int32_t seconds) {
640
641 char *value;
642 if(seconds <= 0)
643 return "00:00:00";
644
645 if(!cs_malloc(&value, 16 * sizeof(char), -1))
646 return "00:00:00";
647
648 int32_t secs = 0, fullmins = 0, mins = 0, fullhours = 0, hours = 0, days = 0;
649
650 secs = seconds % 60;
651 if (seconds > 60) {
652 fullmins = seconds / 60;
653 mins = fullmins % 60;
654 if(fullmins > 60) {
655 fullhours = fullmins / 60;
656 hours = fullhours % 24;
657 days = fullhours / 24;
658 }
659 }
660
661 if(days == 0)
662 snprintf(value, 16, "%02d:%02d:%02d", hours, mins, secs);
663 else
664 snprintf(value, 16, "%02dd %02d:%02d:%02d", days, hours, mins, secs);
665
666 return tpl_addTmp(vars, value);
667}
668
669/* Parse url parameters and save them to params array. The pch pointer is increased to the position where parsing stopped. */
670void parseParams(struct uriparams *params, char *pch) {
671 char *pch2;
672 // parsemode = 1 means parsing next param, parsemode = -1 parsing next
673 //value; pch2 points to the beginning of the currently parsed string, pch is the current position
674 int32_t parsemode = 1;
675
676 pch2=pch;
677 while(pch[0] != '\0') {
678 if((parsemode == 1 && pch[0] == '=') || (parsemode == -1 && pch[0] == '&')) {
679 pch[0] = '\0';
680 urldecode(pch2);
681 if(parsemode == 1) {
682 if(params->paramcount >= MAXGETPARAMS) break;
683 ++params->paramcount;
684 params->params[params->paramcount-1] = pch2;
685 } else {
686 params->values[params->paramcount-1] = pch2;
687 }
688 parsemode = -parsemode;
689 pch2 = pch + 1;
690 }
691 ++pch;
692 }
693 /* last value wasn't processed in the loop yet... */
694 if(parsemode == -1 && params->paramcount <= MAXGETPARAMS) {
695 urldecode(pch2);
696 params->values[params->paramcount-1] = pch2;
697 }
698}
699
700/* Returns the value of the parameter called name or an empty string if it doesn't exist. */
701char *getParam(struct uriparams *params, char *name){
702 int32_t i;
703 for(i=(*params).paramcount-1; i>=0; --i){
704 if(strcmp((*params).params[i], name) == 0) return (*params).values[i];
705 }
706 return "";
707}
708
709struct s_reader *get_reader_by_label(char *lbl){
710 struct s_reader *rdr;
711 LL_ITER *itr = ll_iter_create(configured_readers);
712 while((rdr = ll_iter_next(itr)))
713 if (strcmp(lbl, rdr->label) == 0) break;
714 ll_iter_release(itr);
715 return rdr;
716}
717
718struct s_client *get_client_by_name(char *name) {
719 struct s_client *cl;
720 for (cl = first_client; cl ; cl = cl->next) {
721 if (strcmp(name, cl->account->usr) == 0)
722 return cl;
723 }
724 return NULL;
725}
726
727struct s_auth *get_account_by_name(char *name) {
728 struct s_auth *account;
729 for (account=cfg.account; (account); account=account->next) {
730 if(strcmp(name, account->usr) == 0)
731 return account;
732 }
733 return NULL;
734}
735
736#ifdef WITH_SSL
737pthread_key_t getssl;
738SSL * cur_ssl(void){
739 return (SSL *) pthread_getspecific(getssl);
740}
741
742/* Locking functions for SSL multithreading */
743static pthread_mutex_t *lock_cs;
744struct CRYPTO_dynlock_value{
745 pthread_mutex_t mutex;
746};
747
748/* function really needs unsigned long to prevent compiler warnings... */
749unsigned long SSL_id_function(void){
750 return ((unsigned long) pthread_self());
751}
752
753void SSL_locking_function(int32_t mode, int32_t type, const char *file, int32_t line){
754 if (mode & CRYPTO_LOCK) {
755 pthread_mutex_lock(&lock_cs[type]);
756 } else {
757 pthread_mutex_unlock(&lock_cs[type]);
758 }
759 // just to remove compiler warnings...
760 if(file || line) return;
761}
762
763struct CRYPTO_dynlock_value *SSL_dyn_create_function(const char *file, int32_t line){
764 struct CRYPTO_dynlock_value *l;
765 if(!cs_malloc(&l, sizeof(struct CRYPTO_dynlock_value), -1)) return (NULL);
766 if(pthread_mutex_init(&l->mutex, NULL)) {
767 // Initialization of mutex failed.
768 free(l);
769 return (NULL);
770 }
771 pthread_mutex_init(&l->mutex, NULL);
772 // just to remove compiler warnings...
773 if(file || line) return l;
774 return l;
775}
776
777void SSL_dyn_lock_function(int32_t mode, struct CRYPTO_dynlock_value *l, const char *file, int32_t line){
778 if (mode & CRYPTO_LOCK) {
779 pthread_mutex_lock(&l->mutex);
780 } else {
781 pthread_mutex_unlock(&l->mutex);
782 }
783 // just to remove compiler warnings...
784 if(file || line) return;
785}
786
787void SSL_dyn_destroy_function(struct CRYPTO_dynlock_value *l, const char *file, int32_t line){
788 pthread_mutex_destroy(&l->mutex);
789 free(l);
790 // just to remove compiler warnings...
791 if(file || line) return;
792}
793
794/* Init necessary structures for SSL in WebIf*/
795SSL_CTX *SSL_Webif_Init() {
796 SSL_library_init();
797 SSL_load_error_strings();
798 ERR_load_BIO_strings();
799 ERR_load_SSL_strings();
800
801 SSL_METHOD *meth;
802 SSL_CTX *ctx;
803
804 static const char *cs_cert="oscam.pem";
805
806 // set locking callbacks for SSL
807 int32_t i, num = CRYPTO_num_locks();
808 lock_cs = (pthread_mutex_t*) OPENSSL_malloc(num * sizeof(pthread_mutex_t));
809
810 for (i = 0; i < num; ++i) {
811 if(pthread_mutex_init(&lock_cs[i], NULL)){
812 while(--i > 0){
813 pthread_mutex_destroy(&lock_cs[i]);
814 --i;
815 }
816 free(lock_cs);
817 return NULL;
818 };
819 }
820 /* static lock callbacks */
821 CRYPTO_set_id_callback(SSL_id_function);
822 CRYPTO_set_locking_callback(SSL_locking_function);
823 /* dynamic lock callbacks */
824 CRYPTO_set_dynlock_create_callback(SSL_dyn_create_function);
825 CRYPTO_set_dynlock_lock_callback(SSL_dyn_lock_function);
826 CRYPTO_set_dynlock_destroy_callback(SSL_dyn_destroy_function);
827
828 meth = SSLv23_server_method();
829
830 ctx = SSL_CTX_new(meth);
831
832 char path[128];
833
834 if (cfg.http_cert[0]==0)
835 snprintf(path, sizeof(path), "%s%s", cs_confdir, cs_cert);
836 else
837 cs_strncpy(path, cfg.http_cert, sizeof(path));
838
839 if (!ctx) {
840 ERR_print_errors_fp(stderr);
841 return NULL;
842 }
843
844 if (SSL_CTX_use_certificate_file(ctx, path, SSL_FILETYPE_PEM) <= 0) {
845 ERR_print_errors_fp(stderr);
846 return NULL;
847 }
848
849 if (SSL_CTX_use_PrivateKey_file(ctx, path, SSL_FILETYPE_PEM) <= 0) {
850 ERR_print_errors_fp(stderr);
851 return NULL;
852 }
853
854 if (!SSL_CTX_check_private_key(ctx)) {
855 cs_log("SSL: Private key does not match the certificate public key");
856 return NULL;
857 }
858 cs_log("load ssl certificate file %s", path);
859 return ctx;
860}
861#endif
862#endif
Note: See TracBrowser for help on using the repository browser.