From 7c5146da128688ba2bb6bdad5e98716087a47281 Mon Sep 17 00:00:00 2001 From: Dan Mcgregor Date: Sat, 4 Nov 2023 15:07:56 -0700 Subject: [PATCH] mountd: Add support for spaces in exported directories The previous code would correctly parse strings including quotation marks (") or backslash (/), but the tests when creating the export includes them in the final string. This prevents exporting paths with embedded spaces, for example "/exports/with space". Trying results in log lines resembling: mountd[1337]: bad exports list line '/exports/with\ space': /exports/with\ space: lstat() failed: No such file or directory. Turns out that when creating its exports list, zfs escapes strings in a format compatible with vis(3). Since I expect that zfs sharenfs is the dominating use case for generating an exports list, use strunvis(3) to parse the export path. The result is lines like the following allowing spaces: /exports/with\040space -network 192.168.0 -mask 255.255.255.0 A man page update will be done as a separate commit. MFC after: 1 month Reviewed by: rmacklem Differential Revision: https://reviews.freebsd.org/D42432 --- usr.sbin/mountd/mountd.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/usr.sbin/mountd/mountd.c b/usr.sbin/mountd/mountd.c index 6602dbc09aa0..33c19a81a0cf 100644 --- a/usr.sbin/mountd/mountd.c +++ b/usr.sbin/mountd/mountd.c @@ -83,6 +83,7 @@ static char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95"; #include #include #include +#include #include "pathnames.h" #include "mntopts.h" @@ -1561,10 +1562,13 @@ get_exportlist_one(int passno) char *err_msg = NULL; int len, has_host, got_nondir, dirplen, netgrp; uint64_t exflags; + char unvis_dir[PATH_MAX + 1]; + int unvis_len; v4root_phase = 0; anon.cr_groups = NULL; dirhead = (struct dirlist *)NULL; + unvis_dir[0] = '\0'; while (get_line()) { if (debug) warnx("got line %s", line); @@ -1631,17 +1635,25 @@ get_exportlist_one(int passno) } else if (*cp == '/') { savedc = *endcp; *endcp = '\0'; + unvis_len = strnunvis(unvis_dir, sizeof(unvis_dir), + cp); + if (unvis_len <= 0) { + getexp_err(ep, tgrp, "Cannot strunvis " + "decode dir"); + goto nextline; + } if (v4root_phase > 1) { if (dirp != NULL) { getexp_err(ep, tgrp, "Multiple V4 dirs"); goto nextline; } } - if (check_dirpath(cp, &err_msg) && - check_statfs(cp, &fsb, &err_msg)) { + if (check_dirpath(unvis_dir, &err_msg) && + check_statfs(unvis_dir, &fsb, &err_msg)) { if ((fsb.f_flags & MNT_AUTOMOUNTED) != 0) syslog(LOG_ERR, "Warning: exporting of " - "automounted fs %s not supported", cp); + "automounted fs %s not supported", + unvis_dir); if (got_nondir) { getexp_err(ep, tgrp, "dirs must be first"); goto nextline; @@ -1652,16 +1664,17 @@ get_exportlist_one(int passno) goto nextline; } if (strlen(v4root_dirpath) == 0) { - strlcpy(v4root_dirpath, cp, + strlcpy(v4root_dirpath, unvis_dir, sizeof (v4root_dirpath)); - } else if (strcmp(v4root_dirpath, cp) + } else if (strcmp(v4root_dirpath, unvis_dir) != 0) { syslog(LOG_ERR, - "different V4 dirpath %s", cp); + "different V4 dirpath %s", + unvis_dir); getexp_err(ep, tgrp, NULL); goto nextline; } - dirp = cp; + dirp = unvis_dir; v4root_phase = 2; got_nondir = 1; ep = get_exp(); @@ -1699,8 +1712,9 @@ get_exportlist_one(int passno) /* * Add dirpath to export mount point. */ - dirp = add_expdir(&dirhead, cp, len); - dirplen = len; + dirp = add_expdir(&dirhead, unvis_dir, + unvis_len); + dirplen = unvis_len; } } else { if (err_msg != NULL) {