1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <fcntl.h>
4 #include <stddef.h>
5 #include <stdio.h>
6 #include <stdint.h>
7 #include <string.h>
8 #include <unistd.h>
9 #include <pthread.h>
10 #include <array.h>
11 #include <hash.h>
12 #include <perl.h>
13 #include <setup.h>
14 #include <memory.h>
15 #include <notify.h>
16 #include <cookies.h>
17
18 typedef struct NODE {
19 size_t threadID;
20 COOKIE cookie;
21 struct NODE *next;
22 } NODE;
23
24 struct COOKIES_T {
25 NODE * head;
26 size_t size;
27 char * file;
28 };
29
30 private NODE * __delete_node(NODE *node);
31 private BOOLEAN __exists(char *file);
32 private BOOLEAN __save_cookies(COOKIES this);
33
34 COOKIES
new_cookies()35 new_cookies() {
36 int len;
37 COOKIES this;
38 char name[] = "/.siege/cookies.txt";
39
40 this = calloc(sizeof(struct COOKIES_T), 1);
41 this->size = 0;
42 char *p = getenv("HOME");
43 len = p ? strlen(p) : 60;
44 len += strlen(name)+1;
45 this->file = xmalloc(sizeof (char*) * len);
46 memset(this->file, '\0', len);
47 snprintf(this->file, len, "%s%s", getenv("HOME"), name);
48 return this;
49 }
50
51 COOKIES
cookies_destroy(COOKIES this)52 cookies_destroy(COOKIES this)
53 {
54 NODE *cur = NULL;
55 __save_cookies(this);
56 cur = this->head;
57 while (cur) {
58 cur = __delete_node(cur);
59 }
60 xfree(this->file);
61 free(this);
62 return NULL;
63 }
64
65 BOOLEAN
cookies_add(COOKIES this,char * str,char * host)66 cookies_add(COOKIES this, char *str, char *host)
67 {
68 size_t id = (uintptr_t)pthread_self();
69 int hlen = 0;
70 int dlen = 0;
71 NODE *cur = NULL;
72 NODE *pre = NULL;
73 NODE *new = NULL;
74 BOOLEAN found = FALSE;
75 BOOLEAN valid = FALSE;
76 COOKIE oreo = new_cookie(str, host);
77
78 if (oreo == NULL) return FALSE;
79 if (cookie_get_name(oreo) == NULL || cookie_get_value(oreo) == NULL) return FALSE;
80
81 //pthread_mutex_lock(&(my.lock));
82 for (cur = pre = this->head; cur != NULL; pre = cur, cur = cur->next) {
83 const char *domainptr = cookie_get_domain(cur->cookie);
84 if (*domainptr == '.') ++domainptr;
85 hlen = host ? strlen(host) : 0;
86 dlen = domainptr ? strlen(domainptr) : 0;
87 if (! strcasecmp(host, domainptr)) {
88 valid = TRUE; // host level cookie found
89 }
90 if (! valid && (dlen < hlen) && (! strcasecmp(host + (hlen - dlen), domainptr))) {
91 valid = TRUE; // domain level cookie found
92 }
93 if (valid && cur->threadID == id && !strcasecmp(cookie_get_name(cur->cookie), cookie_get_name(oreo))) {
94 cookie_reset_value(cur->cookie, cookie_get_value(oreo));
95 oreo = cookie_destroy(oreo);
96 found = TRUE;
97 break;
98 }
99 }
100
101 if (!found) {
102 new = (NODE*)malloc(sizeof(NODE));
103 new->threadID = id;
104 new->cookie = oreo;
105 new->next = cur;
106 if (cur == this->head)
107 this->head = new;
108 else
109 pre->next = new;
110 }
111 //pthread_cond_wait(&my.cond, &my.lock);
112 //pthread_mutex_unlock(&(my.lock));
113
114 return TRUE;
115 }
116
117 BOOLEAN
cookies_delete(COOKIES this,char * str)118 cookies_delete(COOKIES this, char *str)
119 {
120 NODE *cur;
121 NODE *pre;
122 BOOLEAN ret = FALSE;
123 pthread_t id = pthread_self();
124
125 for (cur = pre = this->head; cur != NULL; pre = cur, cur = cur->next) {
126 if (cur->threadID == id) {
127 char *name = cookie_get_name(cur->cookie);
128 if (!strcasecmp(name, str)) {
129 cur->cookie = cookie_destroy(cur->cookie);
130 pre->next = cur->next;
131 if (cur == this->head) {
132 this->head = cur->next;
133 pre = this->head;
134 } else {
135 pre->next = cur->next;
136 }
137 ret = TRUE;
138 break;
139 }
140 }
141 }
142 return ret;
143 }
144
145 BOOLEAN
cookies_delete_all(COOKIES this)146 cookies_delete_all(COOKIES this)
147 {
148 NODE *cur;
149 NODE *pre;
150 pthread_t id = pthread_self();
151
152 // XXX: delete cookies by thread; not every cookie in the list
153 for (cur = pre = this->head; cur != NULL; pre = cur, cur = cur->next) {
154 if (cur->threadID == id) {
155 //char *name = cookie_get_name(cur->cookie);
156 cur->cookie = cookie_destroy(cur->cookie);
157 pre->next = cur->next;
158 if (cur == this->head) {
159 this->head = cur->next;
160 pre = this->head;
161 } else {
162 pre->next = cur->next;
163 }
164 }
165 }
166 return TRUE;
167 }
168
169 char *
cookies_header(COOKIES this,char * host,char * newton)170 cookies_header(COOKIES this, char *host, char *newton)
171 {
172 int dlen;
173 int hlen;
174 NODE *pre;
175 NODE *cur;
176 time_t tmp;
177 time_t now;
178 struct tm tm;
179 char oreo[MAX_COOKIES_SIZE];
180 size_t id = (uintptr_t)pthread_self();
181
182 memset(oreo, '\0', sizeof oreo);
183 hlen = strlen(host);
184
185 tmp = time(NULL);
186 gmtime_r(&tmp, &tm);
187 tm.tm_isdst = -1; // force mktime to figure it out!
188 now = mktime(&tm);
189
190 for (cur=pre=this->head; cur != NULL; pre=cur, cur=cur->next) {
191 /**
192 * for the purpose of matching, we'll ignore the leading '.'
193 */
194 const char *domainptr = cookie_get_domain(cur->cookie);
195 if (*domainptr == '.') ++domainptr;
196 dlen = domainptr ? strlen(domainptr) : 0;
197 if (cur->threadID == id) {
198 if (!strcasecmp(domainptr, host)) {
199 if (cookie_get_expires(cur->cookie) <= now && cookie_get_session(cur->cookie) != TRUE) {
200 cookies_delete(this, cookie_get_name(cur->cookie));
201 continue;
202 }
203 if (strlen(oreo) > 0)
204 strncat(oreo, ";", sizeof(oreo) - 10 - strlen(oreo));
205 strncat(oreo, cookie_get_name(cur->cookie), sizeof(oreo) - 10 - strlen(oreo));
206 strncat(oreo, "=", sizeof(oreo) - 10 - strlen(oreo));
207 strncat(oreo, cookie_get_value(cur->cookie), sizeof(oreo) - 10 - strlen(oreo));
208 }
209 if ((dlen < hlen) && (!strcasecmp(host + (hlen - dlen), domainptr))) {
210 if (cookie_get_expires(cur->cookie) <= now && cookie_get_session(cur->cookie) != TRUE) {
211 cookies_delete(this, cookie_get_name(cur->cookie));
212 continue;
213 }
214 if (strlen(oreo) > 0)
215 strncat(oreo, ";", sizeof(oreo) - 10 - strlen(oreo));
216 strncat(oreo, cookie_get_name(cur->cookie), sizeof(oreo) - 10 - strlen(oreo));
217 strncat(oreo, "=", sizeof(oreo) - 10 - strlen(oreo));
218 strncat(oreo, cookie_get_value(cur->cookie), sizeof(oreo) - 10 - strlen(oreo));
219 }
220 }
221 }
222 if (strlen(oreo) > 0) {
223 strncpy(newton, "Cookie: ", 8);
224 strncat(newton, oreo, MAX_COOKIE_SIZE);
225 strncat(newton, "\015\012", 2);
226 }
227
228 return newton;
229 }
230
231 void
cookies_list(COOKIES this)232 cookies_list(COOKIES this)
233 {
234 NODE *cur = NULL;
235 NODE *pre = NULL;
236
237 for (cur = pre = this->head; cur != NULL; pre = cur, cur = cur->next) {
238 COOKIE tmp = cur->cookie;
239 if (tmp == NULL)
240 ;
241 else printf(
242 "%lld: NAME: %s\n VALUE: %s\n Expires: %s\n",
243 (long long)cur->threadID, cookie_get_name(tmp), cookie_get_value(tmp), cookie_expires_string(tmp)
244 );
245 }
246 }
247
248 private NODE *
__delete_node(NODE * node)249 __delete_node(NODE *node)
250 {
251
252 if (node == NULL) return NULL;
253 NODE *tmp = node->next;
254 node->cookie = cookie_destroy(node->cookie);
255 free(node);
256 node = tmp;
257 return node;
258 }
259
260 private void
__strip(char * str)261 __strip(char *str)
262 {
263 char *ch;
264 ch = (char *)strstr(str, "#");
265 if (ch){*ch = '\0';}
266 ch = (char *)strstr(str, "\n");
267 if (ch){*ch = '\0';}
268 }
269
270 HASH
load_cookies(COOKIES this)271 load_cookies(COOKIES this)
272 {
273 FILE * fp;
274 int n = -1;
275 HASH HOH;
276 HASH IDX;
277 const size_t len = 4096; // max cookie size
278 char line[len];
279
280 if (! __exists(this->file)) {
281 return NULL;
282 }
283
284 fp = fopen(this->file, "r");
285 if (fp == NULL) {
286 return NULL;
287 }
288
289 HOH = new_hash();
290 IDX = new_hash();
291
292 /**
293 * We're going to treat this file like it's editable
294 * which means it will permit comments and white space
295 * formatting. Siege users are a savvy bunch, they may
296 * want to add cookies by hand...
297 */
298 memset(line, '\0', len);
299 while (fgets(line, len, fp) != NULL){
300 char *p = strchr(line, '\n');
301 if (p) {
302 *p = '\0';
303 } else {
304 int i;
305 if ((i = fgetc(fp)) != EOF) {
306 while ((i = fgetc(fp)) != EOF && i != '\n');
307 line[0]='\0';
308 }
309 }
310 __strip(line);
311 chomp(line);
312 if (strlen(line) > 1) {
313 int num = 2;
314 char **pair;
315 pair = split('|', line, &num);
316 trim(pair[0]);
317 trim(pair[1]);
318 if (pair[0] != NULL && pair[1] != NULL) {
319 if (hash_get(IDX, pair[0]) == NULL) {
320 char tmp[1024];
321 n += 1;
322 memset(tmp, '\0', 1024);
323 snprintf(tmp, 1024, "%d", n);
324 hash_add(IDX, pair[0], tmp);
325 }
326 HASH tmp = (HASH)hash_get(HOH, hash_get(IDX, pair[0]));
327 if (tmp == NULL) {
328 tmp = new_hash();
329 hash_add(tmp, pair[1], pair[1]);
330 hash_nadd(HOH, hash_get(IDX, pair[0]), tmp, HASHSIZE);
331 } else {
332 hash_add(tmp, pair[1], pair[1]);
333 }
334 }
335 split_free(pair, num);
336 }
337 memset(line, '\0', len);
338 }
339 fclose(fp);
340 hash_destroy(IDX);
341 return HOH;
342 }
343
344 private BOOLEAN
__save_cookies(COOKIES this)345 __save_cookies(COOKIES this)
346 {
347 FILE * fp;
348 char * line;
349 size_t len = 4096+24; // max cookie size plus ID
350 time_t now;
351
352 NODE * cur = NULL;
353 now = time(NULL);
354 fp = fopen(this->file, "w");
355 if (fp == NULL) {
356 fprintf(stderr, "ERROR: Unable to open cookies file: %s\n", this->file);
357 return FALSE;
358 }
359 fputs("#\n", fp);
360 fputs("# Siege cookies file. You may edit this file to add cookies\n",fp);
361 fputs("# manually but comments and formatting will be removed. \n",fp);
362 fputs("# All cookies that expire in the future will be preserved. \n",fp);
363 fputs("# ---------------------------------------------------------\n",fp);
364 line = malloc(sizeof(char *) * len);
365
366 for (cur = this->head; cur != NULL; cur = cur->next) {
367 COOKIE tmp = cur->cookie;
368 /**
369 * Criteria for saving cookies:
370 * 1.) It's not null (obvs)
371 * 2.) It's not a session cookie
372 * 3.) It's not expired.
373 * All cookies which meet the requirement are stored
374 * whether they were used during this session or not.
375 */
376 if (tmp != NULL && cookie_get_session(tmp) != TRUE && cookie_get_expires(cur->cookie) >= now) {
377 memset(line, '\0', len);
378 if (cookie_to_string(tmp) != NULL) {
379 snprintf(line, len, "%ld | %s\n", cur->threadID, cookie_to_string(tmp));
380 }
381 fputs(line, fp);
382 }
383 }
384 free(line);
385 fclose(fp);
386 return TRUE;
387 }
388
389 /**
390 * returns TRUE if the file exists,
391 */
392 private BOOLEAN
__exists(char * file)393 __exists(char *file)
394 {
395 int fd;
396
397 if ((fd = open(file, O_RDONLY)) < 0) {
398 /**
399 * The file does NOT exist so the descriptor is -1
400 * No need to close it.
401 */
402 return FALSE;
403 } else {
404 /**
405 * Party on Garth...
406 */
407 close(fd);
408 return TRUE;
409 }
410 return FALSE;
411 }
412
413