Signed-off-by: Christopher Bii <christopherbii@xxxxxxxx>
---
support/export/export.c | 24 +--
support/include/exportfs.h | 1 +
support/include/nfsd_path.h | 9 +-
support/misc/nfsd_path.c | 362 ++++++++++++------------------------
support/nfs/exports.c | 53 +++---
utils/exportfs/exportfs.c | 8 +-
6 files changed, 165 insertions(+), 292 deletions(-)
diff --git a/support/export/export.c b/support/export/export.c
index 2c8c3335..463ba846 100644
--- a/support/export/export.c
+++ b/support/export/export.c
@@ -40,20 +40,7 @@ static int export_check(const nfs_export *exp, const
struct addrinfo *ai,
static void
exportent_mkrealpath(struct exportent *eep)
{
- const char *chroot = nfsd_path_nfsd_rootdir();
- char *ret = NULL;
-
- if (chroot) {
- char buffer[PATH_MAX];
- if (realpath(chroot, buffer))
- ret = nfsd_path_prepend_dir(buffer, eep->e_path);
- else
- xlog(D_GENERAL, "%s: failed to resolve path %s: %m",
- __func__, chroot);
- }
- if (!ret)
- ret = xstrdup(eep->e_path);
- eep->e_realpath = ret;
+ eep->e_realpath = nfsd_path_prepend_root(eep->e_path);
}
char *
@@ -64,6 +51,13 @@ exportent_realpath(struct exportent *eep)
return eep->e_realpath;
}
+void
+exportent_free_realpath(struct exportent* eep)
+{
+ if (eep->e_realpath && eep->e_realpath != eep->e_path)
+ free(eep->e_realpath);
+};
+
void
exportent_release(struct exportent *eep)
{
@@ -73,7 +67,7 @@ exportent_release(struct exportent *eep)
free(eep->e_fslocdata);
free(eep->e_uuid);
xfree(eep->e_hostname);
- xfree(eep->e_realpath);
+ exportent_free_realpath(eep);
}
static void
diff --git a/support/include/exportfs.h b/support/include/exportfs.h
index 9edf0d04..c65e2a1c 100644
--- a/support/include/exportfs.h
+++ b/support/include/exportfs.h
@@ -173,6 +173,7 @@ struct export_features {
struct export_features *get_export_features(void);
void fix_pseudoflavor_flags(struct exportent *ep);
+void exportent_free_realpath(struct exportent*);
char *exportent_realpath(struct exportent *eep);
int export_test(struct exportent *eep, int with_fsid);
diff --git a/support/include/nfsd_path.h b/support/include/nfsd_path.h
index aa1e1dd0..9c5976e8 100644
--- a/support/include/nfsd_path.h
+++ b/support/include/nfsd_path.h
@@ -8,12 +8,13 @@
struct file_handle;
struct statfs;
+struct nfsd_task_t;
void nfsd_path_init(void);
-const char * nfsd_path_nfsd_rootdir(void);
+const char * nfsd_path_rootdir(void);
char * nfsd_path_strip_root(char *pathname);
-char * nfsd_path_prepend_dir(const char *dir, const char *pathname);
+char * nfsd_path_prepend_root(char *pathname);
int nfsd_path_stat(const char *pathname, struct stat *statbuf);
int nfsd_path_lstat(const char *pathname, struct stat *statbuf);
@@ -23,8 +24,8 @@ int nfsd_path_statfs(const char *pathname,
char * nfsd_realpath(const char *path, char *resolved_path);
-ssize_t nfsd_path_read(int fd, char *buf, size_t len);
-ssize_t nfsd_path_write(int fd, const char *buf, size_t len);
+ssize_t nfsd_path_read(int fd, void* buf, size_t len);
+ssize_t nfsd_path_write(int fd, void* buf, size_t len);
int nfsd_name_to_handle_at(int fd, const char *path,
struct file_handle *fh,
diff --git a/support/misc/nfsd_path.c b/support/misc/nfsd_path.c
index c3dea4f0..b896f091 100644
--- a/support/misc/nfsd_path.c
+++ b/support/misc/nfsd_path.c
@@ -19,95 +19,79 @@
#include "nfsd_path.h"
#include "workqueue.h"
-static struct xthread_workqueue *nfsd_wq;
+static struct xthread_workqueue *nfsd_wq = NULL;
+const char *rootdir;
+size_t rootdir_pathlen = 0;
-static int
-nfsd_path_isslash(const char *path)
-{
- return path[0] == '/' && path[1] == '/';
-}
+struct nfsd_task_t {
+ int ret;
+ void* data;
+};
+/* Function used to offload tasks that must be ran within the correct
+ * chroot environment.
+ * */
+static void
+nfsd_run_task(void (*func)(void*), void* data){
+ nfsd_wq ? xthread_work_run_sync(nfsd_wq, func, data) : func(data);
+};
-static int
-nfsd_path_isdot(const char *path)
+const char*
+nfsd_path_rootdir(void)
{
- return path[0] == '.' && path[1] == '/';
-}
+ return rootdir;
+};
-static const char *
-nfsd_path_strip(const char *path)
+/* Set rootdir global variable. Rootdir must be an absolute path
+ * and resolveable by realpath()
+ * */
+static void
+nfsd_rootdir_set(void)
{
- if (!path || *path == '\0')
- goto out;
- for (;;) {
- if (nfsd_path_isslash(path)) {
- path++;
- continue;
- }
- if (nfsd_path_isdot(path)) {
- path += 2;
- continue;
- }
- break;
- }
-out:
- return path;
-}
+ const char *path;
+ if (!(path = conf_get_str("exports", "rootdir")))
+ return;
-const char *
-nfsd_path_nfsd_rootdir(void)
-{
- const char *rootdir;
-
- rootdir = nfsd_path_strip(conf_get_str("exports", "rootdir"));
- if (!rootdir || rootdir[0] == '\0')
- return NULL;
- if (rootdir[0] == '/' && rootdir[1] == '\0')
- return NULL;
- return rootdir;
+ if (path[0] != '/')
+ xlog(L_FATAL, "%s: NFS export rootdir must be an
absolute path. "
+ "Current value: \"%s\"", __func__, path);
+
+ if (!(rootdir = realpath(path, NULL))){
+ free((void*)rootdir);
+ xlog(L_FATAL, "realpath(): Unable to resolve root
export path \"%s\"", path);
+ };
+
+ rootdir_pathlen = strlen(rootdir);
}
char *
nfsd_path_strip_root(char *pathname)
{
- char buffer[PATH_MAX];
- const char *dir = nfsd_path_nfsd_rootdir();
-
- if (!dir)
- goto out;
-
- if (realpath(dir, buffer))
- return strstr(pathname, buffer) == pathname ?
- pathname + strlen(buffer) : NULL;
+ if (!rootdir)
+ return pathname;
- xlog(D_GENERAL, "%s: failed to resolve path %s: %m", __func__, dir);
-out:
- return pathname;
+ return strstr(pathname, rootdir) == pathname ?
+ pathname + rootdir_pathlen : pathname;
}
char *
-nfsd_path_prepend_dir(const char *dir, const char *pathname)
+nfsd_path_prepend_root(char *pathname)
{
- size_t len, dirlen;
- char *ret;
-
- dirlen = strlen(dir);
- while (dirlen > 0 && dir[dirlen - 1] == '/')
- dirlen--;
- if (!dirlen)
- return NULL;
- while (pathname[0] == '/')
- pathname++;
- len = dirlen + strlen(pathname) + 1;
- ret = xmalloc(len + 1);
- snprintf(ret, len+1, "%.*s/%s", (int)dirlen, dir, pathname);
- return ret;
+ char* buff;
+
+ if (!rootdir)
+ return pathname;
+
+ buff = malloc(strlen(pathname) + rootdir_pathlen + 1);
+ memcpy(buff, rootdir, rootdir_pathlen);
+ strcpy(buff + rootdir_pathlen, pathname);
+
+ return buff;
}
static void
nfsd_setup_workqueue(void)
{
- const char *rootdir = nfsd_path_nfsd_rootdir();
-
+ nfsd_rootdir_set();
if (!rootdir)
return;
@@ -124,224 +108,119 @@ nfsd_path_init(void)
}
struct nfsd_stat_data {
- const char *pathname;
- struct stat *statbuf;
- int ret;
- int err;
+ const char *pathname;
+ struct stat *statbuf;
+ int (*stat_handler)(const char*, struct stat*);
};
static void
-nfsd_statfunc(void *data)
-{
- struct nfsd_stat_data *d = data;
-
- d->ret = xstat(d->pathname, d->statbuf);
- if (d->ret < 0)
- d->err = errno;
-}
-
-static void
-nfsd_lstatfunc(void *data)
+nfsd_handle_stat(void *data)
{
- struct nfsd_stat_data *d = data;
-
- d->ret = xlstat(d->pathname, d->statbuf);
- if (d->ret < 0)
- d->err = errno;
+ struct nfsd_task_t* t = data;
+ struct nfsd_stat_data* d = t->data;
+ t->ret = d->stat_handler(d->pathname, d->statbuf);
}
static int
-nfsd_run_stat(struct xthread_workqueue *wq,
- void (*func)(void *),
- const char *pathname,
- struct stat *statbuf)
+nfsd_run_stat(const char *pathname,
+ struct stat *statbuf,
+ int (*handler)(const char*, struct stat*))
{
- struct nfsd_stat_data data = {
- pathname,
- statbuf,
- 0,
- 0
- };
- xthread_work_run_sync(wq, func, &data);
- if (data.ret < 0)
- errno = data.err;
- return data.ret;
+ struct nfsd_task_t t;
+ struct nfsd_stat_data d = { pathname, statbuf, handler };
+ t.data = &d;
+ nfsd_run_task(nfsd_handle_stat, &t);
+ return t.ret;
}
int
nfsd_path_stat(const char *pathname, struct stat *statbuf)
{
- if (!nfsd_wq)
- return xstat(pathname, statbuf);
- return nfsd_run_stat(nfsd_wq, nfsd_statfunc, pathname, statbuf);
+ return nfsd_run_stat(pathname, statbuf, stat);
}
int
-nfsd_path_lstat(const char *pathname, struct stat *statbuf)
-{
- if (!nfsd_wq)
- return xlstat(pathname, statbuf);
- return nfsd_run_stat(nfsd_wq, nfsd_lstatfunc, pathname, statbuf);
-}
-
-struct nfsd_statfs_data {
- const char *pathname;
- struct statfs *statbuf;
- int ret;
- int err;
+nfsd_path_lstat(const char* pathname, struct stat* statbuf){
+ return nfsd_run_stat(pathname, statbuf, lstat);
};
-static void
-nfsd_statfsfunc(void *data)
-{
- struct nfsd_statfs_data *d = data;
-
- d->ret = statfs(d->pathname, d->statbuf);
- if (d->ret < 0)
- d->err = errno;
-}
-
-static int
-nfsd_run_statfs(struct xthread_workqueue *wq,
- const char *pathname,
- struct statfs *statbuf)
-{
- struct nfsd_statfs_data data = {
- pathname,
- statbuf,
- 0,
- 0
- };
- xthread_work_run_sync(wq, nfsd_statfsfunc, &data);
- if (data.ret < 0)
- errno = data.err;
- return data.ret;
-}
-
int
-nfsd_path_statfs(const char *pathname, struct statfs *statbuf)
+nfsd_path_statfs(const char* pathname, struct statfs* statbuf)
{
- if (!nfsd_wq)
- return statfs(pathname, statbuf);
- return nfsd_run_statfs(nfsd_wq, pathname, statbuf);
-}
+ return nfsd_run_stat(pathname, (struct stat*)statbuf, (int
(*)(const char*, struct stat*))statfs);
+};
-struct nfsd_realpath_data {
- const char *pathname;
- char *resolved;
- int err;
+struct nfsd_realpath_t {
+ const char* path;
+ char* resolved_buf;
+ char* res_ptr;
};
static void
nfsd_realpathfunc(void *data)
{
- struct nfsd_realpath_data *d = data;
-
- d->resolved = realpath(d->pathname, d->resolved);
- if (!d->resolved)
- d->err = errno;
+ struct nfsd_realpath_t *d = data;
+ d->res_ptr = realpath(d->path, d->resolved_buf);
}
-char *
-nfsd_realpath(const char *path, char *resolved_path)
+char*
+nfsd_realpath(const char *path, char *resolved_buf)
{
- struct nfsd_realpath_data data = {
- path,
- resolved_path,
- 0
- };
-
- if (!nfsd_wq)
- return realpath(path, resolved_path);
-
- xthread_work_run_sync(nfsd_wq, nfsd_realpathfunc, &data);
- if (!data.resolved)
- errno = data.err;
- return data.resolved;
+ struct nfsd_realpath_t realpath_buf = {
+ .path = path,
+ .resolved_buf = resolved_buf
+ };
+ nfsd_run_task(nfsd_realpathfunc, &realpath_buf);
+ return realpath_buf.res_ptr;
}
-struct nfsd_read_data {
- int fd;
- char *buf;
- size_t len;
- ssize_t ret;
- int err;
+struct nfsd_rw_data {
+ int fd;
+ void* buf;
+ size_t len;
+ ssize_t bytes_read;
};
static void
nfsd_readfunc(void *data)
{
- struct nfsd_read_data *d = data;
-
- d->ret = read(d->fd, d->buf, d->len);
- if (d->ret < 0)
- d->err = errno;
+ struct nfsd_rw_data* t = (struct nfsd_rw_data*)data;
+ t->bytes_read = read(t->fd, t->buf, t->len);
}
static ssize_t
-nfsd_run_read(struct xthread_workqueue *wq, int fd, char *buf, size_t len)
+nfsd_run_read(int fd, void* buf, size_t len)
{
- struct nfsd_read_data data = {
- fd,
- buf,
- len,
- 0,
- 0
- };
- xthread_work_run_sync(wq, nfsd_readfunc, &data);
- if (data.ret < 0)
- errno = data.err;
- return data.ret;
+ struct nfsd_rw_data d = { .fd = fd, .buf = buf, .len = len };
+ nfsd_run_task(nfsd_readfunc, &d);
+ return d.bytes_read;
}
ssize_t
-nfsd_path_read(int fd, char *buf, size_t len)
+nfsd_path_read(int fd, void* buf, size_t len)
{
- if (!nfsd_wq)
- return read(fd, buf, len);
- return nfsd_run_read(nfsd_wq, fd, buf, len);
+ return nfsd_run_read(fd, buf, len);
}
-struct nfsd_write_data {
- int fd;
- const char *buf;
- size_t len;
- ssize_t ret;
- int err;
-};
-
static void
nfsd_writefunc(void *data)
{
- struct nfsd_write_data *d = data;
-
- d->ret = write(d->fd, d->buf, d->len);
- if (d->ret < 0)
- d->err = errno;
+ struct nfsd_rw_data* d = data;
+ d->bytes_read = write(d->fd, d->buf, d->len);
}
static ssize_t
-nfsd_run_write(struct xthread_workqueue *wq, int fd, const char *buf,
size_t len)
+nfsd_run_write(int fd, void* buf, size_t len)
{
- struct nfsd_write_data data = {
- fd,
- buf,
- len,
- 0,
- 0
- };
- xthread_work_run_sync(wq, nfsd_writefunc, &data);
- if (data.ret < 0)
- errno = data.err;
- return data.ret;
+ struct nfsd_rw_data d = { .fd = fd, .buf = buf, .len = len };
+ nfsd_run_task(nfsd_writefunc, &d);
+ return d.bytes_read;
}
ssize_t
-nfsd_path_write(int fd, const char *buf, size_t len)
+nfsd_path_write(int fd, void* buf, size_t len)
{
- if (!nfsd_wq)
- return write(fd, buf, len);
- return nfsd_run_write(nfsd_wq, fd, buf, len);
+ return nfsd_run_write(fd, buf, len);
}
#if defined(HAVE_NAME_TO_HANDLE_AT)
@@ -352,23 +231,18 @@ struct nfsd_handle_data {
int *mount_id;
int flags;
int ret;
- int err;
};
static void
nfsd_name_to_handle_func(void *data)
{
struct nfsd_handle_data *d = data;
-
- d->ret = name_to_handle_at(d->fd, d->path,
- d->fh, d->mount_id, d->flags);
- if (d->ret < 0)
- d->err = errno;
+ d->ret = name_to_handle_at(d->fd, d->path, d->fh, d->mount_id, d->flags);
}
static int
-nfsd_run_name_to_handle_at(struct xthread_workqueue *wq,
- int fd, const char *path, struct file_handle *fh,
+nfsd_run_name_to_handle_at(int fd, const char *path,
+ struct file_handle *fh,
int *mount_id, int flags)
{
struct nfsd_handle_data data = {
@@ -377,25 +251,19 @@ nfsd_run_name_to_handle_at(struct
xthread_workqueue *wq,
fh,
mount_id,
flags,
- 0,
0
};
- xthread_work_run_sync(wq, nfsd_name_to_handle_func, &data);
- if (data.ret < 0)
- errno = data.err;
+ nfsd_run_task(nfsd_name_to_handle_func, &data);
return data.ret;
}
int
-nfsd_name_to_handle_at(int fd, const char *path, struct file_handle *fh,
+nfsd_name_to_handle_at(int fd, const char *path,
+ struct file_handle *fh,
int *mount_id, int flags)
{
- if (!nfsd_wq)
- return name_to_handle_at(fd, path, fh, mount_id, flags);
-
- return nfsd_run_name_to_handle_at(nfsd_wq, fd, path, fh,
- mount_id, flags);
+ return nfsd_run_name_to_handle_at(fd, path, fh, mount_id, flags);
}
#else
int
diff --git a/support/nfs/exports.c b/support/nfs/exports.c
index a6816e60..c8ce8566 100644
--- a/support/nfs/exports.c
+++ b/support/nfs/exports.c
@@ -32,6 +32,7 @@
#include "xio.h"
#include "pseudoflavors.h"
#include "reexport.h"
+#include "nfsd_path.h"
#define EXPORT_DEFAULT_FLAGS \
(NFSEXP_READONLY|NFSEXP_ROOTSQUASH|NFSEXP_GATHERED_WRITES|NFSEXP_NOSUBTREECHECK)
@@ -160,7 +161,7 @@ getexportent(int fromkernel)
}
xfree(ee.e_hostname);
- xfree(ee.e_realpath);
+ exportent_free_realpath(&ee);
ee = def_ee;
/* Check for default client */
@@ -185,28 +186,34 @@ getexportent(int fromkernel)
}
ee.e_hostname = xstrdup(hostname);
- if (parseopts(opt, &ee, NULL) < 0) {
- if(ee.e_hostname)
- {
- xfree(ee.e_hostname);
- ee.e_hostname=NULL;
- }
- if(ee.e_uuid)
- {
- xfree(ee.e_uuid);
- ee.e_uuid=NULL;
- }
+ if (parseopts(opt, &ee, NULL) < 0)
+ goto out;
- return NULL;
- }
/* resolve symlinks */
- if (realpath(ee.e_path, rpath) != NULL) {
- rpath[sizeof (rpath) - 1] = '\0';
- strncpy(ee.e_path, rpath, sizeof (ee.e_path) - 1);
- ee.e_path[sizeof (ee.e_path) - 1] = '\0';
- }
+ if (nfsd_realpath(ee.e_path, rpath) == NULL) {
+ xlog(L_ERROR, "realpath(): Unable to resolve path at
%s", ee.e_path);
+ goto out;
+ };
- return ⅇ
+ if (strlen(rpath) > sizeof(ee.e_path) - 1){
+ xlog(L_ERROR, "Path %s exceeds limit of %lu chars",
ee.e_path, sizeof(ee.e_path) - 1);
+ goto out;
+ };
+
+ strcpy(ee.e_path, rpath);
+ return ⅇ
+
+out:
+ if (ee.e_hostname){
+ free(ee.e_hostname);
+ ee.e_hostname = NULL;
+ };
+ if (ee.e_uuid){
+ free(ee.e_uuid);
+ ee.e_uuid = NULL;
+ };
+
+ return NULL;
}
static const struct secinfo_flag_displaymap {
@@ -424,15 +431,15 @@ mkexportent(char *hname, char *path, char *options)
xfree(ee.e_hostname);
ee.e_hostname = xstrdup(hname);
- xfree(ee.e_realpath);
+ exportent_free_realpath(&ee);
ee.e_realpath = NULL;
if (strlen(path) >= sizeof(ee.e_path)) {
xlog(L_ERROR, "path name %s too long", path);
return NULL;
}
- strncpy(ee.e_path, path, sizeof (ee.e_path));
- ee.e_path[sizeof (ee.e_path) - 1] = '\0';
+ strcpy(ee.e_path, path);
+
if (parseopts(options, &ee, NULL) < 0)
return NULL;
return ⅇ
diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c
index b03a047b..0697e398 100644
--- a/utils/exportfs/exportfs.c
+++ b/utils/exportfs/exportfs.c
@@ -266,7 +266,6 @@ export_all(int verbose)
}
}
-
static void
exportfs_parsed(char *hname, char *path, char *options, int verbose)
{
@@ -512,11 +511,13 @@ validate_export(nfs_export *exp)
* If a path doesn't exist, or is not a dir or file, give an warning
* otherwise trial-export to '-test-client-' and check for failure.
*/
- struct stat stb;
- char *path = exportent_realpath(&exp->m_export);
+ struct stat stb;
+ char *path;
struct statfs stf;
int fs_has_fsid = 0;
+ path = exportent_realpath(&exp->m_export);
+
if (stat(path, &stb) < 0) {
xlog(L_ERROR, "Failed to stat %s: %m", path);
return;
@@ -547,6 +548,7 @@ validate_export(nfs_export *exp)
return;
}
+
}
static _Bool
--
2.47.1