aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/mountd/mountd.c87
1 files changed, 72 insertions, 15 deletions
diff --git a/usr.sbin/mountd/mountd.c b/usr.sbin/mountd/mountd.c
index d985dd00acf8..f64505f8602f 100644
--- a/usr.sbin/mountd/mountd.c
+++ b/usr.sbin/mountd/mountd.c
@@ -210,7 +210,9 @@ static void add_dlist(struct dirlist **, struct dirlist *,
struct grouplist *, int, struct exportlist *,
struct expcred *, uint64_t);
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 checkmask(struct sockaddr *sa);
static int chk_host(struct dirlist *, struct sockaddr *, int *, int *,
@@ -1557,6 +1559,7 @@ get_exportlist_one(int passno)
struct statfs fsb;
struct expcred anon;
char *cp, *endcp, *dirp, *hst, *usr, *dom, savedc;
+ char *err_msg = NULL;
int len, has_host, got_nondir, dirplen, netgrp;
uint64_t exflags;
@@ -1635,8 +1638,8 @@ get_exportlist_one(int passno)
goto nextline;
}
}
- if (check_dirpath(cp) &&
- statfs(cp, &fsb) >= 0) {
+ if (check_dirpath(cp, &err_msg) &&
+ check_statfs(cp, &fsb, &err_msg)) {
if ((fsb.f_flags & MNT_AUTOMOUNTED) != 0)
syslog(LOG_ERR, "Warning: exporting of "
"automounted fs %s not supported", cp);
@@ -1701,8 +1704,15 @@ get_exportlist_one(int passno)
dirplen = len;
}
} else {
- getexp_err(ep, tgrp,
- "symbolic link in export path or statfs failed");
+ if (err_msg != NULL) {
+ getexp_err(ep, tgrp, err_msg);
+ free(err_msg);
+ err_msg = NULL;
+ } else {
+ getexp_err(ep, tgrp,
+ "symbolic link in export path or "
+ "statfs failed");
+ }
goto nextline;
}
*endcp = savedc;
@@ -3786,29 +3796,76 @@ check_options(struct dirlist *dp)
return (0);
}
+static int
+check_path_component(const char *path, char **err)
+{
+ 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 an absolute directory path for any symbolic links. Return true
+ * Check each path component for the presence of symbolic links. Return true
*/
static int
-check_dirpath(char *dirp)
+check_dirpath(char *dirp, char **err)
{
char *cp;
- int ret = 1;
- struct stat sb;
cp = dirp + 1;
- while (*cp && ret) {
+ while (*cp) {
if (*cp == '/') {
*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++;
}
- if (lstat(dirp, &sb) < 0 || !S_ISDIR(sb.st_mode))
- ret = 0;
- return (ret);
+
+ if (!check_path_component(dirp, err))
+ 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);
}
/*