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
This commit is contained in:
Dan Mcgregor 2023-11-04 15:07:56 -07:00 committed by Rick Macklem
parent bb830e346b
commit 7c5146da12

View file

@ -83,6 +83,7 @@ static char sccsid[] = "@(#)mountd.c 8.15 (Berkeley) 5/1/95";
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <vis.h>
#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) {