summary refs log tree commit diff
path: root/cookie.c
diff options
context:
space:
mode:
Diffstat (limited to 'cookie.c')
-rw-r--r--cookie.c221
1 files changed, 221 insertions, 0 deletions
diff --git a/cookie.c b/cookie.c
new file mode 100644
index 0000000..b5f5beb
--- /dev/null
+++ b/cookie.c
@@ -0,0 +1,221 @@
+/*	$OpenBSD: cookie.c,v 1.10 2021/02/16 16:27:34 naddy Exp $	*/
+
+/*
+ * Copyright (c) 2007 Pierre-Yves Ritschard <pyr@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef NOSSL
+
+#include <sys/types.h>
+#include <sys/queue.h>
+
+#include <err.h>
+#include <errno.h>
+#include <fnmatch.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+#include "ftp_var.h"
+
+struct cookie {
+	TAILQ_ENTRY(cookie)	 entry;
+	TAILQ_ENTRY(cookie)	 tempentry;
+	u_int8_t		 flags;
+#define F_SECURE		 0x01
+#define F_TAILMATCH		 0x02
+#define F_NOEXPIRY		 0x04
+#define F_MATCHPATH		 0x08
+	time_t			 expires;
+	char			*domain;
+	char			*path;
+	char			*key;
+	char			*val;
+};
+TAILQ_HEAD(cookiejar, cookie);
+
+typedef enum {
+	DOMAIN = 0, TAILMATCH = 1, PATH = 2, SECURE = 3,
+	EXPIRES = 4, NAME = 5, VALUE = 6, DONE = 7
+} field_t;
+
+static struct cookiejar jar;
+
+void
+cookie_load(void)
+{
+	field_t		 field;
+	time_t		 date;
+	char		*line;
+	char		*lbuf = NULL;
+	size_t		 lbufsize = 0;
+	char		*param;
+	const char	*estr;
+	FILE		*fp;
+	struct cookie	*ck;
+
+	if (cookiefile == NULL)
+		return;
+
+	TAILQ_INIT(&jar);
+	fp = fopen(cookiefile, "r");
+	if (fp == NULL)
+		err(1, "cannot open cookie file %s", cookiefile);
+	date = time(NULL);
+	while (getline(&lbuf, &lbufsize, fp) != -1) {
+		line = lbuf;
+		line[strcspn(line, "\r\n")] = '\0';
+
+		line += strspn(line, " \t");
+		if ((*line == '#') || (*line == '\0')) {
+			continue;
+		}
+		field = DOMAIN;
+		ck = calloc(1, sizeof(*ck));
+		if (ck == NULL)
+			err(1, NULL);
+		while ((param = strsep(&line, "\t")) != NULL) {
+			switch (field) {
+			case DOMAIN:
+				if (*param == '.') {
+					if (asprintf(&ck->domain,
+					    "*%s", param) == -1)
+						err(1, NULL);
+				} else {
+					ck->domain = strdup(param);
+					if (ck->domain == NULL)
+						err(1, NULL);
+				}
+				break;
+			case TAILMATCH:
+				if (strcasecmp(param, "TRUE") == 0) {
+					ck->flags |= F_TAILMATCH;
+				} else if (strcasecmp(param, "FALSE") != 0) {
+					errx(1, "invalid cookie file");
+				}
+				break;
+			case PATH:
+				if (strcmp(param, "/") != 0) {
+					ck->flags |= F_MATCHPATH;
+					if (asprintf(&ck->path,
+					    "%s*", param) == -1)
+						err(1, NULL);
+				}
+				break;
+			case SECURE:
+				if (strcasecmp(param, "TRUE") == 0) {
+					ck->flags |= F_SECURE;
+				} else if (strcasecmp(param, "FALSE") != 0) {
+					errx(1, "invalid cookie file");
+				}
+				break;
+			case EXPIRES:
+				/*
+				 * rely on sizeof(time_t) being 4
+				 */
+				ck->expires = strtonum(param, 0,
+				    INT_MAX, &estr);
+				if (estr) {
+					if (errno == ERANGE)
+						ck->flags |= F_NOEXPIRY;
+					else
+						errx(1, "invalid cookie file");
+				}
+				break;
+			case NAME:
+				ck->key = strdup(param);
+				if (ck->key == NULL)
+					err(1, NULL);
+				break;
+			case VALUE:
+				ck->val = strdup(param);
+				if (ck->val == NULL)
+					err(1, NULL);
+				break;
+			case DONE:
+				errx(1, "invalid cookie file");
+				break;
+			}
+			field++;
+		}
+		if (field != DONE)
+			errx(1, "invalid cookie file");
+		if (ck->expires < date && !(ck->flags & F_NOEXPIRY)) {
+			free(ck->val);
+			free(ck->key);
+			free(ck->path);
+			free(ck->domain);
+			free(ck);
+		} else
+			TAILQ_INSERT_TAIL(&jar, ck, entry);
+	}
+	free(lbuf);
+	fclose(fp);
+}
+
+void
+cookie_get(const char *domain, const char *path, int secure, char **pstr)
+{
+	size_t		 len;
+	size_t		 headlen;
+	char		*head;
+	char		*str;
+	struct cookie	*ck;
+	struct cookiejar tempjar;
+
+	*pstr = NULL;
+
+	if (cookiefile == NULL)
+		return;
+
+	TAILQ_INIT(&tempjar);
+	len = strlen("Cookie\r\n");
+
+	TAILQ_FOREACH(ck, &jar, entry) {
+		if (fnmatch(ck->domain, domain, 0) == 0 &&
+		    (secure || !(ck->flags & F_SECURE))) {
+
+			if (ck->flags & F_MATCHPATH &&
+			    fnmatch(ck->path, path, 0) != 0)
+				continue;
+
+			len += strlen(ck->key) + strlen(ck->val) +
+			    strlen("; =");
+			TAILQ_INSERT_TAIL(&tempjar, ck, tempentry);
+		}
+	}
+	if (TAILQ_EMPTY(&tempjar))
+		return;
+	len += 1;
+	str = malloc(len);
+	if (str == NULL)
+		err(1, NULL);
+
+	(void)strlcpy(str, "Cookie:", len);
+	TAILQ_FOREACH(ck, &tempjar, tempentry) {
+		head = str + strlen(str);
+		headlen = len - strlen(str);
+
+		snprintf(head, headlen, "%s %s=%s",
+		    (ck == TAILQ_FIRST(&tempjar))? "" : ";", ck->key, ck->val);
+	}
+	if (strlcat(str, "\r\n", len) >= len)
+		errx(1, "cookie header truncated");
+	*pstr = str;
+}
+
+#endif /* !SMALL */
+