1 #include "links.h"
2
3 #define ACCEPT_NONE 0
4 #define ACCEPT_ASK 1
5 #define ACCEPT_ALL 2
6
7 int accept_cookies = ACCEPT_ALL;
8
9 tcount cookie_id = 0;
10
11 struct cookie {
12 struct cookie *next;
13 struct cookie *prev;
14 unsigned char *name, *value;
15 unsigned char *server;
16 unsigned char *path, *domain;
17 time_t expires; /* zero means undefined */
18 int secure;
19 int id;
20 };
21
22 struct list_head cookies = { &cookies, &cookies };
23
24 struct c_domain {
25 struct c_domain *next;
26 struct c_domain *prev;
27 unsigned char domain[1];
28 };
29
30 struct list_head c_domains = { &c_domains, &c_domains };
31
32 struct c_server {
33 struct c_server *next;
34 struct c_server *prev;
35 int accpt;
36 unsigned char server[1];
37 };
38
39 struct list_head c_servers = { &c_servers, &c_servers };
40
41 void accept_cookie(struct cookie *);
42 void delete_cookie(struct cookie *);
43
free_cookie(struct cookie * c)44 void free_cookie(struct cookie *c)
45 {
46 mem_free(c->name);
47 if (c->value) mem_free(c->value);
48 if (c->server) mem_free(c->server);
49 if (c->path) mem_free(c->path);
50 if (c->domain) mem_free(c->domain);
51 }
52
check_domain_security(unsigned char * server,unsigned char * domain)53 int check_domain_security(unsigned char *server, unsigned char *domain)
54 {
55 size_t i, j, dl;
56 int nd;
57 if (domain[0] == '.') domain++;
58 dl = strlen(domain);
59 if (dl > strlen(server)) return 1;
60 for (i = strlen(server) - dl, j = 0; server[i]; i++, j++)
61 if (upcase(server[i]) != upcase(domain[j])) return 1;
62 nd = 2;
63 if (dl > 4 && domain[dl - 4] == '.') {
64 unsigned char *tld[] = { "com", "edu", "net", "org", "gov", "mil", "int", NULL };
65 for (i = 0; tld[i]; i++) if (!casecmp(tld[i], &domain[dl - 3], 3)) {
66 nd = 1;
67 break;
68 }
69 }
70 for (i = 0; domain[i]; i++) if (domain[i] == '.') if (!--nd) break;
71 if (nd > 0) return 1;
72 return 0;
73 }
74
set_cookie(struct terminal * term,unsigned char * url,unsigned char * str)75 int set_cookie(struct terminal *term, unsigned char *url, unsigned char *str)
76 {
77 int noval = 0;
78 struct cookie *cookie;
79 struct c_server *cs;
80 unsigned char *p, *q, *s, *server, *date;
81 if (accept_cookies == ACCEPT_NONE) return 0;
82 for (p = str; *p != ';' && *p; p++) /*if (WHITECHAR(*p)) return 0*/;
83 for (q = str; *q != '='; q++) if (!*q || q >= p) {
84 noval = 1;
85 break;
86 }
87 if (str == q || q + 1 == p) return 0;
88 cookie = mem_alloc(sizeof(struct cookie));
89 server = get_host_name(url);
90 cookie->name = memacpy(str, q - str);
91 cookie->value = !noval ? memacpy(q + 1, p - q - 1) : NULL;
92 cookie->server = stracpy(server);
93 date = parse_header_param(str, "expires");
94 if (date) {
95 cookie->expires = parse_http_date(date);
96 /* kdo tohle napsal a proc ?? */
97 /*if (! cookie->expires) cookie->expires++;*/ /* no harm and we can use zero then */
98 mem_free(date);
99 } else
100 cookie->expires = 0;
101 if (!(cookie->path = parse_header_param(str, "path"))) {
102 /*unsigned char *w;*/
103 cookie->path = stracpy("/");
104 /*
105 add_to_strn(&cookie->path, document);
106 for (w = cookie->path; *w; w++) if (end_of_dir(*w)) {
107 *w = 0;
108 break;
109 }
110 for (w = cookie->path + strlen(cookie->path) - 1; w >= cookie->path; w--)
111 if (*w == '/') {
112 w[1] = 0;
113 break;
114 }
115 */
116 } else {
117 if (cookie->path[0] != '/') {
118 add_to_strn(&cookie->path, "x");
119 memmove(cookie->path + 1, cookie->path, strlen(cookie->path) - 1);
120 cookie->path[0] = '/';
121 }
122 }
123 if (!(cookie->domain = parse_header_param(str, "domain"))) cookie->domain = stracpy(server);
124 if (cookie->domain[0] == '.') memmove(cookie->domain, cookie->domain + 1, strlen(cookie->domain));
125 if ((s = parse_header_param(str, "secure"))) {
126 cookie->secure = 1;
127 mem_free(s);
128 } else cookie->secure = 0;
129 if (check_domain_security(server, cookie->domain)) {
130 mem_free(cookie->domain);
131 cookie->domain = stracpy(server);
132 }
133 cookie->id = cookie_id++;
134 foreach (cs, c_servers) if (!strcasecmp(cs->server, server)) {
135 if (cs->accpt) goto ok;
136 else {
137 free_cookie(cookie);
138 mem_free(cookie);
139 mem_free(server);
140 return 0;
141 }
142 }
143 if (accept_cookies != ACCEPT_ALL) {
144 free_cookie(cookie);
145 mem_free(cookie);
146 mem_free(server);
147 return 1;
148 }
149 ok:
150 accept_cookie(cookie);
151 mem_free(server);
152 return 0;
153 }
154
accept_cookie(struct cookie * c)155 void accept_cookie(struct cookie *c)
156 {
157 struct c_domain *cd;
158 struct cookie *d, *e;
159 foreach(d, cookies) if (!strcasecmp(d->name, c->name) && !strcasecmp(d->domain, c->domain)) {
160 e = d;
161 d = d->prev;
162 del_from_list(e);
163 free_cookie(e);
164 mem_free(e);
165 }
166 if (c->value && !strcasecmp(c->value, "deleted")) {
167 free_cookie(c);
168 mem_free(c);
169 return;
170 }
171 add_to_list(cookies, c);
172 foreach(cd, c_domains) if (!strcasecmp(cd->domain, c->domain)) return;
173 cd = mem_alloc(sizeof(struct c_domain) + strlen(c->domain) + 1);
174 strcpy(cd->domain, c->domain);
175 add_to_list(c_domains, cd);
176 }
177
delete_cookie(struct cookie * c)178 void delete_cookie(struct cookie *c)
179 {
180 struct c_domain *cd;
181 struct cookie *d;
182 foreach(d, cookies) if (!strcasecmp(d->domain, c->domain)) goto x;
183 foreach(cd, c_domains) if (!strcasecmp(cd->domain, c->domain)) {
184 del_from_list(cd);
185 mem_free(cd);
186 break;
187 }
188 x:
189 del_from_list(c);
190 free_cookie(c);
191 mem_free(c);
192 }
193
find_cookie_id(void * idp)194 struct cookie *find_cookie_id(void *idp)
195 {
196 int id = (int)(my_uintptr_t)idp;
197 struct cookie *c;
198 foreach(c, cookies) if (c->id == id) return c;
199 return NULL;
200 }
201
reject_cookie(void * idp)202 void reject_cookie(void *idp)
203 {
204 struct cookie *c;
205 if (!(c = find_cookie_id(idp))) return;
206 delete_cookie(c);
207 }
208
cookie_default(void * idp,int a)209 void cookie_default(void *idp, int a)
210 {
211 struct cookie *c;
212 struct c_server *s;
213 if (!(c = find_cookie_id(idp))) return;
214 foreach(s, c_servers) if (!strcasecmp(s->server, c->server)) goto found;
215 s = mem_alloc(sizeof(struct c_server) + strlen(c->server) + 1);
216 strcpy(s->server, c->server);
217 add_to_list(c_servers, s);
218 found:
219 s->accpt = a;
220 }
221
accept_cookie_always(void * idp)222 void accept_cookie_always(void *idp)
223 {
224 cookie_default(idp, 1);
225 }
226
accept_cookie_never(void * idp)227 void accept_cookie_never(void *idp)
228 {
229 cookie_default(idp, 0);
230 reject_cookie(idp);
231 }
232
is_in_domain(unsigned char * d,unsigned char * s)233 int is_in_domain(unsigned char *d, unsigned char *s)
234 {
235 int dl = strlen(d);
236 int sl = strlen(s);
237 if (dl > sl) return 0;
238 if (dl == sl) return !strcasecmp(d, s);
239 if (s[sl - dl - 1] != '.') return 0;
240 return !casecmp(d, s + sl - dl, dl);
241 }
242
is_path_prefix(unsigned char * d,unsigned char * s)243 int is_path_prefix(unsigned char *d, unsigned char *s)
244 {
245 int dl = strlen(d);
246 int sl = strlen(s);
247 if (!dl) return 1;
248 if (dl > sl) return 0;
249 if (memcmp(d, s, dl)) return 0;
250 return d[dl - 1] == '/' || !s[dl] || s[dl] == '/' || s[dl] == POST_CHAR || s[dl] == '?' || s[dl] == '&';
251 }
252
cookie_expired(struct cookie * c)253 int cookie_expired(struct cookie *c) /* parse_http_date is broken */
254 {
255 time_t t;
256 EINTRLOOPX(t, time(NULL), (time_t)-1);
257 return 0 && (c->expires && c->expires < t);
258 }
259
send_cookies(unsigned char ** s,int * l,unsigned char * url)260 void send_cookies(unsigned char **s, int *l, unsigned char *url)
261 {
262 int nc = 0;
263 struct c_domain *cd;
264 struct cookie *c, *d;
265 unsigned char *server = get_host_name(url);
266 unsigned char *data = get_url_data(url);
267 if (data > url) data--;
268 foreach (cd, c_domains) if (is_in_domain(cd->domain, server)) goto ok;
269 mem_free(server);
270 return;
271 ok:
272 foreach (c, cookies) if (is_in_domain(c->domain, server)) if (is_path_prefix(c->path, data)) {
273 if (cookie_expired(c)) {
274 d = c;
275 c = c->prev;
276 del_from_list(d);
277 free_cookie(d);
278 mem_free(d);
279 continue;
280 }
281 if (c->secure && casecmp(url, "https://", 8)) continue;
282 if (!nc) add_to_str(s, l, "Cookie: "), nc = 1;
283 else add_to_str(s, l, "; ");
284 add_to_str(s, l, c->name);
285 if (c->value) {
286 add_to_str(s, l, "=");
287 add_to_str(s, l, c->value);
288 }
289 }
290 if (nc) add_to_str(s, l, "\r\n");
291 mem_free(server);
292 }
293
init_cookies()294 void init_cookies()
295 {
296 /* !!! FIXME: read cookies */
297 }
298
cleanup_cookies()299 void cleanup_cookies()
300 {
301 struct cookie *c;
302 free_list(c_domains);
303 /* !!! FIXME: save cookies */
304 foreach (c, cookies) free_cookie(c);
305 free_list(cookies);
306 }
307
308