ref: 9ff908d2e99557534056889b6673d7710c37a4c7
parent: 3ab0889db514b8eeb3e675429c9562615211b53e
author: Jacob Moody <moody@posixcafe.org>
date: Thu Jul 20 12:32:58 EDT 2023
mount.9ptls
--- a/Makefile
+++ b/Makefile
@@ -22,6 +22,9 @@
cpu.$O: cpu.c
$(CC) `pkg-config $(OPENSSL) --cflags` $(CFLAGS) $< -o $@
+mount.9ptls: mount.$O
+ $(CC) $(LDFLAGS) -o $@ $<
+
%.$O: %.c
$(CC) $(CFLAGS) $< -o $@
@@ -39,7 +42,7 @@
.PHONY: clean
clean:
- rm -f *.o lib*/*.o lib*/*.a tlsclient pam_p9.so login_-dp9ik
+ rm -f *.o lib*/*.o lib*/*.a tlsclient pam_p9.so login_-dp9ik mount.9ptls
linux.tar.gz: tlsclient pam_p9.so tlsclient.1
tar cf - tlsclient pam_p9.so tlsclient.1 | gzip > $@
--- /dev/null
+++ b/mount.9ptls.8
@@ -1,0 +1,63 @@
+.Dd July 20, 2023
+.Dt MOUNT.9PTLS 8
+.Os tlsclient
+.
+.Sh NAME
+.Nm mount.9ptls
+.Nd tlsclient mount helper
+.Sh SYNOPSIS
+.Nm
+.Op Fl sfnvh
+.Op Fl N Ar namespace
+.Op Fl o Ar options
+.Ar fileserver
+.Ar mountpoint
+.
+.Sh DESCRIPTION
+The
+.Nm
+helper is used by
+.Xr mount 8
+to wrap a 9p filesystem through a dp9ik authenticated
+tls tunnel provided by
+.Xr tlsclient 1 .
+This is accomplished by interpreting the arguments provided,
+setting up the connection and then passing the file descriptiors
+to the kernel 9p mount.
+.Ar Fileserver
+is connected to over TCP, doing DNS resolution as required.
+As there is no standard port for this type of service a
+.Fl o Ar port
+option is required.
+.
+.Sh OPTIONS
+The
+.Fl s ,
+.Fl f ,
+.Fl n ,
+.Fl v ,
+and
+.Fl N
+flags are passed to
+.Xr mount 8
+without any interpretation by
+.Nm .
+Most
+.Ar options
+are passed through untouched, with
+.Nm
+ingesting the
+.Ar port
+and
+.Ar auth
+.Ar options
+for itself. The former specifying the
+port to connect to
+.Ar fileserver
+on and the later specifying the hostname of the mutal authentication
+server that is to be used in the dp9ik handshake.
+.
+.Sh SEE ALSO
+.Xr tlsclient 1 ,
+.Xr fstab 5 ,
+.Xr mount 8
--- /dev/null
+++ b/mount.c
@@ -1,0 +1,223 @@
+#ifdef __linux__
+#define _GNU_SOURCE
+#endif
+
+#include <unistd.h>
+#include <getopt.h>
+#include <errno.h>
+#include <err.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define nelem(x) (sizeof x / sizeof x[0])
+
+enum {
+ OPT_MAX = 4108,
+ PATH_MAX = 4096,
+};
+
+static char *mountargv[256];
+static int mountargc = 0;
+
+static char *optargv[256];
+static int optargc = 0;
+
+static char *port = NULL;
+static char *user = NULL;
+static char *authbox = NULL;
+
+static void
+appendarg(char *s)
+{
+ if(mountargc >= nelem(mountargv)-1)
+ errx(EINVAL, "argument overflow");
+ mountargv[mountargc++] = strdup(s);
+ mountargv[mountargc] = NULL;
+}
+
+static void
+_appendopt(char *key, char *val)
+{
+ char buf[OPT_MAX];
+
+ if(optargc >= nelem(optargv)-1)
+ errx(EINVAL, "option overflow");
+ if(val == NULL)
+ snprintf(buf, sizeof buf, "%s%s", optargc == 0 ? "" : ",", key);
+ else
+ snprintf(buf, sizeof buf, "%s%s=%s", optargc == 0 ? "" : ",", key, val);
+ optargv[optargc++] = strdup(buf);
+ optargv[optargc] = NULL;
+}
+
+static void
+appendopt(char *key, char *val)
+{
+ if(strcmp(key, "port") == 0){
+ port = strdup(val);
+ return;
+ } else if(strcmp(key, "auth") == 0){
+ authbox = strdup(val);
+ return;
+ } else if(strcmp(key, "user") == 0){
+ user = strdup(val);
+ /* passthrough as well */
+ } else if(strcmp(key, "trans") == 0){
+ errx(EINVAL, "trans=fd is set by 9ptls and can not be overriden");
+ } else if(strcmp(key, "rfdno") == 0 || strcmp(key, "wfdno") == 0){
+ errx(EINVAL, "rfdno and wfdno are reserved by 9ptls and can not be overriden");
+ }
+ _appendopt(key, val);
+}
+
+static void
+parseoptions(char *opt)
+{
+ char *s;
+ char *key, *val;
+
+ key = val = NULL;
+ for(s = opt; *s != '\0'; s++){
+ switch(*s){
+ case '=':
+ if(key == NULL)
+ errx(EINVAL, "option argument has no key, only a value");
+ *s = '\0';
+ if(s[1] == '\0')
+ errx(EINVAL, "key %s has no value", key);
+ val = s+1;
+ continue;
+ case ',':
+ if(key == NULL)
+ errx(EINVAL, "extra comma");
+ *s = '\0';
+ appendopt(key, val);
+ key = val = NULL;
+ continue;
+ }
+ if(key == NULL)
+ key = s;
+ }
+ if(key != NULL && val != NULL)
+ appendopt(key, val);
+
+ _appendopt("trans", "fd");
+ _appendopt("rfdno", "0");
+ _appendopt("wfdno", "1");
+}
+
+static void
+flattenoptions(char *opt, int n)
+{
+ char *s, *e;
+ int i, j;
+
+ s = opt;
+ e = opt + n - 2;
+
+ for(i = 0; i < optargc; i++){
+ j = strlen(optargv[i]);
+ if(s+j >= e)
+ n = e-s;
+ memcpy(s, optargv[i], j);
+ s[j] = '\0';
+ s += j;
+ }
+}
+
+void
+usage(void)
+{
+ errx(EINVAL, "Usage: mount.9ptls [-sfnvh] [-o options] [-N namespace] <host> <mountpoint>");
+}
+
+int
+main(int argc, char **argv)
+{
+ int c;
+ int sflag, fflag, nflag, vflag;
+ char options[OPT_MAX];
+ char namespace[PATH_MAX];
+
+ sflag = fflag = nflag = vflag = 0;
+ options[0] = namespace[0] = '\0';
+
+ while((c = getopt_long(argc, argv, "sfnvo:N:h?", 0, 0)) != -1){
+ switch(c){
+ case 's':
+ sflag = 1;
+ break;
+ case 'f':
+ fflag = 1;
+ break;
+ case 'n':
+ nflag = 1;
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ case 'o':
+ snprintf(options, sizeof options, "%s", optarg);
+ break;
+ case 'N':
+ snprintf(namespace, sizeof namespace, "%s", optarg);
+ break;
+ case '?': case 'h':
+ if(optopt)
+ errx(EINVAL, "invalid option '%c'", optopt);
+ usage();
+ break;
+ }
+ }
+
+ argc -= optind;
+ argv += optind;
+
+ if(argc != 2)
+ usage();
+
+ parseoptions(options);
+ if(port == NULL)
+ errx(EINVAL, "a port option must be given");
+ if(user == NULL && (user = getenv("USER")) == NULL)
+ errx(EINVAL, "user option not given and count not infer");
+ flattenoptions(options, sizeof options);
+
+ appendarg("tlsclient");
+ appendarg("-b");
+ appendarg("-h");
+ appendarg(argv[0]);
+ if(authbox != NULL){
+ appendarg("-a");
+ appendarg(authbox);
+ }
+ appendarg("-u");
+ appendarg(user);
+ appendarg("-p");
+ appendarg(port);
+
+ appendarg("mount");
+ if(sflag)
+ appendarg("-s");
+ if(fflag)
+ appendarg("-f");
+ if(nflag)
+ appendarg("-n");
+ if(vflag)
+ appendarg("-v");
+ if(namespace[0] != '\0'){
+ appendarg("-N");
+ appendarg(namespace);
+ }
+ appendarg("-i");
+ appendarg("-t");
+ appendarg("9p");
+ appendarg("-o");
+ appendarg(options);
+ appendarg(argv[0]);
+ appendarg(argv[1]);
+
+ execvp("tlsclient", mountargv);
+ err(EXIT_FAILURE, "could not exec");
+}