source: trunk/module-webif-lib.c@ 8436

Last change on this file since 8436 was 8436, checked in by gf, 9 years ago

webif: Simplify template loading and checking.

The subdir logic seems to complicate the code for no good reason and
as far as I can work out it does nothing. It looks like a leftover
that can be removed.

  • Property svn:eol-style set to LF
File size: 21.2 KB
Line 
1#include "globals.h"
2
3#ifdef WEBIF
4#include "cscrypt/md5.h"
5#include "module-webif-lib.h"
6#include "module-webif-tpl.h"
7#include "oscam-config.h"
8#include "oscam-files.h"
9#include "oscam-lock.h"
10#include "oscam-string.h"
11#include "oscam-time.h"
12#include "oscam-net.h"
13
14extern int32_t ssl_active;
15extern pthread_key_t getkeepalive;
16extern pthread_key_t getssl;
17extern CS_MUTEX_LOCK *lock_cs;
18extern char noncekey[33];
19
20static int8_t b64decoder[256];
21struct s_nonce *nonce_first[AUTHNONCEHASHBUCKETS];
22CS_MUTEX_LOCK nonce_lock[AUTHNONCEHASHBUCKETS];
23
24/* Parses a value in an authentication string by removing all quotes/whitespace. Note that the original array is modified. */
25static char *parse_auth_value(char *value){
26 char *pch = value;
27 char *pch2;
28 value = strstr(value, "=");
29 if(value != NULL){
30 do{
31 ++value;
32 } while (value[0] == ' ' || value[0] == '"');
33 pch = value;
34 for(pch2 = value + strlen(value) - 1; pch2 >= value && (pch2[0] == ' ' || pch2[0] == '"' || pch2[0] == '\r' || pch2[0] == '\n'); --pch2) pch2[0] = '\0';
35 }
36 return pch;
37}
38
39/* Parses the date out of a "If-Modified-Since"-header. Note that the original string is modified. */
40time_t parse_modifiedsince(char * value){
41 int32_t day = -1, month = -1, year = -1, hour = -1, minutes = -1, seconds = -1;
42 char months[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
43 char *str, *saveptr1 = NULL;
44 time_t modifiedheader = 0;
45 value += 18;
46 // Parse over weekday at beginning...
47 while(value[0] == ' ' && value[0] != '\0') ++value;
48 while(value[0] != ' ' && value[0] != '\0') ++value;
49 // According to http://www.w3.org/Protocols/rfc2616/rfc2616-sec3.html#sec3.3.1 three different timeformats are allowed so we need a bit logic to parse all of them...
50 if(value[0] != '\0'){
51 ++value;
52 for(month = 0; month < 12; ++month){
53 if(strstr(value, months[month])) break;
54 }
55 if(month > 11) month = -1;
56 for (str=strtok_r(value, " ", &saveptr1); str; str=strtok_r(NULL, " ", &saveptr1)){
57 switch(strlen(str)){
58 case 1:
59 case 2:
60 day = atoi(str);
61 break;
62
63 case 4:
64 if(str[0] != 'G')
65 year = atoi(str);
66 break;
67
68 case 8:
69 if(str[2] == ':' && str[5] == ':'){
70 hour = atoi(str);
71 minutes = atoi(str + 3);
72 seconds = atoi(str + 6);
73 }
74 break;
75
76 case 9:
77 if(str[2] == '-' && str[6] == '-'){
78 day = atoi(str);
79 year = atoi(str + 7) + 2000;
80 }
81 break;
82 }
83 }
84 if(day > 0 && day < 32 && month > 0 && year > 0 && year < 9999 && hour > -1 && hour < 24 && minutes > -1 && minutes < 60 && seconds > -1 && seconds < 60){
85 struct tm timeinfo;
86 memset(&timeinfo, 0, sizeof(timeinfo));
87 timeinfo.tm_mday = day;
88 timeinfo.tm_mon = month;
89 timeinfo.tm_year = year - 1900;
90 timeinfo.tm_hour = hour;
91 timeinfo.tm_min = minutes;
92 timeinfo.tm_sec = seconds;
93 modifiedheader = cs_timegm(&timeinfo);
94 }
95 }
96 return modifiedheader;
97}
98
99/* Calculates a new opaque value. Please note that opaque needs to be at least (MD5_DIGEST_LENGTH * 2) + 1 large. */
100void calculate_opaque(IN_ADDR_T addr, char *opaque){
101 char noncetmp[128];
102 unsigned char md5tmp[MD5_DIGEST_LENGTH];
103 snprintf(noncetmp, sizeof(noncetmp), "%d:%s:%d", (int32_t)time((time_t)0), cs_inet_ntoa(addr), (int16_t)rand());
104 char_to_hex(MD5((unsigned char*)noncetmp, strlen(noncetmp), md5tmp), MD5_DIGEST_LENGTH, (unsigned char*)opaque);
105}
106
107void init_noncelocks(void){
108 int32_t i;
109 for(i = 0; i < AUTHNONCEHASHBUCKETS; ++i){
110 cs_lock_create(&nonce_lock[i], 5, "nonce_lock");
111 nonce_first[i] = NULL;
112 }
113}
114
115/* Calculates the currently valid nonce value and copies it to result. Please note that nonce (may be NULL), opaque and result needs to be at least (MD5_DIGEST_LENGTH * 2) + 1 large. */
116void calculate_nonce(char *nonce, char *result, char *opaque){
117 struct s_nonce *noncelist, *prev, *foundnonce = NULL, *foundopaque = NULL, *foundexpired = NULL;
118 int32_t bucket = opaque[0] % AUTHNONCEHASHBUCKETS;
119 time_t now = time((time_t)0);
120 cs_writelock(&nonce_lock[bucket]);
121 for(noncelist = nonce_first[bucket], prev = NULL; noncelist; prev = noncelist, noncelist = noncelist->next){
122 if(now > noncelist->expirationdate){
123 if(prev) prev->next = NULL;
124 else {
125 nonce_first[bucket] = NULL;
126 }
127 foundexpired = noncelist;
128 break;
129 }
130 if(nonce && !memcmp(noncelist->nonce, nonce, (MD5_DIGEST_LENGTH * 2) + 1)) {
131 memcpy(result, noncelist->nonce, (MD5_DIGEST_LENGTH * 2) + 1);
132 foundnonce = noncelist;
133 if(!noncelist->firstuse) noncelist->firstuse = now;
134 else if(now - foundnonce->firstuse > AUTHNONCEVALIDSECS){
135 if(prev) prev->next = noncelist->next;
136 else {
137 nonce_first[bucket] = noncelist->next;
138 }
139 }
140 break;
141 } else if (!noncelist->firstuse && !memcmp(noncelist->opaque, opaque, (MD5_DIGEST_LENGTH * 2) + 1)){
142 foundopaque = noncelist;
143 }
144 }
145 if(foundnonce && now - foundnonce->firstuse > AUTHNONCEVALIDSECS){
146 free(foundnonce);
147 foundnonce = NULL;
148 }
149 if(!foundnonce && foundopaque)
150 memcpy(result, foundopaque->nonce, (MD5_DIGEST_LENGTH * 2) + 1);
151 if(!foundnonce && !foundopaque){
152 char noncetmp[128], randstr[16];
153 unsigned char md5tmp[MD5_DIGEST_LENGTH];
154 get_random_bytes((uint8_t*)randstr, sizeof(randstr)-1);
155 randstr[sizeof(randstr)-1] = '\0';
156 snprintf(noncetmp, sizeof(noncetmp), "%d:%s:%s", (int32_t)now, randstr, noncekey);
157 char_to_hex(MD5((unsigned char*)noncetmp, strlen(noncetmp), md5tmp), MD5_DIGEST_LENGTH, (unsigned char*)result);
158 if(cs_malloc(&noncelist, sizeof(struct s_nonce))){
159 noncelist->expirationdate = now + AUTHNONCEEXPIRATION;
160 memcpy(noncelist->nonce, result, (MD5_DIGEST_LENGTH * 2) + 1);
161 memcpy(noncelist->opaque, opaque, (MD5_DIGEST_LENGTH * 2) + 1);
162 noncelist->next = nonce_first[bucket];
163 nonce_first[bucket] = noncelist;
164 }
165 }
166 cs_writeunlock(&nonce_lock[bucket]);
167 while(foundexpired){
168 prev = foundexpired;
169 foundexpired = foundexpired->next;
170 free(prev);
171 }
172}
173
174/* Checks if authentication is correct. Returns -1 if not correct, 1 if correct and 2 if nonce isn't valid anymore.
175 Note that authstring will be modified. */
176int32_t check_auth(char *authstring, char *method, char *path, IN_ADDR_T addr, char *expectednonce, char *opaque){
177 int32_t authok = 0, uriok = 0;
178 char authnonce[(MD5_DIGEST_LENGTH * 2) + 1];
179 memset(authnonce, 0, sizeof(authnonce));
180 char *authnc = "";
181 char *authcnonce = "";
182 char *authresponse = "";
183 char *uri = "";
184 char *username = "";
185 char *expectedPassword = cfg.http_pwd;
186 char *pch = authstring + 22;
187 char *pch2;
188 char *saveptr1=NULL;
189 memset(opaque, 0, (MD5_DIGEST_LENGTH * 2) + 1);
190
191 for(pch = strtok_r (pch, ",", &saveptr1); pch; pch = strtok_r (NULL, ",", &saveptr1)){
192 pch2 = pch;
193 while(pch2[0] == ' ' && pch2[0] != '\0') ++pch2;
194 if(strncmp(pch2, "nonce", 5) == 0){
195 cs_strncpy(authnonce, parse_auth_value(pch2), sizeof(authnonce));
196 } else if (strncmp(pch2, "nc", 2) == 0){
197 authnc=parse_auth_value(pch2);
198 } else if (strncmp(pch2, "cnonce", 6) == 0){
199 authcnonce=parse_auth_value(pch2);
200 } else if (strncmp(pch2, "response", 8) == 0){
201 authresponse=parse_auth_value(pch2);
202 } else if (strncmp(pch2, "uri", 3) == 0){
203 uri=parse_auth_value(pch2);
204 } else if (strncmp(pch2, "username", 8) == 0){
205 username=parse_auth_value(pch2);
206 } else if (strncmp(pch2, "opaque", 6) == 0){
207 char *tmp=parse_auth_value(pch2);
208 cs_strncpy(opaque, tmp, (MD5_DIGEST_LENGTH * 2) + 1);
209 }
210 }
211
212 if(strncmp(uri, path, strlen(path)) == 0) uriok = 1;
213 else {
214 pch2 = uri;
215 for(pch = uri; pch[0] != '\0'; ++pch) {
216 if(pch[0] == '/') pch2 = pch;
217 if(strncmp(pch2, path, strlen(path)) == 0) uriok = 1;
218 }
219 }
220 if (uriok == 1 && streq(username, cfg.http_user)) {
221 char A1tmp[3 + strlen(username) + strlen(AUTHREALM) + strlen(expectedPassword)];
222 char A1[(MD5_DIGEST_LENGTH * 2) + 1], A2[(MD5_DIGEST_LENGTH * 2) + 1], A3[(MD5_DIGEST_LENGTH * 2) + 1];
223 unsigned char md5tmp[MD5_DIGEST_LENGTH];
224 snprintf(A1tmp, sizeof(A1tmp), "%s:%s:%s", username, AUTHREALM, expectedPassword);
225 char_to_hex(MD5((unsigned char*)A1tmp, strlen(A1tmp), md5tmp), MD5_DIGEST_LENGTH, (unsigned char*)A1);
226
227 char A2tmp[2 + strlen(method) + strlen(uri)];
228 snprintf(A2tmp, sizeof(A2tmp), "%s:%s", method, uri);
229 char_to_hex(MD5((unsigned char*)A2tmp, strlen(A2tmp), md5tmp), MD5_DIGEST_LENGTH, (unsigned char*)A2);
230
231 char A3tmp[10 + strlen(A1) + strlen(A2) + strlen(authnonce) + strlen(authnc) + strlen(authcnonce)];
232 snprintf(A3tmp, sizeof(A3tmp), "%s:%s:%s:%s:auth:%s", A1, authnonce, authnc, authcnonce, A2);
233 char_to_hex(MD5((unsigned char*)A3tmp, strlen(A3tmp), md5tmp), MD5_DIGEST_LENGTH, (unsigned char*)A3);
234
235 if(strcmp(A3, authresponse) == 0) {
236 if(strlen(opaque) != MD5_DIGEST_LENGTH*2) calculate_opaque(addr, opaque);
237 calculate_nonce(authnonce, expectednonce, opaque);
238 if(strcmp(expectednonce, authnonce) == 0) authok = 1;
239 else {
240 authok = 2;
241 cs_debug_mask(D_TRACE, "WebIf: Received stale header from %s (nonce=%s, expectednonce=%s, opaque=%s).", cs_inet_ntoa(addr), authnonce, expectednonce, opaque);
242 }
243 }
244 }
245 return authok;
246}
247
248int32_t webif_write_raw(char *buf, FILE* f, int32_t len) {
249 errno=0;
250#ifdef WITH_SSL
251 if (ssl_active) {
252 return SSL_write((SSL*)f, buf, len);
253 } else
254#endif
255 return fwrite(buf, 1, len, f);
256}
257
258int32_t webif_write(char *buf, FILE* f) {
259 return webif_write_raw(buf, f, strlen(buf));
260}
261
262int32_t webif_read(char *buf, int32_t num, FILE *f) {
263 errno=0;
264#ifdef WITH_SSL
265 if (ssl_active) {
266 return SSL_read((SSL*)f, buf, num);
267 } else
268#endif
269 return read(fileno(f), buf, num);
270}
271
272void send_headers(FILE *f, int32_t status, char *title, char *extra, char *mime, int32_t cache, int32_t length, char *content, int8_t forcePlain){
273 time_t now;
274 char timebuf[32];
275 char buf[sizeof(PROTOCOL) + sizeof(SERVER) + strlen(title) + (extra == NULL?0:strlen(extra)+2) + (mime == NULL?0:strlen(mime)+2) + 350];
276 char *pos = buf;
277 struct tm timeinfo;
278
279 pos += snprintf(pos, sizeof(buf)-(pos-buf), "%s %d %s\r\n", PROTOCOL, status, title);
280 pos += snprintf(pos, sizeof(buf)-(pos-buf), "Server: %s\r\n", SERVER);
281
282 now = time(NULL);
283 cs_gmtime_r(&now, &timeinfo);
284 strftime(timebuf, sizeof(timebuf), RFC1123FMT, &timeinfo);
285 pos += snprintf(pos, sizeof(buf)-(pos-buf), "Date: %s\r\n", timebuf);
286
287 if (extra)
288 pos += snprintf(pos, sizeof(buf)-(pos-buf),"%s\r\n", extra);
289
290 if (mime)
291 pos += snprintf(pos, sizeof(buf)-(pos-buf),"Content-Type: %s\r\n", mime);
292
293 if(status != 304){
294 if(!cache){
295 pos += snprintf(pos, sizeof(buf)-(pos-buf),"Cache-Control: no-store, no-cache, must-revalidate\r\n");
296 pos += snprintf(pos, sizeof(buf)-(pos-buf),"Expires: Sat, 10 Jan 2000 05:00:00 GMT\r\n");
297 } else {
298 pos += snprintf(pos, sizeof(buf)-(pos-buf),"Cache-Control: public, max-age=7200\r\n");
299 }
300 pos += snprintf(pos, sizeof(buf)-(pos-buf),"Content-Length: %d\r\n", length);
301 pos += snprintf(pos, sizeof(buf)-(pos-buf),"Last-Modified: %s\r\n", timebuf);
302 if(content){
303 uint32_t checksum = (uint32_t)crc32(0L, (uchar *)content, length);
304 pos += snprintf(pos, sizeof(buf)-(pos-buf),"ETag: \"%u\"\r\n", checksum==0?1:checksum);
305 }
306 }
307 if(*(int8_t *)pthread_getspecific(getkeepalive))
308 pos += snprintf(pos, sizeof(buf)-(pos-buf), "Connection: Keep-Alive\r\n");
309 else
310 pos += snprintf(pos, sizeof(buf)-(pos-buf), "Connection: close\r\n");
311 pos += snprintf(pos, sizeof(buf)-(pos-buf),"\r\n");
312 if(forcePlain == 1) fwrite(buf, 1, strlen(buf), f);
313 else webif_write(buf, f);
314}
315
316void send_error(FILE *f, int32_t status, char *title, char *extra, char *text, int8_t forcePlain){
317 char buf[(2* strlen(title)) + strlen(text) + 128];
318 char *pos = buf;
319 pos += snprintf(pos, sizeof(buf)-(pos-buf), "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\r\n", status, title);
320 pos += snprintf(pos, sizeof(buf)-(pos-buf), "<BODY><H4>%d %s</H4>\r\n", status, title);
321 pos += snprintf(pos, sizeof(buf)-(pos-buf), "%s\r\n", text);
322 pos += snprintf(pos, sizeof(buf)-(pos-buf), "</BODY></HTML>\r\n");
323 send_headers(f, status, title, extra, "text/html", 0, strlen(buf), NULL, forcePlain);
324 if(forcePlain == 1) fwrite(buf, 1, strlen(buf), f);
325 else webif_write(buf, f);
326}
327
328void send_error500(FILE *f){
329 send_error(f, 500, "Internal Server Error", NULL, "The server encountered an internal error that prevented it from fulfilling this request.", 0);
330}
331
332void send_header304(FILE *f, char *extraheader){
333 send_headers(f, 304, "Not Modified", extraheader, NULL, 1, 0, NULL, 0);
334}
335
336/*
337 * function for sending files.
338 */
339void send_file(FILE *f, char *filename, char* subdir, time_t modifiedheader, uint32_t etagheader, char *extraheader){
340 int8_t filen = 0;
341 int32_t size = 0;
342 char* mimetype = "", *result = " ", *allocated = NULL;
343 time_t moddate;
344 char path[255];
345 char* CSS = NULL;
346 char* JSCRIPT = NULL;
347 char* TOUCH_CSS = NULL;
348 char* TOUCH_JSCRIPT = NULL;
349
350 if (!strcmp(filename, "CSS")){
351 filename = cfg.http_css ? cfg.http_css : "";
352 if (subdir && strlen(subdir) > 0) {
353 filename = tpl_getFilePathInSubdir(cfg.http_tpl ? cfg.http_tpl : "", subdir, "site", ".css", path, 255);
354 }
355 mimetype = "text/css";
356 filen = 1;
357 } else if (!strcmp(filename, "JS")){
358 filename = cfg.http_jscript ? cfg.http_jscript : "";
359 if (subdir && strlen(subdir) > 0) {
360 filename = tpl_getFilePathInSubdir(cfg.http_tpl ? cfg.http_tpl : "", subdir, "oscam", ".js", path, 255);
361 }
362 mimetype = "text/javascript";
363 filen = 2;
364 }
365
366 if (strlen(filename) > 0 && file_exists(filename)) {
367 struct stat st;
368 stat(filename, &st);
369 moddate = st.st_mtime;
370 // We need at least size 1 or keepalive gets problems on some browsers...
371 if(st.st_size > 0){
372 FILE *fp;
373 int32_t readen;
374 if((fp = fopen(filename, "r"))==NULL) return;
375 if (!cs_malloc(&allocated, st.st_size + 1)) {
376 send_error500(f);
377 fclose(fp);
378 return;
379 }
380 if((readen = fread(allocated, 1, st.st_size, fp)) == st.st_size){
381 allocated[readen] = '\0';
382 }
383 fclose(fp);
384 }
385
386 if (filen == 1 && cfg.http_prepend_embedded_css) { // Prepend Embedded CSS
387 char* separator = "/* External CSS */";
388 char* oldallocated = allocated;
389 CSS = tpl_getUnparsedTpl("CSS");
390 int32_t newsize = strlen(CSS) + strlen(separator) + 2;
391 if (oldallocated) newsize += strlen(oldallocated) + 1;
392 if (!cs_malloc(&allocated, newsize)) {
393 if (oldallocated) free(oldallocated);
394 free(CSS);
395 send_error500(f);
396 return;
397 }
398 snprintf(allocated, newsize, "%s\n%s\n%s",
399 CSS, separator, (oldallocated != NULL ? oldallocated : ""));
400 if (oldallocated) free(oldallocated);
401 }
402
403 if (allocated) result = allocated;
404
405 } else {
406 CSS = tpl_getUnparsedTpl("CSS");
407 JSCRIPT = tpl_getUnparsedTpl("JSCRIPT");
408#ifdef TOUCH
409 TOUCH_CSS = tpl_getUnparsedTpl("TOUCH_CSS");
410 TOUCH_JSCRIPT = tpl_getUnparsedTpl("TOUCH_JSCRIPT");
411 char* res_tpl = !subdir || strcmp(subdir, TOUCH_SUBDIR)
412 ? (filen == 1 ? CSS : JSCRIPT)
413 : (filen == 1 ? TOUCH_CSS : TOUCH_JSCRIPT);
414 if (strlen(res_tpl) > 0) result = res_tpl;
415#else
416 if (filen == 1 && strlen(CSS) > 0){
417 result = CSS;
418 } else if (filen == 2 && strlen(JSCRIPT) > 0){
419 result = JSCRIPT;
420 }
421#endif
422 moddate = first_client->login;
423 }
424
425 size = strlen(result);
426
427 if((etagheader == 0 && moddate < modifiedheader) || (etagheader > 0 && (uint32_t)crc32(0L, (uchar *)result, size) == etagheader)){
428 send_header304(f, extraheader);
429 } else {
430 send_headers(f, 200, "OK", NULL, mimetype, 1, size, result, 0);
431 webif_write(result, f);
432 }
433 if (allocated) free(allocated);
434 free(CSS);
435 free(JSCRIPT);
436 free(TOUCH_CSS);
437 free(TOUCH_JSCRIPT);
438}
439
440/* Prepares the base64 decoding array */
441void b64prepare(void) {
442 const unsigned char alphabet[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
443 int32_t i;
444 for (i = sizeof(b64decoder) - 1; i >= 0; --i) {
445 b64decoder[i] = -1;
446 }
447
448 for (i = sizeof(alphabet) - 1; i >= 0; --i) {
449 b64decoder[alphabet[i]] = i;
450 }
451}
452
453/* Decodes a base64-encoded string. The given array will be used directly for output and is thus modified! */
454int32_t b64decode(unsigned char *result){
455 int32_t i, len = strlen((char *)result), j = 0, bits = 0, char_count = 0;
456
457 for(i = 0; i < len; ++i){
458 if (result[i] == '=') break;
459 int8_t tmp = b64decoder[result[i]];
460 if(tmp == -1) continue;
461 bits += tmp;
462 ++char_count;
463 if (char_count == 4) {
464 result[j++] = bits >> 16;
465 result[j++] = (bits >> 8) & 0xff;
466 result[j++] = bits & 0xff;
467 bits = 0;
468 char_count = 0;
469 } else {
470 bits <<= 6;
471 }
472 }
473 if (i == len) {
474 if (char_count) {
475 result[j] = '\0';
476 return 0;
477 }
478 } else {
479 switch (char_count) {
480 case 1:
481 result[j] = '\0';
482 return 0;
483 case 2:
484 result[j++] = bits >> 10;
485 result[j] = '\0';
486 break;
487 case 3:
488 result[j++] = bits >> 16;
489 result[j++] = (bits >> 8) & 0xff;
490 result[j] = '\0';
491 break;
492 }
493 }
494 return j;
495}
496
497/* Parse url parameters and save them to params array. The pch pointer is increased to the position where parsing stopped. */
498void parseParams(struct uriparams *params, char *pch) {
499 char *pch2;
500 // parsemode = 1 means parsing next param, parsemode = -1 parsing next
501 //value; pch2 points to the beginning of the currently parsed string, pch is the current position
502 int32_t parsemode = 1;
503
504 pch2=pch;
505 while(pch[0] != '\0') {
506 if((parsemode == 1 && pch[0] == '=') || (parsemode == -1 && pch[0] == '&')) {
507 pch[0] = '\0';
508 urldecode(pch2);
509 if(parsemode == 1) {
510 if(params->paramcount >= MAXGETPARAMS) break;
511 ++params->paramcount;
512 params->params[params->paramcount-1] = pch2;
513 } else {
514 params->values[params->paramcount-1] = pch2;
515 }
516 parsemode = -parsemode;
517 pch2 = pch + 1;
518 }
519 ++pch;
520 }
521 /* last value wasn't processed in the loop yet... */
522 if(parsemode == -1 && params->paramcount <= MAXGETPARAMS) {
523 urldecode(pch2);
524 params->values[params->paramcount-1] = pch2;
525 }
526}
527
528/* Returns the value of the parameter called name or an empty string if it doesn't exist. */
529char *getParam(struct uriparams *params, char *name){
530 int32_t i;
531 for(i=(*params).paramcount-1; i>=0; --i){
532 if(strcmp((*params).params[i], name) == 0) return (*params).values[i];
533 }
534 return "";
535}
536
537
538#ifdef WITH_SSL
539SSL * cur_ssl(void){
540 return (SSL *) pthread_getspecific(getssl);
541}
542
543/* Locking functions for SSL multithreading */
544struct CRYPTO_dynlock_value{
545 pthread_mutex_t mutex;
546};
547
548/* function really needs unsigned long to prevent compiler warnings... */
549static unsigned long SSL_id_function(void){
550 return ((unsigned long) pthread_self());
551}
552
553static void SSL_locking_function(int32_t mode, int32_t type, const char *file, int32_t line) {
554 if (mode & CRYPTO_LOCK) {
555 cs_writelock(&lock_cs[type]);
556 } else {
557 cs_writeunlock(&lock_cs[type]);
558 }
559 // just to remove compiler warnings...
560 if(file || line) return;
561}
562
563static struct CRYPTO_dynlock_value *SSL_dyn_create_function(const char *file, int32_t line) {
564 struct CRYPTO_dynlock_value *l;
565 if (!cs_malloc(&l, sizeof(struct CRYPTO_dynlock_value)))
566 return NULL;
567
568 if(pthread_mutex_init(&l->mutex, NULL)) {
569 // Initialization of mutex failed.
570 free(l);
571 return (NULL);
572 }
573 pthread_mutex_init(&l->mutex, NULL);
574 // just to remove compiler warnings...
575 if(file || line) return l;
576 return l;
577}
578
579static void SSL_dyn_lock_function(int32_t mode, struct CRYPTO_dynlock_value *l, const char *file, int32_t line) {
580 if (mode & CRYPTO_LOCK) {
581 pthread_mutex_lock(&l->mutex);
582 } else {
583 pthread_mutex_unlock(&l->mutex);
584 }
585 // just to remove compiler warnings...
586 if(file || line) return;
587}
588
589static void SSL_dyn_destroy_function(struct CRYPTO_dynlock_value *l, const char *file, int32_t line) {
590 pthread_mutex_destroy(&l->mutex);
591 free(l);
592 // just to remove compiler warnings...
593 if(file || line) return;
594}
595
596/* Init necessary structures for SSL in WebIf*/
597SSL_CTX *SSL_Webif_Init(void) {
598 SSL_library_init();
599 SSL_load_error_strings();
600 ERR_load_BIO_strings();
601 ERR_load_SSL_strings();
602
603 SSL_CTX *ctx;
604
605 static const char *cs_cert="oscam.pem";
606
607 if (pthread_key_create(&getssl, NULL)) {
608 cs_log("Could not create getssl");
609 }
610
611 // set locking callbacks for SSL
612 int32_t i, num = CRYPTO_num_locks();
613 lock_cs = (CS_MUTEX_LOCK*) OPENSSL_malloc(num * sizeof(CS_MUTEX_LOCK));
614
615 for (i = 0; i < num; ++i) {
616 cs_lock_create(&lock_cs[i], 10, "ssl_lock_cs");
617 }
618 /* static lock callbacks */
619 CRYPTO_set_id_callback(SSL_id_function);
620 CRYPTO_set_locking_callback(SSL_locking_function);
621 /* dynamic lock callbacks */
622 CRYPTO_set_dynlock_create_callback(SSL_dyn_create_function);
623 CRYPTO_set_dynlock_lock_callback(SSL_dyn_lock_function);
624 CRYPTO_set_dynlock_destroy_callback(SSL_dyn_destroy_function);
625
626 if(cfg.http_force_sslv3){
627 ctx = SSL_CTX_new(SSLv3_server_method());
628 #ifdef SSL_CTX_clear_options
629 SSL_CTX_clear_options(ctx, SSL_OP_ALL); //we CLEAR all bug workarounds! This is for security reason
630 #else
631 cs_log("WARNING: You enabled to force sslv3 but your system does not support to clear the ssl workarounds! SSL security will be reduced!");
632 #endif
633 SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2); // we force SSL v3 !
634 SSL_CTX_set_cipher_list(ctx, SSL_TXT_RC4);
635 } else
636 ctx = SSL_CTX_new(SSLv23_server_method());
637
638 char path[128];
639
640 if (!cfg.http_cert)
641 get_config_filename(path, sizeof(path), cs_cert);
642 else
643 cs_strncpy(path, cfg.http_cert, sizeof(path));
644
645 if (!ctx) {
646 ERR_print_errors_fp(stderr);
647 return NULL;
648 }
649
650 if (SSL_CTX_use_certificate_file(ctx, path, SSL_FILETYPE_PEM) <= 0) {
651 ERR_print_errors_fp(stderr);
652 return NULL;
653 }
654
655 if (SSL_CTX_use_PrivateKey_file(ctx, path, SSL_FILETYPE_PEM) <= 0) {
656 ERR_print_errors_fp(stderr);
657 return NULL;
658 }
659
660 if (!SSL_CTX_check_private_key(ctx)) {
661 cs_log("SSL: Private key does not match the certificate public key");
662 return NULL;
663 }
664 cs_log("load ssl certificate file %s", path);
665 return ctx;
666}
667#endif
668
669#endif
Note: See TracBrowser for help on using the repository browser.