cookies.c (6060B)
1 /* cookies.c 2 * Cookies 3 * (c) 2002 Mikulas Patocka 4 * This file is a part of the Links program, released under GPL 5 */ 6 7 #include <limits.h> 8 9 #include "links.h" 10 11 #define ACCEPT_NONE 0 12 #define ACCEPT_ALL 1 13 14 static int accept_cookies = ACCEPT_ALL; 15 16 struct list_head all_cookies = { &all_cookies, &all_cookies }; 17 18 struct list_head c_domains = { &c_domains, &c_domains }; 19 20 struct c_server { 21 list_entry_1st; 22 int accpt; 23 unsigned char server[1]; 24 }; 25 26 static struct list_head c_servers = { &c_servers, &c_servers }; 27 28 static void accept_cookie(struct cookie *); 29 30 void 31 free_cookie(struct cookie *c) 32 { 33 free(c->name); 34 free(c->value); 35 free(c->server); 36 free(c->path); 37 free(c->domain); 38 free(c); 39 } 40 41 /* sezere 1 cookie z retezce str, na zacatku nesmi byt zadne whitechars 42 * na konci muze byt strednik nebo 0 43 * cookie musi byt ve tvaru nazev=hodnota, kolem rovnase nesmi byt zadne mezery 44 * (respektive mezery se budou pocitat do nazvu a do hodnoty) 45 */ 46 int 47 set_cookie(struct terminal *term, unsigned char *url, unsigned char *str) 48 { 49 if (!accept_cookies) 50 return 0; 51 int noval = 0; 52 struct cookie *cookie; 53 struct c_server *cs = NULL; 54 struct list_head *lcs; 55 unsigned char *p, *q, *s, *server, *date, *dom; 56 for (p = str; *p != ';' && *p; p++) 57 ; 58 for (q = str; *q != '='; q++) 59 if (!*q || q >= p) { 60 noval = 1; 61 break; 62 } 63 if (str == q || q + 1 == p) 64 return 0; 65 cookie = xmalloc(sizeof(struct cookie)); 66 server = get_host_name(url); 67 cookie->name = memacpy(str, q - str); 68 cookie->value = !noval ? memacpy(q + 1, p - q - 1) : NULL; 69 cookie->server = stracpy(server); 70 date = parse_header_param(str, cast_uchar "expires", 0); 71 if (date) { 72 cookie->expires = parse_http_date(date); 73 free(date); 74 } else 75 cookie->expires = 0; 76 if (!(cookie->path = parse_header_param(str, cast_uchar "path", 0))) 77 cookie->path = stracpy(cast_uchar "/"); 78 else if (cookie->path[0] != '/') { 79 add_to_strn(&cookie->path, cast_uchar "x"); 80 memmove(cookie->path + 1, cookie->path, 81 strlen((const char *)cookie->path) - 1); 82 cookie->path[0] = '/'; 83 } 84 dom = parse_header_param(str, cast_uchar "domain", 0); 85 if (!dom) 86 cookie->domain = stracpy(server); 87 else { 88 cookie->domain = idn_encode_host(dom, strlen((const char *)dom), 89 cast_uchar ".", 0); 90 if (!cookie->domain) 91 cookie->domain = stracpy(server); 92 free(dom); 93 } 94 if (cookie->domain[0] == '.') 95 memmove(cookie->domain, cookie->domain + 1, 96 strlen((const char *)cookie->domain)); 97 if ((s = parse_header_param(str, cast_uchar "secure", 0))) { 98 cookie->secure = 1; 99 free(s); 100 } else 101 cookie->secure = 0; 102 if (!allow_cookie_domain(server, cookie->domain)) { 103 free(cookie->domain); 104 cookie->domain = stracpy(server); 105 } 106 foreach (struct c_server, cs, lcs, c_servers) 107 if (!casestrcmp(cs->server, server)) { 108 if (cs->accpt) 109 goto ok; 110 else { 111 free_cookie(cookie); 112 free(server); 113 return 0; 114 } 115 } 116 if (!accept_cookies) { 117 free_cookie(cookie); 118 free(server); 119 return 1; 120 } 121 ok: 122 accept_cookie(cookie); 123 free(server); 124 return 0; 125 } 126 127 static void 128 accept_cookie(struct cookie *c) 129 { 130 struct c_domain *cd = NULL; 131 struct list_head *lcd; 132 struct cookie *d = NULL; 133 struct list_head *ld; 134 size_t sl; 135 foreach (struct cookie, d, ld, all_cookies) 136 if (!casestrcmp(d->name, c->name) 137 && !casestrcmp(d->domain, c->domain)) { 138 ld = ld->prev; 139 del_from_list(d); 140 free_cookie(d); 141 } 142 if (c->value && !casestrcmp(c->value, cast_uchar "deleted")) { 143 free_cookie(c); 144 return; 145 } 146 add_to_list(all_cookies, c); 147 foreach (struct c_domain, cd, lcd, c_domains) 148 if (!casestrcmp(cd->domain, c->domain)) 149 return; 150 sl = strlen((const char *)c->domain); 151 if (sl > INT_MAX - sizeof(struct c_domain)) 152 overalloc(); 153 cd = xmalloc(sizeof(struct c_domain) + sl); 154 strcpy(cast_char cd->domain, cast_const_char c->domain); 155 add_to_list(c_domains, cd); 156 } 157 158 int 159 is_in_domain(unsigned char *d, unsigned char *s) 160 { 161 const int dl = strlen((const char *)d); 162 const int sl = strlen((const char *)s); 163 if (dl > sl) 164 return 0; 165 if (dl == sl) 166 return !casestrcmp(d, s); 167 if (s[sl - dl - 1] != '.') 168 return 0; 169 return !casecmp(d, s + sl - dl, dl); 170 } 171 172 int 173 is_path_prefix(unsigned char *d, unsigned char *s) 174 { 175 const int dl = strlen((const char *)d); 176 const int sl = strlen((const char *)s); 177 if (!dl) 178 return 1; 179 if (dl > sl) 180 return 0; 181 if (memcmp(d, s, dl)) 182 return 0; 183 return d[dl - 1] == '/' || !s[dl] || s[dl] == '/' || s[dl] == POST_CHAR 184 || s[dl] == '?' || s[dl] == '&'; 185 } 186 187 int 188 cookie_expired(struct cookie *c) 189 { 190 time_t t; 191 errno = 0; 192 EINTRLOOPX(t, time(NULL), (time_t)-1); 193 return c->expires && c->expires < t; 194 } 195 196 size_t 197 add_cookies(unsigned char **s, size_t l, unsigned char *url) 198 { 199 int nc = 0; 200 struct c_domain *cd = NULL; 201 struct list_head *lcd; 202 struct cookie *c = NULL; 203 struct list_head *lc; 204 unsigned char *server = get_host_name(url); 205 unsigned char *data = get_url_data(url); 206 if (data > url) 207 data--; 208 foreach (struct c_domain, cd, lcd, c_domains) 209 if (is_in_domain(cd->domain, server)) 210 goto ok; 211 free(server); 212 return l; 213 ok: 214 foreachback (struct cookie, c, lc, all_cookies) 215 if (is_in_domain(c->domain, server)) 216 if (is_path_prefix(c->path, data)) { 217 if (cookie_expired(c)) { 218 lc = lc->prev; 219 del_from_list(c); 220 free_cookie(c); 221 continue; 222 } 223 if (c->secure 224 && casecmp(url, cast_uchar "https://", 8)) 225 continue; 226 if (!nc) { 227 l = add_to_str(s, l, 228 cast_uchar "Cookie: "); 229 nc = 1; 230 } else 231 l = add_to_str(s, l, cast_uchar "; "); 232 l = add_to_str(s, l, c->name); 233 if (c->value) { 234 l = add_chr_to_str(s, l, '='); 235 l = add_to_str(s, l, c->value); 236 } 237 } 238 if (nc) 239 l = add_to_str(s, l, cast_uchar "\r\n"); 240 free(server); 241 return l; 242 } 243 244 void 245 free_cookies(void) 246 { 247 free_list(struct c_domain, c_domains); 248 /* !!! FIXME: save cookies */ 249 while (!list_empty(all_cookies)) { 250 struct cookie *c = list_struct(all_cookies.next, struct cookie); 251 del_from_list(c); 252 free_cookie(c); 253 } 254 } 255 256 void 257 init_cookies(void) 258 { 259 /* !!! FIXME: read cookies */ 260 }