1 | //FIXME Not checked on threadsafety yet; after checking please remove this line
|
---|
2 | #include "globals.h"
|
---|
3 | #ifdef WEBIF
|
---|
4 |
|
---|
5 | #include "module-webif-lib.h"
|
---|
6 | #include "module-webif-pages.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 |
|
---|
14 | extern uint8_t cs_http_use_utf8;
|
---|
15 |
|
---|
16 | extern const char *templates[][3];
|
---|
17 | extern char *JSCRIPT;
|
---|
18 | extern char *CSS;
|
---|
19 |
|
---|
20 | #ifdef TOUCH
|
---|
21 | #define TOUCH_SUBDIR "touch/"
|
---|
22 | extern char *TOUCH_JSCRIPT;
|
---|
23 | extern char *TOUCH_CSS;
|
---|
24 | extern char *TOUCH_TPLSTATUS;
|
---|
25 | #endif
|
---|
26 |
|
---|
27 | extern int32_t ssl_active;
|
---|
28 | extern pthread_key_t getkeepalive;
|
---|
29 | extern pthread_key_t getssl;
|
---|
30 | extern CS_MUTEX_LOCK *lock_cs;
|
---|
31 | extern char noncekey[33];
|
---|
32 |
|
---|
33 | static int8_t b64decoder[256];
|
---|
34 | static int8_t *tplchksum;
|
---|
35 | struct s_nonce *nonce_first[AUTHNONCEHASHBUCKETS];
|
---|
36 | CS_MUTEX_LOCK nonce_lock[AUTHNONCEHASHBUCKETS];
|
---|
37 |
|
---|
38 | /* Adds a name->value-mapping or appends to it. You will get a reference back which you may freely
|
---|
39 | use (but you should not call free/realloc on this!)*/
|
---|
40 | char *tpl_addVar(struct templatevars *vars, uint8_t addmode, char *name, char *value){
|
---|
41 | if(name == NULL) return "";
|
---|
42 | if(value == NULL) value = "";
|
---|
43 | int32_t i;
|
---|
44 | char *tmp = NULL, *result = NULL;
|
---|
45 | for(i = (*vars).varscnt-1; i >= 0; --i){
|
---|
46 | if(strcmp((*vars).names[i], name) == 0){
|
---|
47 | result = (*vars).values[i];
|
---|
48 | break;
|
---|
49 | }
|
---|
50 | }
|
---|
51 | if(result == NULL){
|
---|
52 | if((*vars).varsalloc <= (*vars).varscnt){
|
---|
53 | if (!cs_realloc(&(*vars).names, (*vars).varsalloc * 2 * sizeof(char**))) return "";
|
---|
54 | if (!cs_realloc(&(*vars).values, (*vars).varsalloc * 2 * sizeof(char**))) return "";
|
---|
55 | if (!cs_realloc(&(*vars).vartypes, (*vars).varsalloc * 2 * sizeof(uint8_t*))) return "";
|
---|
56 | (*vars).varsalloc = (*vars).varscnt * 2;
|
---|
57 | }
|
---|
58 | int32_t len = strlen(name) + 1;
|
---|
59 | if (!cs_malloc(&tmp, len)) return "";
|
---|
60 | memcpy(tmp, name, len);
|
---|
61 | (*vars).names[(*vars).varscnt] = tmp;
|
---|
62 |
|
---|
63 | len = strlen(value) + 1;
|
---|
64 | if (!cs_malloc(&tmp, len)) {
|
---|
65 | free((*vars).names[(*vars).varscnt]);
|
---|
66 | return "";
|
---|
67 | }
|
---|
68 | memcpy(tmp, value, len);
|
---|
69 | (*vars).values[(*vars).varscnt] = tmp;
|
---|
70 | (*vars).vartypes[(*vars).varscnt] = addmode;
|
---|
71 | (*vars).varscnt++;
|
---|
72 | } else {
|
---|
73 | int32_t oldlen = 0, newlen = strlen(value);
|
---|
74 | if(addmode == TPLAPPEND || addmode == TPLAPPENDONCE) oldlen = strlen((*vars).values[i]);
|
---|
75 | if (!cs_realloc(&((*vars).values[i]), oldlen + newlen + 1)) return value;
|
---|
76 | memcpy((*vars).values[i] + oldlen, value, newlen + 1);
|
---|
77 | (*vars).vartypes[i] = addmode;
|
---|
78 | }
|
---|
79 | return tmp;
|
---|
80 | }
|
---|
81 |
|
---|
82 | /* Adds a message to be output on the page using the TPLMESSAGE template. */
|
---|
83 | char *tpl_addMsg(struct templatevars *vars, char *value){
|
---|
84 | tpl_addVar(vars, TPLADDONCE, "MESSAGE", value);
|
---|
85 | (*vars).messages++;
|
---|
86 | return tpl_addVar(vars, TPLAPPEND, "MESSAGES", tpl_getTpl(vars, "MESSAGEBIT"));
|
---|
87 | }
|
---|
88 |
|
---|
89 | /* Allows to add a char array which has been allocated by malloc. It will automatically get
|
---|
90 | freed when calling tpl_clear(). Please do NOT free the memory yourself or realloc
|
---|
91 | it after having added the array here! */
|
---|
92 | char *tpl_addTmp(struct templatevars *vars, char *value){
|
---|
93 | if(value == NULL) return "";
|
---|
94 | if((*vars).tmpalloc <= (*vars).tmpcnt){
|
---|
95 | if (!cs_realloc(&(*vars).tmp, (*vars).tmpalloc * 2 * sizeof(char**))) return value;
|
---|
96 | (*vars).tmpalloc = (*vars).tmpcnt * 2;
|
---|
97 | }
|
---|
98 | (*vars).tmp[(*vars).tmpcnt] = value;
|
---|
99 | (*vars).tmpcnt++;
|
---|
100 | return value;
|
---|
101 | }
|
---|
102 |
|
---|
103 | /* Allows to do a dynamic printf without knowing and defining the needed memory size. If you specify
|
---|
104 | varname, the printf-result will be added/appended to the varlist, if varname=NULL it will only be returned.
|
---|
105 | In either case you will always get a reference back which you may freely use (but you should not call
|
---|
106 | free/realloc on this as it will be automatically cleaned!)*/
|
---|
107 | char *tpl_printf(struct templatevars *vars, uint8_t addmode, char *varname, char *fmtstring, ...){
|
---|
108 | uint32_t needed;
|
---|
109 | char test[1];
|
---|
110 | va_list argptr;
|
---|
111 |
|
---|
112 | va_start(argptr,fmtstring);
|
---|
113 | needed = vsnprintf(test, 1, fmtstring, argptr);
|
---|
114 | va_end(argptr);
|
---|
115 |
|
---|
116 | char *result;
|
---|
117 | if (!cs_malloc(&result, needed + 1)) return "";
|
---|
118 | va_start(argptr,fmtstring);
|
---|
119 | vsnprintf(result, needed + 1, fmtstring, argptr);
|
---|
120 | va_end(argptr);
|
---|
121 |
|
---|
122 | if(varname == NULL) tpl_addTmp(vars, result);
|
---|
123 | else {
|
---|
124 | char *tmp = tpl_addVar(vars, addmode, varname, result);
|
---|
125 | free(result);
|
---|
126 | result = tmp;
|
---|
127 | }
|
---|
128 | return result;
|
---|
129 | }
|
---|
130 |
|
---|
131 | /* Returns the value for a name or an empty string if nothing was found. */
|
---|
132 | char *tpl_getVar(struct templatevars *vars, char *name){
|
---|
133 | int32_t i;
|
---|
134 | char *result = NULL;
|
---|
135 | for(i = (*vars).varscnt-1; i >= 0; --i){
|
---|
136 | if(strcmp((*vars).names[i], name) == 0){
|
---|
137 | result = (*vars).values[i];
|
---|
138 | break;
|
---|
139 | }
|
---|
140 | }
|
---|
141 | if(result == NULL) return "";
|
---|
142 | else {
|
---|
143 | if((*vars).vartypes[i] == TPLADDONCE || (*vars).vartypes[i] == TPLAPPENDONCE){
|
---|
144 | // This is a one-time-use variable which gets cleaned up automatically after retrieving it
|
---|
145 | if (!cs_malloc(&(*vars).values[i], 1)) {
|
---|
146 | (*vars).values[i] = result;
|
---|
147 | result[0] = '\0';
|
---|
148 | return result;
|
---|
149 | } else {
|
---|
150 | (*vars).values[i][0] = '\0';
|
---|
151 | return tpl_addTmp(vars, result);
|
---|
152 | }
|
---|
153 | } else return result;
|
---|
154 | }
|
---|
155 | }
|
---|
156 |
|
---|
157 | /* Initializes all variables for a templatevar-structure and returns a pointer to it. Make
|
---|
158 | sure to call tpl_clear() when you are finished or you'll run into a memory leak! */
|
---|
159 | struct templatevars *tpl_create(void) {
|
---|
160 | struct templatevars *vars;
|
---|
161 | if (!cs_malloc(&vars, sizeof(struct templatevars))) return NULL;
|
---|
162 | (*vars).varsalloc = 64;
|
---|
163 | (*vars).varscnt = 0;
|
---|
164 | (*vars).tmpalloc = 64;
|
---|
165 | (*vars).tmpcnt = 0;
|
---|
166 | if (!cs_malloc(&(*vars).names, (*vars).varsalloc * sizeof(char**))) {
|
---|
167 | free(vars);
|
---|
168 | return NULL;
|
---|
169 | }
|
---|
170 | if (!cs_malloc(&(*vars).values, (*vars).varsalloc * sizeof(char**))) {
|
---|
171 | free((*vars).names);
|
---|
172 | free(vars);
|
---|
173 | return NULL;
|
---|
174 | }
|
---|
175 | if (!cs_malloc(&(*vars).vartypes, (*vars).varsalloc * sizeof(uint8_t*))) {
|
---|
176 | free((*vars).names);
|
---|
177 | free((*vars).values);
|
---|
178 | free(vars);
|
---|
179 | return NULL;
|
---|
180 | }
|
---|
181 | if (!cs_malloc(&(*vars).tmp, (*vars).tmpalloc * sizeof(char**))) {
|
---|
182 | free((*vars).names);
|
---|
183 | free((*vars).values);
|
---|
184 | free((*vars).vartypes);
|
---|
185 | free(vars);
|
---|
186 | return NULL;
|
---|
187 | }
|
---|
188 | return vars;
|
---|
189 | }
|
---|
190 |
|
---|
191 | /* Clears all allocated memory for the specified templatevar-structure. */
|
---|
192 | void tpl_clear(struct templatevars *vars){
|
---|
193 | int32_t i;
|
---|
194 | for(i = (*vars).varscnt-1; i >= 0; --i){
|
---|
195 | free((*vars).names[i]);
|
---|
196 | free((*vars).values[i]);
|
---|
197 | }
|
---|
198 | free((*vars).names);
|
---|
199 | free((*vars).values);
|
---|
200 | free((*vars).vartypes);
|
---|
201 | for(i = (*vars).tmpcnt-1; i >= 0; --i){
|
---|
202 | free((*vars).tmp[i]);
|
---|
203 | }
|
---|
204 | free((*vars).tmp);
|
---|
205 | free(vars);
|
---|
206 | }
|
---|
207 |
|
---|
208 | /* Creates a path to a template file. You need to set the resultsize to the correct size of result. */
|
---|
209 | char *tpl_getFilePathInSubdir(const char *path, const char* subdir, const char *name, const char* ext, char *result, uint32_t resultsize){
|
---|
210 | int path_len = strlen(path);
|
---|
211 | const char *path_fixup = "";
|
---|
212 | if (path_len && path[path_len - 1] != '/')
|
---|
213 | path_fixup = "/";
|
---|
214 | if (path_len + strlen(path_fixup) + strlen(name) + strlen(subdir) + strlen(ext) < resultsize) {
|
---|
215 | snprintf(result, resultsize, "%s%s%s%s%s", path, path_fixup, subdir, name, ext);
|
---|
216 | } else result[0] = '\0';
|
---|
217 |
|
---|
218 | return result;
|
---|
219 | }
|
---|
220 |
|
---|
221 | char *tpl_getTplPath(const char *name, const char *path, char *result, uint32_t resultsize){
|
---|
222 | return tpl_getFilePathInSubdir(path, "", name, ".tpl", result, resultsize);
|
---|
223 | }
|
---|
224 |
|
---|
225 | #define check_conf(CONFIG_VAR, text) \
|
---|
226 | if (config_enabled(CONFIG_VAR) && strncmp(#CONFIG_VAR, text, len) == 0) {ok = 1; break;}
|
---|
227 |
|
---|
228 | /* Returns an unparsed template either from disk or from internal templates.
|
---|
229 | Note: You must free() the result after using it and you may get NULL if an error occured!*/
|
---|
230 | static char *tpl_getUnparsedTpl(const char* name, int8_t removeHeader, const char* subdir){
|
---|
231 | int32_t i;
|
---|
232 | int32_t tplcnt = tpl_count();
|
---|
233 | char *result;
|
---|
234 |
|
---|
235 | if (cfg.http_tpl) {
|
---|
236 | char path[255];
|
---|
237 | if ( (strlen(tpl_getFilePathInSubdir(cfg.http_tpl, subdir, name, ".tpl", path, 255)) > 0 && file_exists(path))
|
---|
238 | || (strlen(subdir) > 0
|
---|
239 | #ifdef TOUCH
|
---|
240 | && strcmp(subdir, TOUCH_SUBDIR)
|
---|
241 | #endif
|
---|
242 | && strlen(tpl_getFilePathInSubdir(cfg.http_tpl, "" , name, ".tpl", path, 255)) > 0 && file_exists(path))) {
|
---|
243 | FILE *fp;
|
---|
244 | char buffer[1024];
|
---|
245 | memset(buffer, 0, sizeof(buffer));
|
---|
246 | int32_t readen, allocated = 1025, offset, size = 0;
|
---|
247 | if (!cs_malloc(&result, allocated)) return NULL;
|
---|
248 | if((fp = fopen(path,"r"))!=NULL){
|
---|
249 | while((readen = fread(&buffer,sizeof(char),1024,fp)) > 0){
|
---|
250 | offset = 0;
|
---|
251 | if(size == 0 && removeHeader){
|
---|
252 | /* Remove version string from output and check if it is valid for output */
|
---|
253 | char *pch1 = strstr(buffer,"<!--OSCam");
|
---|
254 | if(pch1 != NULL){
|
---|
255 | char *pch2 = strstr(pch1,"-->");
|
---|
256 | if(pch2 != NULL){
|
---|
257 | offset = pch2 - buffer + 4;
|
---|
258 | readen -= offset;
|
---|
259 | pch2[0] = '\0';
|
---|
260 | char *ptr1, *ptr2, *saveptr1 = NULL, *saveptr2 = NULL;
|
---|
261 | for (i = 0, ptr1 = strtok_r(pch1 + 10, ";", &saveptr1); (ptr1) && i < 4 ; ptr1 = strtok_r(NULL, ";", &saveptr1), i++){
|
---|
262 | if(i == 3 && strlen(ptr1) > 2){
|
---|
263 | int8_t ok = 0;
|
---|
264 | for (ptr2 = strtok_r(ptr1, ",", &saveptr2); (ptr2) && ok == 0 ; ptr2 = strtok_r(NULL, ",", &saveptr2)){
|
---|
265 | size_t len = strlen(ptr2);
|
---|
266 | check_conf(WITH_CARDREADER, ptr2);
|
---|
267 | check_conf(CARDREADER_PHOENIX, ptr2);
|
---|
268 | check_conf(CARDREADER_INTERNAL_AZBOX, ptr2);
|
---|
269 | check_conf(CARDREADER_INTERNAL_COOLAPI, ptr2);
|
---|
270 | check_conf(CARDREADER_INTERNAL_SCI, ptr2);
|
---|
271 | check_conf(CARDREADER_SC8IN1, ptr2);
|
---|
272 | check_conf(CARDREADER_MP35, ptr2);
|
---|
273 | check_conf(CARDREADER_SMARGO, ptr2);
|
---|
274 | check_conf(CARDREADER_PCSC, ptr2);
|
---|
275 | check_conf(CARDREADER_SMART, ptr2);
|
---|
276 | check_conf(CARDREADER_DB2COM, ptr2);
|
---|
277 | check_conf(CARDREADER_STAPI, ptr2);
|
---|
278 | check_conf(CS_ANTICASC, ptr2);
|
---|
279 | check_conf(CS_CACHEEX, ptr2);
|
---|
280 | check_conf(HAVE_DVBAPI, ptr2);
|
---|
281 | check_conf(IPV6SUPPORT, ptr2);
|
---|
282 | check_conf(IRDETO_GUESSING, ptr2);
|
---|
283 | check_conf(LCDSUPPORT, ptr2);
|
---|
284 | check_conf(LEDSUPPORT, ptr2);
|
---|
285 | check_conf(MODULE_CAMD33, ptr2);
|
---|
286 | check_conf(MODULE_CAMD35, ptr2);
|
---|
287 | check_conf(MODULE_CAMD35_TCP, ptr2);
|
---|
288 | check_conf(MODULE_CCCAM, ptr2);
|
---|
289 | check_conf(MODULE_CCCSHARE, ptr2);
|
---|
290 | check_conf(MODULE_CONSTCW, ptr2);
|
---|
291 | check_conf(MODULE_GBOX, ptr2);
|
---|
292 | check_conf(MODULE_GHTTP, ptr2);
|
---|
293 | check_conf(MODULE_MONITOR, ptr2);
|
---|
294 | check_conf(MODULE_NEWCAMD, ptr2);
|
---|
295 | check_conf(MODULE_PANDORA, ptr2);
|
---|
296 | check_conf(MODULE_RADEGAST, ptr2);
|
---|
297 | check_conf(MODULE_SERIAL, ptr2);
|
---|
298 | check_conf(READER_BULCRYPT, ptr2);
|
---|
299 | check_conf(READER_CONAX, ptr2);
|
---|
300 | check_conf(READER_CRYPTOWORKS, ptr2);
|
---|
301 | check_conf(READER_GRIFFIN, ptr2);
|
---|
302 | check_conf(READER_DGCRYPT, ptr2);
|
---|
303 | check_conf(READER_DRE, ptr2);
|
---|
304 | check_conf(READER_IRDETO, ptr2);
|
---|
305 | check_conf(READER_NAGRA, ptr2);
|
---|
306 | check_conf(READER_SECA, ptr2);
|
---|
307 | check_conf(READER_TONGFANG, ptr2);
|
---|
308 | check_conf(READER_VIACCESS, ptr2);
|
---|
309 | check_conf(READER_VIDEOGUARD, ptr2);
|
---|
310 | check_conf(WITH_CARDREADER, ptr2);
|
---|
311 | check_conf(WITH_DEBUG, ptr2);
|
---|
312 | check_conf(WITH_LB, ptr2);
|
---|
313 | check_conf(WITH_LIBCRYPTO, ptr2);
|
---|
314 | check_conf(WITH_SSL, ptr2);
|
---|
315 | check_conf(WITH_STAPI, ptr2);
|
---|
316 | }
|
---|
317 | if(ok == 0) return result;
|
---|
318 | break;
|
---|
319 | }
|
---|
320 | }
|
---|
321 | }
|
---|
322 | }
|
---|
323 | }
|
---|
324 | if(allocated < size + readen + 1) {
|
---|
325 | allocated += size + 1024;
|
---|
326 | if (!cs_realloc(&result, allocated)) return NULL;
|
---|
327 | }
|
---|
328 | memcpy(result + size, buffer + offset, readen);
|
---|
329 | size += readen;
|
---|
330 | }
|
---|
331 | result[size] = '\0';
|
---|
332 | fclose (fp);
|
---|
333 | return result;
|
---|
334 | }
|
---|
335 | }
|
---|
336 | }
|
---|
337 |
|
---|
338 | int8_t chksum = 0;
|
---|
339 | for(i = strlen(name); i > 0; --i){
|
---|
340 | chksum += name[i];
|
---|
341 | }
|
---|
342 |
|
---|
343 | for(i = 0; i < tplcnt; ++i){
|
---|
344 | if(tplchksum && chksum == tplchksum[i] && name[0] == templates[i][0][0]){ // basic check to save strcmp calls as we are doing this hundreds of times per page in some cases
|
---|
345 | if(strcmp(name, templates[i][0]) == 0) break;
|
---|
346 | }
|
---|
347 | }
|
---|
348 |
|
---|
349 | if(i >= 0 && i < tplcnt){
|
---|
350 | #ifdef TOUCH
|
---|
351 | const char* tpl_res = (!strcmp(subdir, TOUCH_SUBDIR) && i == 12) ? TOUCH_TPLSTATUS : templates[i][1];
|
---|
352 | #else
|
---|
353 | const char* tpl_res = templates[i][1];
|
---|
354 | #endif
|
---|
355 | int32_t len = strlen(tpl_res) + 1;
|
---|
356 | if (!cs_malloc(&result, len)) return NULL;
|
---|
357 | memcpy(result, tpl_res, len);
|
---|
358 | } else {
|
---|
359 | if (!cs_malloc(&result, 1)) return NULL;
|
---|
360 | result[0] = '\0';
|
---|
361 | }
|
---|
362 | return result;
|
---|
363 | }
|
---|
364 |
|
---|
365 | /* Returns the specified template with all variables/other templates replaced or an
|
---|
366 | empty string if the template doesn't exist. Do not free the result yourself, it
|
---|
367 | will get automatically cleaned up! */
|
---|
368 | char *tpl_getTpl(struct templatevars *vars, const char* name){
|
---|
369 |
|
---|
370 | char *tplorg = tpl_getUnparsedTpl(name, 1, tpl_getVar(vars, "SUBDIR"));
|
---|
371 | if(!tplorg) return "";
|
---|
372 | char *tplend = tplorg + strlen(tplorg);
|
---|
373 | char *pch, *pch2, *tpl=tplorg;
|
---|
374 | char varname[33];
|
---|
375 |
|
---|
376 | int32_t tmp,respos = 0;
|
---|
377 | int32_t allocated = 2 * strlen(tpl) + 1;
|
---|
378 | char *result;
|
---|
379 | if (!cs_malloc(&result, allocated)) return "";
|
---|
380 |
|
---|
381 | while(tpl < tplend){
|
---|
382 | if(tpl[0] == '#' && tpl[1] == '#' && tpl[2] != '#'){
|
---|
383 | pch2 = tpl;
|
---|
384 | pch = tpl + 2;
|
---|
385 | while(pch[0] != '\0' && (pch[0] != '#' || pch[1] != '#')) ++pch;
|
---|
386 | if(pch - pch2 < 32 && pch[0] == '#' && pch[1] == '#'){
|
---|
387 | memcpy(varname, pch2 + 2, pch - pch2 - 2);
|
---|
388 | varname[pch - pch2 - 2] = '\0';
|
---|
389 | if(strncmp(varname, "TPL", 3) == 0){
|
---|
390 | if((*vars).messages > 0 || strncmp(varname, "TPLMESSAGE", 10) != 0)
|
---|
391 | pch2 = tpl_getTpl(vars, varname + 3);
|
---|
392 | else pch2 = "";
|
---|
393 | } else {
|
---|
394 | pch2 = tpl_getVar(vars, varname);
|
---|
395 | }
|
---|
396 | tmp = strlen(pch2);
|
---|
397 | if(tmp + respos + 2 >= allocated){
|
---|
398 | allocated = tmp + respos + 256;
|
---|
399 | if (!cs_realloc(&result, allocated)) return "";
|
---|
400 | }
|
---|
401 | memcpy(result + respos, pch2, tmp);
|
---|
402 | respos += tmp;
|
---|
403 | tpl = pch + 2;
|
---|
404 | }
|
---|
405 | } else {
|
---|
406 | if(respos + 2 >= allocated){
|
---|
407 | allocated = respos + 256;
|
---|
408 | if (!cs_realloc(&result, allocated)) return "";
|
---|
409 | }
|
---|
410 | result[respos] = tpl[0];
|
---|
411 | ++respos;
|
---|
412 | ++tpl;
|
---|
413 | }
|
---|
414 | }
|
---|
415 | free(tplorg);
|
---|
416 | result[respos] = '\0';
|
---|
417 | tpl_addTmp(vars, result);
|
---|
418 | return result;
|
---|
419 | }
|
---|
420 |
|
---|
421 | /* Saves all templates to the specified paths. Existing files will be overwritten! */
|
---|
422 | int32_t tpl_saveIncludedTpls(const char *path){
|
---|
423 | int32_t tplcnt = tpl_count();
|
---|
424 | int32_t i, cnt = 0;
|
---|
425 | char tmp[256];
|
---|
426 | FILE *fp;
|
---|
427 | for(i = 0; i < tplcnt; ++i){
|
---|
428 | if(strlen(tpl_getTplPath(templates[i][0], path, tmp, 256)) > 0 && (fp = fopen(tmp,"w")) != NULL){
|
---|
429 | int32_t len = strlen(templates[i][1]);
|
---|
430 | if(strncmp(templates[i][0], "IC", 2) != 0){
|
---|
431 | fprintf(fp, "<!--OSCam;%lu;%s;%s;%s-->\n", crc32(0L, (unsigned char*)templates[i][1], len), CS_VERSION, CS_SVN_VERSION, templates[i][2]);
|
---|
432 | }
|
---|
433 | fwrite(templates[i][1], sizeof(char), len, fp);
|
---|
434 | fclose (fp);
|
---|
435 | ++cnt;
|
---|
436 | }
|
---|
437 | }
|
---|
438 | return cnt;
|
---|
439 | }
|
---|
440 |
|
---|
441 | /* Checks all disk templates in a directory if they are still current or may need upgrade! */
|
---|
442 | void tpl_checkOneDirDiskRevisions(const char* subdir) {
|
---|
443 | char dirpath[255] = "\0";
|
---|
444 | snprintf(dirpath, 255, "%s%s", cfg.http_tpl ? cfg.http_tpl : "", subdir);
|
---|
445 |
|
---|
446 | int32_t i, tplcnt = tpl_count();
|
---|
447 | char path[255];
|
---|
448 | for(i = 0; i < tplcnt; ++i){
|
---|
449 | if(strncmp(templates[i][0], "IC", 2) != 0 && strlen(tpl_getTplPath(templates[i][0], dirpath, path, 255)) > 0 && file_exists(path)){
|
---|
450 | int8_t error = 1;
|
---|
451 | char *tplorg = tpl_getUnparsedTpl(templates[i][0], 0, subdir);
|
---|
452 | unsigned long checksum = 0, curchecksum = crc32(0L, (unsigned char*)templates[i][1], strlen(templates[i][1]));
|
---|
453 | char *ifdefs = "", *pch1 = strstr(tplorg,"<!--OSCam");
|
---|
454 | if(pch1 != NULL){
|
---|
455 | char *version = "?", *revision = "?";
|
---|
456 | char *pch2 = strstr(pch1,"-->");
|
---|
457 | if(pch2 != NULL){
|
---|
458 | pch2[0] = '\0';
|
---|
459 | int32_t j;
|
---|
460 | char *ptr1, *saveptr1 = NULL;
|
---|
461 | for (j = 0, ptr1 = strtok_r(pch1 + 10, ";", &saveptr1); (ptr1) && j < 4 ; ptr1 = strtok_r(NULL, ";", &saveptr1), j++){
|
---|
462 | if(j == 0) checksum = strtoul(ptr1, NULL, 10);
|
---|
463 | else if(j == 1) version = ptr1;
|
---|
464 | else if(j == 2) revision = ptr1;
|
---|
465 | else if(j == 3) ifdefs = ptr1;
|
---|
466 | }
|
---|
467 | }
|
---|
468 | if(checksum != curchecksum){
|
---|
469 | cs_log("WARNING: Your http disk template %s was created for an older revision of OSCam and was changed in original OSCam (%s,r%s). Please consider upgrading it!", path, version, revision);
|
---|
470 | } else error = 0;
|
---|
471 | } else cs_log("WARNING: Your http disk template %s is in the old template format without revision info. Please consider upgrading it!", path);
|
---|
472 | if(error) cs_log("If you are sure that it is current, add the following line at the beginning of the template to suppress this warning: <!--OSCam;%lu;%s;%s;%s-->", curchecksum, CS_VERSION, CS_SVN_VERSION, ifdefs);
|
---|
473 | free(tplorg);
|
---|
474 | }
|
---|
475 | }
|
---|
476 | }
|
---|
477 |
|
---|
478 | /* Checks whether disk templates need upgrade - including sub-directories */
|
---|
479 | void tpl_checkDiskRevisions(void) {
|
---|
480 | char subdir[255];
|
---|
481 | char dirpath[255];
|
---|
482 | if (cfg.http_tpl) {
|
---|
483 | tpl_checkOneDirDiskRevisions("");
|
---|
484 |
|
---|
485 | DIR *hdir;
|
---|
486 | struct dirent entry;
|
---|
487 | struct dirent *result;
|
---|
488 | struct stat s;
|
---|
489 | if((hdir = opendir(cfg.http_tpl)) != NULL) {
|
---|
490 | while(cs_readdir_r(hdir, &entry, &result) == 0 && result != NULL) {
|
---|
491 | if (strcmp(".", entry.d_name) == 0 || strcmp("..", entry.d_name) == 0) {
|
---|
492 | continue;
|
---|
493 | }
|
---|
494 | snprintf(dirpath, 255, "%s%s", cfg.http_tpl, entry.d_name);
|
---|
495 | if (stat(dirpath, &s) == 0) {
|
---|
496 | if (s.st_mode & S_IFDIR) {
|
---|
497 | snprintf(subdir, 255,
|
---|
498 | #ifdef WIN32
|
---|
499 | "%s\\"
|
---|
500 | #else
|
---|
501 | "%s/"
|
---|
502 | #endif
|
---|
503 | , entry.d_name);
|
---|
504 | tpl_checkOneDirDiskRevisions(subdir);
|
---|
505 | }
|
---|
506 | }
|
---|
507 | }
|
---|
508 | closedir(hdir);
|
---|
509 | }
|
---|
510 | }
|
---|
511 | }
|
---|
512 |
|
---|
513 | /* Create some easy checksums (but they should be sufficient for our needs) in order to speedup lookup of templates. */
|
---|
514 | void prepareTplChecksums(void) {
|
---|
515 | int32_t i, j;
|
---|
516 | int32_t tplcnt = tpl_count();
|
---|
517 | if (!cs_malloc(&tplchksum, tplcnt))
|
---|
518 | return;
|
---|
519 |
|
---|
520 | for(i = 0; i < tplcnt; ++i){
|
---|
521 | tplchksum[i] = 0;
|
---|
522 | for(j = strlen(templates[i][0]); j > 0; --j){
|
---|
523 | tplchksum[i] += templates[i][0][j];
|
---|
524 | }
|
---|
525 | }
|
---|
526 | }
|
---|
527 |
|
---|
528 | /* Parses a value in an authentication string by removing all quotes/whitespace. Note that the original array is modified. */
|
---|
529 | static char *parse_auth_value(char *value){
|
---|
530 | char *pch = value;
|
---|
531 | char *pch2;
|
---|
532 | value = strstr(value, "=");
|
---|
533 | if(value != NULL){
|
---|
534 | do{
|
---|
535 | ++value;
|
---|
536 | } while (value[0] == ' ' || value[0] == '"');
|
---|
537 | pch = value;
|
---|
538 | for(pch2 = value + strlen(value) - 1; pch2 >= value && (pch2[0] == ' ' || pch2[0] == '"' || pch2[0] == '\r' || pch2[0] == '\n'); --pch2) pch2[0] = '\0';
|
---|
539 | }
|
---|
540 | return pch;
|
---|
541 | }
|
---|
542 |
|
---|
543 | /* Parses the date out of a "If-Modified-Since"-header. Note that the original string is modified. */
|
---|
544 | time_t parse_modifiedsince(char * value){
|
---|
545 | int32_t day = -1, month = -1, year = -1, hour = -1, minutes = -1, seconds = -1;
|
---|
546 | char months[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
|
---|
547 | char *str, *saveptr1 = NULL;
|
---|
548 | time_t modifiedheader = 0;
|
---|
549 | value += 18;
|
---|
550 | // Parse over weekday at beginning...
|
---|
551 | while(value[0] == ' ' && value[0] != '\0') ++value;
|
---|
552 | while(value[0] != ' ' && value[0] != '\0') ++value;
|
---|
553 | // 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...
|
---|
554 | if(value[0] != '\0'){
|
---|
555 | ++value;
|
---|
556 | for(month = 0; month < 12; ++month){
|
---|
557 | if(strstr(value, months[month])) break;
|
---|
558 | }
|
---|
559 | if(month > 11) month = -1;
|
---|
560 | for (str=strtok_r(value, " ", &saveptr1); str; str=strtok_r(NULL, " ", &saveptr1)){
|
---|
561 | switch(strlen(str)){
|
---|
562 | case 1:
|
---|
563 | case 2:
|
---|
564 | day = atoi(str);
|
---|
565 | break;
|
---|
566 |
|
---|
567 | case 4:
|
---|
568 | if(str[0] != 'G')
|
---|
569 | year = atoi(str);
|
---|
570 | break;
|
---|
571 |
|
---|
572 | case 8:
|
---|
573 | if(str[2] == ':' && str[5] == ':'){
|
---|
574 | hour = atoi(str);
|
---|
575 | minutes = atoi(str + 3);
|
---|
576 | seconds = atoi(str + 6);
|
---|
577 | }
|
---|
578 | break;
|
---|
579 |
|
---|
580 | case 9:
|
---|
581 | if(str[2] == '-' && str[6] == '-'){
|
---|
582 | day = atoi(str);
|
---|
583 | year = atoi(str + 7) + 2000;
|
---|
584 | }
|
---|
585 | break;
|
---|
586 | }
|
---|
587 | }
|
---|
588 | if(day > 0 && day < 32 && month > 0 && year > 0 && year < 9999 && hour > -1 && hour < 24 && minutes > -1 && minutes < 60 && seconds > -1 && seconds < 60){
|
---|
589 | struct tm timeinfo;
|
---|
590 | memset(&timeinfo, 0, sizeof(timeinfo));
|
---|
591 | timeinfo.tm_mday = day;
|
---|
592 | timeinfo.tm_mon = month;
|
---|
593 | timeinfo.tm_year = year - 1900;
|
---|
594 | timeinfo.tm_hour = hour;
|
---|
595 | timeinfo.tm_min = minutes;
|
---|
596 | timeinfo.tm_sec = seconds;
|
---|
597 | modifiedheader = cs_timegm(&timeinfo);
|
---|
598 | }
|
---|
599 | }
|
---|
600 | return modifiedheader;
|
---|
601 | }
|
---|
602 |
|
---|
603 | /* Converts a char to it's hex representation. See urlencode and char_to_hex on how to use it.*/
|
---|
604 | static char to_hex(char code) {
|
---|
605 | static const char hex[] = "0123456789abcdef";
|
---|
606 | return hex[(int)code & 15];
|
---|
607 | }
|
---|
608 |
|
---|
609 | /* Converts a char array to a char array with hex values (needed for example for md5).
|
---|
610 | Note that result needs to be at least (p_array_len * 2) + 1 large. */
|
---|
611 | static void char_to_hex(const unsigned char* p_array, uint32_t p_array_len, unsigned char *result) {
|
---|
612 | result[p_array_len * 2] = '\0';
|
---|
613 | const unsigned char *p_end = p_array + p_array_len;
|
---|
614 | uint32_t pos = 0;
|
---|
615 | const unsigned char* p;
|
---|
616 | for (p = p_array; p != p_end; p++, pos+=2 ) {
|
---|
617 | result[pos ] = to_hex(*p >> 4);
|
---|
618 | result[pos + 1] = to_hex(*p & 15);
|
---|
619 | }
|
---|
620 | }
|
---|
621 |
|
---|
622 | /* Calculates a new opaque value. Please note that opaque needs to be at least (MD5_DIGEST_LENGTH * 2) + 1 large. */
|
---|
623 | void calculate_opaque(IN_ADDR_T addr, char *opaque){
|
---|
624 | char noncetmp[128];
|
---|
625 | unsigned char md5tmp[MD5_DIGEST_LENGTH];
|
---|
626 | snprintf(noncetmp, sizeof(noncetmp), "%d:%s:%d", (int32_t)time((time_t)0), cs_inet_ntoa(addr), (int16_t)rand());
|
---|
627 | char_to_hex(MD5((unsigned char*)noncetmp, strlen(noncetmp), md5tmp), MD5_DIGEST_LENGTH, (unsigned char*)opaque);
|
---|
628 | }
|
---|
629 |
|
---|
630 | void init_noncelocks(void){
|
---|
631 | int32_t i;
|
---|
632 | for(i = 0; i < AUTHNONCEHASHBUCKETS; ++i){
|
---|
633 | cs_lock_create(&nonce_lock[i], 5, "nonce_lock");
|
---|
634 | nonce_first[i] = NULL;
|
---|
635 | }
|
---|
636 | }
|
---|
637 |
|
---|
638 | /* 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. */
|
---|
639 | void calculate_nonce(char *nonce, char *result, char *opaque){
|
---|
640 | struct s_nonce *noncelist, *prev, *foundnonce = NULL, *foundopaque = NULL, *foundexpired = NULL;
|
---|
641 | int32_t bucket = opaque[0] % AUTHNONCEHASHBUCKETS;
|
---|
642 | time_t now = time((time_t)0);
|
---|
643 | cs_writelock(&nonce_lock[bucket]);
|
---|
644 | for(noncelist = nonce_first[bucket], prev = NULL; noncelist; prev = noncelist, noncelist = noncelist->next){
|
---|
645 | if(now > noncelist->expirationdate){
|
---|
646 | if(prev) prev->next = NULL;
|
---|
647 | else {
|
---|
648 | nonce_first[bucket] = NULL;
|
---|
649 | }
|
---|
650 | foundexpired = noncelist;
|
---|
651 | break;
|
---|
652 | }
|
---|
653 | if(nonce && !memcmp(noncelist->nonce, nonce, (MD5_DIGEST_LENGTH * 2) + 1)) {
|
---|
654 | memcpy(result, noncelist->nonce, (MD5_DIGEST_LENGTH * 2) + 1);
|
---|
655 | foundnonce = noncelist;
|
---|
656 | if(!noncelist->firstuse) noncelist->firstuse = now;
|
---|
657 | else if(now - foundnonce->firstuse > AUTHNONCEVALIDSECS){
|
---|
658 | if(prev) prev->next = noncelist->next;
|
---|
659 | else {
|
---|
660 | nonce_first[bucket] = noncelist->next;
|
---|
661 | }
|
---|
662 | }
|
---|
663 | break;
|
---|
664 | } else if (!noncelist->firstuse && !memcmp(noncelist->opaque, opaque, (MD5_DIGEST_LENGTH * 2) + 1)){
|
---|
665 | foundopaque = noncelist;
|
---|
666 | }
|
---|
667 | }
|
---|
668 | if(foundnonce && now - foundnonce->firstuse > AUTHNONCEVALIDSECS){
|
---|
669 | free(foundnonce);
|
---|
670 | foundnonce = NULL;
|
---|
671 | }
|
---|
672 | if(!foundnonce && foundopaque)
|
---|
673 | memcpy(result, foundopaque->nonce, (MD5_DIGEST_LENGTH * 2) + 1);
|
---|
674 | if(!foundnonce && !foundopaque){
|
---|
675 | char noncetmp[128], randstr[16];
|
---|
676 | unsigned char md5tmp[MD5_DIGEST_LENGTH];
|
---|
677 | get_random_bytes((uint8_t*)randstr, sizeof(randstr)-1);
|
---|
678 | randstr[sizeof(randstr)-1] = '\0';
|
---|
679 | snprintf(noncetmp, sizeof(noncetmp), "%d:%s:%s", (int32_t)now, randstr, noncekey);
|
---|
680 | char_to_hex(MD5((unsigned char*)noncetmp, strlen(noncetmp), md5tmp), MD5_DIGEST_LENGTH, (unsigned char*)result);
|
---|
681 | if(cs_malloc(&noncelist, sizeof(struct s_nonce))){
|
---|
682 | noncelist->expirationdate = now + AUTHNONCEEXPIRATION;
|
---|
683 | memcpy(noncelist->nonce, result, (MD5_DIGEST_LENGTH * 2) + 1);
|
---|
684 | memcpy(noncelist->opaque, opaque, (MD5_DIGEST_LENGTH * 2) + 1);
|
---|
685 | noncelist->next = nonce_first[bucket];
|
---|
686 | nonce_first[bucket] = noncelist;
|
---|
687 | }
|
---|
688 | }
|
---|
689 | cs_writeunlock(&nonce_lock[bucket]);
|
---|
690 | while(foundexpired){
|
---|
691 | prev = foundexpired;
|
---|
692 | foundexpired = foundexpired->next;
|
---|
693 | free(prev);
|
---|
694 | }
|
---|
695 | }
|
---|
696 |
|
---|
697 | /* Checks if authentication is correct. Returns -1 if not correct, 1 if correct and 2 if nonce isn't valid anymore.
|
---|
698 | Note that authstring will be modified. */
|
---|
699 | int32_t check_auth(char *authstring, char *method, char *path, IN_ADDR_T addr, char *expectednonce, char *opaque){
|
---|
700 | int32_t authok = 0, uriok = 0;
|
---|
701 | char authnonce[(MD5_DIGEST_LENGTH * 2) + 1];
|
---|
702 | memset(authnonce, 0, sizeof(authnonce));
|
---|
703 | char *authnc = "";
|
---|
704 | char *authcnonce = "";
|
---|
705 | char *authresponse = "";
|
---|
706 | char *uri = "";
|
---|
707 | char *username = "";
|
---|
708 | char *expectedPassword = cfg.http_pwd;
|
---|
709 | char *pch = authstring + 22;
|
---|
710 | char *pch2;
|
---|
711 | char *saveptr1=NULL;
|
---|
712 | memset(opaque, 0, (MD5_DIGEST_LENGTH * 2) + 1);
|
---|
713 |
|
---|
714 | for(pch = strtok_r (pch, ",", &saveptr1); pch; pch = strtok_r (NULL, ",", &saveptr1)){
|
---|
715 | pch2 = pch;
|
---|
716 | while(pch2[0] == ' ' && pch2[0] != '\0') ++pch2;
|
---|
717 | if(strncmp(pch2, "nonce", 5) == 0){
|
---|
718 | cs_strncpy(authnonce, parse_auth_value(pch2), sizeof(authnonce));
|
---|
719 | } else if (strncmp(pch2, "nc", 2) == 0){
|
---|
720 | authnc=parse_auth_value(pch2);
|
---|
721 | } else if (strncmp(pch2, "cnonce", 6) == 0){
|
---|
722 | authcnonce=parse_auth_value(pch2);
|
---|
723 | } else if (strncmp(pch2, "response", 8) == 0){
|
---|
724 | authresponse=parse_auth_value(pch2);
|
---|
725 | } else if (strncmp(pch2, "uri", 3) == 0){
|
---|
726 | uri=parse_auth_value(pch2);
|
---|
727 | } else if (strncmp(pch2, "username", 8) == 0){
|
---|
728 | username=parse_auth_value(pch2);
|
---|
729 | } else if (strncmp(pch2, "opaque", 6) == 0){
|
---|
730 | char *tmp=parse_auth_value(pch2);
|
---|
731 | cs_strncpy(opaque, tmp, (MD5_DIGEST_LENGTH * 2) + 1);
|
---|
732 | }
|
---|
733 | }
|
---|
734 |
|
---|
735 | if(strncmp(uri, path, strlen(path)) == 0) uriok = 1;
|
---|
736 | else {
|
---|
737 | pch2 = uri;
|
---|
738 | for(pch = uri; pch[0] != '\0'; ++pch) {
|
---|
739 | if(pch[0] == '/') pch2 = pch;
|
---|
740 | if(strncmp(pch2, path, strlen(path)) == 0) uriok = 1;
|
---|
741 | }
|
---|
742 | }
|
---|
743 | if (uriok == 1 && streq(username, cfg.http_user)) {
|
---|
744 | char A1tmp[3 + strlen(username) + strlen(AUTHREALM) + strlen(expectedPassword)];
|
---|
745 | char A1[(MD5_DIGEST_LENGTH * 2) + 1], A2[(MD5_DIGEST_LENGTH * 2) + 1], A3[(MD5_DIGEST_LENGTH * 2) + 1];
|
---|
746 | unsigned char md5tmp[MD5_DIGEST_LENGTH];
|
---|
747 | snprintf(A1tmp, sizeof(A1tmp), "%s:%s:%s", username, AUTHREALM, expectedPassword);
|
---|
748 | char_to_hex(MD5((unsigned char*)A1tmp, strlen(A1tmp), md5tmp), MD5_DIGEST_LENGTH, (unsigned char*)A1);
|
---|
749 |
|
---|
750 | char A2tmp[2 + strlen(method) + strlen(uri)];
|
---|
751 | snprintf(A2tmp, sizeof(A2tmp), "%s:%s", method, uri);
|
---|
752 | char_to_hex(MD5((unsigned char*)A2tmp, strlen(A2tmp), md5tmp), MD5_DIGEST_LENGTH, (unsigned char*)A2);
|
---|
753 |
|
---|
754 | char A3tmp[10 + strlen(A1) + strlen(A2) + strlen(authnonce) + strlen(authnc) + strlen(authcnonce)];
|
---|
755 | snprintf(A3tmp, sizeof(A3tmp), "%s:%s:%s:%s:auth:%s", A1, authnonce, authnc, authcnonce, A2);
|
---|
756 | char_to_hex(MD5((unsigned char*)A3tmp, strlen(A3tmp), md5tmp), MD5_DIGEST_LENGTH, (unsigned char*)A3);
|
---|
757 |
|
---|
758 | if(strcmp(A3, authresponse) == 0) {
|
---|
759 | if(strlen(opaque) != MD5_DIGEST_LENGTH*2) calculate_opaque(addr, opaque);
|
---|
760 | calculate_nonce(authnonce, expectednonce, opaque);
|
---|
761 | if(strcmp(expectednonce, authnonce) == 0) authok = 1;
|
---|
762 | else {
|
---|
763 | authok = 2;
|
---|
764 | cs_debug_mask(D_TRACE, "WebIf: Received stale header from %s (nonce=%s, expectednonce=%s, opaque=%s).", cs_inet_ntoa(addr), authnonce, expectednonce, opaque);
|
---|
765 | }
|
---|
766 | }
|
---|
767 | }
|
---|
768 | return authok;
|
---|
769 | }
|
---|
770 |
|
---|
771 | int32_t webif_write_raw(char *buf, FILE* f, int32_t len) {
|
---|
772 | errno=0;
|
---|
773 | #ifdef WITH_SSL
|
---|
774 | if (ssl_active) {
|
---|
775 | return SSL_write((SSL*)f, buf, len);
|
---|
776 | } else
|
---|
777 | #endif
|
---|
778 | return fwrite(buf, 1, len, f);
|
---|
779 | }
|
---|
780 |
|
---|
781 | int32_t webif_write(char *buf, FILE* f) {
|
---|
782 | return webif_write_raw(buf, f, strlen(buf));
|
---|
783 | }
|
---|
784 |
|
---|
785 | int32_t webif_read(char *buf, int32_t num, FILE *f) {
|
---|
786 | errno=0;
|
---|
787 | #ifdef WITH_SSL
|
---|
788 | if (ssl_active) {
|
---|
789 | return SSL_read((SSL*)f, buf, num);
|
---|
790 | } else
|
---|
791 | #endif
|
---|
792 | return read(fileno(f), buf, num);
|
---|
793 | }
|
---|
794 |
|
---|
795 | void send_headers(FILE *f, int32_t status, char *title, char *extra, char *mime, int32_t cache, int32_t length, char *content, int8_t forcePlain){
|
---|
796 | time_t now;
|
---|
797 | char timebuf[32];
|
---|
798 | char buf[sizeof(PROTOCOL) + sizeof(SERVER) + strlen(title) + (extra == NULL?0:strlen(extra)+2) + (mime == NULL?0:strlen(mime)+2) + 350];
|
---|
799 | char *pos = buf;
|
---|
800 | struct tm timeinfo;
|
---|
801 |
|
---|
802 | pos += snprintf(pos, sizeof(buf)-(pos-buf), "%s %d %s\r\n", PROTOCOL, status, title);
|
---|
803 | pos += snprintf(pos, sizeof(buf)-(pos-buf), "Server: %s\r\n", SERVER);
|
---|
804 |
|
---|
805 | now = time(NULL);
|
---|
806 | cs_gmtime_r(&now, &timeinfo);
|
---|
807 | strftime(timebuf, sizeof(timebuf), RFC1123FMT, &timeinfo);
|
---|
808 | pos += snprintf(pos, sizeof(buf)-(pos-buf), "Date: %s\r\n", timebuf);
|
---|
809 |
|
---|
810 | if (extra)
|
---|
811 | pos += snprintf(pos, sizeof(buf)-(pos-buf),"%s\r\n", extra);
|
---|
812 |
|
---|
813 | if (mime)
|
---|
814 | pos += snprintf(pos, sizeof(buf)-(pos-buf),"Content-Type: %s\r\n", mime);
|
---|
815 |
|
---|
816 | if(status != 304){
|
---|
817 | if(!cache){
|
---|
818 | pos += snprintf(pos, sizeof(buf)-(pos-buf),"Cache-Control: no-store, no-cache, must-revalidate\r\n");
|
---|
819 | pos += snprintf(pos, sizeof(buf)-(pos-buf),"Expires: Sat, 10 Jan 2000 05:00:00 GMT\r\n");
|
---|
820 | } else {
|
---|
821 | pos += snprintf(pos, sizeof(buf)-(pos-buf),"Cache-Control: public, max-age=7200\r\n");
|
---|
822 | }
|
---|
823 | pos += snprintf(pos, sizeof(buf)-(pos-buf),"Content-Length: %d\r\n", length);
|
---|
824 | pos += snprintf(pos, sizeof(buf)-(pos-buf),"Last-Modified: %s\r\n", timebuf);
|
---|
825 | if(content){
|
---|
826 | uint32_t checksum = (uint32_t)crc32(0L, (uchar *)content, length);
|
---|
827 | pos += snprintf(pos, sizeof(buf)-(pos-buf),"ETag: \"%u\"\r\n", checksum==0?1:checksum);
|
---|
828 | }
|
---|
829 | }
|
---|
830 | if(*(int8_t *)pthread_getspecific(getkeepalive))
|
---|
831 | pos += snprintf(pos, sizeof(buf)-(pos-buf), "Connection: Keep-Alive\r\n");
|
---|
832 | else
|
---|
833 | pos += snprintf(pos, sizeof(buf)-(pos-buf), "Connection: close\r\n");
|
---|
834 | pos += snprintf(pos, sizeof(buf)-(pos-buf),"\r\n");
|
---|
835 | if(forcePlain == 1) fwrite(buf, 1, strlen(buf), f);
|
---|
836 | else webif_write(buf, f);
|
---|
837 | }
|
---|
838 |
|
---|
839 | void send_error(FILE *f, int32_t status, char *title, char *extra, char *text, int8_t forcePlain){
|
---|
840 | char buf[(2* strlen(title)) + strlen(text) + 128];
|
---|
841 | char *pos = buf;
|
---|
842 | pos += snprintf(pos, sizeof(buf)-(pos-buf), "<HTML><HEAD><TITLE>%d %s</TITLE></HEAD>\r\n", status, title);
|
---|
843 | pos += snprintf(pos, sizeof(buf)-(pos-buf), "<BODY><H4>%d %s</H4>\r\n", status, title);
|
---|
844 | pos += snprintf(pos, sizeof(buf)-(pos-buf), "%s\r\n", text);
|
---|
845 | pos += snprintf(pos, sizeof(buf)-(pos-buf), "</BODY></HTML>\r\n");
|
---|
846 | send_headers(f, status, title, extra, "text/html", 0, strlen(buf), NULL, forcePlain);
|
---|
847 | if(forcePlain == 1) fwrite(buf, 1, strlen(buf), f);
|
---|
848 | else webif_write(buf, f);
|
---|
849 | }
|
---|
850 |
|
---|
851 | void send_error500(FILE *f){
|
---|
852 | send_error(f, 500, "Internal Server Error", NULL, "The server encountered an internal error that prevented it from fulfilling this request.", 0);
|
---|
853 | }
|
---|
854 |
|
---|
855 | void send_header304(FILE *f, char *extraheader){
|
---|
856 | send_headers(f, 304, "Not Modified", extraheader, NULL, 1, 0, NULL, 0);
|
---|
857 | }
|
---|
858 |
|
---|
859 | /*
|
---|
860 | * function for sending files.
|
---|
861 | */
|
---|
862 | void send_file(FILE *f, char *filename, char* subdir, time_t modifiedheader, uint32_t etagheader, char *extraheader){
|
---|
863 | int8_t filen = 0;
|
---|
864 | int32_t size = 0;
|
---|
865 | char* mimetype = "", *result = " ", *allocated = NULL;
|
---|
866 | time_t moddate;
|
---|
867 | char path[255];
|
---|
868 |
|
---|
869 | if (!strcmp(filename, "CSS")){
|
---|
870 | filename = cfg.http_css ? cfg.http_css : "";
|
---|
871 | if (subdir && strlen(subdir) > 0) {
|
---|
872 | filename = tpl_getFilePathInSubdir(cfg.http_tpl ? cfg.http_tpl : "", subdir, "site", ".css", path, 255);
|
---|
873 | }
|
---|
874 | mimetype = "text/css";
|
---|
875 | filen = 1;
|
---|
876 | } else if (!strcmp(filename, "JS")){
|
---|
877 | filename = cfg.http_jscript ? cfg.http_jscript : "";
|
---|
878 | if (subdir && strlen(subdir) > 0) {
|
---|
879 | filename = tpl_getFilePathInSubdir(cfg.http_tpl ? cfg.http_tpl : "", subdir, "oscam", ".js", path, 255);
|
---|
880 | }
|
---|
881 | mimetype = "text/javascript";
|
---|
882 | filen = 2;
|
---|
883 | }
|
---|
884 |
|
---|
885 | if (strlen(filename) > 0 && file_exists(filename)) {
|
---|
886 | struct stat st;
|
---|
887 | stat(filename, &st);
|
---|
888 | moddate = st.st_mtime;
|
---|
889 | // We need at least size 1 or keepalive gets problems on some browsers...
|
---|
890 | if(st.st_size > 0){
|
---|
891 | FILE *fp;
|
---|
892 | int32_t readen;
|
---|
893 | if((fp = fopen(filename, "r"))==NULL) return;
|
---|
894 | if (!cs_malloc(&allocated, st.st_size + 1)) {
|
---|
895 | send_error500(f);
|
---|
896 | fclose(fp);
|
---|
897 | return;
|
---|
898 | }
|
---|
899 | if((readen = fread(allocated, 1, st.st_size, fp)) == st.st_size){
|
---|
900 | allocated[readen] = '\0';
|
---|
901 | }
|
---|
902 | fclose(fp);
|
---|
903 | }
|
---|
904 |
|
---|
905 | if (filen == 1 && cfg.http_prepend_embedded_css) { // Prepend Embedded CSS
|
---|
906 | char* separator = "/* External CSS */";
|
---|
907 | char* oldallocated = allocated;
|
---|
908 | int32_t newsize = strlen(CSS) + strlen(separator) + 2;
|
---|
909 | if (oldallocated) newsize += strlen(oldallocated) + 1;
|
---|
910 | if (!cs_malloc(&allocated, newsize)) {
|
---|
911 | if (oldallocated) free(oldallocated);
|
---|
912 | send_error500(f);
|
---|
913 | return;
|
---|
914 | }
|
---|
915 | snprintf(allocated, newsize, "%s\n%s\n%s",
|
---|
916 | CSS, separator, (oldallocated != NULL ? oldallocated : ""));
|
---|
917 | if (oldallocated) free(oldallocated);
|
---|
918 | }
|
---|
919 |
|
---|
920 | if (allocated) result = allocated;
|
---|
921 |
|
---|
922 | } else {
|
---|
923 | #ifdef TOUCH
|
---|
924 | char* res_tpl = !subdir || strcmp(subdir, TOUCH_SUBDIR)
|
---|
925 | ? (filen == 1 ? CSS : JSCRIPT)
|
---|
926 | : (filen == 1 ? TOUCH_CSS : TOUCH_JSCRIPT);
|
---|
927 | if (strlen(res_tpl) > 0) result = res_tpl;
|
---|
928 | #else
|
---|
929 | if (filen == 1 && strlen(CSS) > 0){
|
---|
930 | result = CSS;
|
---|
931 | } else if (filen == 2 && strlen(JSCRIPT) > 0){
|
---|
932 | result = JSCRIPT;
|
---|
933 | }
|
---|
934 | #endif
|
---|
935 | moddate = first_client->login;
|
---|
936 | }
|
---|
937 |
|
---|
938 | size = strlen(result);
|
---|
939 |
|
---|
940 | if((etagheader == 0 && moddate < modifiedheader) || (etagheader > 0 && (uint32_t)crc32(0L, (uchar *)result, size) == etagheader)){
|
---|
941 | send_header304(f, extraheader);
|
---|
942 | } else {
|
---|
943 | send_headers(f, 200, "OK", NULL, mimetype, 1, size, result, 0);
|
---|
944 | webif_write(result, f);
|
---|
945 | }
|
---|
946 | if (allocated) free(allocated);
|
---|
947 | }
|
---|
948 |
|
---|
949 | /* Helper function for urldecode.*/
|
---|
950 | static int32_t x2i(int32_t i){
|
---|
951 | i=toupper(i);
|
---|
952 | i = i - '0';
|
---|
953 | if(i > 9) i = i - 'A' + '9' + 1;
|
---|
954 | return i;
|
---|
955 | }
|
---|
956 |
|
---|
957 | /* Decodes values in a http url. Note: The original value is modified! */
|
---|
958 | void urldecode(char *s){
|
---|
959 | int32_t c, c1, n;
|
---|
960 | char *t;
|
---|
961 | t = s;
|
---|
962 | n = strlen(s);
|
---|
963 | while(n >0){
|
---|
964 | c = *s++;
|
---|
965 | if(c == '+') c = ' ';
|
---|
966 | else if(c == '%' && n > 2){
|
---|
967 | c = *s++;
|
---|
968 | c1 = c;
|
---|
969 | c = *s++;
|
---|
970 | c = 16*x2i(c1) + x2i(c);
|
---|
971 | n -= 2;
|
---|
972 | }
|
---|
973 | *t++ = c;
|
---|
974 | n--;
|
---|
975 | }
|
---|
976 | *t = 0;
|
---|
977 | }
|
---|
978 |
|
---|
979 | /* Encode values in a http url. Do not call free() or realloc on the returned reference or you will get memory corruption! */
|
---|
980 | char *urlencode(struct templatevars *vars, char *str){
|
---|
981 | char *buf;
|
---|
982 | if (!cs_malloc(&buf, strlen(str) * 3 + 1)) return "";
|
---|
983 | char *pstr = str, *pbuf = buf;
|
---|
984 | while (*pstr) {
|
---|
985 | if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' || *pstr == '.' || *pstr == '~') *pbuf++ = *pstr;
|
---|
986 | else if (*pstr == ' ') *pbuf++ = '+';
|
---|
987 | else {
|
---|
988 | *pbuf++ = '%';
|
---|
989 | *pbuf++ = to_hex(*pstr >> 4);
|
---|
990 | *pbuf++ = to_hex(*pstr & 15);
|
---|
991 | }
|
---|
992 | ++pstr;
|
---|
993 | }
|
---|
994 | *pbuf = '\0';
|
---|
995 | /* Allocate the needed memory size and store it in the templatevars */
|
---|
996 | if (!cs_realloc(&buf, strlen(buf) + 1)) return "";
|
---|
997 | return tpl_addTmp(vars, buf);
|
---|
998 | }
|
---|
999 |
|
---|
1000 | /* XML-Escapes a char array. The returned reference will be automatically cleaned through the templatevars-mechanism tpl_clear().
|
---|
1001 | Do not call free() or realloc on the returned reference or you will get memory corruption! */
|
---|
1002 | char *xml_encode(struct templatevars *vars, char *chartoencode) {
|
---|
1003 | if (chartoencode == NULL) return "";
|
---|
1004 | int32_t i, pos = 0, len = strlen(chartoencode);
|
---|
1005 | char *encoded;
|
---|
1006 | char buffer[7];
|
---|
1007 | /* In worst case, every character could get converted to 6 chars (we only support ASCII, for Unicode it would be 7)*/
|
---|
1008 | if (!cs_malloc(&encoded, len * 6 + 1)) return "";
|
---|
1009 | for (i = 0; i < len; ++i){
|
---|
1010 | unsigned char tmp = chartoencode[i];
|
---|
1011 | switch(tmp) {
|
---|
1012 | case '&': memcpy(encoded + pos, "&", 5); pos+=5; break;
|
---|
1013 | case '<': memcpy(encoded + pos, "<", 4); pos+=4; break;
|
---|
1014 | case '>': memcpy(encoded + pos, ">", 4); pos+=4; break;
|
---|
1015 | case '"': memcpy(encoded + pos, """, 6); pos+=6; break;
|
---|
1016 | case '\'': memcpy(encoded + pos, "'", 5); pos+=5; break; //' not supported on older IE
|
---|
1017 | case '\n': memcpy(encoded + pos, "\n", 1); pos+=1; break;
|
---|
1018 |
|
---|
1019 | default:
|
---|
1020 | if (tmp < 32 || (cs_http_use_utf8 != 1 && tmp > 127)) {
|
---|
1021 | snprintf(buffer, 7, "&#%d;", tmp);
|
---|
1022 | memcpy(encoded + pos, buffer, strlen(buffer));
|
---|
1023 | pos+=strlen(buffer);
|
---|
1024 |
|
---|
1025 | } else {
|
---|
1026 | encoded[pos] = tmp;
|
---|
1027 | ++pos;
|
---|
1028 | }
|
---|
1029 |
|
---|
1030 | }
|
---|
1031 | }
|
---|
1032 | /* Reduce to the really needed memory size and store it in the templatevars */
|
---|
1033 | if (!cs_realloc(&encoded, pos + 1)) return "";
|
---|
1034 | encoded[pos] = '\0';
|
---|
1035 | return tpl_addTmp(vars, encoded);
|
---|
1036 | }
|
---|
1037 |
|
---|
1038 | /* Prepares the base64 decoding array */
|
---|
1039 | void b64prepare(void) {
|
---|
1040 | const unsigned char alphabet[64] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
---|
1041 | int32_t i;
|
---|
1042 | for (i = sizeof(b64decoder) - 1; i >= 0; --i) {
|
---|
1043 | b64decoder[i] = -1;
|
---|
1044 | }
|
---|
1045 |
|
---|
1046 | for (i = sizeof(alphabet) - 1; i >= 0; --i) {
|
---|
1047 | b64decoder[alphabet[i]] = i;
|
---|
1048 | }
|
---|
1049 | }
|
---|
1050 |
|
---|
1051 | /* Decodes a base64-encoded string. The given array will be used directly for output and is thus modified! */
|
---|
1052 | int32_t b64decode(unsigned char *result){
|
---|
1053 | int32_t i, len = strlen((char *)result), j = 0, bits = 0, char_count = 0;
|
---|
1054 |
|
---|
1055 | for(i = 0; i < len; ++i){
|
---|
1056 | if (result[i] == '=') break;
|
---|
1057 | int8_t tmp = b64decoder[result[i]];
|
---|
1058 | if(tmp == -1) continue;
|
---|
1059 | bits += tmp;
|
---|
1060 | ++char_count;
|
---|
1061 | if (char_count == 4) {
|
---|
1062 | result[j++] = bits >> 16;
|
---|
1063 | result[j++] = (bits >> 8) & 0xff;
|
---|
1064 | result[j++] = bits & 0xff;
|
---|
1065 | bits = 0;
|
---|
1066 | char_count = 0;
|
---|
1067 | } else {
|
---|
1068 | bits <<= 6;
|
---|
1069 | }
|
---|
1070 | }
|
---|
1071 | if (i == len) {
|
---|
1072 | if (char_count) {
|
---|
1073 | result[j] = '\0';
|
---|
1074 | return 0;
|
---|
1075 | }
|
---|
1076 | } else {
|
---|
1077 | switch (char_count) {
|
---|
1078 | case 1:
|
---|
1079 | result[j] = '\0';
|
---|
1080 | return 0;
|
---|
1081 | case 2:
|
---|
1082 | result[j++] = bits >> 10;
|
---|
1083 | result[j] = '\0';
|
---|
1084 | break;
|
---|
1085 | case 3:
|
---|
1086 | result[j++] = bits >> 16;
|
---|
1087 | result[j++] = (bits >> 8) & 0xff;
|
---|
1088 | result[j] = '\0';
|
---|
1089 | break;
|
---|
1090 | }
|
---|
1091 | }
|
---|
1092 | return j;
|
---|
1093 | }
|
---|
1094 |
|
---|
1095 | /* Format a seconds integer to hh:mm:ss or dd hh:mm:ss depending hrs >24 */
|
---|
1096 | char *sec2timeformat(struct templatevars *vars, int32_t seconds) {
|
---|
1097 |
|
---|
1098 | char *value;
|
---|
1099 | if(seconds <= 0)
|
---|
1100 | return "00:00:00";
|
---|
1101 |
|
---|
1102 | if (!cs_malloc(&value, 16))
|
---|
1103 | return "00:00:00";
|
---|
1104 |
|
---|
1105 | int32_t secs = 0, fullmins = 0, mins = 0, fullhours = 0, hours = 0, days = 0;
|
---|
1106 |
|
---|
1107 | secs = seconds % 60;
|
---|
1108 | if (seconds >= 60) {
|
---|
1109 | fullmins = seconds / 60;
|
---|
1110 | mins = fullmins % 60;
|
---|
1111 | if(fullmins >= 60) {
|
---|
1112 | fullhours = fullmins / 60;
|
---|
1113 | hours = fullhours % 24;
|
---|
1114 | days = fullhours / 24;
|
---|
1115 | }
|
---|
1116 | }
|
---|
1117 |
|
---|
1118 | if(days == 0)
|
---|
1119 | snprintf(value, 16, "%02d:%02d:%02d", hours, mins, secs);
|
---|
1120 | else
|
---|
1121 | snprintf(value, 16, "%02dd %02d:%02d:%02d", days, hours, mins, secs);
|
---|
1122 |
|
---|
1123 | return tpl_addTmp(vars, value);
|
---|
1124 | }
|
---|
1125 |
|
---|
1126 | /* Parse url parameters and save them to params array. The pch pointer is increased to the position where parsing stopped. */
|
---|
1127 | void parseParams(struct uriparams *params, char *pch) {
|
---|
1128 | char *pch2;
|
---|
1129 | // parsemode = 1 means parsing next param, parsemode = -1 parsing next
|
---|
1130 | //value; pch2 points to the beginning of the currently parsed string, pch is the current position
|
---|
1131 | int32_t parsemode = 1;
|
---|
1132 |
|
---|
1133 | pch2=pch;
|
---|
1134 | while(pch[0] != '\0') {
|
---|
1135 | if((parsemode == 1 && pch[0] == '=') || (parsemode == -1 && pch[0] == '&')) {
|
---|
1136 | pch[0] = '\0';
|
---|
1137 | urldecode(pch2);
|
---|
1138 | if(parsemode == 1) {
|
---|
1139 | if(params->paramcount >= MAXGETPARAMS) break;
|
---|
1140 | ++params->paramcount;
|
---|
1141 | params->params[params->paramcount-1] = pch2;
|
---|
1142 | } else {
|
---|
1143 | params->values[params->paramcount-1] = pch2;
|
---|
1144 | }
|
---|
1145 | parsemode = -parsemode;
|
---|
1146 | pch2 = pch + 1;
|
---|
1147 | }
|
---|
1148 | ++pch;
|
---|
1149 | }
|
---|
1150 | /* last value wasn't processed in the loop yet... */
|
---|
1151 | if(parsemode == -1 && params->paramcount <= MAXGETPARAMS) {
|
---|
1152 | urldecode(pch2);
|
---|
1153 | params->values[params->paramcount-1] = pch2;
|
---|
1154 | }
|
---|
1155 | }
|
---|
1156 |
|
---|
1157 | /* Returns the value of the parameter called name or an empty string if it doesn't exist. */
|
---|
1158 | char *getParam(struct uriparams *params, char *name){
|
---|
1159 | int32_t i;
|
---|
1160 | for(i=(*params).paramcount-1; i>=0; --i){
|
---|
1161 | if(strcmp((*params).params[i], name) == 0) return (*params).values[i];
|
---|
1162 | }
|
---|
1163 | return "";
|
---|
1164 | }
|
---|
1165 |
|
---|
1166 |
|
---|
1167 | #ifdef WITH_SSL
|
---|
1168 | SSL * cur_ssl(void){
|
---|
1169 | return (SSL *) pthread_getspecific(getssl);
|
---|
1170 | }
|
---|
1171 |
|
---|
1172 | /* Locking functions for SSL multithreading */
|
---|
1173 | struct CRYPTO_dynlock_value{
|
---|
1174 | pthread_mutex_t mutex;
|
---|
1175 | };
|
---|
1176 |
|
---|
1177 | /* function really needs unsigned long to prevent compiler warnings... */
|
---|
1178 | static unsigned long SSL_id_function(void){
|
---|
1179 | return ((unsigned long) pthread_self());
|
---|
1180 | }
|
---|
1181 |
|
---|
1182 | static void SSL_locking_function(int32_t mode, int32_t type, const char *file, int32_t line) {
|
---|
1183 | if (mode & CRYPTO_LOCK) {
|
---|
1184 | cs_writelock(&lock_cs[type]);
|
---|
1185 | } else {
|
---|
1186 | cs_writeunlock(&lock_cs[type]);
|
---|
1187 | }
|
---|
1188 | // just to remove compiler warnings...
|
---|
1189 | if(file || line) return;
|
---|
1190 | }
|
---|
1191 |
|
---|
1192 | static struct CRYPTO_dynlock_value *SSL_dyn_create_function(const char *file, int32_t line) {
|
---|
1193 | struct CRYPTO_dynlock_value *l;
|
---|
1194 | if (!cs_malloc(&l, sizeof(struct CRYPTO_dynlock_value)))
|
---|
1195 | return NULL;
|
---|
1196 |
|
---|
1197 | if(pthread_mutex_init(&l->mutex, NULL)) {
|
---|
1198 | // Initialization of mutex failed.
|
---|
1199 | free(l);
|
---|
1200 | return (NULL);
|
---|
1201 | }
|
---|
1202 | pthread_mutex_init(&l->mutex, NULL);
|
---|
1203 | // just to remove compiler warnings...
|
---|
1204 | if(file || line) return l;
|
---|
1205 | return l;
|
---|
1206 | }
|
---|
1207 |
|
---|
1208 | static void SSL_dyn_lock_function(int32_t mode, struct CRYPTO_dynlock_value *l, const char *file, int32_t line) {
|
---|
1209 | if (mode & CRYPTO_LOCK) {
|
---|
1210 | pthread_mutex_lock(&l->mutex);
|
---|
1211 | } else {
|
---|
1212 | pthread_mutex_unlock(&l->mutex);
|
---|
1213 | }
|
---|
1214 | // just to remove compiler warnings...
|
---|
1215 | if(file || line) return;
|
---|
1216 | }
|
---|
1217 |
|
---|
1218 | static void SSL_dyn_destroy_function(struct CRYPTO_dynlock_value *l, const char *file, int32_t line) {
|
---|
1219 | pthread_mutex_destroy(&l->mutex);
|
---|
1220 | free(l);
|
---|
1221 | // just to remove compiler warnings...
|
---|
1222 | if(file || line) return;
|
---|
1223 | }
|
---|
1224 |
|
---|
1225 | /* Init necessary structures for SSL in WebIf*/
|
---|
1226 | SSL_CTX *SSL_Webif_Init(void) {
|
---|
1227 | SSL_library_init();
|
---|
1228 | SSL_load_error_strings();
|
---|
1229 | ERR_load_BIO_strings();
|
---|
1230 | ERR_load_SSL_strings();
|
---|
1231 |
|
---|
1232 | SSL_CTX *ctx;
|
---|
1233 |
|
---|
1234 | static const char *cs_cert="oscam.pem";
|
---|
1235 |
|
---|
1236 | if (pthread_key_create(&getssl, NULL)) {
|
---|
1237 | cs_log("Could not create getssl");
|
---|
1238 | }
|
---|
1239 |
|
---|
1240 | // set locking callbacks for SSL
|
---|
1241 | int32_t i, num = CRYPTO_num_locks();
|
---|
1242 | lock_cs = (CS_MUTEX_LOCK*) OPENSSL_malloc(num * sizeof(CS_MUTEX_LOCK));
|
---|
1243 |
|
---|
1244 | for (i = 0; i < num; ++i) {
|
---|
1245 | cs_lock_create(&lock_cs[i], 10, "ssl_lock_cs");
|
---|
1246 | }
|
---|
1247 | /* static lock callbacks */
|
---|
1248 | CRYPTO_set_id_callback(SSL_id_function);
|
---|
1249 | CRYPTO_set_locking_callback(SSL_locking_function);
|
---|
1250 | /* dynamic lock callbacks */
|
---|
1251 | CRYPTO_set_dynlock_create_callback(SSL_dyn_create_function);
|
---|
1252 | CRYPTO_set_dynlock_lock_callback(SSL_dyn_lock_function);
|
---|
1253 | CRYPTO_set_dynlock_destroy_callback(SSL_dyn_destroy_function);
|
---|
1254 |
|
---|
1255 | if(cfg.http_force_sslv3){
|
---|
1256 | ctx = SSL_CTX_new(SSLv3_server_method());
|
---|
1257 | #ifdef SSL_CTX_clear_options
|
---|
1258 | SSL_CTX_clear_options(ctx, SSL_OP_ALL); //we CLEAR all bug workarounds! This is for security reason
|
---|
1259 | #else
|
---|
1260 | cs_log("WARNING: You enabled to force sslv3 but your system does not support to clear the ssl workarounds! SSL security will be reduced!");
|
---|
1261 | #endif
|
---|
1262 | SSL_CTX_set_options(ctx, SSL_OP_NO_SSLv2); // we force SSL v3 !
|
---|
1263 | SSL_CTX_set_cipher_list(ctx, SSL_TXT_RC4);
|
---|
1264 | } else
|
---|
1265 | ctx = SSL_CTX_new(SSLv23_server_method());
|
---|
1266 |
|
---|
1267 | char path[128];
|
---|
1268 |
|
---|
1269 | if (!cfg.http_cert)
|
---|
1270 | get_config_filename(path, sizeof(path), cs_cert);
|
---|
1271 | else
|
---|
1272 | cs_strncpy(path, cfg.http_cert, sizeof(path));
|
---|
1273 |
|
---|
1274 | if (!ctx) {
|
---|
1275 | ERR_print_errors_fp(stderr);
|
---|
1276 | return NULL;
|
---|
1277 | }
|
---|
1278 |
|
---|
1279 | if (SSL_CTX_use_certificate_file(ctx, path, SSL_FILETYPE_PEM) <= 0) {
|
---|
1280 | ERR_print_errors_fp(stderr);
|
---|
1281 | return NULL;
|
---|
1282 | }
|
---|
1283 |
|
---|
1284 | if (SSL_CTX_use_PrivateKey_file(ctx, path, SSL_FILETYPE_PEM) <= 0) {
|
---|
1285 | ERR_print_errors_fp(stderr);
|
---|
1286 | return NULL;
|
---|
1287 | }
|
---|
1288 |
|
---|
1289 | if (!SSL_CTX_check_private_key(ctx)) {
|
---|
1290 | cs_log("SSL: Private key does not match the certificate public key");
|
---|
1291 | return NULL;
|
---|
1292 | }
|
---|
1293 | cs_log("load ssl certificate file %s", path);
|
---|
1294 | return ctx;
|
---|
1295 | }
|
---|
1296 | #endif
|
---|
1297 |
|
---|
1298 | #endif
|
---|