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