summaryrefslogtreecommitdiff
path: root/usr.bin/ftp/cookie.c
diff options
context:
space:
mode:
authorPierre-Yves Ritschard <pyr@cvs.openbsd.org>2007-06-13 13:52:27 +0000
committerPierre-Yves Ritschard <pyr@cvs.openbsd.org>2007-06-13 13:52:27 +0000
commit07f12b53833edbc0410dbe749af247d0edd53475 (patch)
tree78d3c66f135051fd9d67a8541de9d0f151fb10a7 /usr.bin/ftp/cookie.c
parentfb0f545ebe3be5c285564033ac85664305a0baeb (diff)
Enable cookie support. This allows parsing of netscape-like cookie jars
and sending of appropriate cookies. No retrieval of new cookies is done. Careful review and lots of input by millert and ray. ok millert@, ray@
Diffstat (limited to 'usr.bin/ftp/cookie.c')
-rw-r--r--usr.bin/ftp/cookie.c231
1 files changed, 231 insertions, 0 deletions
diff --git a/usr.bin/ftp/cookie.c b/usr.bin/ftp/cookie.c
new file mode 100644
index 00000000000..34ee3569d1d
--- /dev/null
+++ b/usr.bin/ftp/cookie.c
@@ -0,0 +1,231 @@
+/* $OpenBSD: cookie.c,v 1.1 2007/06/13 13:52:26 pyr 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 SMALL
+#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;
+ size_t len;
+ time_t date;
+ char *line;
+ char *lbuf;
+ 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);
+ lbuf = NULL;
+ while ((line = fgetln(fp, &len)) != NULL) {
+ if (line[len - 1] == '\n') {
+ line[len - 1] = '\0';
+ --len;
+ } else {
+ if ((lbuf = malloc(len + 1)) == NULL)
+ err(1, NULL);
+ memcpy(lbuf, line, len);
+ lbuf[len] = '\0';
+ line = lbuf;
+ }
+ if (len > 0 && line[len - 1] == '\r') {
+ line[len - 1] = '\0';
+ --len;
+ }
+
+ 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,
+ UINT_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 */