source: branches/monitor-improvement/oscam-http-helpers.c@ 1256

Last change on this file since 1256 was 1256, checked in by Admin, 11 years ago

Add cs_strncpy as a replacement for strncpy. This function always terminates the string and works pretty much like strlcpy but without return value.

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