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
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
cookie_load(void)58 cookie_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
169 void
cookie_get(const char * domain,const char * path,int secure,char ** pstr)170 cookie_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