1/* $OpenBSD: cookie.c,v 1.10 2021/02/16 16:27:34 naddy 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 NOSSL 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 34struct 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}; 48TAILQ_HEAD(cookiejar, cookie); 49 50typedef enum { 51 DOMAIN = 0, TAILMATCH = 1, PATH = 2, SECURE = 3, 52 EXPIRES = 4, NAME = 5, VALUE = 6, DONE = 7 53} field_t; 54 55static struct cookiejar jar; 56 57void 58cookie_load(void) 59{ 60 field_t field; 61 time_t date; 62 char *line; 63 char *lbuf = NULL; 64 size_t lbufsize = 0; 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 while (getline(&lbuf, &lbufsize, fp) != -1) { 79 line = lbuf; 80 line[strcspn(line, "\r\n")] = '\0'; 81 82 line += strspn(line, " \t"); 83 if ((*line == '#') || (*line == '\0')) { 84 continue; 85 } 86 field = DOMAIN; 87 ck = calloc(1, sizeof(*ck)); 88 if (ck == NULL) 89 err(1, NULL); 90 while ((param = strsep(&line, "\t")) != NULL) { 91 switch (field) { 92 case DOMAIN: 93 if (*param == '.') { 94 if (asprintf(&ck->domain, 95 "*%s", param) == -1) 96 err(1, NULL); 97 } else { 98 ck->domain = strdup(param); 99 if (ck->domain == NULL) 100 err(1, NULL); 101 } 102 break; 103 case TAILMATCH: 104 if (strcasecmp(param, "TRUE") == 0) { 105 ck->flags |= F_TAILMATCH; 106 } else if (strcasecmp(param, "FALSE") != 0) { 107 errx(1, "invalid cookie file"); 108 } 109 break; 110 case PATH: 111 if (strcmp(param, "/") != 0) { 112 ck->flags |= F_MATCHPATH; 113 if (asprintf(&ck->path, 114 "%s*", param) == -1) 115 err(1, NULL); 116 } 117 break; 118 case SECURE: 119 if (strcasecmp(param, "TRUE") == 0) { 120 ck->flags |= F_SECURE; 121 } else if (strcasecmp(param, "FALSE") != 0) { 122 errx(1, "invalid cookie file"); 123 } 124 break; 125 case EXPIRES: 126 /* 127 * rely on sizeof(time_t) being 4 128 */ 129 ck->expires = strtonum(param, 0, 130 INT_MAX, &estr); 131 if (estr) { 132 if (errno == ERANGE) 133 ck->flags |= F_NOEXPIRY; 134 else 135 errx(1, "invalid cookie file"); 136 } 137 break; 138 case NAME: 139 ck->key = strdup(param); 140 if (ck->key == NULL) 141 err(1, NULL); 142 break; 143 case VALUE: 144 ck->val = strdup(param); 145 if (ck->val == NULL) 146 err(1, NULL); 147 break; 148 case DONE: 149 errx(1, "invalid cookie file"); 150 break; 151 } 152 field++; 153 } 154 if (field != DONE) 155 errx(1, "invalid cookie file"); 156 if (ck->expires < date && !(ck->flags & F_NOEXPIRY)) { 157 free(ck->val); 158 free(ck->key); 159 free(ck->path); 160 free(ck->domain); 161 free(ck); 162 } else 163 TAILQ_INSERT_TAIL(&jar, ck, entry); 164 } 165 free(lbuf); 166 fclose(fp); 167} 168 169void 170cookie_get(const char *domain, const char *path, int secure, char **pstr) 171{ 172 size_t len; 173 size_t headlen; 174 char *head; 175 char *str; 176 struct cookie *ck; 177 struct cookiejar tempjar; 178 179 *pstr = NULL; 180 181 if (cookiefile == NULL) 182 return; 183 184 TAILQ_INIT(&tempjar); 185 len = strlen("Cookie\r\n"); 186 187 TAILQ_FOREACH(ck, &jar, entry) { 188 if (fnmatch(ck->domain, domain, 0) == 0 && 189 (secure || !(ck->flags & F_SECURE))) { 190 191 if (ck->flags & F_MATCHPATH && 192 fnmatch(ck->path, path, 0) != 0) 193 continue; 194 195 len += strlen(ck->key) + strlen(ck->val) + 196 strlen("; ="); 197 TAILQ_INSERT_TAIL(&tempjar, ck, tempentry); 198 } 199 } 200 if (TAILQ_EMPTY(&tempjar)) 201 return; 202 len += 1; 203 str = malloc(len); 204 if (str == NULL) 205 err(1, NULL); 206 207 (void)strlcpy(str, "Cookie:", len); 208 TAILQ_FOREACH(ck, &tempjar, tempentry) { 209 head = str + strlen(str); 210 headlen = len - strlen(str); 211 212 snprintf(head, headlen, "%s %s=%s", 213 (ck == TAILQ_FIRST(&tempjar))? "" : ";", ck->key, ck->val); 214 } 215 if (strlcat(str, "\r\n", len) >= len) 216 errx(1, "cookie header truncated"); 217 *pstr = str; 218} 219 220#endif /* !SMALL */ 221 222