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

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

Some small fixes.

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 char *save=NULL;
337
338 pch = strtok_r (pch,",",&save);
339 while (pch != NULL){
340 pch2 = pch;
341 while(pch2[0] == ' ' && pch2[0] != '\0') ++pch2;
342 if(strncmp(pch2, "nonce", 5) == 0){
343 authnonce=parse_auth_value(pch2);
344 } else if (strncmp(pch2, "nc", 2) == 0){
345 authnc=parse_auth_value(pch2);
346 } else if (strncmp(pch2, "cnonce", 6) == 0){
347 authcnonce=parse_auth_value(pch2);
348 } else if (strncmp(pch2, "response", 8) == 0){
349 authresponse=parse_auth_value(pch2);
350 } else if (strncmp(pch2, "uri", 3) == 0){
351 uri=parse_auth_value(pch2);
352 } else if (strncmp(pch2, "username", 8) == 0){
353 username=parse_auth_value(pch2);
354 }
355 pch = strtok_r (NULL, ",",&save);
356 }
357
358 if(strncmp(uri, path, strlen(path)) == 0) uriok = 1;
359 else {
360 pch2 = uri;
361 for(pch = uri; pch[0] != '\0'; ++pch) {
362 if(pch[0] == '/') pch2 = pch;
363 }
364 if(strncmp(pch2, path, strlen(path)) == 0) uriok = 1;
365 }
366 if(uriok == 1 && strcmp(username, cfg.http_user) == 0){
367 char A1tmp[3 + strlen(username) + strlen(AUTHREALM) + strlen(expectedPassword)];
368 char A1[(MD5_DIGEST_LENGTH * 2) + 1], A2[(MD5_DIGEST_LENGTH * 2) + 1], A3[(MD5_DIGEST_LENGTH * 2) + 1];
369 unsigned char md5tmp[MD5_DIGEST_LENGTH];
370 snprintf(A1tmp, sizeof(A1tmp), "%s:%s:%s", username, AUTHREALM, expectedPassword);
371 char_to_hex(MD5((unsigned char*)A1tmp, strlen(A1tmp), md5tmp), MD5_DIGEST_LENGTH, (unsigned char*)A1);
372
373 char A2tmp[2 + strlen(method) + strlen(uri)];
374 snprintf(A2tmp, sizeof(A2tmp), "%s:%s", method, uri);
375 char_to_hex(MD5((unsigned char*)A2tmp, strlen(A2tmp), md5tmp), MD5_DIGEST_LENGTH, (unsigned char*)A2);
376
377 char A3tmp[10 + strlen(A1) + strlen(A2) + strlen(authnonce) + strlen(authnc) + strlen(authcnonce)];
378 snprintf(A3tmp, sizeof(A3tmp), "%s:%s:%s:%s:auth:%s", A1, authnonce, authnc, authcnonce, A2);
379 char_to_hex(MD5((unsigned char*)A3tmp, strlen(A3tmp), md5tmp), MD5_DIGEST_LENGTH, (unsigned char*)A3);
380
381 if(strcmp(A3, authresponse) == 0) {
382 if(strcmp(expectednonce, authnonce) == 0) authok = 1;
383 else authok = 2;
384 }
385 }
386 return authok;
387}
388
389int32_t webif_write_raw(char *buf, FILE* f, int32_t len) {
390 errno=0;
391#ifdef WITH_SSL
392 if (ssl_active) {
393 return SSL_write((SSL*)f, buf, len);
394 } else
395#endif
396 return fwrite(buf, 1, len, f);
397}
398
399int32_t webif_write(char *buf, FILE* f) {
400 return webif_write_raw(buf, f, strlen(buf));
401}
402
403int32_t webif_read(char *buf, int32_t num, FILE *f) {
404 errno=0;
405#ifdef WITH_SSL
406 if (ssl_active) {
407 return SSL_read((SSL*)f, buf, num);
408 } else
409#endif
410 return read(fileno(f), buf, num);
411}
412
413void send_headers(FILE *f, int32_t status, char *title, char *extra, char *mime, int32_t cache, int32_t length, int8_t forcePlain){
414 time_t now;
415 char timebuf[32];
416 char buf[sizeof(PROTOCOL) + sizeof(SERVER) + strlen(title) + (extra == NULL?0:strlen(extra)+2) + (mime == NULL?0:strlen(mime)+2) + 300];
417 char *pos = buf;
418
419 pos += snprintf(pos, sizeof(buf)-(pos-buf), "%s %d %s\r\n", PROTOCOL, status, title);
420 pos += snprintf(pos, sizeof(buf)-(pos-buf), "Server: %s\r\n", SERVER);
421
422 now = time(NULL);
423 strftime(timebuf, sizeof(timebuf), RFC1123FMT, gmtime(&now));
424 pos += snprintf(pos, sizeof(buf)-(pos-buf), "Date: %s\r\n", timebuf);
425
426 if (extra)
427 pos += snprintf(pos, sizeof(buf)-(pos-buf),"%s\r\n", extra);
428
429 if (mime)
430 pos += snprintf(pos, sizeof(buf)-(pos-buf),"Content-Type: %s\r\n", mime);
431
432 if(!cache){
433 pos += snprintf(pos, sizeof(buf)-(pos-buf),"Cache-Control: no-store, no-cache, must-revalidate\r\n");
434 pos += snprintf(pos, sizeof(buf)-(pos-buf),"Expires: Sat, 26 Jul 1997 05:00:00 GMT\r\n");
435 } else {
436 pos += snprintf(pos, sizeof(buf)-(pos-buf),"Cache-Control: public, max-age=7200\r\n");
437 }
438 pos += snprintf(pos, sizeof(buf)-(pos-buf),"Content-Length: %d\r\n", length);
439 pos += snprintf(pos, sizeof(buf)-(pos-buf),"Last-Modified: %s\r\n", timebuf);
440 pos += snprintf(pos, sizeof(buf)-(pos-buf), "Connection: close\r\n");
441 pos += snprintf(pos, sizeof(buf)-(pos-buf),"\r\n");
442 if(forcePlain == 1) fwrite(buf, 1, strlen(buf), f);
443 else webif_write(buf, f);
444}
445
446/*
447 * function for sending files.
448 */
449void send_file(FILE *f, char *filename){
450 int32_t fileno = 0;
451 char* mimetype = "";
452
453 if (!strcmp(filename, "CSS")){
454 filename = cfg.http_css;
455 mimetype = "text/css";
456 fileno = 1;
457 } else if (!strcmp(filename, "JS")){
458 filename = cfg.http_jscript;
459 mimetype = "text/javascript";
460 fileno = 2;
461 }
462
463 if(strlen(filename) > 0 && file_exists(filename) == 1){
464 FILE *fp;
465 char buffer[1024];
466 int32_t read;
467 struct stat st;
468
469 stat(filename, &st);
470 if((fp = fopen(filename, "r"))==NULL) return;
471 send_headers(f, 200, "OK", NULL, mimetype, 1, st.st_size, 0);
472 while((read = fread(buffer,sizeof(char), 1023, fp)) > 0) {
473 buffer[read] = '\0';
474 webif_write(buffer, f);
475 }
476
477 fclose (fp);
478 } else {
479 if (fileno == 1){
480 send_headers(f, 200, "OK", NULL, mimetype, 1, strlen(CSS), 0);
481 webif_write(CSS, f);
482 } else if (fileno == 2){
483 send_headers(f, 200, "OK", NULL, mimetype, 1, strlen(JSCRIPT), 0);
484 webif_write(JSCRIPT, f);
485 }
486 }
487}
488
489void send_error(FILE *f, int32_t status, char *title, char *extra, char *text, int8_t forcePlain){
490 char buf[(2* strlen(title)) + strlen(text) + 128];
491 char *pos = buf;
492 send_headers(f, status, title, extra, "text/html", 0, strlen(buf), forcePlain);
493 pos += snprintf(pos, sizeof(buf)-(pos-buf), "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\r\n", status, title);
494 pos += snprintf(pos, sizeof(buf)-(pos-buf), "<BODY><H4>%d %s</H4>\r\n", status, title);
495 pos += snprintf(pos, sizeof(buf)-(pos-buf), "%s\r\n", text);
496 pos += snprintf(pos, sizeof(buf)-(pos-buf), "</BODY></HTML>\r\n");
497 if(forcePlain == 1) fwrite(buf, 1, strlen(buf), f);
498 else webif_write(buf, f);
499}
500
501void send_error500(FILE *f){
502 send_error(f, 500, "Internal Server Error", NULL, "The server encountered an internal error that prevented it from fulfilling this request.", 0);
503}
504
505/* Helper function for urldecode.*/
506int32_t x2i(int32_t i){
507 i=toupper(i);
508 i = i - '0';
509 if(i > 9) i = i - 'A' + '9' + 1;
510 return i;
511}
512
513/* Decodes values in a http url. Note: The original value is modified! */
514void urldecode(char *s){
515 int32_t c, c1, n;
516 char *s0,*t;
517 t = s0 = s;
518 n = strlen(s);
519 while(n >0){
520 c = *s++;
521 if(c == '+') c = ' ';
522 else if(c == '%' && n > 2){
523 c = *s++;
524 c1 = c;
525 c = *s++;
526 c = 16*x2i(c1) + x2i(c);
527 n -= 2;
528 }
529 *t++ = c;
530 n--;
531 }
532 *t = 0;
533}
534
535/* Encode values in a http url. Do not call free() or realloc on the returned reference or you will get memory corruption! */
536char *urlencode(struct templatevars *vars, char *str){
537 char buf[strlen(str) * 3 + 1];
538 char *pstr = str, *pbuf = buf;
539 while (*pstr) {
540 if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~') *pbuf++ = *pstr;
541 else if (*pstr == ' ') *pbuf++ = '+';
542 else {
543 *pbuf++ = '%';
544 *pbuf++ = to_hex(*pstr >> 4);
545 *pbuf++ = to_hex(*pstr & 15);
546 }
547 ++pstr;
548 }
549 *pbuf = '\0';
550 /* Allocate the needed memory size and store it in the templatevars */
551 if(!cs_malloc(&pbuf, strlen(buf) + 1, -1)) return "";
552 memcpy(pbuf, buf, strlen(buf) + 1);
553 return tpl_addTmp(vars, pbuf);
554}
555
556/* XML-Escapes a char array. The returned reference will be automatically cleaned through the templatevars-mechanism tpl_clear().
557 Do not call free() or realloc on the returned reference or you will get memory corruption! */
558char *xml_encode(struct templatevars *vars, char *chartoencode) {
559 int32_t i, pos = 0, len = strlen(chartoencode);
560 char *result;
561 /* In worst case, every character could get converted to 6 chars (we only support ASCII, for Unicode it would be 7)*/
562 char encoded[len * 6 + 1], buffer[7];
563 for (i = 0; i < len; ++i){
564 switch(chartoencode[i]) {
565 case '&': memcpy(encoded + pos, "&amp;", 5); pos+=5; break;
566 case '<': memcpy(encoded + pos, "&lt;", 4); pos+=4; break;
567 case '>': memcpy(encoded + pos, "&gt;", 4); pos+=4; break;
568 case '"': memcpy(encoded + pos, "&quot;", 6); pos+=6; break;
569 case '\'': memcpy(encoded + pos, "&apos;", 6); pos+=6; break;
570
571 default:
572 if ( (unsigned int)chartoencode[i] < 32 || (unsigned int)chartoencode[i] > 127 ) {
573 snprintf(buffer, 7, "&#%d;", chartoencode[i] + 256);
574 memcpy(encoded + pos, buffer, strlen(buffer));
575 pos+=strlen(buffer);
576
577 } else {
578 encoded[pos] = chartoencode[i];
579 ++pos;
580 }
581
582 }
583 }
584 /* Allocate the needed memory size and store it in the templatevars */
585 if(!cs_malloc(&result, pos + 1, -1)) return "";
586 memcpy(result, encoded, pos);
587 result[pos] = '\0';
588 return tpl_addTmp(vars, result);
589}
590
591int32_t b64decode(unsigned char *result){
592 char inalphabet[256], decoder[256];
593 unsigned char alphabet[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
594 int32_t i, len = strlen((char *)result), j = 0, bits = 0, char_count = 0;
595
596 for (i = sizeof(alphabet) - 1; i >= 0; --i) {
597 inalphabet[alphabet[i]] = 1;
598 decoder[alphabet[i]] = i;
599 }
600 for(i = 0; i < len; ++i){
601 if (result[i] == '=') break;
602 if (!inalphabet[result[i]]) continue;
603 bits += decoder[result[i]];
604 ++char_count;
605 if (char_count == 4) {
606 result[j++] = bits >> 16;
607 result[j++] = (bits >> 8) & 0xff;
608 result[j++] = bits & 0xff;
609 bits = 0;
610 char_count = 0;
611 } else {
612 bits <<= 6;
613 }
614 }
615 if (i == len) {
616 if (char_count) {
617 result[j] = '\0';
618 return 0;
619 }
620 } else {
621 switch (char_count) {
622 case 1:
623 result[j] = '\0';
624 return 0;
625 case 2:
626 result[j++] = bits >> 10;
627 result[j] = '\0';
628 break;
629 case 3:
630 result[j++] = bits >> 16;
631 result[j++] = (bits >> 8) & 0xff;
632 result[j] = '\0';
633 break;
634 }
635 }
636 return j;
637}
638
639/* Format a seconds integer to hh:mm:ss or dd hh:mm:ss depending hrs >24 */
640char *sec2timeformat(struct templatevars *vars, int32_t seconds) {
641
642 char *value;
643 if(seconds <= 0)
644 return "00:00:00";
645
646 if(!cs_malloc(&value, 16 * sizeof(char), -1))
647 return "00:00:00";
648
649 int32_t secs = 0, fullmins = 0, mins = 0, fullhours = 0, hours = 0, days = 0;
650
651 secs = seconds % 60;
652 if (seconds > 60) {
653 fullmins = seconds / 60;
654 mins = fullmins % 60;
655 if(fullmins > 60) {
656 fullhours = fullmins / 60;
657 hours = fullhours % 24;
658 days = fullhours / 24;
659 }
660 }
661
662 if(days == 0)
663 snprintf(value, 16, "%02d:%02d:%02d", hours, mins, secs);
664 else
665 snprintf(value, 16, "%02dd %02d:%02d:%02d", days, hours, mins, secs);
666
667 return tpl_addTmp(vars, value);
668}
669
670/* Parse url parameters and save them to params array. The pch pointer is increased to the position where parsing stopped. */
671void parseParams(struct uriparams *params, char *pch) {
672 char *pch2;
673 // parsemode = 1 means parsing next param, parsemode = -1 parsing next
674 //value; pch2 points to the beginning of the currently parsed string, pch is the current position
675 int32_t parsemode = 1;
676
677 pch2=pch;
678 while(pch[0] != '\0') {
679 if((parsemode == 1 && pch[0] == '=') || (parsemode == -1 && pch[0] == '&')) {
680 pch[0] = '\0';
681 urldecode(pch2);
682 if(parsemode == 1) {
683 if(params->paramcount >= MAXGETPARAMS) break;
684 ++params->paramcount;
685 params->params[params->paramcount-1] = pch2;
686 } else {
687 params->values[params->paramcount-1] = pch2;
688 }
689 parsemode = -parsemode;
690 pch2 = pch + 1;
691 }
692 ++pch;
693 }
694 /* last value wasn't processed in the loop yet... */
695 if(parsemode == -1 && params->paramcount <= MAXGETPARAMS) {
696 urldecode(pch2);
697 params->values[params->paramcount-1] = pch2;
698 }
699}
700
701/* Returns the value of the parameter called name or an empty string if it doesn't exist. */
702char *getParam(struct uriparams *params, char *name){
703 int32_t i;
704 for(i=(*params).paramcount-1; i>=0; --i){
705 if(strcmp((*params).params[i], name) == 0) return (*params).values[i];
706 }
707 return "";
708}
709
710struct s_reader *get_reader_by_label(char *lbl){
711 struct s_reader *rdr;
712 LL_ITER *itr = ll_iter_create(configured_readers);
713 while((rdr = ll_iter_next(itr)))
714 if (strcmp(lbl, rdr->label) == 0) break;
715 ll_iter_release(itr);
716 return rdr;
717}
718
719struct s_client *get_client_by_name(char *name) {
720 struct s_client *cl;
721 for (cl = first_client; cl ; cl = cl->next) {
722 if (strcmp(name, cl->account->usr) == 0)
723 return cl;
724 }
725 return NULL;
726}
727
728struct s_auth *get_account_by_name(char *name) {
729 struct s_auth *account;
730 for (account=cfg.account; (account); account=account->next) {
731 if(strcmp(name, account->usr) == 0)
732 return account;
733 }
734 return NULL;
735}
736
737#ifdef WITH_SSL
738pthread_key_t getssl;
739SSL * cur_ssl(void){
740 return (SSL *) pthread_getspecific(getssl);
741}
742
743/* Locking functions for SSL multithreading */
744static pthread_mutex_t *lock_cs;
745struct CRYPTO_dynlock_value{
746 pthread_mutex_t mutex;
747};
748
749/* function really needs unsigned long to prevent compiler warnings... */
750unsigned long SSL_id_function(void){
751 return ((unsigned long) pthread_self());
752}
753
754void SSL_locking_function(int32_t mode, int32_t type, const char *file, int32_t line){
755 if (mode & CRYPTO_LOCK) {
756 pthread_mutex_lock(&lock_cs[type]);
757 } else {
758 pthread_mutex_unlock(&lock_cs[type]);
759 }
760 // just to remove compiler warnings...
761 if(file || line) return;
762}
763
764struct CRYPTO_dynlock_value *SSL_dyn_create_function(const char *file, int32_t line){
765 struct CRYPTO_dynlock_value *l;
766 if(!cs_malloc(&l, sizeof(struct CRYPTO_dynlock_value), -1)) return (NULL);
767 if(pthread_mutex_init(&l->mutex, NULL)) {
768 // Initialization of mutex failed.
769 free(l);
770 return (NULL);
771 }
772 pthread_mutex_init(&l->mutex, NULL);
773 // just to remove compiler warnings...
774 if(file || line) return l;
775 return l;
776}
777
778void SSL_dyn_lock_function(int32_t mode, struct CRYPTO_dynlock_value *l, const char *file, int32_t line){
779 if (mode & CRYPTO_LOCK) {
780 pthread_mutex_lock(&l->mutex);
781 } else {
782 pthread_mutex_unlock(&l->mutex);
783 }
784 // just to remove compiler warnings...
785 if(file || line) return;
786}
787
788void SSL_dyn_destroy_function(struct CRYPTO_dynlock_value *l, const char *file, int32_t line){
789 pthread_mutex_destroy(&l->mutex);
790 free(l);
791 // just to remove compiler warnings...
792 if(file || line) return;
793}
794
795/* Init necessary structures for SSL in WebIf*/
796SSL_CTX *SSL_Webif_Init() {
797 SSL_library_init();
798 SSL_load_error_strings();
799 ERR_load_BIO_strings();
800 ERR_load_SSL_strings();
801
802 SSL_METHOD *meth;
803 SSL_CTX *ctx;
804
805 static const char *cs_cert="oscam.pem";
806
807 // set locking callbacks for SSL
808 int32_t i, num = CRYPTO_num_locks();
809 lock_cs = (pthread_mutex_t*) OPENSSL_malloc(num * sizeof(pthread_mutex_t));
810
811 for (i = 0; i < num; ++i) {
812 if(pthread_mutex_init(&lock_cs[i], NULL)){
813 while(--i > 0){
814 pthread_mutex_destroy(&lock_cs[i]);
815 --i;
816 }
817 free(lock_cs);
818 return NULL;
819 };
820 }
821 /* static lock callbacks */
822 CRYPTO_set_id_callback(SSL_id_function);
823 CRYPTO_set_locking_callback(SSL_locking_function);
824 /* dynamic lock callbacks */
825 CRYPTO_set_dynlock_create_callback(SSL_dyn_create_function);
826 CRYPTO_set_dynlock_lock_callback(SSL_dyn_lock_function);
827 CRYPTO_set_dynlock_destroy_callback(SSL_dyn_destroy_function);
828
829 meth = SSLv23_server_method();
830
831 ctx = SSL_CTX_new(meth);
832
833 char path[128];
834
835 if (cfg.http_cert[0]==0)
836 snprintf(path, sizeof(path), "%s%s", cs_confdir, cs_cert);
837 else
838 cs_strncpy(path, cfg.http_cert, sizeof(path));
839
840 if (!ctx) {
841 ERR_print_errors_fp(stderr);
842 return NULL;
843 }
844
845 if (SSL_CTX_use_certificate_file(ctx, path, SSL_FILETYPE_PEM) <= 0) {
846 ERR_print_errors_fp(stderr);
847 return NULL;
848 }
849
850 if (SSL_CTX_use_PrivateKey_file(ctx, path, SSL_FILETYPE_PEM) <= 0) {
851 ERR_print_errors_fp(stderr);
852 return NULL;
853 }
854
855 if (!SSL_CTX_check_private_key(ctx)) {
856 cs_log("SSL: Private key does not match the certificate public key");
857 return NULL;
858 }
859 cs_log("load ssl certificate file %s", path);
860 return ctx;
861}
862#endif
863#endif
Note: See TracBrowser for help on using the repository browser.