1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <time.h>
5 #include <ctype.h>
6
7 #ifndef WIN32
8 #include <sys/time.h>
9 #include <sys/types.h>
10 #include <dirent.h>
11 #include <sys/stat.h>
12 #include <unistd.h>
13 #endif
14
15 #include "config.h"
16 #include "core.h"
17 #include "list.h"
18 #include "user.h"
19 #include "fileapi.h"
20 #include "variables.h"
21 #include "compat.h"
22 #include "cookie.h"
23 #include "mystring.h"
24
25 struct cookie_data *cookies;
26 static int gcookiecount;
27
28 /* initializes the cookie type storage */
new_cookies()29 void new_cookies()
30 {
31 cookies = NULL;
32 gcookiecount = 0;
33 }
34
35 /* cleans up the cookie type storage */
nuke_cookies()36 void nuke_cookies()
37 {
38 struct cookie_data *temp, *temp2;
39 temp = cookies;
40 while(temp) {
41 temp2 = temp->next;
42 if(temp->expire) free(temp->expire);
43 free(temp);
44 temp = temp2;
45 }
46 cookies = NULL;
47 }
48
find_cookie_info(char type)49 struct cookie_data *find_cookie_info(char type)
50 {
51 struct cookie_data *temp = cookies;
52 while(temp) {
53 if(temp->type == type) return temp;
54 temp = temp->next;
55 }
56 return NULL;
57 }
58
59 /* Register a new type of cookie for us to deal with */
register_cookie(char type,const char * expirevar,CookieFn create,CookieFn destroy)60 void register_cookie(char type, const char *expirevar, CookieFn create,
61 CookieFn destroy)
62 {
63 struct cookie_data *temp = find_cookie_info(type);
64 if(temp) {
65 log_printf(0, "Reregistration of cookie type '%c'\n", type);
66 return;
67 }
68 temp = (struct cookie_data *)malloc(sizeof(struct cookie_data));
69 temp->type = type;
70 temp->create = create;
71 temp->destroy = destroy;
72 temp->expire = NULL;
73 if(expirevar)
74 temp->expire = strdup(expirevar);
75 temp->next = cookies;
76 cookies = temp;
77 }
78
79 /* Generates a cookie. 'encstring' is the string to encode,
80 * finalstr is the buffer for the resulting cookie. This is
81 * used internally. */
gen_cookie(const char * encstring,char * finalstr)82 void gen_cookie(const char *encstring, char *finalstr)
83 {
84 char tbuf[SMALL_BUF];
85 signed char *tptr;
86 const signed char *cptr;
87 time_t now;
88 int temp;
89
90 time(&now);
91
92 tptr = (signed char *)tbuf;
93 cptr = (const signed char *)encstring;
94
95 while(*cptr) {
96 if (isalpha((int)*cptr)) {
97 *tptr = tolower(*cptr);
98
99 temp = (*tptr - 96) - 13;
100 if (temp <= 0)
101 temp += 26;
102 *tptr = (char)(temp + 96);
103 tptr++;
104 }
105 cptr++;
106 }
107 *tptr = '\0';
108
109 gcookiecount++;
110
111 #ifdef OBSDMOD
112 buffer_printf(finalstr, BIG_BUF - 1, "%lX:%X.%X:%s", (long)now, (int)getpid(),
113 gcookiecount, tbuf);
114 #else
115 #if DEC_UNIX || _AIX
116 buffer_printf(finalstr, BIG_BUF - 1, "%X:%X.%X:%s", now, (int)getpid(), gcookiecount, tbuf);
117 #else
118 buffer_printf(finalstr, BIG_BUF - 1, "%lX:%X.%X:%s", now, (int)getpid(), gcookiecount,
119 tbuf);
120 #endif /* DEC_UNIX */
121 #endif /* OBSDMOD */
122 }
123
124 /* Used internally, checks an plain-text string against the encoded
125 * string portion of a given cookie, and returns 1 if matched, 0 if not.
126 * Used internally. */
match_cookie(const char * cookie,const char * match)127 int match_cookie(const char *cookie, const char *match)
128 {
129 char buffer[BIG_BUF];
130 const char *tcheck;
131 char *tcheck2;
132
133 log_printf(9, "Checking cookies %s and %s\n", cookie, match);
134
135 memset(buffer, 0, sizeof(buffer));
136
137 gen_cookie(match,buffer);
138
139 tcheck = (char *)strrchr(cookie,':');
140 tcheck2 = (char *)strrchr(buffer,':');
141
142 if (tcheck && tcheck2) {
143 tcheck++;
144 tcheck2++;
145 if (!strcmp(tcheck,tcheck2))
146 return 1;
147 }
148
149 return 0;
150 }
151
152 /* Requests a cookie. Filename is the cookiefile to place it in,
153 * cookiedata is the string to tie to the cookie, and cookie is
154 * a buffer to place the cookie into. */
request_cookie(const char * filename,char * cookie,char type,const char * cookiedata)155 int request_cookie(const char *filename, char *cookie, char type,
156 const char *cookiedata)
157 {
158 FILE *cookiefile;
159 const char *cookiefor;
160 struct cookie_data *temp = find_cookie_info(type);
161
162 if(!temp) {
163 log_printf(0, "Cookie requested for unknown type '%c'\n", type);
164 return 0;
165 }
166
167 if ((cookiefile = open_file(filename,"a")) == NULL)
168 return 0;
169
170 cookiefor = get_var("cookie-for");
171 if (!cookiefor)
172 cookiefor = get_string("realsender");
173
174 gen_cookie(cookiefor,cookie);
175
176 write_file(cookiefile,"%s : %c%s\n", cookie, type, cookiedata);
177 close_file(cookiefile);
178
179 if(temp->create)
180 return !(((temp->create)(cookie, type, cookiedata)));
181
182 return 1;
183 }
184
185 /* Verifies a cookie. Filename is the filename to check for the cookie,
186 * cookie is the cookie to check for, and reason is a buffer to place
187 * the reason for the cookie into (the cookiedata from above). */
verify_cookie(const char * filename,const char * cookie,char type,char * data)188 int verify_cookie(const char *filename, const char *cookie, char type,
189 char *data)
190 {
191 FILE *cookiefile;
192 char cookiestring[BIG_BUF];
193 int foundcookie;
194 char tbuf[BIG_BUF];
195 struct cookie_data *temp = find_cookie_info(type);
196
197 if(!temp) {
198 log_printf(0, "Cookie verification attempted on unknown type '%s'\n",
199 type);
200 return 0;
201 }
202
203 if (!exists_file(filename)) return 0;
204
205 if ((cookiefile = open_file(filename,"r")) == NULL)
206 return 0;
207
208 log_printf(9, "Looking for cookie : %s\n", cookie);
209
210 foundcookie = 0;
211
212 while (read_file(cookiestring, sizeof(cookiestring), cookiefile) && !foundcookie) {
213 if (strchr(cookiestring,':')) {
214 sscanf(cookiestring, "%s :", &tbuf[0]);
215 log_printf(9, "Checking cookie : %s and tbuf : %s\n", cookie, tbuf);
216 if (!strcmp(tbuf,cookie)) {
217 char *tval;
218
219 foundcookie = 1;
220 if (cookiestring[strlen(cookiestring) - 1] == '\n')
221 cookiestring[strlen(cookiestring) - 1] = '\0';
222 tval = strchr(cookiestring,':');
223 *tval++ = '\0';
224 tval = strstr(tval," : ");
225 tval = tval + 3;
226 if(temp->type != *tval) {
227 log_printf(1, "Wrong cookie type! '%c'!='%c'\n", *tval,
228 temp->type);
229 return 0;
230 }
231 buffer_printf(data, BIG_BUF - 1, "%s", tval+1);
232 }
233 }
234 }
235
236 close_file(cookiefile);
237
238 return foundcookie;
239 }
240
modify_cookie(const char * filename,const char * cookie,const char * data)241 int modify_cookie(const char *filename, const char *cookie, const char *data)
242 {
243 FILE *cookiefile, *newcookiefile;
244 char cookiestring[BIG_BUF];
245 char tbuf[BIG_BUF];
246
247 if (!exists_file(filename)) return 0;
248
249 if((cookiefile = open_exclusive(filename, "r+")) == NULL)
250 return 0;
251 buffer_printf(tbuf, sizeof(tbuf) - 1, "%s.cookiechange", get_string("queuefile"));
252 if ((newcookiefile = open_file(tbuf,"w+")) == NULL) {
253 close_file(cookiefile);
254 return 0;
255 }
256
257 while (read_file(cookiestring, sizeof(cookiestring), cookiefile)) {
258 char *loc = strchr(cookiestring, ':');
259 if (!loc)
260 continue;
261 sscanf(cookiestring, "%s :", &tbuf[0]);
262 if (strcmp(tbuf,cookie)) {
263 write_file(newcookiefile,"%s",cookiestring);
264 } else {
265 if(cookiestring[strlen(cookiestring)-1] == '\n')
266 cookiestring[strlen(cookiestring)-1] = '\0'; /* smash newline*/
267 loc = strstr(loc, " : ");
268 loc = loc + 4;
269 *loc = '\0';
270 if(data[strlen(data)-1] != '\n')
271 write_file(newcookiefile, "%s%s\n", cookiestring, data);
272 else
273 write_file(newcookiefile, "%s%s", cookiestring, data);
274 }
275 }
276 rewind_file(newcookiefile);
277 rewind_file(cookiefile);
278 truncate_file(cookiefile, 0);
279 while(read_file(tbuf, sizeof(tbuf), newcookiefile)) {
280 write_file(cookiefile, "%s", tbuf);
281 }
282 close_file(cookiefile);
283 close_file(newcookiefile);
284
285 buffer_printf(tbuf, sizeof(tbuf) - 1, "%s.cookiechange", get_string("queuefile"));
286 (void)unlink_file(tbuf);
287
288 return 1;
289 }
290
291 /* matches a cookie given a type and portion of the data field */
292 /* You *MUST* free this string when you are done with it */
find_cookie(const char * filename,char type,const char * partial)293 char *find_cookie(const char *filename, char type, const char *partial)
294 {
295 FILE *cookiefile;
296 char *res = NULL;
297 char cookiestring[BIG_BUF];
298 int done = 0;
299
300 if (!exists_file(filename)) return 0;
301
302 if((cookiefile = open_file(filename, "r")) == NULL)
303 return NULL;
304
305 while (!done && read_file(cookiestring, sizeof(cookiestring), cookiefile)) {
306 char *loc = strstr(cookiestring, " : ");
307 if(!loc)
308 continue;
309 loc+=3;
310 if(*loc != type)
311 continue;
312 loc++;
313 if(cookiestring[strlen(cookiestring)-1] == '\n')
314 cookiestring[strlen(cookiestring)-1] = '\0'; /* smash newline*/
315 if(strstr(loc, partial)) {
316 res = strdup(cookiestring);
317 done = 1;
318 }
319 }
320 close_file(cookiefile);
321 return res;
322 }
323
324
325 /* Deletes a cookie from a file. */
del_cookie(const char * filename,const char * cookie)326 int del_cookie(const char *filename, const char *cookie)
327 {
328 FILE *cookiefile, *newcookiefile;
329 char cookiestring[BIG_BUF];
330 char tbuf[BIG_BUF];
331 struct cookie_data *temp;
332 int res = 1;
333
334 if (!exists_file(filename)) return 0;
335
336 if((cookiefile = open_exclusive(filename, "r+")) == NULL)
337 return 0;
338 buffer_printf(tbuf, sizeof(tbuf) - 1, "%s.cookiechange", get_string("queuefile"));
339 if ((newcookiefile = open_file(tbuf,"w+")) == NULL) {
340 close_file(cookiefile);
341 return 0;
342 }
343
344 while (read_file(cookiestring, sizeof(cookiestring), cookiefile)) {
345 char *loc = strchr(cookiestring, ':');
346 if (loc) {
347 sscanf(cookiestring, "%s :", &tbuf[0]);
348 if (strcmp(tbuf,cookie)) {
349 write_file(newcookiefile,"%s",cookiestring);
350 } else {
351 char type;
352 if(cookiestring[strlen(cookiestring)-1] == '\n')
353 cookiestring[strlen(cookiestring)-1] = '\0'; /* smash newline*/
354 loc = strstr(loc, " : ");
355 *loc = '\0';
356 loc = loc + 3;
357 type = *loc++;
358 temp = find_cookie_info(type);
359 if(temp && temp->destroy)
360 res = !((temp->destroy)(cookie, type, loc));
361 }
362 }
363 }
364 rewind_file(newcookiefile);
365 rewind_file(cookiefile);
366 truncate_file(cookiefile, 0);
367 while(read_file(tbuf, sizeof(tbuf), newcookiefile)) {
368 write_file(cookiefile, "%s", tbuf);
369 }
370 close_file(cookiefile);
371 close_file(newcookiefile);
372
373 buffer_printf(tbuf, sizeof(tbuf) - 1, "%s.cookiechange", get_string("queuefile"));
374 (void)unlink_file(tbuf);
375
376 return res;
377 }
378
379 /* Expires cookies in a file. */
expire_cookies(const char * filename)380 void expire_cookies(const char *filename)
381 {
382 char buf[BIG_BUF];
383 char buf2[BIG_BUF];
384 char cookie[BIG_BUF];
385 #ifdef OBSDMOD
386 long cookiedate;
387 #else
388 time_t cookiedate;
389 #endif
390 int age;
391 time_t old = time(NULL);
392 FILE *oldfile, *newfile;
393
394 if(!exists_file(filename)) return;
395
396 if((oldfile = open_exclusive(filename, "r+")) == NULL)
397 return;
398 buffer_printf(buf, sizeof(buf) - 1, "%s.cookiechange", get_string("queuefile"));
399 if ((newfile = open_exclusive(buf,"w+")) == NULL) {
400 close_file(oldfile);
401 return;
402 }
403
404
405 while(read_file(buf, sizeof(buf), oldfile)) {
406 #ifdef OBSDMOD
407 long expiretime = 0;
408 #else
409 time_t expiretime = 0;
410 #endif
411 char *tmp;
412 char type = ' ';
413 int bogus = 1;
414 struct cookie_data *temp = NULL;
415 /* Now you know the deep, dark secret of why the first chunk of
416 * the cookie is a hexadecimal timestamp. Easier to expire. :) */
417 #ifdef OBSDMOD
418 sscanf(buf, "%lX:%s", &cookiedate, &cookie[0]);
419 #else
420 #if DEC_UNIX || _AIX
421 sscanf(buf, "%X:%s", &cookiedate, &cookie[0]);
422 #else
423 sscanf(buf, "%lX:%s", &cookiedate, &cookie[0]);
424 #endif
425 #endif
426 stringcpy(buf2, buf);
427 if(buf2[strlen(buf2)-1] == '\n')
428 buf2[strlen(buf2)-1] = '\0'; /* smash newline*/
429 tmp = strstr(buf2, " : ");
430 if(tmp) {
431 *tmp = '\0';
432 tmp = tmp + 3;
433 type = *tmp++;
434 temp = find_cookie_info(type);
435 /* expire older cookies */
436 if(temp) {
437 bogus = 0;
438 if(temp->expire) {
439 /*
440 * This hack is to handle cookies which carry their
441 * own timeout inside their data
442 */
443 if(strcasecmp(temp->expire, "$$COOKIE$$") == 0) {
444 #ifdef OBSDMOD
445 sscanf(tmp, "%lX;", &expiretime);
446 #else
447 #if DEC_UNIX || _AIX
448 sscanf(tmp, "%X;", &expiretime);
449 #else
450 sscanf(tmp, "%lX;", &expiretime);
451 #endif
452 #endif
453 } else if(get_var(temp->expire)) {
454 age = get_seconds(temp->expire);
455 old -= age;
456 } else {
457 age = get_seconds("cookie-expiration-time");
458 old -= age;
459 }
460 } else {
461 old = 0;
462 }
463 }
464 }
465 if(bogus)
466 continue;
467 if((expiretime && (old > expiretime)) ||
468 (!expiretime && (cookiedate < old))) {
469 if(temp && temp->destroy)
470 (temp->destroy)(cookie, type, tmp);
471 continue;
472 }
473 write_file(newfile, "%s", buf);
474 }
475 rewind_file(newfile);
476 rewind_file(oldfile);
477 truncate_file(oldfile, 0);
478 while(read_file(buf, sizeof(buf), newfile)) {
479 write_file(oldfile, "%s", buf);
480 }
481 close_file(oldfile);
482 close_file(newfile);
483
484 buffer_printf(buf, sizeof(buf) - 1, "%s.cookiechange", get_string("queuefile"));
485 (void)unlink_file(buf);
486 }
487
488 /* Expires cookies in all lists. */
expire_all_cookies(void)489 void expire_all_cookies(void)
490 {
491 char buf[BIG_BUF];
492 char tbuf[BIG_BUF];
493 int status;
494
495 status = 0;
496
497 buffer_printf(buf, sizeof(buf) - 1, "%s/SITEDATA/cookies", get_string("lists-root"));
498 if(exists_file(buf)){
499 wipe_vars(VAR_LIST|VAR_TEMP);
500 set_var("mode", "nolist", VAR_TEMP);
501 expire_cookies(buf);
502 }
503
504 if (!get_bool("expire-all-cookies")) return;
505
506 status = walk_lists(&tbuf[0]);
507 while(status) {
508 if(list_valid(tbuf)) {
509 listdir_file(buf, tbuf, "cookies");
510 if(exists_file(buf)){
511 wipe_vars(VAR_LIST|VAR_TEMP);
512 set_var("mode", "nolist", VAR_TEMP);
513 set_var("list", tbuf, VAR_TEMP);
514 list_read_conf();
515 expire_cookies(buf);
516 }
517 }
518 status = next_lists(&tbuf[0]);
519 }
520 wipe_vars(VAR_LIST|VAR_TEMP);
521 }
522