1 /* $OpenBSD: cookie.c,v 1.5 2009/05/05 19:35:30 martynas Exp $ */ 2 3 /* 4 * Copyright (c) 2007 Pierre-Yves Ritschard <pyr@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #ifndef SMALL 20 21 #include <sys/types.h> 22 #include <sys/queue.h> 23 24 #include <err.h> 25 #include <errno.h> 26 #include <fnmatch.h> 27 #include <stdio.h> 28 #include <string.h> 29 #include <stdlib.h> 30 #include <time.h> 31 32 #include "ftp_var.h" 33 34 struct cookie { 35 TAILQ_ENTRY(cookie) entry; 36 TAILQ_ENTRY(cookie) tempentry; 37 u_int8_t flags; 38 #define F_SECURE 0x01 39 #define F_TAILMATCH 0x02 40 #define F_NOEXPIRY 0x04 41 #define F_MATCHPATH 0x08 42 time_t expires; 43 char *domain; 44 char *path; 45 char *key; 46 char *val; 47 }; 48 TAILQ_HEAD(cookiejar, cookie); 49 50 typedef enum { 51 DOMAIN = 0, TAILMATCH = 1, PATH = 2, SECURE = 3, 52 EXPIRES = 4, NAME = 5, VALUE = 6, DONE = 7 53 } field_t; 54 55 static struct cookiejar jar; 56 57 void 58 cookie_load(void) 59 { 60 field_t field; 61 size_t len; 62 time_t date; 63 char *line; 64 char *lbuf; 65 char *param; 66 const char *estr; 67 FILE *fp; 68 struct cookie *ck; 69 70 if (cookiefile == NULL) 71 return; 72 73 TAILQ_INIT(&jar); 74 fp = fopen(cookiefile, "r"); 75 if (fp == NULL) 76 err(1, "cannot open cookie file %s", cookiefile); 77 date = time(NULL); 78 lbuf = NULL; 79 while ((line = fgetln(fp, &len)) != NULL) { 80 if (line[len - 1] == '\n') { 81 line[len - 1] = '\0'; 82 --len; 83 } else { 84 if ((lbuf = malloc(len + 1)) == NULL) 85 err(1, NULL); 86 memcpy(lbuf, line, len); 87 lbuf[len] = '\0'; 88 line = lbuf; 89 } 90 line[strcspn(line, "\r")] = '\0'; 91 92 line += strspn(line, " \t"); 93 if ((*line == '#') || (*line == '\0')) { 94 continue; 95 } 96 field = DOMAIN; 97 ck = calloc(1, sizeof(*ck)); 98 if (ck == NULL) 99 err(1, NULL); 100 while ((param = strsep(&line, "\t")) != NULL) { 101 switch (field) { 102 case DOMAIN: 103 if (*param == '.') { 104 if (asprintf(&ck->domain, 105 "*%s", param) == -1) 106 err(1, NULL); 107 } else { 108 ck->domain = strdup(param); 109 if (ck->domain == NULL) 110 err(1, NULL); 111 } 112 break; 113 case TAILMATCH: 114 if (strcasecmp(param, "TRUE") == 0) { 115 ck->flags |= F_TAILMATCH; 116 } else if (strcasecmp(param, "FALSE") != 0) { 117 errx(1, "invalid cookie file"); 118 } 119 break; 120 case PATH: 121 if (strcmp(param, "/") != 0) { 122 ck->flags |= F_MATCHPATH; 123 if (asprintf(&ck->path, 124 "%s*", param) == -1) 125 err(1, NULL); 126 } 127 break; 128 case SECURE: 129 if (strcasecmp(param, "TRUE") == 0) { 130 ck->flags |= F_SECURE; 131 } else if (strcasecmp(param, "FALSE") != 0) { 132 errx(1, "invalid cookie file"); 133 } 134 break; 135 case EXPIRES: 136 /* 137 * rely on sizeof(time_t) being 4 138 */ 139 ck->expires = strtonum(param, 0, 140 INT_MAX, &estr); 141 if (estr) { 142 if (errno == ERANGE) 143 ck->flags |= F_NOEXPIRY; 144 else 145 errx(1, "invalid cookie file"); 146 } 147 break; 148 case NAME: 149 ck->key = strdup(param); 150 if (ck->key == NULL) 151 err(1, NULL); 152 break; 153 case VALUE: 154 ck->val = strdup(param); 155 if (ck->val == NULL) 156 err(1, NULL); 157 break; 158 case DONE: 159 errx(1, "invalid cookie file"); 160 break; 161 } 162 field++; 163 } 164 if (field != DONE) 165 errx(1, "invalid cookie file"); 166 if (ck->expires < date && !(ck->flags & F_NOEXPIRY)) { 167 free(ck->val); 168 free(ck->key); 169 free(ck->path); 170 free(ck->domain); 171 free(ck); 172 } else 173 TAILQ_INSERT_TAIL(&jar, ck, entry); 174 } 175 free(lbuf); 176 fclose(fp); 177 } 178 179 void 180 cookie_get(const char *domain, const char *path, int secure, char **pstr) 181 { 182 size_t len; 183 size_t headlen; 184 char *head; 185 char *str; 186 struct cookie *ck; 187 struct cookiejar tempjar; 188 189 *pstr = NULL; 190 191 if (cookiefile == NULL) 192 return; 193 194 TAILQ_INIT(&tempjar); 195 len = strlen("Cookie\r\n"); 196 197 TAILQ_FOREACH(ck, &jar, entry) { 198 if (fnmatch(ck->domain, domain, 0) == 0 && 199 (secure || !(ck->flags & F_SECURE))) { 200 201 if (ck->flags & F_MATCHPATH && 202 fnmatch(ck->path, path, 0) != 0) 203 continue; 204 205 len += strlen(ck->key) + strlen(ck->val) + 206 strlen("; ="); 207 TAILQ_INSERT_TAIL(&tempjar, ck, tempentry); 208 } 209 } 210 if (TAILQ_EMPTY(&tempjar)) 211 return; 212 len += 1; 213 str = malloc(len); 214 if (str == NULL) 215 err(1, NULL); 216 217 (void)strlcpy(str, "Cookie:", len); 218 TAILQ_FOREACH(ck, &tempjar, tempentry) { 219 head = str + strlen(str); 220 headlen = len - strlen(str); 221 222 snprintf(head, headlen, "%s %s=%s", 223 (ck == TAILQ_FIRST(&tempjar))? "" : ";", ck->key, ck->val); 224 } 225 if (strlcat(str, "\r\n", len) >= len) 226 errx(1, "cookie header truncated"); 227 *pstr = str; 228 } 229 230 #endif /* !SMALL */ 231 232