This moves valid_filename() to validate.c and splits out a helper
portable_filename() which can be used from the RSC code. While moving
valid_filename() is not necessary, I thought it makes sense to keep the
two functions next to each other.
I could not find a short name with valid_ prefix for portable_filename()
that I liked. valid_posix_filename()? valid_checklist_file()?
Also, valid_filename() could be stricter and enforce that the unique '.'
is followed by a 3-letter suffix.
Index: extern.h
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.134
diff -u -p -r1.134 extern.h
--- extern.h 9 May 2022 17:19:32 -0000 1.134
+++ extern.h 10 May 2022 06:03:19 -0000
@@ -502,6 +502,8 @@ int valid_cert(const char *, struct au
int valid_roa(const char *, struct auth *, struct roa *);
int valid_filehash(int, const char *, size_t);
int valid_hash(unsigned char *, size_t, const char *, size_t);
+int portable_filename(const char *, size_t);
+int valid_filename(const char *, size_t);
int valid_uri(const char *, size_t, const char *);
int valid_origin(const char *, const char *);
int valid_x509(char *, X509_STORE_CTX *, X509 *, struct auth *,
Index: mft.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/mft.c,v
retrieving revision 1.61
diff -u -p -r1.61 mft.c
--- mft.c 9 May 2022 17:02:34 -0000 1.61
+++ mft.c 10 May 2022 06:03:19 -0000
@@ -127,27 +127,6 @@ rtype_from_file_extension(const char *fn
}
/*
- * Validate that a filename listed on a Manifest only contains characters
- * permitted in draft-ietf-sidrops-6486bis section 4.2.2
- */
-static int
-valid_filename(const char *fn, size_t len)
-{
- const unsigned char *c;
- size_t i;
-
- for (c = fn, i = 0; i < len; i++, c++)
- if (!isalnum(*c) && *c != '-' && *c != '_' && *c != '.')
- return 0;
-
- c = memchr(fn, '.', len);
- if (c == NULL || c != memrchr(fn, '.', len))
- return 0;
-
- return 1;
-}
-
-/*
* Check that the file is an ASPA, CER, CRL, GBR or a ROA.
* Returns corresponding rtype or RTYPE_INVALID on error.
*/
Index: rsc.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/rsc.c,v
retrieving revision 1.1
diff -u -p -r1.1 rsc.c
--- rsc.c 9 May 2022 17:02:34 -0000 1.1
+++ rsc.c 10 May 2022 06:03:46 -0000
@@ -147,6 +147,8 @@ rsc_parse_filenamehash(struct parse *p,
}
if (elemsz == 2) {
+ ASN1_IA5STRING *filename;
+
file = sk_ASN1_TYPE_value(seq, i++);
if (file->type != V_ASN1_IA5STRING) {
warnx("%s: RSC FileNameAndHash: want ASN.1 IA5 string,"
@@ -154,25 +156,17 @@ rsc_parse_filenamehash(struct parse *p,
ASN1_tag2str(file->type), file->type);
goto out;
}
- fn = strndup((const char *)file->value.ia5string->data,
- file->value.ia5string->length);
- if (fn == NULL)
- err(1, NULL);
- /*
- * filename must confirm to portable file name character set
- * XXX: use valid_filename() instead
- */
- if (strchr(fn, '/') != NULL) {
- warnx("%s: path components disallowed in filename: %s",
- p->fn, fn);
- goto out;
- }
- if (strchr(fn, '\n') != NULL) {
- warnx("%s: newline disallowed in filename: %s",
- p->fn, fn);
+ filename = file->value.ia5string;
+
+ if (!portable_filename(filename->data, filename->length)) {
+ warnx("%s: RSC FileNameAndHash: bad filename", p->fn);
goto out;
}
+
+ fn = strndup(filename->data, filename->length);
+ if (fn == NULL)
+ err(1, NULL);
}
/* Now hash value. */
Index: validate.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/validate.c,v
retrieving revision 1.31
diff -u -p -r1.31 validate.c
--- validate.c 21 Apr 2022 09:53:07 -0000 1.31
+++ validate.c 10 May 2022 06:03:19 -0000
@@ -275,6 +275,42 @@ valid_hash(unsigned char *buf, size_t le
}
/*
+ * Validate that a filename only contains characters from the POSIX portable
+ * filename character set [A-Za-z0-9._-], see IEEE Std 1003.1-2013, 3.278.
+ */
+int
+portable_filename(const char *fn, size_t len)
+{
+ const unsigned char *c;
+ size_t i;
+
+ for (c = fn, i = 0; i < len; i++, c++)
+ if (!isalnum(*c) && *c != '-' && *c != '_' && *c != '.')
+ return 0;
+ return 1;
+}
+
+/*
+ * Validate that a filename listed on a Manifest only contains characters
+ * permitted in draft-ietf-sidrops-6486bis section 4.2.2
+ * Also ensure that there is exactly one '.'.
+ */
+int
+valid_filename(const char *fn, size_t len)
+{
+ const unsigned char *c;
+
+ if (!portable_filename(fn, len))
+ return 0;
+
+ c = memchr(fn, '.', len);
+ if (c == NULL || c != memrchr(fn, '.', len))
+ return 0;
+
+ return 1;
+}
+
+/*
* Validate a URI to make sure it is pure ASCII and does not point backwards
* or doing some other silly tricks. To enforce the protocol pass either
* https:// or rsync:// as proto, if NULL is passed no protocol is enforced.