Message ID | 20190528203122.11401-5-trond.myklebust@hammerspace.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Add the "[exports] rootdir" option to nfs.conf | expand |
On Tue, May 28, 2019 at 04:31:15PM -0400, Trond Myklebust wrote: > +char * > +nfsd_path_strip_root(char *pathname) > +{ > + const char *dir = nfsd_path_nfsd_rootdir(); > + char *ret; > + > + ret = strstr(pathname, dir); > + if (!ret || ret != pathname) > + return pathname; Shouldn't we return NULL or an error or something here? It seems a little strange not to care if the path began with root or not. I guess I need to look at the caller.... --b. > + return pathname + strlen(dir); > +} > + > +char * > +nfsd_path_prepend_dir(const char *dir, const char *pathname) > +{ > + size_t len, dirlen; > + char *ret; > + > + dirlen = strlen(dir); > + while (dirlen > 0 && dir[dirlen - 1] == '/') > + dirlen--; > + if (!dirlen) > + return NULL; > + len = dirlen + strlen(pathname) + 1; > + ret = xmalloc(len + 1); > + snprintf(ret, len, "%.*s/%s", (int)dirlen, dir, pathname); > + return ret; > +} > + > +static void > +nfsd_setup_workqueue(void) > +{ > + const char *rootdir = nfsd_path_nfsd_rootdir(); > + > + if (!rootdir) > + return; > + nfsd_wq = xthread_workqueue_alloc(); > + if (!nfsd_wq) > + return; > + xthread_workqueue_chroot(nfsd_wq, rootdir); > +} > + > +void > +nfsd_path_init(void) > +{ > + nfsd_setup_workqueue(); > +} > + > +struct nfsd_stat_data { > + const char *pathname; > + struct stat *statbuf; > + int ret; > + int err; > +}; > + > +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) > +{ > + struct nfsd_stat_data *d = data; > + > + d->ret = xlstat(d->pathname, d->statbuf); > + if (d->ret < 0) > + d->err = errno; > +} > + > +static int > +nfsd_run_stat(struct xthread_workqueue *wq, > + void (*func)(void *), > + const char *pathname, > + struct stat *statbuf) > +{ > + 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; > +} > + > +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); > +} > + > +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); > +} > diff --git a/support/misc/xstat.c b/support/misc/xstat.c > new file mode 100644 > index 000000000000..d092f73dfd65 > --- /dev/null > +++ b/support/misc/xstat.c > @@ -0,0 +1,33 @@ > +#include <sys/types.h> > +#include <fcntl.h> > +#include <sys/stat.h> > +#include <unistd.h> > + > +#include "config.h" > +#include "xstat.h" > + > +#ifdef HAVE_FSTATAT > + > +int xlstat(const char *pathname, struct stat *statbuf) > +{ > + return fstatat(AT_FDCWD, pathname, statbuf, AT_NO_AUTOMOUNT | > + AT_SYMLINK_NOFOLLOW); > +} > + > +int xstat(const char *pathname, struct stat *statbuf) > +{ > + return fstatat(AT_FDCWD, pathname, statbuf, AT_NO_AUTOMOUNT); > +} > + > +#else > + > +int xlstat(const char *pathname, struct stat *statbuf) > +{ > + return lstat(pathname, statbuf); > +} > + > +int xstat(const char *pathname, struct stat *statbuf) > +{ > + return stat(pathname, statbuf); > +} > +#endif > -- > 2.21.0
On 5/31/19 11:52 AM, J. Bruce Fields wrote: > On Tue, May 28, 2019 at 04:31:15PM -0400, Trond Myklebust wrote: >> +char * >> +nfsd_path_strip_root(char *pathname) >> +{ >> + const char *dir = nfsd_path_nfsd_rootdir(); >> + char *ret; >> + >> + ret = strstr(pathname, dir); >> + if (!ret || ret != pathname) >> + return pathname; > > Shouldn't we return NULL or an error or something here? It seems a > little strange not to care if the path began with root or not. I guess > I need to look at the caller.... Well pathname will never be NULL... It is returning what is passed in, but it might be nice to know about the memory failure. steved. > > --b. > >> + return pathname + strlen(dir); >> +} >> + >> +char * >> +nfsd_path_prepend_dir(const char *dir, const char *pathname) >> +{ >> + size_t len, dirlen; >> + char *ret; >> + >> + dirlen = strlen(dir); >> + while (dirlen > 0 && dir[dirlen - 1] == '/') >> + dirlen--; >> + if (!dirlen) >> + return NULL; >> + len = dirlen + strlen(pathname) + 1; >> + ret = xmalloc(len + 1); >> + snprintf(ret, len, "%.*s/%s", (int)dirlen, dir, pathname); >> + return ret; >> +} >> + >> +static void >> +nfsd_setup_workqueue(void) >> +{ >> + const char *rootdir = nfsd_path_nfsd_rootdir(); >> + >> + if (!rootdir) >> + return; >> + nfsd_wq = xthread_workqueue_alloc(); >> + if (!nfsd_wq) >> + return; >> + xthread_workqueue_chroot(nfsd_wq, rootdir); >> +} >> + >> +void >> +nfsd_path_init(void) >> +{ >> + nfsd_setup_workqueue(); >> +} >> + >> +struct nfsd_stat_data { >> + const char *pathname; >> + struct stat *statbuf; >> + int ret; >> + int err; >> +}; >> + >> +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) >> +{ >> + struct nfsd_stat_data *d = data; >> + >> + d->ret = xlstat(d->pathname, d->statbuf); >> + if (d->ret < 0) >> + d->err = errno; >> +} >> + >> +static int >> +nfsd_run_stat(struct xthread_workqueue *wq, >> + void (*func)(void *), >> + const char *pathname, >> + struct stat *statbuf) >> +{ >> + 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; >> +} >> + >> +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); >> +} >> + >> +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); >> +} >> diff --git a/support/misc/xstat.c b/support/misc/xstat.c >> new file mode 100644 >> index 000000000000..d092f73dfd65 >> --- /dev/null >> +++ b/support/misc/xstat.c >> @@ -0,0 +1,33 @@ >> +#include <sys/types.h> >> +#include <fcntl.h> >> +#include <sys/stat.h> >> +#include <unistd.h> >> + >> +#include "config.h" >> +#include "xstat.h" >> + >> +#ifdef HAVE_FSTATAT >> + >> +int xlstat(const char *pathname, struct stat *statbuf) >> +{ >> + return fstatat(AT_FDCWD, pathname, statbuf, AT_NO_AUTOMOUNT | >> + AT_SYMLINK_NOFOLLOW); >> +} >> + >> +int xstat(const char *pathname, struct stat *statbuf) >> +{ >> + return fstatat(AT_FDCWD, pathname, statbuf, AT_NO_AUTOMOUNT); >> +} >> + >> +#else >> + >> +int xlstat(const char *pathname, struct stat *statbuf) >> +{ >> + return lstat(pathname, statbuf); >> +} >> + >> +int xstat(const char *pathname, struct stat *statbuf) >> +{ >> + return stat(pathname, statbuf); >> +} >> +#endif >> -- >> 2.21.0
On Mon, 2019-06-03 at 10:21 -0400, Steve Dickson wrote: > > On 5/31/19 11:52 AM, J. Bruce Fields wrote: > > On Tue, May 28, 2019 at 04:31:15PM -0400, Trond Myklebust wrote: > > > +char * > > > +nfsd_path_strip_root(char *pathname) > > > +{ > > > + const char *dir = nfsd_path_nfsd_rootdir(); > > > + char *ret; > > > + > > > + ret = strstr(pathname, dir); > > > + if (!ret || ret != pathname) > > > + return pathname; > > > > Shouldn't we return NULL or an error or something here? It seems a > > little strange not to care if the path began with root or not. I > > guess > > I need to look at the caller.... > Well pathname will never be NULL... It is returning what is passed > in, > but it might be nice to know about the memory failure. > Either way, I figure we also want to canonicalise 'dir' before we apply it, just in case people have amused themselves by composing rootdir values of the form '/foo/./bar/./../bar/'. Another patch forthcoming for this.
diff --git a/configure.ac b/configure.ac index c6c2d73b06dd..e870862a8abb 100644 --- a/configure.ac +++ b/configure.ac @@ -321,7 +321,7 @@ AC_CHECK_FUNC([getservbyname], , AC_CHECK_LIB([crypt], [crypt], [LIBCRYPT="-lcrypt"]) AC_CHECK_HEADERS([sched.h], [], []) -AC_CHECK_FUNCS([unshare], [] , []) +AC_CHECK_FUNCS([unshare fstatat], [] , []) AC_LIBPTHREAD([]) if test "$enable_nfsv4" = yes; then diff --git a/support/include/Makefile.am b/support/include/Makefile.am index df5e47836d29..1373891a7c76 100644 --- a/support/include/Makefile.am +++ b/support/include/Makefile.am @@ -10,6 +10,7 @@ noinst_HEADERS = \ misc.h \ nfs_mntent.h \ nfs_paths.h \ + nfsd_path.h \ nfslib.h \ nfsrpc.h \ nls.h \ @@ -24,6 +25,7 @@ noinst_HEADERS = \ xlog.h \ xmalloc.h \ xcommon.h \ + xstat.h \ conffile.h MAINTAINERCLEANFILES = Makefile.in diff --git a/support/include/nfsd_path.h b/support/include/nfsd_path.h new file mode 100644 index 000000000000..db9b41a179ad --- /dev/null +++ b/support/include/nfsd_path.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2019 Trond Myklebust <trond.myklebust@hammerspace.com> + */ +#ifndef NFSD_PATH_H +#define NFSD_PATH_H + +void nfsd_path_init(void); + +const char * nfsd_path_nfsd_rootdir(void); +char * nfsd_path_strip_root(char *pathname); +char * nfsd_path_prepend_dir(const char *dir, const char *pathname); + +int nfsd_path_stat(const char *pathname, struct stat *statbuf); +int nfsd_path_lstat(const char *pathname, struct stat *statbuf); + +#endif diff --git a/support/include/xstat.h b/support/include/xstat.h new file mode 100644 index 000000000000..f1241bbfdc0e --- /dev/null +++ b/support/include/xstat.h @@ -0,0 +1,11 @@ +/* + * Copyright (C) 2019 Trond Myklebust <trond.myklebust@hammerspace.com> + */ +#ifndef XSTAT_H +#define XSTAT_H + +struct stat; + +int xlstat(const char *pathname, struct stat *statbuf); +int xstat(const char *pathname, struct stat *statbuf); +#endif diff --git a/support/misc/Makefile.am b/support/misc/Makefile.am index d0bff8feb6ae..f9993e3ac897 100644 --- a/support/misc/Makefile.am +++ b/support/misc/Makefile.am @@ -1,6 +1,7 @@ ## Process this file with automake to produce Makefile.in noinst_LIBRARIES = libmisc.a -libmisc_a_SOURCES = tcpwrapper.c from_local.c mountpoint.c file.c workqueue.c +libmisc_a_SOURCES = tcpwrapper.c from_local.c mountpoint.c file.c \ + nfsd_path.c workqueue.c xstat.c MAINTAINERCLEANFILES = Makefile.in diff --git a/support/misc/nfsd_path.c b/support/misc/nfsd_path.c new file mode 100644 index 000000000000..fe2c011b1521 --- /dev/null +++ b/support/misc/nfsd_path.c @@ -0,0 +1,168 @@ +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "config.h" +#include "conffile.h" +#include "xmalloc.h" +#include "xlog.h" +#include "xstat.h" +#include "nfsd_path.h" +#include "workqueue.h" + +static struct xthread_workqueue *nfsd_wq; + +static int +nfsd_path_isslash(const char *path) +{ + return path[0] == '/' && path[1] == '/'; +} + +static int +nfsd_path_isdot(const char *path) +{ + return path[0] == '.' && path[1] == '/'; +} + +static const char * +nfsd_path_strip(const char *path) +{ + 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 * +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; +} + +char * +nfsd_path_strip_root(char *pathname) +{ + const char *dir = nfsd_path_nfsd_rootdir(); + char *ret; + + ret = strstr(pathname, dir); + if (!ret || ret != pathname) + return pathname; + return pathname + strlen(dir); +} + +char * +nfsd_path_prepend_dir(const char *dir, const char *pathname) +{ + size_t len, dirlen; + char *ret; + + dirlen = strlen(dir); + while (dirlen > 0 && dir[dirlen - 1] == '/') + dirlen--; + if (!dirlen) + return NULL; + len = dirlen + strlen(pathname) + 1; + ret = xmalloc(len + 1); + snprintf(ret, len, "%.*s/%s", (int)dirlen, dir, pathname); + return ret; +} + +static void +nfsd_setup_workqueue(void) +{ + const char *rootdir = nfsd_path_nfsd_rootdir(); + + if (!rootdir) + return; + nfsd_wq = xthread_workqueue_alloc(); + if (!nfsd_wq) + return; + xthread_workqueue_chroot(nfsd_wq, rootdir); +} + +void +nfsd_path_init(void) +{ + nfsd_setup_workqueue(); +} + +struct nfsd_stat_data { + const char *pathname; + struct stat *statbuf; + int ret; + int err; +}; + +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) +{ + struct nfsd_stat_data *d = data; + + d->ret = xlstat(d->pathname, d->statbuf); + if (d->ret < 0) + d->err = errno; +} + +static int +nfsd_run_stat(struct xthread_workqueue *wq, + void (*func)(void *), + const char *pathname, + struct stat *statbuf) +{ + 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; +} + +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); +} + +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); +} diff --git a/support/misc/xstat.c b/support/misc/xstat.c new file mode 100644 index 000000000000..d092f73dfd65 --- /dev/null +++ b/support/misc/xstat.c @@ -0,0 +1,33 @@ +#include <sys/types.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <unistd.h> + +#include "config.h" +#include "xstat.h" + +#ifdef HAVE_FSTATAT + +int xlstat(const char *pathname, struct stat *statbuf) +{ + return fstatat(AT_FDCWD, pathname, statbuf, AT_NO_AUTOMOUNT | + AT_SYMLINK_NOFOLLOW); +} + +int xstat(const char *pathname, struct stat *statbuf) +{ + return fstatat(AT_FDCWD, pathname, statbuf, AT_NO_AUTOMOUNT); +} + +#else + +int xlstat(const char *pathname, struct stat *statbuf) +{ + return lstat(pathname, statbuf); +} + +int xstat(const char *pathname, struct stat *statbuf) +{ + return stat(pathname, statbuf); +} +#endif
Add helper functions that can resolve nfsd paths by prepending the necessary prefix if the admin has specified a root path in the nfs.conf file. Signed-off-by: Trond Myklebust <trond.myklebust@hammerspace.com> --- configure.ac | 2 +- support/include/Makefile.am | 2 + support/include/nfsd_path.h | 16 ++++ support/include/xstat.h | 11 +++ support/misc/Makefile.am | 3 +- support/misc/nfsd_path.c | 168 ++++++++++++++++++++++++++++++++++++ support/misc/xstat.c | 33 +++++++ 7 files changed, 233 insertions(+), 2 deletions(-) create mode 100644 support/include/nfsd_path.h create mode 100644 support/include/xstat.h create mode 100644 support/misc/nfsd_path.c create mode 100644 support/misc/xstat.c