Download raw body.
cookiejar support in ftp(1)
That stuff is remarkably ill-documented
I just tried an extension for firefox
(https://github.com/rotemdan/ExportCookies)
that says it will export to a
netscape cookie jar, and of course ftp(1) failed to load it.
Turns out modern cookies have sub-second expiry date... which we don't really
care about, but would more or less like to support
Here's a small patch that does two things:
- exit with something more of an indication of what went wrong if the
cookie jar didn't load (lineno + automaton state indication)
- "support" floating expiry date, by simply cutting the timestamp at the
first dot.
This (at least) allows ftp to load that cookiejar for me.
Index: cookie.c
===================================================================
RCS file: /build/data/openbsd/cvs/src/usr.bin/ftp/cookie.c,v
diff -u -p -r1.10 cookie.c
--- cookie.c 16 Feb 2021 16:27:34 -0000 1.10
+++ cookie.c 28 Oct 2025 17:51:26 -0000
@@ -54,6 +54,12 @@ typedef enum {
static struct cookiejar jar;
+static void
+bad_cookie(const char *automaton, size_t lineno)
+{
+ errx(1, "invalid cookie file (%s) at line %zu\n", automaton, lineno);
+}
+
void
cookie_load(void)
{
@@ -62,8 +68,10 @@ cookie_load(void)
char *line;
char *lbuf = NULL;
size_t lbufsize = 0;
+ size_t lineno = 0;
char *param;
const char *estr;
+ char *dot;
FILE *fp;
struct cookie *ck;
@@ -76,6 +84,7 @@ cookie_load(void)
err(1, "cannot open cookie file %s", cookiefile);
date = time(NULL);
while (getline(&lbuf, &lbufsize, fp) != -1) {
+ lineno++;
line = lbuf;
line[strcspn(line, "\r\n")] = '\0';
@@ -104,7 +113,7 @@ cookie_load(void)
if (strcasecmp(param, "TRUE") == 0) {
ck->flags |= F_TAILMATCH;
} else if (strcasecmp(param, "FALSE") != 0) {
- errx(1, "invalid cookie file");
+ bad_cookie("TAILMATCH", lineno);
}
break;
case PATH:
@@ -119,10 +128,14 @@ cookie_load(void)
if (strcasecmp(param, "TRUE") == 0) {
ck->flags |= F_SECURE;
} else if (strcasecmp(param, "FALSE") != 0) {
- errx(1, "invalid cookie file");
+ bad_cookie("SECURE", lineno);
}
break;
case EXPIRES:
+ /* XXX "supports" floating expiry dates */
+ dot = strchr(param, '.');
+ if (dot)
+ *dot = 0;
/*
* rely on sizeof(time_t) being 4
*/
@@ -131,8 +144,10 @@ cookie_load(void)
if (estr) {
if (errno == ERANGE)
ck->flags |= F_NOEXPIRY;
- else
- errx(1, "invalid cookie file");
+ else {
+ perror("strnum");
+ bad_cookie("EXPIRE", lineno);
+ }
}
break;
case NAME:
@@ -146,13 +161,13 @@ cookie_load(void)
err(1, NULL);
break;
case DONE:
- errx(1, "invalid cookie file");
+ bad_cookie("EARLY DONE", lineno);
break;
}
field++;
}
if (field != DONE)
- errx(1, "invalid cookie file");
+ bad_cookie("NOT DONE", lineno);
if (ck->expires < date && !(ck->flags & F_NOEXPIRY)) {
free(ck->val);
free(ck->key);
cookiejar support in ftp(1)