mountd: Improve error message for exports lines

Currently mountd print error message "symbolic link in export path or
statfs failed" in case some path component in an exports line fails
validation.  This revision improves the error message by giving more
information about the precise error as well as the path component that
caused the issue.

Submitted by:	Andrew Walker <awalker@ixsystems.com>
Reviewed by:	mav, rmacklem
Differential Revision:	https://reviews.freebsd.org/D39840
This commit is contained in:
Alexander Motin 2023-05-06 14:57:14 -04:00
parent 39f92a76a9
commit 572b77f8da

View File

@ -210,7 +210,9 @@ static void add_dlist(struct dirlist **, struct dirlist *,
struct grouplist *, int, struct exportlist *, struct grouplist *, int, struct exportlist *,
struct expcred *, uint64_t); struct expcred *, uint64_t);
static void add_mlist(char *, char *); static void add_mlist(char *, char *);
static int check_dirpath(char *); static int check_path_component(const char *, char **);
static int check_dirpath(char *, char **);
static int check_statfs(const char *, struct statfs *, char **);
static int check_options(struct dirlist *); static int check_options(struct dirlist *);
static int checkmask(struct sockaddr *sa); static int checkmask(struct sockaddr *sa);
static int chk_host(struct dirlist *, struct sockaddr *, int *, int *, static int chk_host(struct dirlist *, struct sockaddr *, int *, int *,
@ -1557,6 +1559,7 @@ get_exportlist_one(int passno)
struct statfs fsb; struct statfs fsb;
struct expcred anon; struct expcred anon;
char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc; char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
char *err_msg = NULL;
int len, has_host, got_nondir, dirplen, netgrp; int len, has_host, got_nondir, dirplen, netgrp;
uint64_t exflags; uint64_t exflags;
@ -1635,8 +1638,8 @@ get_exportlist_one(int passno)
goto nextline; goto nextline;
} }
} }
if (check_dirpath(cp) && if (check_dirpath(cp, &err_msg) &&
statfs(cp, &fsb) >= 0) { check_statfs(cp, &fsb, &err_msg)) {
if ((fsb.f_flags & MNT_AUTOMOUNTED) != 0) if ((fsb.f_flags & MNT_AUTOMOUNTED) != 0)
syslog(LOG_ERR, "Warning: exporting of " syslog(LOG_ERR, "Warning: exporting of "
"automounted fs %s not supported", cp); "automounted fs %s not supported", cp);
@ -1700,9 +1703,16 @@ get_exportlist_one(int passno)
dirp = add_expdir(&dirhead, cp, len); dirp = add_expdir(&dirhead, cp, len);
dirplen = len; dirplen = len;
} }
} else {
if (err_msg != NULL) {
getexp_err(ep, tgrp, err_msg);
free(err_msg);
err_msg = NULL;
} else { } else {
getexp_err(ep, tgrp, getexp_err(ep, tgrp,
"symbolic link in export path or statfs failed"); "symbolic link in export path or "
"statfs failed");
}
goto nextline; goto nextline;
} }
*endcp = savedc; *endcp = savedc;
@ -3786,29 +3796,76 @@ check_options(struct dirlist *dp)
return (0); return (0);
} }
/*
* Check an absolute directory path for any symbolic links. Return true
*/
static int static int
check_dirpath(char *dirp) check_path_component(const char *path, char **err)
{ {
char *cp;
int ret = 1;
struct stat sb; struct stat sb;
if (lstat(path, &sb)) {
asprintf(err, "%s: lstat() failed: %s.\n",
path, strerror(errno));
return (0);
}
switch (sb.st_mode & S_IFMT) {
case S_IFDIR:
return (1);
case S_IFLNK:
asprintf(err, "%s: path is a symbolic link.\n", path);
break;
case S_IFREG:
asprintf(err, "%s: path is a file rather than a directory.\n",
path);
break;
default:
asprintf(err, "%s: path is not a directory.\n", path);
}
return (0);
}
/*
* Check each path component for the presence of symbolic links. Return true
*/
static int
check_dirpath(char *dirp, char **err)
{
char *cp;
cp = dirp + 1; cp = dirp + 1;
while (*cp && ret) { while (*cp) {
if (*cp == '/') { if (*cp == '/') {
*cp = '\0'; *cp = '\0';
if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
ret = 0; if (!check_path_component(dirp, err)) {
*cp = '/';
return (0);
}
*cp = '/'; *cp = '/';
} }
cp++; cp++;
} }
if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
ret = 0; if (!check_path_component(dirp, err))
return (ret); return (0);
return (1);
}
/*
* Populate statfs information. Return true on success.
*/
static int
check_statfs(const char *dirp, struct statfs *fsb, char **err)
{
if (statfs(dirp, fsb)) {
asprintf(err, "%s: statfs() failed: %s\n", dirp,
strerror(errno));
return (0);
}
return (1);
} }
/* /*