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