Annotation of src/usr.bin/ftp/cookie.c, Revision 1.2
1.2 ! pyr 1: /* $OpenBSD: cookie.c,v 1.1 2007/06/13 13:52:26 pyr Exp $ */
1.1 pyr 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: }
1.2 ! pyr 88: line[strcspn(line, "\r")] = '\0';
1.1 pyr 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: UINT_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 */