diff options
Diffstat (limited to '')
130 files changed, 40052 insertions, 0 deletions
diff --git a/support/Makefile.am b/support/Makefile.am new file mode 100644 index 0000000..07cfd87 --- /dev/null +++ b/support/Makefile.am @@ -0,0 +1,16 @@ +## Process this file with automake to produce Makefile.in + +OPTDIRS = + +if CONFIG_NFSV4 +OPTDIRS += nfsidmap +endif + +if CONFIG_JUNCTION +OPTDIRS += junction +endif + +SUBDIRS = export include misc nfs nsm reexport $(OPTDIRS) + +MAINTAINERCLEANFILES = Makefile.in + diff --git a/support/Makefile.in b/support/Makefile.in new file mode 100644 index 0000000..017242d --- /dev/null +++ b/support/Makefile.in @@ -0,0 +1,716 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +@CONFIG_NFSV4_TRUE@am__append_1 = nfsidmap +@CONFIG_JUNCTION_TRUE@am__append_2 = junction +subdir = support +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ax_gcc_func_attribute.m4 \ + $(top_srcdir)/aclocal/bsdsignals.m4 \ + $(top_srcdir)/aclocal/getrandom.m4 \ + $(top_srcdir)/aclocal/ipv6.m4 \ + $(top_srcdir)/aclocal/kerberos5.m4 \ + $(top_srcdir)/aclocal/keyutils.m4 \ + $(top_srcdir)/aclocal/libblkid.m4 \ + $(top_srcdir)/aclocal/libcap.m4 \ + $(top_srcdir)/aclocal/libevent.m4 \ + $(top_srcdir)/aclocal/libpthread.m4 \ + $(top_srcdir)/aclocal/libsqlite3.m4 \ + $(top_srcdir)/aclocal/libtirpc.m4 \ + $(top_srcdir)/aclocal/libxml2.m4 \ + $(top_srcdir)/aclocal/nfs-utils.m4 \ + $(top_srcdir)/aclocal/rpcsec_vers.m4 \ + $(top_srcdir)/aclocal/tcp-wrappers.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/support/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +DIST_SUBDIRS = export include misc nfs nsm reexport nfsidmap junction +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GREP = @GREP@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GSSD = @GSSD@ +GSSGLUE_CFLAGS = @GSSGLUE_CFLAGS@ +GSSGLUE_LIBS = @GSSGLUE_LIBS@ +GSSKRB_CFLAGS = @GSSKRB_CFLAGS@ +GSSKRB_LIBS = @GSSKRB_LIBS@ +HAVE_GETRANDOM = @HAVE_GETRANDOM@ +HAVE_LIBWRAP = @HAVE_LIBWRAP@ +HAVE_TCP_WRAPPER = @HAVE_TCP_WRAPPER@ +IDMAPD = @IDMAPD@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +K5VERS = @K5VERS@ +KRBCFLAGS = @KRBCFLAGS@ +KRBDIR = @KRBDIR@ +KRBLDFLAGS = @KRBLDFLAGS@ +KRBLIBS = @KRBLIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ +LIBBLKID = @LIBBLKID@ +LIBBSD = @LIBBSD@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBEVENT = @LIBEVENT@ +LIBKEYUTILS = @LIBKEYUTILS@ +LIBMOUNT = @LIBMOUNT@ +LIBMOUNT_CFLAGS = @LIBMOUNT_CFLAGS@ +LIBMOUNT_LIBS = @LIBMOUNT_LIBS@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPTHREAD = @LIBPTHREAD@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSQLITE = @LIBSQLITE@ +LIBTIRPC = @LIBTIRPC@ +LIBTOOL = @LIBTOOL@ +LIBWRAP = @LIBWRAP@ +LIBXML2 = @LIBXML2@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_PLUGINS = @PATH_PLUGINS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +RELEASE = @RELEASE@ +RPCGEN_PATH = @RPCGEN_PATH@ +RPCSECGSS_CFLAGS = @RPCSECGSS_CFLAGS@ +RPCSECGSS_LIBS = @RPCSECGSS_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SVCGSSD = @SVCGSSD@ +TIRPC_CFLAGS = @TIRPC_CFLAGS@ +TIRPC_LIBS = @TIRPC_LIBS@ +VERSION = @VERSION@ +XML2_CFLAGS = @XML2_CFLAGS@ +XML2_LIBS = @XML2_LIBS@ +_rpc_pipefsmount = @_rpc_pipefsmount@ +_statedir = @_statedir@ +_sysconfdir = @_sysconfdir@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_gss = @enable_gss@ +enable_ipv6 = @enable_ipv6@ +enable_mountconfig = @enable_mountconfig@ +enable_nfsv4 = @enable_nfsv4@ +enable_nfsv41 = @enable_nfsv41@ +enable_svcgss = @enable_svcgss@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +kprefix = @kprefix@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +mountfile = @mountfile@ +nfsconfig = @nfsconfig@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rpc_pipefsmount = @rpc_pipefsmount@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +startstatd = @startstatd@ +statdpath = @statdpath@ +statduser = @statduser@ +statedir = @statedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +unitdir = @unitdir@ +OPTDIRS = $(am__append_1) $(am__append_2) +SUBDIRS = export include misc nfs nsm reexport $(OPTDIRS) +MAINTAINERCLEANFILES = Makefile.in +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu support/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu support/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/support/export/Makefile.am b/support/export/Makefile.am new file mode 100644 index 0000000..7338e1c --- /dev/null +++ b/support/export/Makefile.am @@ -0,0 +1,52 @@ +## Process this file with automake to produce Makefile.in + + +GENFILES_CLNT = mount_clnt.c +GENFILES_XDR = mount_xdr.c +GENFILES_H = mount.h + +GENFILES = $(GENFILES_CLNT) $(GENFILES_SVC) $(GENFILES_XDR) $(GENFILES_H) + +EXTRA_DIST = mount.x + +noinst_LIBRARIES = libexport.a +libexport_a_SOURCES = client.c export.c hostname.c \ + xtab.c mount_clnt.c mount_xdr.c \ + cache.c auth.c v4root.c fsloc.c \ + v4clients.c +libexport_a_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) -I$(top_srcdir)/support/reexport + +BUILT_SOURCES = $(GENFILES) + +noinst_HEADERS = mount.h + +dist-hook: + for f in $(GENFILES); do \ + rm ${distdir}/$$f; \ + done + +if CONFIG_RPCGEN +RPCGEN = $(top_builddir)/tools/rpcgen/rpcgen +$(RPCGEN): + make -C $(top_srcdir)/tools/rpcgen all +else +RPCGEN = @RPCGEN_PATH@ +endif + +$(GENFILES_CLNT): %_clnt.c: %.x $(RPCGEN) + test -f $@ && rm -rf $@ || true + $(RPCGEN) -l -o $@ $< + +$(GENFILES_XDR): %_xdr.c: %.x $(RPCGEN) + test -f $@ && rm -rf $@ || true + $(RPCGEN) -c -i 0 -o $@ $< + +$(GENFILES_H): %.h: %.x $(RPCGEN) + test -f $@ && rm -rf $@ || true + $(RPCGEN) -h -o $@ $< + rm -f $(top_builddir)/support/include/mount.h + $(LN_S) ../export/mount.h $(top_builddir)/support/include/mount.h + +MAINTAINERCLEANFILES = Makefile.in + +CLEANFILES = $(GENFILES) $(top_builddir)/support/include/mount.h diff --git a/support/export/Makefile.in b/support/export/Makefile.in new file mode 100644 index 0000000..6d8a25a --- /dev/null +++ b/support/export/Makefile.in @@ -0,0 +1,934 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = support/export +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ax_gcc_func_attribute.m4 \ + $(top_srcdir)/aclocal/bsdsignals.m4 \ + $(top_srcdir)/aclocal/getrandom.m4 \ + $(top_srcdir)/aclocal/ipv6.m4 \ + $(top_srcdir)/aclocal/kerberos5.m4 \ + $(top_srcdir)/aclocal/keyutils.m4 \ + $(top_srcdir)/aclocal/libblkid.m4 \ + $(top_srcdir)/aclocal/libcap.m4 \ + $(top_srcdir)/aclocal/libevent.m4 \ + $(top_srcdir)/aclocal/libpthread.m4 \ + $(top_srcdir)/aclocal/libsqlite3.m4 \ + $(top_srcdir)/aclocal/libtirpc.m4 \ + $(top_srcdir)/aclocal/libxml2.m4 \ + $(top_srcdir)/aclocal/nfs-utils.m4 \ + $(top_srcdir)/aclocal/rpcsec_vers.m4 \ + $(top_srcdir)/aclocal/tcp-wrappers.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/support/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +AM_V_AR = $(am__v_AR_@AM_V@) +am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) +am__v_AR_0 = @echo " AR " $@; +am__v_AR_1 = +libexport_a_AR = $(AR) $(ARFLAGS) +libexport_a_LIBADD = +am_libexport_a_OBJECTS = libexport_a-client.$(OBJEXT) \ + libexport_a-export.$(OBJEXT) libexport_a-hostname.$(OBJEXT) \ + libexport_a-xtab.$(OBJEXT) libexport_a-mount_clnt.$(OBJEXT) \ + libexport_a-mount_xdr.$(OBJEXT) libexport_a-cache.$(OBJEXT) \ + libexport_a-auth.$(OBJEXT) libexport_a-v4root.$(OBJEXT) \ + libexport_a-fsloc.$(OBJEXT) libexport_a-v4clients.$(OBJEXT) +libexport_a_OBJECTS = $(am_libexport_a_OBJECTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/support/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/libexport_a-auth.Po \ + ./$(DEPDIR)/libexport_a-cache.Po \ + ./$(DEPDIR)/libexport_a-client.Po \ + ./$(DEPDIR)/libexport_a-export.Po \ + ./$(DEPDIR)/libexport_a-fsloc.Po \ + ./$(DEPDIR)/libexport_a-hostname.Po \ + ./$(DEPDIR)/libexport_a-mount_clnt.Po \ + ./$(DEPDIR)/libexport_a-mount_xdr.Po \ + ./$(DEPDIR)/libexport_a-v4clients.Po \ + ./$(DEPDIR)/libexport_a-v4root.Po \ + ./$(DEPDIR)/libexport_a-xtab.Po +am__mv = mv -f +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libexport_a_SOURCES) +DIST_SOURCES = $(libexport_a_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GREP = @GREP@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GSSD = @GSSD@ +GSSGLUE_CFLAGS = @GSSGLUE_CFLAGS@ +GSSGLUE_LIBS = @GSSGLUE_LIBS@ +GSSKRB_CFLAGS = @GSSKRB_CFLAGS@ +GSSKRB_LIBS = @GSSKRB_LIBS@ +HAVE_GETRANDOM = @HAVE_GETRANDOM@ +HAVE_LIBWRAP = @HAVE_LIBWRAP@ +HAVE_TCP_WRAPPER = @HAVE_TCP_WRAPPER@ +IDMAPD = @IDMAPD@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +K5VERS = @K5VERS@ +KRBCFLAGS = @KRBCFLAGS@ +KRBDIR = @KRBDIR@ +KRBLDFLAGS = @KRBLDFLAGS@ +KRBLIBS = @KRBLIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ +LIBBLKID = @LIBBLKID@ +LIBBSD = @LIBBSD@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBEVENT = @LIBEVENT@ +LIBKEYUTILS = @LIBKEYUTILS@ +LIBMOUNT = @LIBMOUNT@ +LIBMOUNT_CFLAGS = @LIBMOUNT_CFLAGS@ +LIBMOUNT_LIBS = @LIBMOUNT_LIBS@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPTHREAD = @LIBPTHREAD@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSQLITE = @LIBSQLITE@ +LIBTIRPC = @LIBTIRPC@ +LIBTOOL = @LIBTOOL@ +LIBWRAP = @LIBWRAP@ +LIBXML2 = @LIBXML2@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_PLUGINS = @PATH_PLUGINS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +RELEASE = @RELEASE@ +RPCGEN_PATH = @RPCGEN_PATH@ +RPCSECGSS_CFLAGS = @RPCSECGSS_CFLAGS@ +RPCSECGSS_LIBS = @RPCSECGSS_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SVCGSSD = @SVCGSSD@ +TIRPC_CFLAGS = @TIRPC_CFLAGS@ +TIRPC_LIBS = @TIRPC_LIBS@ +VERSION = @VERSION@ +XML2_CFLAGS = @XML2_CFLAGS@ +XML2_LIBS = @XML2_LIBS@ +_rpc_pipefsmount = @_rpc_pipefsmount@ +_statedir = @_statedir@ +_sysconfdir = @_sysconfdir@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_gss = @enable_gss@ +enable_ipv6 = @enable_ipv6@ +enable_mountconfig = @enable_mountconfig@ +enable_nfsv4 = @enable_nfsv4@ +enable_nfsv41 = @enable_nfsv41@ +enable_svcgss = @enable_svcgss@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +kprefix = @kprefix@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +mountfile = @mountfile@ +nfsconfig = @nfsconfig@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rpc_pipefsmount = @rpc_pipefsmount@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +startstatd = @startstatd@ +statdpath = @statdpath@ +statduser = @statduser@ +statedir = @statedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +unitdir = @unitdir@ +GENFILES_CLNT = mount_clnt.c +GENFILES_XDR = mount_xdr.c +GENFILES_H = mount.h +GENFILES = $(GENFILES_CLNT) $(GENFILES_SVC) $(GENFILES_XDR) $(GENFILES_H) +EXTRA_DIST = mount.x +noinst_LIBRARIES = libexport.a +libexport_a_SOURCES = client.c export.c hostname.c \ + xtab.c mount_clnt.c mount_xdr.c \ + cache.c auth.c v4root.c fsloc.c \ + v4clients.c + +libexport_a_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) -I$(top_srcdir)/support/reexport +BUILT_SOURCES = $(GENFILES) +noinst_HEADERS = mount.h +@CONFIG_RPCGEN_FALSE@RPCGEN = @RPCGEN_PATH@ +@CONFIG_RPCGEN_TRUE@RPCGEN = $(top_builddir)/tools/rpcgen/rpcgen +MAINTAINERCLEANFILES = Makefile.in +CLEANFILES = $(GENFILES) $(top_builddir)/support/include/mount.h +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu support/export/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu support/export/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +libexport.a: $(libexport_a_OBJECTS) $(libexport_a_DEPENDENCIES) $(EXTRA_libexport_a_DEPENDENCIES) + $(AM_V_at)-rm -f libexport.a + $(AM_V_AR)$(libexport_a_AR) libexport.a $(libexport_a_OBJECTS) $(libexport_a_LIBADD) + $(AM_V_at)$(RANLIB) libexport.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libexport_a-auth.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libexport_a-cache.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libexport_a-client.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libexport_a-export.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libexport_a-fsloc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libexport_a-hostname.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libexport_a-mount_clnt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libexport_a-mount_xdr.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libexport_a-v4clients.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libexport_a-v4root.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libexport_a-xtab.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +libexport_a-client.o: client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libexport_a-client.o -MD -MP -MF $(DEPDIR)/libexport_a-client.Tpo -c -o libexport_a-client.o `test -f 'client.c' || echo '$(srcdir)/'`client.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libexport_a-client.Tpo $(DEPDIR)/libexport_a-client.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='client.c' object='libexport_a-client.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libexport_a-client.o `test -f 'client.c' || echo '$(srcdir)/'`client.c + +libexport_a-client.obj: client.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libexport_a-client.obj -MD -MP -MF $(DEPDIR)/libexport_a-client.Tpo -c -o libexport_a-client.obj `if test -f 'client.c'; then $(CYGPATH_W) 'client.c'; else $(CYGPATH_W) '$(srcdir)/client.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libexport_a-client.Tpo $(DEPDIR)/libexport_a-client.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='client.c' object='libexport_a-client.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libexport_a-client.obj `if test -f 'client.c'; then $(CYGPATH_W) 'client.c'; else $(CYGPATH_W) '$(srcdir)/client.c'; fi` + +libexport_a-export.o: export.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libexport_a-export.o -MD -MP -MF $(DEPDIR)/libexport_a-export.Tpo -c -o libexport_a-export.o `test -f 'export.c' || echo '$(srcdir)/'`export.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libexport_a-export.Tpo $(DEPDIR)/libexport_a-export.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='export.c' object='libexport_a-export.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libexport_a-export.o `test -f 'export.c' || echo '$(srcdir)/'`export.c + +libexport_a-export.obj: export.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libexport_a-export.obj -MD -MP -MF $(DEPDIR)/libexport_a-export.Tpo -c -o libexport_a-export.obj `if test -f 'export.c'; then $(CYGPATH_W) 'export.c'; else $(CYGPATH_W) '$(srcdir)/export.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libexport_a-export.Tpo $(DEPDIR)/libexport_a-export.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='export.c' object='libexport_a-export.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libexport_a-export.obj `if test -f 'export.c'; then $(CYGPATH_W) 'export.c'; else $(CYGPATH_W) '$(srcdir)/export.c'; fi` + +libexport_a-hostname.o: hostname.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libexport_a-hostname.o -MD -MP -MF $(DEPDIR)/libexport_a-hostname.Tpo -c -o libexport_a-hostname.o `test -f 'hostname.c' || echo '$(srcdir)/'`hostname.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libexport_a-hostname.Tpo $(DEPDIR)/libexport_a-hostname.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hostname.c' object='libexport_a-hostname.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libexport_a-hostname.o `test -f 'hostname.c' || echo '$(srcdir)/'`hostname.c + +libexport_a-hostname.obj: hostname.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libexport_a-hostname.obj -MD -MP -MF $(DEPDIR)/libexport_a-hostname.Tpo -c -o libexport_a-hostname.obj `if test -f 'hostname.c'; then $(CYGPATH_W) 'hostname.c'; else $(CYGPATH_W) '$(srcdir)/hostname.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libexport_a-hostname.Tpo $(DEPDIR)/libexport_a-hostname.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='hostname.c' object='libexport_a-hostname.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libexport_a-hostname.obj `if test -f 'hostname.c'; then $(CYGPATH_W) 'hostname.c'; else $(CYGPATH_W) '$(srcdir)/hostname.c'; fi` + +libexport_a-xtab.o: xtab.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libexport_a-xtab.o -MD -MP -MF $(DEPDIR)/libexport_a-xtab.Tpo -c -o libexport_a-xtab.o `test -f 'xtab.c' || echo '$(srcdir)/'`xtab.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libexport_a-xtab.Tpo $(DEPDIR)/libexport_a-xtab.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xtab.c' object='libexport_a-xtab.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libexport_a-xtab.o `test -f 'xtab.c' || echo '$(srcdir)/'`xtab.c + +libexport_a-xtab.obj: xtab.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libexport_a-xtab.obj -MD -MP -MF $(DEPDIR)/libexport_a-xtab.Tpo -c -o libexport_a-xtab.obj `if test -f 'xtab.c'; then $(CYGPATH_W) 'xtab.c'; else $(CYGPATH_W) '$(srcdir)/xtab.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libexport_a-xtab.Tpo $(DEPDIR)/libexport_a-xtab.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xtab.c' object='libexport_a-xtab.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libexport_a-xtab.obj `if test -f 'xtab.c'; then $(CYGPATH_W) 'xtab.c'; else $(CYGPATH_W) '$(srcdir)/xtab.c'; fi` + +libexport_a-mount_clnt.o: mount_clnt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libexport_a-mount_clnt.o -MD -MP -MF $(DEPDIR)/libexport_a-mount_clnt.Tpo -c -o libexport_a-mount_clnt.o `test -f 'mount_clnt.c' || echo '$(srcdir)/'`mount_clnt.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libexport_a-mount_clnt.Tpo $(DEPDIR)/libexport_a-mount_clnt.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mount_clnt.c' object='libexport_a-mount_clnt.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libexport_a-mount_clnt.o `test -f 'mount_clnt.c' || echo '$(srcdir)/'`mount_clnt.c + +libexport_a-mount_clnt.obj: mount_clnt.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libexport_a-mount_clnt.obj -MD -MP -MF $(DEPDIR)/libexport_a-mount_clnt.Tpo -c -o libexport_a-mount_clnt.obj `if test -f 'mount_clnt.c'; then $(CYGPATH_W) 'mount_clnt.c'; else $(CYGPATH_W) '$(srcdir)/mount_clnt.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libexport_a-mount_clnt.Tpo $(DEPDIR)/libexport_a-mount_clnt.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mount_clnt.c' object='libexport_a-mount_clnt.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libexport_a-mount_clnt.obj `if test -f 'mount_clnt.c'; then $(CYGPATH_W) 'mount_clnt.c'; else $(CYGPATH_W) '$(srcdir)/mount_clnt.c'; fi` + +libexport_a-mount_xdr.o: mount_xdr.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libexport_a-mount_xdr.o -MD -MP -MF $(DEPDIR)/libexport_a-mount_xdr.Tpo -c -o libexport_a-mount_xdr.o `test -f 'mount_xdr.c' || echo '$(srcdir)/'`mount_xdr.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libexport_a-mount_xdr.Tpo $(DEPDIR)/libexport_a-mount_xdr.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mount_xdr.c' object='libexport_a-mount_xdr.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libexport_a-mount_xdr.o `test -f 'mount_xdr.c' || echo '$(srcdir)/'`mount_xdr.c + +libexport_a-mount_xdr.obj: mount_xdr.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libexport_a-mount_xdr.obj -MD -MP -MF $(DEPDIR)/libexport_a-mount_xdr.Tpo -c -o libexport_a-mount_xdr.obj `if test -f 'mount_xdr.c'; then $(CYGPATH_W) 'mount_xdr.c'; else $(CYGPATH_W) '$(srcdir)/mount_xdr.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libexport_a-mount_xdr.Tpo $(DEPDIR)/libexport_a-mount_xdr.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mount_xdr.c' object='libexport_a-mount_xdr.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libexport_a-mount_xdr.obj `if test -f 'mount_xdr.c'; then $(CYGPATH_W) 'mount_xdr.c'; else $(CYGPATH_W) '$(srcdir)/mount_xdr.c'; fi` + +libexport_a-cache.o: cache.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libexport_a-cache.o -MD -MP -MF $(DEPDIR)/libexport_a-cache.Tpo -c -o libexport_a-cache.o `test -f 'cache.c' || echo '$(srcdir)/'`cache.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libexport_a-cache.Tpo $(DEPDIR)/libexport_a-cache.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cache.c' object='libexport_a-cache.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libexport_a-cache.o `test -f 'cache.c' || echo '$(srcdir)/'`cache.c + +libexport_a-cache.obj: cache.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libexport_a-cache.obj -MD -MP -MF $(DEPDIR)/libexport_a-cache.Tpo -c -o libexport_a-cache.obj `if test -f 'cache.c'; then $(CYGPATH_W) 'cache.c'; else $(CYGPATH_W) '$(srcdir)/cache.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libexport_a-cache.Tpo $(DEPDIR)/libexport_a-cache.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cache.c' object='libexport_a-cache.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libexport_a-cache.obj `if test -f 'cache.c'; then $(CYGPATH_W) 'cache.c'; else $(CYGPATH_W) '$(srcdir)/cache.c'; fi` + +libexport_a-auth.o: auth.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libexport_a-auth.o -MD -MP -MF $(DEPDIR)/libexport_a-auth.Tpo -c -o libexport_a-auth.o `test -f 'auth.c' || echo '$(srcdir)/'`auth.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libexport_a-auth.Tpo $(DEPDIR)/libexport_a-auth.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='auth.c' object='libexport_a-auth.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libexport_a-auth.o `test -f 'auth.c' || echo '$(srcdir)/'`auth.c + +libexport_a-auth.obj: auth.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libexport_a-auth.obj -MD -MP -MF $(DEPDIR)/libexport_a-auth.Tpo -c -o libexport_a-auth.obj `if test -f 'auth.c'; then $(CYGPATH_W) 'auth.c'; else $(CYGPATH_W) '$(srcdir)/auth.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libexport_a-auth.Tpo $(DEPDIR)/libexport_a-auth.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='auth.c' object='libexport_a-auth.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libexport_a-auth.obj `if test -f 'auth.c'; then $(CYGPATH_W) 'auth.c'; else $(CYGPATH_W) '$(srcdir)/auth.c'; fi` + +libexport_a-v4root.o: v4root.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libexport_a-v4root.o -MD -MP -MF $(DEPDIR)/libexport_a-v4root.Tpo -c -o libexport_a-v4root.o `test -f 'v4root.c' || echo '$(srcdir)/'`v4root.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libexport_a-v4root.Tpo $(DEPDIR)/libexport_a-v4root.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='v4root.c' object='libexport_a-v4root.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libexport_a-v4root.o `test -f 'v4root.c' || echo '$(srcdir)/'`v4root.c + +libexport_a-v4root.obj: v4root.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libexport_a-v4root.obj -MD -MP -MF $(DEPDIR)/libexport_a-v4root.Tpo -c -o libexport_a-v4root.obj `if test -f 'v4root.c'; then $(CYGPATH_W) 'v4root.c'; else $(CYGPATH_W) '$(srcdir)/v4root.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libexport_a-v4root.Tpo $(DEPDIR)/libexport_a-v4root.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='v4root.c' object='libexport_a-v4root.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libexport_a-v4root.obj `if test -f 'v4root.c'; then $(CYGPATH_W) 'v4root.c'; else $(CYGPATH_W) '$(srcdir)/v4root.c'; fi` + +libexport_a-fsloc.o: fsloc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libexport_a-fsloc.o -MD -MP -MF $(DEPDIR)/libexport_a-fsloc.Tpo -c -o libexport_a-fsloc.o `test -f 'fsloc.c' || echo '$(srcdir)/'`fsloc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libexport_a-fsloc.Tpo $(DEPDIR)/libexport_a-fsloc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fsloc.c' object='libexport_a-fsloc.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libexport_a-fsloc.o `test -f 'fsloc.c' || echo '$(srcdir)/'`fsloc.c + +libexport_a-fsloc.obj: fsloc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libexport_a-fsloc.obj -MD -MP -MF $(DEPDIR)/libexport_a-fsloc.Tpo -c -o libexport_a-fsloc.obj `if test -f 'fsloc.c'; then $(CYGPATH_W) 'fsloc.c'; else $(CYGPATH_W) '$(srcdir)/fsloc.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libexport_a-fsloc.Tpo $(DEPDIR)/libexport_a-fsloc.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fsloc.c' object='libexport_a-fsloc.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libexport_a-fsloc.obj `if test -f 'fsloc.c'; then $(CYGPATH_W) 'fsloc.c'; else $(CYGPATH_W) '$(srcdir)/fsloc.c'; fi` + +libexport_a-v4clients.o: v4clients.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libexport_a-v4clients.o -MD -MP -MF $(DEPDIR)/libexport_a-v4clients.Tpo -c -o libexport_a-v4clients.o `test -f 'v4clients.c' || echo '$(srcdir)/'`v4clients.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libexport_a-v4clients.Tpo $(DEPDIR)/libexport_a-v4clients.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='v4clients.c' object='libexport_a-v4clients.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libexport_a-v4clients.o `test -f 'v4clients.c' || echo '$(srcdir)/'`v4clients.c + +libexport_a-v4clients.obj: v4clients.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libexport_a-v4clients.obj -MD -MP -MF $(DEPDIR)/libexport_a-v4clients.Tpo -c -o libexport_a-v4clients.obj `if test -f 'v4clients.c'; then $(CYGPATH_W) 'v4clients.c'; else $(CYGPATH_W) '$(srcdir)/v4clients.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libexport_a-v4clients.Tpo $(DEPDIR)/libexport_a-v4clients.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='v4clients.c' object='libexport_a-v4clients.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libexport_a_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libexport_a-v4clients.obj `if test -f 'v4clients.c'; then $(CYGPATH_W) 'v4clients.c'; else $(CYGPATH_W) '$(srcdir)/v4clients.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" distdir="$(distdir)" \ + dist-hook +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(LIBRARIES) $(HEADERS) +installdirs: +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/libexport_a-auth.Po + -rm -f ./$(DEPDIR)/libexport_a-cache.Po + -rm -f ./$(DEPDIR)/libexport_a-client.Po + -rm -f ./$(DEPDIR)/libexport_a-export.Po + -rm -f ./$(DEPDIR)/libexport_a-fsloc.Po + -rm -f ./$(DEPDIR)/libexport_a-hostname.Po + -rm -f ./$(DEPDIR)/libexport_a-mount_clnt.Po + -rm -f ./$(DEPDIR)/libexport_a-mount_xdr.Po + -rm -f ./$(DEPDIR)/libexport_a-v4clients.Po + -rm -f ./$(DEPDIR)/libexport_a-v4root.Po + -rm -f ./$(DEPDIR)/libexport_a-xtab.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/libexport_a-auth.Po + -rm -f ./$(DEPDIR)/libexport_a-cache.Po + -rm -f ./$(DEPDIR)/libexport_a-client.Po + -rm -f ./$(DEPDIR)/libexport_a-export.Po + -rm -f ./$(DEPDIR)/libexport_a-fsloc.Po + -rm -f ./$(DEPDIR)/libexport_a-hostname.Po + -rm -f ./$(DEPDIR)/libexport_a-mount_clnt.Po + -rm -f ./$(DEPDIR)/libexport_a-mount_xdr.Po + -rm -f ./$(DEPDIR)/libexport_a-v4clients.Po + -rm -f ./$(DEPDIR)/libexport_a-v4root.Po + -rm -f ./$(DEPDIR)/libexport_a-xtab.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: all check install install-am install-exec install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-noinstLIBRARIES \ + cscopelist-am ctags ctags-am dist-hook distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +dist-hook: + for f in $(GENFILES); do \ + rm ${distdir}/$$f; \ + done +@CONFIG_RPCGEN_TRUE@$(RPCGEN): +@CONFIG_RPCGEN_TRUE@ make -C $(top_srcdir)/tools/rpcgen all + +$(GENFILES_CLNT): %_clnt.c: %.x $(RPCGEN) + test -f $@ && rm -rf $@ || true + $(RPCGEN) -l -o $@ $< + +$(GENFILES_XDR): %_xdr.c: %.x $(RPCGEN) + test -f $@ && rm -rf $@ || true + $(RPCGEN) -c -i 0 -o $@ $< + +$(GENFILES_H): %.h: %.x $(RPCGEN) + test -f $@ && rm -rf $@ || true + $(RPCGEN) -h -o $@ $< + rm -f $(top_builddir)/support/include/mount.h + $(LN_S) ../export/mount.h $(top_builddir)/support/include/mount.h + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/support/export/auth.c b/support/export/auth.c new file mode 100644 index 0000000..2d7960f --- /dev/null +++ b/support/export/auth.c @@ -0,0 +1,320 @@ +/* + * utils/mountd/auth.c + * + * Authentication procedures for mountd. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> + +#include "sockaddr.h" +#include "misc.h" +#include "nfslib.h" +#include "exportfs.h" +#include "export.h" +#include "v4root.h" + +enum auth_error +{ + bad_path, + unknown_host, + no_entry, + not_exported, + illegal_port, + success +}; + +static void auth_fixpath(char *path); +static nfs_export my_exp; +static nfs_client my_client; + +extern int use_ipaddr; + +/* +void +auth_init(void) +{ + auth_reload(); +} +*/ + +/* + * A client can match many different netgroups and it's tough to know + * beforehand whether it will. If the concatenated string of netgroup + * m_hostnames is >512 bytes, then enable the "use_ipaddr" mode. This + * makes mountd change how it matches a client ip address when a mount + * request comes in. It's more efficient at handling netgroups at the + * expense of larger kernel caches. + */ +static void +check_useipaddr(void) +{ + nfs_client *clp; + int old_use_ipaddr = use_ipaddr; + unsigned int len = 0; + + if (use_ipaddr > 1) + /* fixed - don't check */ + return; + + /* add length of m_hostname + 1 for the comma */ + for (clp = clientlist[MCL_NETGROUP]; clp; clp = clp->m_next) + len += (strlen(clp->m_hostname) + 1); + + if (len > (NFSCLNT_IDMAX / 2)) + use_ipaddr = 1; + else + use_ipaddr = 0; + + if (use_ipaddr != old_use_ipaddr) + cache_flush(); +} + +unsigned int +auth_reload(void) +{ + struct stat stb; + static ino_t last_inode; + static int last_fd = -1; + static unsigned int counter; + int fd; + + if ((fd = open(etab.statefn, O_RDONLY)) < 0) { + xlog(L_FATAL, "couldn't open %s", etab.statefn); + } else if (fstat(fd, &stb) < 0) { + xlog(L_FATAL, "couldn't stat %s", etab.statefn); + close(fd); + } else if (last_fd != -1 && stb.st_ino == last_inode) { + /* We opened the etab file before, and its inode + * number hasn't changed since then. + */ + close(fd); + return counter; + } else { + /* Need to process entries from the etab file. Close + * the file descriptor from the previous open (last_fd), + * and keep the current file descriptor open to prevent + * the file system reusing the current inode number + * (last_inode). + */ + if (last_fd != -1) + close(last_fd); + last_fd = fd; + last_inode = stb.st_ino; + } + + export_freeall(); + memset(&my_client, 0, sizeof(my_client)); + xtab_export_read(); + check_useipaddr(); + v4root_set(); + + ++counter; + + return counter; +} + +static char *get_client_ipaddr_name(const struct sockaddr *caller) +{ + char buf[INET6_ADDRSTRLEN + 1]; + + buf[0] = '$'; + host_ntop(caller, buf + 1, sizeof(buf) - 1); + return strdup(buf); +} + +static char * +get_client_hostname(const struct sockaddr *caller, struct addrinfo *ai, + enum auth_error *error) +{ + char *n; + + if (use_ipaddr) + return get_client_ipaddr_name(caller); + n = client_compose(ai); + *error = unknown_host; + if (!n) + return NULL; + if (*n) + return n; + free(n); + return strdup("DEFAULT"); +} + +bool ipaddr_client_matches(nfs_export *exp, struct addrinfo *ai) +{ + return client_check(exp->m_client, ai); +} + +bool namelist_client_matches(nfs_export *exp, char *dom) +{ + return client_member(dom, exp->m_client->m_hostname); +} + +bool client_matches(nfs_export *exp, char *dom, struct addrinfo *ai) +{ + if (is_ipaddr_client(dom)) + return ipaddr_client_matches(exp, ai); + return namelist_client_matches(exp, dom); +} + +/* return static nfs_export with details filled in */ +static nfs_export * +auth_authenticate_newcache(const struct sockaddr *caller, + const char *path, struct addrinfo *ai, + enum auth_error *error) +{ + nfs_export *exp; + int i; + + free(my_client.m_hostname); + + my_client.m_hostname = get_client_hostname(caller, ai, error); + if (my_client.m_hostname == NULL) + return NULL; + + my_client.m_naddr = 1; + set_addrlist(&my_client, 0, caller); + my_exp.m_client = &my_client; + + exp = NULL; + for (i = 0; !exp && i < MCL_MAXTYPES; i++) + for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { + if (strcmp(path, exp->m_export.e_path)) + continue; + if (!client_matches(exp, my_client.m_hostname, ai)) + continue; + if (exp->m_export.e_flags & NFSEXP_V4ROOT) + /* not acceptable for v[23] export */ + continue; + break; + } + *error = not_exported; + if (!exp) + return NULL; + + my_exp.m_export = exp->m_export; + exp = &my_exp; + return exp; +} + +static nfs_export * +auth_authenticate_internal(const struct sockaddr *caller, const char *path, + struct addrinfo *ai, enum auth_error *error) +{ + nfs_export *exp; + + exp = auth_authenticate_newcache(caller, path, ai, error); + if (!exp) + return NULL; + if (!(exp->m_export.e_flags & NFSEXP_INSECURE_PORT) && + nfs_get_port(caller) >= IPPORT_RESERVED) { + *error = illegal_port; + return NULL; + } + *error = success; + + return exp; +} + +nfs_export * +auth_authenticate(const char *what, const struct sockaddr *caller, + const char *path) +{ + nfs_export *exp = NULL; + char epath[MAXPATHLEN+1]; + char *p = NULL; + char buf[INET6_ADDRSTRLEN]; + struct addrinfo *ai = NULL; + enum auth_error error = bad_path; + + if (path[0] != '/') { + xlog(L_WARNING, "Bad path in %s request from %s: \"%s\"", + what, host_ntop(caller, buf, sizeof(buf)), path); + return exp; + } + + strncpy(epath, path, sizeof (epath) - 1); + epath[sizeof (epath) - 1] = '\0'; + auth_fixpath(epath); /* strip duplicate '/' etc */ + + ai = client_resolve(caller); + if (ai == NULL) + return exp; + + /* Try the longest matching exported pathname. */ + while (1) { + exp = auth_authenticate_internal(caller, epath, ai, &error); + if (exp || (error != not_exported && error != no_entry)) + break; + /* We have to treat the root, "/", specially. */ + if (p == &epath[1]) break; + p = strrchr(epath, '/'); + if (p == epath) p++; + *p = '\0'; + } + + host_ntop(caller, buf, sizeof(buf)); + switch (error) { + case bad_path: + xlog(L_WARNING, "bad path in %s request from %s: \"%s\"", + what, buf, path); + break; + + case unknown_host: + xlog(L_WARNING, "refused %s request from %s for %s (%s): unmatched host", + what, buf, path, epath); + break; + + case no_entry: + xlog(L_WARNING, "refused %s request from %s for %s (%s): no export entry", + what, buf, path, epath); + break; + + case not_exported: + xlog(L_WARNING, "refused %s request from %s for %s (%s): not exported", + what, buf, path, epath); + break; + + case illegal_port: + xlog(L_WARNING, "refused %s request from %s for %s (%s): illegal port %u", + what, buf, path, epath, nfs_get_port(caller)); + break; + + case success: + xlog(L_NOTICE, "authenticated %s request from %s:%u for %s (%s)", + what, buf, nfs_get_port(caller), path, epath); + break; + default: + xlog(L_NOTICE, "%s request from %s:%u for %s (%s) gave %d", + what, buf, nfs_get_port(caller), path, epath, error); + } + + nfs_freeaddrinfo(ai); + return exp; +} + +static void +auth_fixpath(char *path) +{ + char *sp, *cp; + + for (sp = cp = path; *sp; sp++) { + if (*sp != '/' || sp[1] != '/') + *cp++ = *sp; + } + while (cp > path+1 && cp[-1] == '/') + cp--; + *cp = '\0'; +} diff --git a/support/export/cache.c b/support/export/cache.c new file mode 100644 index 0000000..6c0a44a --- /dev/null +++ b/support/export/cache.c @@ -0,0 +1,1934 @@ +/* + * Handle communication with knfsd internal cache + * + * We open /proc/net/rpc/{auth.unix.ip,nfsd.export,nfsd.fh}/channel + * and listen for requests (using my_svc_run) + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/sysmacros.h> +#include <sys/types.h> +#include <sys/select.h> +#include <sys/stat.h> +#include <sys/vfs.h> +#include <sys/wait.h> +#include <time.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> +#include <ctype.h> +#include <pwd.h> +#include <grp.h> +#include <mntent.h> +#include "misc.h" +#include "nfsd_path.h" +#include "nfslib.h" +#include "exportfs.h" +#include "export.h" +#include "pseudoflavors.h" +#include "xcommon.h" +#include "reexport.h" + +#ifdef HAVE_JUNCTION_SUPPORT +#include "fsloc.h" +#endif + +#ifdef USE_BLKID +#include "blkid/blkid.h" +#endif + +enum nfsd_fsid { + FSID_DEV = 0, + FSID_NUM, + FSID_MAJOR_MINOR, + FSID_ENCODE_DEV, + FSID_UUID4_INUM, + FSID_UUID8, + FSID_UUID16, + FSID_UUID16_INUM, +}; + +#undef is_mountpoint +static int is_mountpoint(const char *path) +{ + return check_is_mountpoint(path, nfsd_path_lstat); +} + +static ssize_t cache_read(int fd, char *buf, size_t len) +{ + return nfsd_path_read(fd, buf, len); +} + +static ssize_t cache_write(int fd, const char *buf, size_t len) +{ + return nfsd_path_write(fd, buf, len); +} + +static bool path_lookup_error(int err) +{ + switch (err) { + case ELOOP: + case ENAMETOOLONG: + case ENOENT: + case ENOTDIR: + case EACCES: + return 1; + } + return 0; +} + +/* + * Support routines for text-based upcalls. + * Fields are separated by spaces. + * Fields are either mangled to quote space tab newline slosh with slosh + * or a hexified with a leading \x + * Record is terminated with newline. + * + */ + +#define INITIAL_MANAGED_GROUPS 100 + +extern int use_ipaddr; + +static void auth_unix_ip(int f) +{ + /* requests are + * class IP-ADDR + * Ignore if class != "nfsd" + * Otherwise find domainname and write back: + * + * "nfsd" IP-ADDR expiry domainname + */ + char class[20]; + char ipaddr[INET6_ADDRSTRLEN + 1]; + char *client = NULL; + struct addrinfo *ai = NULL; + struct addrinfo *tmp = NULL; + char buf[RPC_CHAN_BUF_SIZE], *bp; + int blen; + + blen = read(f, buf, sizeof(buf)); + if (blen <= 0 || buf[blen-1] != '\n') return; + buf[blen-1] = 0; + + xlog(D_CALL, "auth_unix_ip: inbuf '%s'", buf); + + bp = buf; + + if (qword_get(&bp, class, 20) <= 0 || + strcmp(class, "nfsd") != 0) + return; + + if (qword_get(&bp, ipaddr, sizeof(ipaddr) - 1) <= 0) + return; + + tmp = host_pton(ipaddr); + if (tmp == NULL) + return; + + auth_reload(); + + /* addr is a valid address, find the domain name... */ + ai = client_resolve(tmp->ai_addr); + if (ai) { + client = client_compose(ai); + nfs_freeaddrinfo(ai); + } + if (!client) + xlog(D_AUTH, "failed authentication for IP %s", ipaddr); + else if (!use_ipaddr) + xlog(D_AUTH, "successful authentication for IP %s as %s", + ipaddr, *client ? client : "DEFAULT"); + else + xlog(D_AUTH, "successful authentication for IP %s", + ipaddr); + + bp = buf; blen = sizeof(buf); + qword_add(&bp, &blen, "nfsd"); + qword_add(&bp, &blen, ipaddr); + qword_adduint(&bp, &blen, time(0) + default_ttl); + if (use_ipaddr && client) { + memmove(ipaddr + 1, ipaddr, strlen(ipaddr) + 1); + ipaddr[0] = '$'; + qword_add(&bp, &blen, ipaddr); + } else if (client) + qword_add(&bp, &blen, *client?client:"DEFAULT"); + qword_addeol(&bp, &blen); + if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) + xlog(L_ERROR, "auth_unix_ip: error writing reply"); + + xlog(D_CALL, "auth_unix_ip: client %p '%s'", client, client?client: "DEFAULT"); + + free(client); + nfs_freeaddrinfo(tmp); + +} + +static void auth_unix_gid(int f) +{ + /* Request are + * uid + * reply is + * uid expiry count list of group ids + */ + uid_t uid; + struct passwd *pw; + static gid_t *groups = NULL; + static int groups_len = 0; + gid_t *more_groups; + int ngroups; + int rv, i; + char buf[RPC_CHAN_BUF_SIZE], *bp; + int blen; + + if (groups_len == 0) { + groups = malloc(sizeof(gid_t) * INITIAL_MANAGED_GROUPS); + if (!groups) + return; + + groups_len = INITIAL_MANAGED_GROUPS; + } + + ngroups = groups_len; + + blen = read(f, buf, sizeof(buf)); + if (blen <= 0 || buf[blen-1] != '\n') return; + buf[blen-1] = 0; + + bp = buf; + if (qword_get_uint(&bp, &uid) != 0) + return; + + pw = getpwuid(uid); + if (!pw) + rv = -1; + else { + rv = getgrouplist(pw->pw_name, pw->pw_gid, groups, &ngroups); + if (rv == -1 && ngroups >= groups_len) { + more_groups = realloc(groups, sizeof(gid_t)*ngroups); + if (!more_groups) + rv = -1; + else { + groups = more_groups; + groups_len = ngroups; + rv = getgrouplist(pw->pw_name, pw->pw_gid, + groups, &ngroups); + } + } + } + + bp = buf; blen = sizeof(buf); + qword_adduint(&bp, &blen, uid); + qword_adduint(&bp, &blen, time(0) + default_ttl); + if (rv >= 0) { + qword_adduint(&bp, &blen, ngroups); + for (i=0; i<ngroups; i++) + qword_adduint(&bp, &blen, groups[i]); + } else + qword_adduint(&bp, &blen, 0); + qword_addeol(&bp, &blen); + if (blen <= 0 || write(f, buf, bp - buf) != bp - buf) + xlog(L_ERROR, "auth_unix_gid: error writing reply"); +} + +static int match_crossmnt_fsidnum(uint32_t parsed_fsidnum, char *path) +{ + uint32_t fsidnum; + + if (reexpdb_fsidnum_by_path(path, &fsidnum, 0) == 0) + return 0; + + return fsidnum == parsed_fsidnum; +} + +#ifdef USE_BLKID +static const char *get_uuid_blkdev(char *path) +{ + /* We set *safe if we know that we need the + * fsid from statfs too. + */ + static blkid_cache cache = NULL; + struct stat stb; + char *devname; + blkid_tag_iterate iter; + blkid_dev dev; + const char *type; + const char *val, *uuid = NULL; + + if (cache == NULL) + blkid_get_cache(&cache, NULL); + + if (nfsd_path_stat(path, &stb) != 0) + return NULL; + devname = blkid_devno_to_devname(stb.st_dev); + if (!devname) + return NULL; + dev = blkid_get_dev(cache, devname, BLKID_DEV_NORMAL); + free(devname); + if (!dev) + return NULL; + iter = blkid_tag_iterate_begin(dev); + if (!iter) + return NULL; + while (blkid_tag_next(iter, &type, &val) == 0) { + if (strcmp(type, "UUID") == 0) + uuid = val; + if (strcmp(type, "TYPE") == 0 && + strcmp(val, "btrfs") == 0) { + uuid = NULL; + break; + } + } + blkid_tag_iterate_end(iter); + return uuid; +} +#else +#define get_uuid_blkdev(path) (NULL) +#endif + +static int get_uuid(const char *val, size_t uuidlen, char *u) +{ + /* extract hex digits from uuidstr and compose a uuid + * of the given length (max 16), xoring bytes to make + * a smaller uuid. + */ + size_t i = 0; + + memset(u, 0, uuidlen); + for ( ; *val ; val++) { + int c = *val; + if (!isxdigit(c)) + continue; + if (isalpha(c)) { + if (isupper(c)) + c = c - 'A' + 10; + else + c = c - 'a' + 10; + } else + c = c - '0' + 0; + if ((i&1) == 0) + c <<= 4; + u[i/2] ^= (char)c; + i++; + if (i == uuidlen*2) + i = 0; + } + return 1; +} + + +/* + * Don't ask libblkid for these filesystems. Note that BTRF is ignored, because + * we generate the identifier from statfs->f_fsid. The rest are network or + * pseudo filesystems. (See <linux/magic.h> for the basic IDs.) + */ +static const unsigned long nonblkid_filesystems[] = { + 0x2fc12fc1, /* ZFS_SUPER_MAGIC */ + 0x9123683E, /* BTRFS_SUPER_MAGIC */ + 0xFF534D42, /* CIFS_MAGIC_NUMBER */ + 0x1373, /* DEVFS_SUPER_MAGIC */ + 0x73757245, /* CODA_SUPER_MAGIC */ + 0x564C, /* NCP_SUPER_MAGIC */ + 0x6969, /* NFS_SUPER_MAGIC */ + 0x9FA0, /* PROC_SUPER_MAGIC */ + 0x62656572, /* SYSFS_MAGIC */ + 0x517B, /* SMB_SUPER_MAGIC */ + 0x01021994, /* TMPFS_SUPER_MAGIC */ + 0 /* last */ +}; + +static int uuid_by_path(char *path, int type, size_t uuidlen, char *uuid) +{ + /* get a uuid for the filesystem found at 'path'. + * There are several possible ways of generating the + * uuids (types). + * Type 0 is used for new filehandles, while other types + * may be used to interpret old filehandle - to ensure smooth + * forward migration. + * We return 1 if a uuid was found (and it might be worth + * trying the next type) or 0 if no more uuid types can be + * extracted. + */ + + /* Possible sources of uuid are + * - blkid uuid + * - statfs uuid + * + * On some filesystems (e.g. vfat) the statfs uuid is simply an + * encoding of the device that the filesystem is mounted from, so + * it we be very bad to use that (as device numbers change). blkid + * must be preferred. + * On other filesystems (e.g. btrfs) the statfs uuid contains + * important info that the blkid uuid cannot contain: This happens + * when multiple subvolumes are exported (they have the same + * blkid uuid but different statfs uuids). + * We rely on get_uuid_blkdev *knowing* which is which and not returning + * a uuid for filesystems where the statfs uuid is better. + * + */ + struct statfs st; + char fsid_val[17]; + const char *blkid_val = NULL; + const char *val; + int rc; + + rc = nfsd_path_statfs(path, &st); + + if (type == 0 && rc == 0) { + const unsigned long *bad; + for (bad = nonblkid_filesystems; *bad; bad++) { + if (*bad == (unsigned long)st.f_type) + break; + } + if (*bad == 0) + blkid_val = get_uuid_blkdev(path); + } + + if (rc == 0 && + (st.f_fsid.__val[0] || st.f_fsid.__val[1])) + snprintf(fsid_val, 17, "%08x%08x", + st.f_fsid.__val[0], st.f_fsid.__val[1]); + else + fsid_val[0] = 0; + + if (blkid_val && (type--) == 0) + val = blkid_val; + else if (fsid_val[0] && (type--) == 0) + val = fsid_val; + else + return 0; + + get_uuid(val, uuidlen, uuid); + return 1; +} + +/* Iterate through /etc/mtab, finding mountpoints + * at or below a given path + */ +static char *next_mnt(void **v, char *p) +{ + FILE *f; + struct mntent *me; + size_t l = strlen(p); + + if (*v == NULL) { + f = setmntent("/etc/mtab", "r"); + *v = f; + } else + f = *v; + while ((me = getmntent(f)) != NULL && l >= 1) { + char *mnt_dir = nfsd_path_strip_root(me->mnt_dir); + + if (!mnt_dir) + continue; + + /* Everything below "/" is a proper sub-mount */ + if (strcmp(p, "/") == 0) + return mnt_dir; + + if (strncmp(mnt_dir, p, l) == 0 && mnt_dir[l] == '/') + return mnt_dir; + } + endmntent(f); + *v = NULL; + return NULL; +} + +/* same_path() check is two paths refer to the same directory. + * We don't rely on 'strcmp()' as some filesystems support case-insensitive + * names and we might have two different names for the one directory. + * Theoretically the lengths of the names could be different, but the + * number of components must be the same. + * So if the paths have the same number of components (but aren't identical) + * we ask the kernel if they are the same thing. + * By preference we use name_to_handle_at(), as the mntid it returns + * will distinguish between bind-mount points. If that isn't available + * we fall back on lstat, which is usually good enough. + */ +static inline int count_slashes(char *p) +{ + int cnt = 0; + while (*p) + if (*p++ == '/') + cnt++; + return cnt; +} + +#if defined(HAVE_STRUCT_FILE_HANDLE) +static int check_same_path_by_handle(const char *child, const char *parent) +{ + struct { + struct file_handle fh; + unsigned char handle[128]; + } fchild, fparent; + int mnt_child, mnt_parent; + + fchild.fh.handle_bytes = 128; + fparent.fh.handle_bytes = 128; + + /* This process should have the CAP_DAC_READ_SEARCH capability */ + if (nfsd_name_to_handle_at(AT_FDCWD, child, &fchild.fh, &mnt_child, 0) < 0) + return -1; + if (nfsd_name_to_handle_at(AT_FDCWD, parent, &fparent.fh, &mnt_parent, 0) < 0) { + /* If the child resolved, but the parent did not, they differ */ + if (path_lookup_error(errno)) + return 0; + /* Otherwise, we just don't know */ + return -1; + } + + if (mnt_child != mnt_parent || + fchild.fh.handle_bytes != fparent.fh.handle_bytes || + fchild.fh.handle_type != fparent.fh.handle_type || + memcmp(fchild.handle, fparent.handle, + fchild.fh.handle_bytes) != 0) + return 0; + + return 1; +} +#else +static int check_same_path_by_handle(const char *child, const char *parent) +{ + errno = ENOSYS; + return -1; +} +#endif + +static int check_same_path_by_inode(const char *child, const char *parent) +{ + struct stat sc, sp; + + /* This is nearly good enough. However if a directory is + * bind-mounted in two places and both are exported, it + * could give a false positive + */ + if (nfsd_path_lstat(child, &sc) != 0) + return 0; + if (nfsd_path_lstat(parent, &sp) != 0) + return 0; + if (sc.st_dev != sp.st_dev) + return 0; + if (sc.st_ino != sp.st_ino) + return 0; + + return 1; +} + +static int same_path(char *child, char *parent, int len) +{ + static char p[PATH_MAX]; + int err; + + if (len <= 0) + len = strlen(child); + strncpy(p, child, len); + p[len] = 0; + if (strcmp(p, parent) == 0) + return 1; + + /* If number of '/' are different, they must be different */ + if (count_slashes(p) != count_slashes(parent)) + return 0; + + /* Try to use filehandle approach before falling back to stat() */ + err = check_same_path_by_handle(p, parent); + if (err != -1) + return err; + return check_same_path_by_inode(p, parent); +} + +static int is_subdirectory(char *child, char *parent) +{ + /* Check is child is strictly a subdirectory of + * parent or a more distant descendant. + */ + size_t l = strlen(parent); + + if (strcmp(parent, "/") == 0 && child[1] != 0) + return 1; + + return (same_path(child, parent, l) && child[l] == '/'); +} + +static int path_matches(nfs_export *exp, char *path) +{ + /* Does the path match the export? I.e. is it an + * exact match, or does the export have CROSSMOUNT, and path + * is a descendant? + */ + return same_path(path, exp->m_export.e_path, 0) + || ((exp->m_export.e_flags & NFSEXP_CROSSMOUNT) + && is_subdirectory(path, exp->m_export.e_path)); +} + +static int +export_matches(nfs_export *exp, char *dom, char *path, struct addrinfo *ai) +{ + return path_matches(exp, path) && client_matches(exp, dom, ai); +} + +/* True iff e1 is a child of e2 (or descendant) and e2 has crossmnt set: */ +static bool subexport(struct exportent *e1, struct exportent *e2) +{ + char *p1 = e1->e_path, *p2 = e2->e_path; + + return e2->e_flags & NFSEXP_CROSSMOUNT + && is_subdirectory(p1, p2); +} + +struct parsed_fsid { + int fsidtype; + /* We could use a union for this, but it would be more + * complicated; why bother? */ + uint64_t inode; + unsigned int minor; + unsigned int major; + uint32_t fsidnum; + size_t uuidlen; + char *fhuuid; +}; + +static int parse_fsid(int fsidtype, int fsidlen, char *fsid, + struct parsed_fsid *parsed) +{ + uint32_t dev; + uint32_t inode32; + + memset(parsed, 0, sizeof(*parsed)); + parsed->fsidtype = fsidtype; + switch(fsidtype) { + case FSID_DEV: /* 4 bytes: 2 major, 2 minor, 4 inode */ + if (fsidlen != 8) + return -1; + memcpy(&dev, fsid, 4); + memcpy(&inode32, fsid+4, 4); + parsed->inode = inode32; + parsed->major = ntohl(dev)>>16; + parsed->minor = ntohl(dev) & 0xFFFF; + break; + + case FSID_NUM: /* 4 bytes - fsid */ + if (fsidlen != 4) + return -1; + memcpy(&parsed->fsidnum, fsid, 4); + break; + + case FSID_MAJOR_MINOR: /* 12 bytes: 4 major, 4 minor, 4 inode + * This format is never actually used but was + * an historical accident + */ + if (fsidlen != 12) + return -1; + memcpy(&dev, fsid, 4); + parsed->major = ntohl(dev); + memcpy(&dev, fsid+4, 4); + parsed->minor = ntohl(dev); + memcpy(&inode32, fsid+8, 4); + parsed->inode = inode32; + break; + + case FSID_ENCODE_DEV: /* 8 bytes: 4 byte packed device number, 4 inode */ + /* This is *host* endian, not net-byte-order, because + * no-one outside this host has any business interpreting it + */ + if (fsidlen != 8) + return -1; + memcpy(&dev, fsid, 4); + memcpy(&inode32, fsid+4, 4); + parsed->inode = inode32; + parsed->major = (dev & 0xfff00) >> 8; + parsed->minor = (dev & 0xff) | ((dev >> 12) & 0xfff00); + break; + + case FSID_UUID4_INUM: /* 4 byte inode number and 4 byte uuid */ + if (fsidlen != 8) + return -1; + memcpy(&inode32, fsid, 4); + parsed->inode = inode32; + parsed->uuidlen = 4; + parsed->fhuuid = fsid+4; + break; + case FSID_UUID8: /* 8 byte uuid */ + if (fsidlen != 8) + return -1; + parsed->uuidlen = 8; + parsed->fhuuid = fsid; + break; + case FSID_UUID16: /* 16 byte uuid */ + if (fsidlen != 16) + return -1; + parsed->uuidlen = 16; + parsed->fhuuid = fsid; + break; + case FSID_UUID16_INUM: /* 8 byte inode number and 16 byte uuid */ + if (fsidlen != 24) + return -1; + memcpy(&parsed->inode, fsid, 8); + parsed->uuidlen = 16; + parsed->fhuuid = fsid+8; + break; + } + return 0; +} + +static int match_fsid(struct parsed_fsid *parsed, nfs_export *exp, char *path) +{ + struct stat stb; + int type; + char u[16]; + + if (nfsd_path_stat(path, &stb) != 0) + goto path_error; + if (!S_ISDIR(stb.st_mode) && !S_ISREG(stb.st_mode)) + goto nomatch; + + switch (parsed->fsidtype) { + case FSID_DEV: + case FSID_MAJOR_MINOR: + case FSID_ENCODE_DEV: + if (stb.st_ino != parsed->inode) + goto nomatch; + if (parsed->major != major(stb.st_dev) || + parsed->minor != minor(stb.st_dev)) + goto nomatch; + goto match; + case FSID_NUM: + if (((exp->m_export.e_flags & NFSEXP_FSID) == 0 || + exp->m_export.e_fsid != parsed->fsidnum)) { + if ((exp->m_export.e_flags & NFSEXP_CROSSMOUNT) && exp->m_export.e_reexport != REEXP_NONE && + match_crossmnt_fsidnum(parsed->fsidnum, path)) + goto match; + + goto nomatch; + } + goto match; + case FSID_UUID4_INUM: + case FSID_UUID16_INUM: + if (stb.st_ino != parsed->inode) + goto nomatch; + goto check_uuid; + case FSID_UUID8: + case FSID_UUID16: + errno = 0; + if (!is_mountpoint(path)) { + if (!errno) + goto nomatch; + goto path_error; + } + check_uuid: + if (exp->m_export.e_uuid) { + get_uuid(exp->m_export.e_uuid, parsed->uuidlen, u); + if (memcmp(u, parsed->fhuuid, parsed->uuidlen) == 0) + goto match; + } + else + for (type = 0; + uuid_by_path(path, type, parsed->uuidlen, u); + type++) + if (memcmp(u, parsed->fhuuid, parsed->uuidlen) == 0) + goto match; + } +nomatch: + return 0; +match: + return 1; +path_error: + if (path_lookup_error(errno)) + goto nomatch; + return -1; +} + +static struct addrinfo *lookup_client_addr(char *dom) +{ + struct addrinfo *ret; + struct addrinfo *tmp; + + dom++; /* skip initial "$" */ + + tmp = host_pton(dom); + if (tmp == NULL) + return NULL; + ret = client_resolve(tmp->ai_addr); + nfs_freeaddrinfo(tmp); + return ret; +} + +#define RETRY_SEC 120 +struct delayed { + char *message; + time_t last_attempt; + int f; + struct delayed *next; +} *delayed; + +static int nfsd_handle_fh(int f, char *bp, int blen) +{ + /* request are: + * domain fsidtype fsid + * interpret fsid, find export point and options, and write: + * domain fsidtype fsid expiry path + */ + char *dom; + int fsidtype; + int fsidlen; + char fsid[32]; + struct parsed_fsid parsed; + struct exportent *found = NULL; + struct addrinfo *ai = NULL; + char *found_path = NULL; + nfs_export *exp; + int i; + int dev_missing = 0; + char buf[RPC_CHAN_BUF_SIZE]; + int did_uncover = 0; + int ret = 0; + + dom = malloc(blen); + if (dom == NULL) + return ret; + if (qword_get(&bp, dom, blen) <= 0) + goto out; + if (qword_get_int(&bp, &fsidtype) != 0) + goto out; + if (fsidtype < 0 || fsidtype > 7) + goto out; /* unknown type */ + if ((fsidlen = qword_get(&bp, fsid, 32)) <= 0) + goto out; + if (parse_fsid(fsidtype, fsidlen, fsid, &parsed)) + goto out; + + auth_reload(); + + if (is_ipaddr_client(dom)) { + ai = lookup_client_addr(dom); + if (!ai) + goto out; + } + + /* Now determine export point for this fsid/domain */ + for (i=0 ; i < MCL_MAXTYPES; i++) { + nfs_export *next_exp; + for (exp = exportlist[i].p_head; exp; exp = next_exp) { + char *path; + + if (!did_uncover && parsed.fsidnum && parsed.fsidtype == FSID_NUM && exp->m_export.e_reexport != REEXP_NONE) { + reexpdb_uncover_subvolume(parsed.fsidnum); + did_uncover = 1; + } + + if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT) { + static nfs_export *prev = NULL; + static void *mnt = NULL; + + if (prev == exp) { + /* try a submount */ + path = next_mnt(&mnt, exp->m_export.e_path); + if (!path) { + next_exp = exp->m_next; + prev = NULL; + continue; + } + next_exp = exp; + } else { + prev = exp; + mnt = NULL; + path = exp->m_export.e_path; + next_exp = exp; + } + } else { + path = exp->m_export.e_path; + next_exp = exp->m_next; + } + + if (!is_ipaddr_client(dom) + && !namelist_client_matches(exp, dom)) + continue; + if (exp->m_export.e_mountpoint && + !is_mountpoint(exp->m_export.e_mountpoint[0]? + exp->m_export.e_mountpoint: + exp->m_export.e_path)) + dev_missing ++; + + switch(match_fsid(&parsed, exp, path)) { + case 0: + continue; + case -1: + dev_missing ++; + continue; + } + if (is_ipaddr_client(dom) + && !ipaddr_client_matches(exp, ai)) + continue; + if (!found || subexport(&exp->m_export, found)) { + found = &exp->m_export; + free(found_path); + found_path = strdup(path); + if (found_path == NULL) + goto out; + } else if (strcmp(found->e_path, exp->m_export.e_path) != 0 + && !subexport(found, &exp->m_export)) + { + xlog(L_WARNING, "%s and %s have same filehandle for %s, using first", + found_path, path, dom); + } else { + /* same path, if one is V4ROOT, choose the other */ + if (found->e_flags & NFSEXP_V4ROOT) { + found = &exp->m_export; + free(found_path); + found_path = strdup(path); + if (found_path == NULL) + goto out; + } + } + } + } + + if (!found) { + /* The missing dev could be what we want, so just be + * quiet rather than returning stale yet + */ + if (dev_missing) { + ret = 1; + goto out; + } + } else if (found->e_mountpoint && + !is_mountpoint(found->e_mountpoint[0]? + found->e_mountpoint: + found->e_path)) { + /* Cannot export this yet + * should log a warning, but need to rate limit + xlog(L_WARNING, "%s not exported as %d not a mountpoint", + found->e_path, found->e_mountpoint); + */ + ret = 1; + goto out; + } + + bp = buf; blen = sizeof(buf); + qword_add(&bp, &blen, dom); + qword_addint(&bp, &blen, fsidtype); + qword_addhex(&bp, &blen, fsid, fsidlen); + /* The fsid -> path lookup can be quite expensive as it + * potentially stats and reads lots of devices, and some of those + * might have spun-down. The Answer is not likely to + * change underneath us, and an 'exportfs -f' can always + * remove this from the kernel, so use a really log + * timeout. Maybe this should be configurable on the command + * line. + */ + qword_addint(&bp, &blen, 0x7fffffff); + if (found) + qword_add(&bp, &blen, found_path); + qword_addeol(&bp, &blen); + if (blen <= 0 || cache_write(f, buf, bp - buf) != bp - buf) + xlog(L_ERROR, "nfsd_fh: error writing reply"); + if (!found) + xlog(D_AUTH, "denied access to %s", *dom == '$' ? dom+1 : dom); +out: + if (found_path) + free(found_path); + nfs_freeaddrinfo(ai); + free(dom); + if (!ret) + xlog(D_CALL, "nfsd_fh: found %p path %s", + found, found ? found->e_path : NULL); + return ret; +} + +static void nfsd_fh(int f) +{ + struct delayed *d, **dp; + char inbuf[RPC_CHAN_BUF_SIZE]; + int blen; + + blen = cache_read(f, inbuf, sizeof(inbuf)); + if (blen <= 0 || inbuf[blen-1] != '\n') return; + inbuf[blen-1] = 0; + + xlog(D_CALL, "nfsd_fh: inbuf '%s'", inbuf); + + if (nfsd_handle_fh(f, inbuf, blen) == 0) + return; + /* We don't have a definitive answer to give the kernel. + * This is because an export marked "mountpoint" isn't a + * mountpoint, or because a stat of a mountpoint fails with + * a strange error like ETIMEDOUT as is possible with an + * NFS mount marked "softerr" which is being re-exported. + * + * We cannot tell the kernel to retry, so we have to + * retry ourselves. + */ + d = malloc(sizeof(*d)); + + if (!d) + return; + d->message = strndup(inbuf, blen); + if (!d->message) { + free(d); + return; + } + d->f = f; + d->last_attempt = time(NULL); + d->next = NULL; + dp = &delayed; + while (*dp) + dp = &(*dp)->next; + *dp = d; +} + +static void nfsd_retry_fh(struct delayed *d) +{ + struct delayed **dp; + + if (nfsd_handle_fh(d->f, d->message, strlen(d->message)+1) == 0) { + free(d->message); + free(d); + return; + } + d->last_attempt = time(NULL); + d->next = NULL; + dp = &delayed; + while (*dp) + dp = &(*dp)->next; + *dp = d; +} + +#ifdef HAVE_JUNCTION_SUPPORT +static void write_fsloc(char **bp, int *blen, struct exportent *ep) +{ + struct servers *servers; + + if (ep->e_fslocmethod == FSLOC_NONE) + return; + + servers = replicas_lookup(ep->e_fslocmethod, ep->e_fslocdata); + if (!servers) + return; + qword_add(bp, blen, "fsloc"); + qword_addint(bp, blen, servers->h_num); + if (servers->h_num >= 0) { + int i; + for (i=0; i<servers->h_num; i++) { + qword_add(bp, blen, servers->h_mp[i]->h_host); + qword_add(bp, blen, servers->h_mp[i]->h_path); + } + } + qword_addint(bp, blen, servers->h_referral); + release_replicas(servers); +} +#endif + +static void write_secinfo(char **bp, int *blen, struct exportent *ep, int flag_mask, int extra_flag) +{ + struct sec_entry *p; + + for (p = ep->e_secinfo; p->flav; p++) + ; /* Do nothing */ + if (p == ep->e_secinfo) { + /* There was no sec= option */ + return; + } + fix_pseudoflavor_flags(ep); + qword_add(bp, blen, "secinfo"); + qword_addint(bp, blen, p - ep->e_secinfo); + for (p = ep->e_secinfo; p->flav; p++) { + qword_addint(bp, blen, p->flav->fnum); + qword_addint(bp, blen, (p->flags | extra_flag) & flag_mask); + } +} + +static void write_xprtsec(char **bp, int *blen, struct exportent *ep) +{ + struct xprtsec_entry *p; + + for (p = ep->e_xprtsec; p->info; p++); + if (p == ep->e_xprtsec) + return; + + qword_add(bp, blen, "xprtsec"); + qword_addint(bp, blen, p - ep->e_xprtsec); + for (p = ep->e_xprtsec; p->info; p++) + qword_addint(bp, blen, p->info->number); +} + +static int can_reexport_via_fsidnum(struct exportent *exp, struct statfs *st) +{ + if (st->f_type != 0x6969 /* NFS_SUPER_MAGIC */) + return 0; + + return exp->e_reexport == REEXP_PREDEFINED_FSIDNUM || + exp->e_reexport == REEXP_AUTO_FSIDNUM; +} + +static int dump_to_cache(int f, char *buf, int blen, char *domain, + char *path, struct exportent *exp, int ttl) +{ + char *bp = buf; + time_t now = time(0); + size_t buflen; + ssize_t err; + + if (ttl <= 1) + ttl = default_ttl; + + qword_add(&bp, &blen, domain); + qword_add(&bp, &blen, path); + if (exp) { + int different_fs = strcmp(path, exp->e_path) != 0; + int flag_mask = different_fs ? ~NFSEXP_FSID : ~0; + int rc, do_fsidnum = 0; + uint32_t fsidnum = exp->e_fsid; + + if (different_fs) { + struct statfs st; + + rc = nfsd_path_statfs(path, &st); + if (rc) { + xlog(L_WARNING, "unable to statfs %s", path); + errno = EINVAL; + return -1; + } + + if (can_reexport_via_fsidnum(exp, &st)) { + do_fsidnum = 1; + flag_mask = ~0; + } + } + + qword_adduint(&bp, &blen, now + exp->e_ttl); + + if (do_fsidnum) { + uint32_t search_fsidnum = 0; + if (exp->e_reexport != REEXP_NONE && reexpdb_fsidnum_by_path(path, &search_fsidnum, + exp->e_reexport == REEXP_AUTO_FSIDNUM) == 0) { + errno = EINVAL; + return -1; + } + fsidnum = search_fsidnum; + qword_addint(&bp, &blen, exp->e_flags | NFSEXP_FSID); + } else { + qword_addint(&bp, &blen, exp->e_flags & flag_mask); + } + + qword_addint(&bp, &blen, exp->e_anonuid); + qword_addint(&bp, &blen, exp->e_anongid); + qword_addint(&bp, &blen, fsidnum); + +#ifdef HAVE_JUNCTION_SUPPORT + write_fsloc(&bp, &blen, exp); +#endif + write_secinfo(&bp, &blen, exp, flag_mask, do_fsidnum ? NFSEXP_FSID : 0); + if (exp->e_uuid == NULL || different_fs) { + char u[16]; + if ((exp->e_flags & flag_mask & NFSEXP_FSID) == 0 && + uuid_by_path(path, 0, 16, u)) { + qword_add(&bp, &blen, "uuid"); + qword_addhex(&bp, &blen, u, 16); + } + } else { + char u[16]; + get_uuid(exp->e_uuid, 16, u); + qword_add(&bp, &blen, "uuid"); + qword_addhex(&bp, &blen, u, 16); + } + write_xprtsec(&bp, &blen, exp); + xlog(D_AUTH, "granted access to %s for %s", + path, *domain == '$' ? domain+1 : domain); + } else { + qword_adduint(&bp, &blen, now + ttl); + xlog(D_AUTH, "denied access to %s for %s", + path, *domain == '$' ? domain+1 : domain); + } + qword_addeol(&bp, &blen); + if (blen <= 0) { + errno = ENOBUFS; + return -1; + } + buflen = bp - buf; + err = cache_write(f, buf, buflen); + if (err < 0) + return err; + if ((size_t)err != buflen) { + errno = ENOSPC; + return -1; + } + return 0; +} + +static nfs_export * +lookup_export(char *dom, char *path, struct addrinfo *ai) +{ + nfs_export *exp; + nfs_export *found = NULL; + int found_type = 0; + int i; + + for (i=0 ; i < MCL_MAXTYPES; i++) { + for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { + if (!export_matches(exp, dom, path, ai)) + continue; + if (!found) { + found = exp; + found_type = i; + continue; + } + /* Always prefer non-V4ROOT exports */ + if (exp->m_export.e_flags & NFSEXP_V4ROOT) + continue; + if (found->m_export.e_flags & NFSEXP_V4ROOT) { + found = exp; + found_type = i; + continue; + } + + /* If one is a CROSSMOUNT, then prefer the longest path */ + if (((found->m_export.e_flags & NFSEXP_CROSSMOUNT) || + (exp->m_export.e_flags & NFSEXP_CROSSMOUNT)) && + strlen(found->m_export.e_path) != + strlen(exp->m_export.e_path)) { + + if (strlen(exp->m_export.e_path) > + strlen(found->m_export.e_path)) { + found = exp; + found_type = i; + } + continue; + + } else if (found_type == i && found->m_warned == 0) { + xlog(L_WARNING, "%s exported to both %s and %s, " + "arbitrarily choosing options from first", + path, found->m_client->m_hostname, exp->m_client->m_hostname); + found->m_warned = 1; + } + } + } + return found; +} + +#ifdef HAVE_JUNCTION_SUPPORT + +#include <libxml/parser.h> +#include "junction.h" + +struct nfs_fsloc_set { + int ns_ttl; + struct nfs_fsloc *ns_current; + struct nfs_fsloc *ns_list; +}; + +/* + * Find the export entry for the parent of "pathname". + * Caller must not free returned exportent. + */ +static struct exportent *lookup_parent_export(char *dom, + const char *pathname, struct addrinfo *ai) +{ + char *parent, *slash; + nfs_export *result; + + parent = strdup(pathname); + if (parent == NULL) { + xlog(D_GENERAL, "%s: failed to allocate parent path buffer", + __func__); + goto out_default; + } + xlog(D_CALL, "%s: pathname = '%s'", __func__, pathname); + +again: + /* shorten pathname by one component */ + slash = strrchr(parent, '/'); + if (slash == NULL) { + xlog(D_GENERAL, "%s: no slash found in pathname", + __func__); + goto out_default; + } + *slash = '\0'; + + if (strlen(parent) == 0) { + result = lookup_export(dom, "/", ai); + if (result == NULL) { + xlog(L_ERROR, "%s: no root export found.", __func__); + goto out_default; + } + goto out; + } + + result = lookup_export(dom, parent, ai); + if (result == NULL) { + xlog(D_GENERAL, "%s: lookup_export(%s) found nothing", + __func__, parent); + goto again; + } + +out: + xlog(D_CALL, "%s: found export for %s", __func__, parent); + free(parent); + return &result->m_export; + +out_default: + free(parent); + return mkexportent("*", "/", "insecure"); +} + +static int get_next_location(struct nfs_fsloc_set *locset, + char **hostname, char **export_path, int *ttl) +{ + char *hostname_tmp, *export_path_tmp; + struct nfs_fsloc *fsloc; + + if (locset->ns_current == NULL) + return ENOENT; + fsloc = locset->ns_current; + + hostname_tmp = strdup(fsloc->nfl_hostname); + if (hostname_tmp == NULL) + return ENOMEM; + + if (nsdb_path_array_to_posix(fsloc->nfl_rootpath, + &export_path_tmp)) { + free(hostname_tmp); + return EINVAL; + } + + *hostname = hostname_tmp; + *export_path = export_path_tmp; + *ttl = locset->ns_ttl; + locset->ns_current = locset->ns_current->nfl_next; + return 0; +} + +/* + * Walk through a set of FS locations and build an e_fslocdata string. + * Returns true if all went to plan; otherwise, false. + */ +static bool locations_to_fslocdata(struct nfs_fsloc_set *locations, + char *fslocdata, size_t remaining, int *ttl) +{ + char *server, *last_path, *rootpath, *ptr; + _Bool seen = false; + + last_path = NULL; + rootpath = NULL; + server = NULL; + ptr = fslocdata; + *ttl = 0; + + for (;;) { + int len, status; + + status = get_next_location(locations, &server, + &rootpath, ttl); + if (status == ENOENT) + break; + if (status) { + xlog(D_GENERAL, "%s: failed to parse location: %s", + __func__, strerror(status)); + goto out_false; + } + xlog(D_GENERAL, "%s: Location: %s:%s", + __func__, server, rootpath); + + if (last_path && strcmp(rootpath, last_path) == 0) { + len = snprintf(ptr, remaining, "+%s", server); + if (len < 0) { + xlog(D_GENERAL, "%s: snprintf: %m", __func__); + goto out_false; + } + if ((size_t)len >= remaining) { + xlog(D_GENERAL, "%s: fslocdata buffer overflow", __func__); + goto out_false; + } + remaining -= (size_t)len; + ptr += len; + } else { + if (last_path == NULL) + len = snprintf(ptr, remaining, "%s@%s", + rootpath, server); + else + len = snprintf(ptr, remaining, ":%s@%s", + rootpath, server); + if (len < 0) { + xlog(D_GENERAL, "%s: snprintf: %m", __func__); + goto out_false; + } + if ((size_t)len >= remaining) { + xlog(D_GENERAL, "%s: fslocdata buffer overflow", + __func__); + goto out_false; + } + remaining -= (size_t)len; + ptr += len; + last_path = rootpath; + } + + seen = true; + free(rootpath); + free(server); + } + + xlog(D_CALL, "%s: fslocdata='%s', ttl=%d", + __func__, fslocdata, *ttl); + return seen; + +out_false: + free(rootpath); + free(server); + return false; +} + +/* + * Duplicate the junction's parent's export options and graft in + * the fslocdata we constructed from the locations list. + */ +static struct exportent *create_junction_exportent(struct exportent *parent, + const char *junction, const char *fslocdata, int ttl) +{ + static struct exportent *eep; + + eep = (struct exportent *)malloc(sizeof(*eep)); + if (eep == NULL) + goto out_nomem; + + dupexportent(eep, parent); + strcpy(eep->e_path, junction); + eep->e_hostname = strdup(parent->e_hostname); + if (eep->e_hostname == NULL) { + free(eep); + goto out_nomem; + } + free(eep->e_uuid); + eep->e_uuid = NULL; + eep->e_ttl = (unsigned int)ttl; + + free(eep->e_fslocdata); + eep->e_fslocdata = strdup(fslocdata); + if (eep->e_fslocdata == NULL) { + free(eep->e_hostname); + free(eep); + goto out_nomem; + } + eep->e_fslocmethod = FSLOC_REFER; + return eep; + +out_nomem: + xlog(L_ERROR, "%s: No memory", __func__); + return NULL; +} + +/* + * Walk through the set of FS locations and build an exportent. + * Returns pointer to an exportent if "junction" refers to a junction. + */ +static struct exportent *locations_to_export(struct nfs_fsloc_set *locations, + const char *junction, struct exportent *parent) +{ + static char fslocdata[BUFSIZ]; + int ttl; + + fslocdata[0] = '\0'; + if (!locations_to_fslocdata(locations, fslocdata, sizeof(fslocdata), &ttl)) + return NULL; + return create_junction_exportent(parent, junction, fslocdata, ttl); +} + +static int +nfs_get_basic_junction(const char *junct_path, struct nfs_fsloc_set **locset) +{ + struct nfs_fsloc_set *new; + FedFsStatus retval; + + new = calloc(1, sizeof(struct nfs_fsloc_set)); + if (new == NULL) + return ENOMEM; + + retval = nfs_get_locations(junct_path, &new->ns_list); + if (retval) { + nfs_free_locations(new->ns_list); + free(new); + return EINVAL; + } + + new->ns_current = new->ns_list; + new->ns_ttl = 300; + *locset = new; + return 0; +} + +static struct exportent *lookup_junction(char *dom, const char *pathname, + struct addrinfo *ai) +{ + struct exportent *parent, *exp = NULL; + struct nfs_fsloc_set *locations; + int status; + + xmlInitParser(); + + if (nfs_is_junction(pathname)) { + xlog(D_GENERAL, "%s: %s is not a junction", + __func__, pathname); + goto out; + } + status = nfs_get_basic_junction(pathname, &locations); + if (status) { + xlog(L_WARNING, "Dangling junction %s: %s", + pathname, strerror(status)); + goto out; + } + + parent = lookup_parent_export(dom, pathname, ai); + if (parent == NULL) + goto free_locations; + + exp = locations_to_export(locations, pathname, parent); + +free_locations: + nfs_free_locations(locations->ns_list); + free(locations); + +out: + xmlCleanupParser(); + return exp; +} + +static void lookup_nonexport(int f, char *buf, int buflen, char *dom, char *path, + struct addrinfo *ai) +{ + struct exportent *eep; + + eep = lookup_junction(dom, path, ai); + dump_to_cache(f, buf, buflen, dom, path, eep, 0); + if (eep == NULL) + return; + exportent_release(eep); + free(eep); +} + +#else /* !HAVE_JUNCTION_SUPPORT */ + +static void lookup_nonexport(int f, char *buf, int buflen, char *dom, char *path, + struct addrinfo *UNUSED(ai)) +{ + dump_to_cache(f, buf, buflen, dom, path, NULL, 0); +} + +#endif /* !HAVE_JUNCTION_SUPPORT */ + +static void nfsd_export(int f) +{ + /* requests are: + * domain path + * determine export options and return: + * domain path expiry flags anonuid anongid fsid + */ + + char *dom, *path; + nfs_export *found = NULL; + struct addrinfo *ai = NULL; + char buf[RPC_CHAN_BUF_SIZE], *bp; + int blen; + + blen = cache_read(f, buf, sizeof(buf)); + if (blen <= 0 || buf[blen-1] != '\n') return; + buf[blen-1] = 0; + + xlog(D_CALL, "nfsd_export: inbuf '%s'", buf); + + bp = buf; + dom = malloc(blen); + path = malloc(blen); + + if (!dom || !path) + goto out; + + if (qword_get(&bp, dom, blen) <= 0) + goto out; + if (qword_get(&bp, path, blen) <= 0) + goto out; + + auth_reload(); + + if (is_ipaddr_client(dom)) { + ai = lookup_client_addr(dom); + if (!ai) + goto out; + } + + found = lookup_export(dom, path, ai); + + if (found) { + char *mp = found->m_export.e_mountpoint; + + if (mp && !*mp) + mp = found->m_export.e_path; + errno = 0; + if (mp && !is_mountpoint(mp)) { + if (errno != 0 && !path_lookup_error(errno)) + goto out; + /* Exportpoint is not mounted, so tell kernel it is + * not available. + * This will cause it not to appear in the V4 Pseudo-root + * and so a "mount" of this path will fail, just like with + * V3. + * Any filehandle for this mountpoint from an earlier + * mount will block in nfsd.fh lookup. + */ + xlog(L_WARNING, + "Cannot export path '%s': not a mountpoint", + path); + dump_to_cache(f, buf, sizeof(buf), dom, path, + NULL, 60); + } else if (dump_to_cache(f, buf, sizeof(buf), dom, path, + &found->m_export, 0) < 0) { + xlog(L_WARNING, + "Cannot export %s, possibly unsupported filesystem" + " or fsid= required", path); + dump_to_cache(f, buf, sizeof(buf), dom, path, NULL, 0); + } + } else + lookup_nonexport(f, buf, sizeof(buf), dom, path, ai); + + out: + xlog(D_CALL, "nfsd_export: found %p path %s", found, path ? path : NULL); + if (dom) free(dom); + if (path) free(path); + nfs_freeaddrinfo(ai); +} + + +struct { + char *cache_name; + void (*cache_handle)(int f); + int f; +} cachelist[] = { + { "auth.unix.ip", auth_unix_ip, -1 }, + { "auth.unix.gid", auth_unix_gid, -1 }, + { "nfsd.export", nfsd_export, -1 }, + { "nfsd.fh", nfsd_fh, -1 }, + { NULL, NULL, -1 } +}; + +extern int manage_gids; + +/** + * cache_open - prepare communications channels with kernel RPC caches + * + */ +void cache_open(void) +{ + int i; + + for (i=0; cachelist[i].cache_name; i++ ) { + char path[100]; + if (!manage_gids && cachelist[i].cache_handle == auth_unix_gid) + continue; + sprintf(path, "/proc/net/rpc/%s/channel", cachelist[i].cache_name); + cachelist[i].f = open(path, O_RDWR); + } +} + +/** + * cache_set_fds - prepare cache file descriptors for one iteration of the service loop + * @fdset: pointer to fd_set to prepare + */ +void cache_set_fds(fd_set *fdset) +{ + int i; + for (i=0; cachelist[i].cache_name; i++) { + if (cachelist[i].f >= 0) + FD_SET(cachelist[i].f, fdset); + } +} + +/** + * cache_process_req - process any active cache file descriptors during service loop iteration + * @fdset: pointer to fd_set to examine for activity + */ +int cache_process_req(fd_set *readfds) +{ + int i; + int cnt = 0; + for (i=0; cachelist[i].cache_name; i++) { + if (cachelist[i].f >= 0 && + FD_ISSET(cachelist[i].f, readfds)) { + cnt++; + cachelist[i].cache_handle(cachelist[i].f); + FD_CLR(cachelist[i].f, readfds); + } + } + return cnt; +} + +/** + * cache_process - process incoming upcalls + * Returns -ve on error, or number of fds in svc_fds + * that might need processing. + */ +int cache_process(fd_set *readfds) +{ + fd_set fdset; + int selret; + struct timeval tv = { 24*3600, 0 }; + + if (!readfds) { + FD_ZERO(&fdset); + readfds = &fdset; + } + cache_set_fds(readfds); + v4clients_set_fds(readfds); + + if (delayed) { + time_t now = time(NULL); + time_t delay; + if (delayed->last_attempt > now) + /* Clock updated - retry immediately */ + delayed->last_attempt = now - RETRY_SEC; + delay = delayed->last_attempt + RETRY_SEC - now; + if (delay < 0) + delay = 0; + tv.tv_sec = delay; + } + selret = select(FD_SETSIZE, readfds, NULL, NULL, &tv); + + if (delayed) { + time_t now = time(NULL); + struct delayed *d = delayed; + + if (d->last_attempt + RETRY_SEC <= now) { + delayed = d->next; + d->next = NULL; + nfsd_retry_fh(d); + } + } + + switch (selret) { + case -1: + if (errno == EINTR || errno == ECONNREFUSED + || errno == ENETUNREACH || errno == EHOSTUNREACH) + return 0; + return -1; + + default: + selret -= cache_process_req(readfds); + selret -= v4clients_process(readfds); + if (selret < 0) + selret = 0; + } + return selret; +} + +/* + * Give IP->domain and domain+path->options to kernel + * % echo nfsd $IP $[now+DEFAULT_TTL] $domain > /proc/net/rpc/auth.unix.ip/channel + * % echo $domain $path $[now+DEFAULT_TTL] $options $anonuid $anongid $fsid > /proc/net/rpc/nfsd.export/channel + */ + +static int cache_export_ent(char *buf, int buflen, char *domain, struct exportent *exp, char *path) +{ + int f, err; + + f = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY); + if (f < 0) return -1; + + err = dump_to_cache(f, buf, buflen, domain, exp->e_path, exp, 0); + if (err) { + xlog(L_WARNING, + "Cannot export %s, possibly unsupported filesystem or" + " fsid= required", exp->e_path); + } + + while (err == 0 && (exp->e_flags & NFSEXP_CROSSMOUNT) && path) { + /* really an 'if', but we can break out of + * a 'while' more easily */ + /* Look along 'path' for other filesystems + * and export them with the same options + */ + struct stat stb; + size_t l = strlen(exp->e_path); + dev_t dev; + + if (strlen(path) <= l || path[l] != '/' || + strncmp(exp->e_path, path, l) != 0) + break; + if (nfsd_path_stat(exp->e_path, &stb) != 0) + break; + dev = stb.st_dev; + while(path[l] == '/') { + char c; + /* errors for submount should fail whole filesystem */ + int err2; + + l++; + while (path[l] != '/' && path[l]) + l++; + c = path[l]; + path[l] = 0; + err2 = nfsd_path_lstat(path, &stb); + path[l] = c; + if (err2 < 0) + break; + if (stb.st_dev == dev) + continue; + dev = stb.st_dev; + path[l] = 0; + dump_to_cache(f, buf, buflen, domain, path, exp, 0); + path[l] = c; + } + break; + } + + close(f); + return err; +} + +/** + * cache_export - Inform kernel of a new nfs_export + * @exp: target nfs_export + * @path: NUL-terminated C string containing export path + */ +int cache_export(nfs_export *exp, char *path) +{ + char ip[INET6_ADDRSTRLEN]; + char buf[RPC_CHAN_BUF_SIZE], *bp; + int blen, f; + + f = open("/proc/net/rpc/auth.unix.ip/channel", O_WRONLY); + if (f < 0) + return -1; + + bp = buf, blen = sizeof(buf); + qword_add(&bp, &blen, "nfsd"); + qword_add(&bp, &blen, host_ntop(get_addrlist(exp->m_client, 0), ip, sizeof(ip))); + qword_adduint(&bp, &blen, time(0) + exp->m_export.e_ttl); + qword_add(&bp, &blen, exp->m_client->m_hostname); + qword_addeol(&bp, &blen); + if (blen <= 0 || cache_write(f, buf, bp - buf) != bp - buf) blen = -1; + close(f); + if (blen < 0) return -1; + + return cache_export_ent(buf, sizeof(buf), exp->m_client->m_hostname, &exp->m_export, path); +} + +/** + * cache_get_filehandle - given an nfs_export, get its root filehandle + * @exp: target nfs_export + * @len: length of requested file handle + * @p: NUL-terminated C string containing export path + * + * Returns pointer to NFS file handle of root directory of export + * + * { + * echo $domain $path $length + * read filehandle <&0 + * } <> /proc/fs/nfsd/filehandle + */ +struct nfs_fh_len * +cache_get_filehandle(nfs_export *exp, int len, char *p) +{ + static struct nfs_fh_len fh; + char buf[RPC_CHAN_BUF_SIZE], *bp; + int blen, f; + + f = open("/proc/fs/nfsd/filehandle", O_RDWR); + if (f < 0) { + f = open("/proc/fs/nfs/filehandle", O_RDWR); + if (f < 0) return NULL; + } + + bp = buf, blen = sizeof(buf); + qword_add(&bp, &blen, exp->m_client->m_hostname); + qword_add(&bp, &blen, p); + qword_addint(&bp, &blen, len); + qword_addeol(&bp, &blen); + if (blen <= 0 || cache_write(f, buf, bp - buf) != bp - buf) { + close(f); + return NULL; + } + bp = buf; + blen = cache_read(f, buf, sizeof(buf)); + close(f); + + if (blen <= 0 || buf[blen-1] != '\n') + return NULL; + buf[blen-1] = 0; + + memset(fh.fh_handle, 0, sizeof(fh.fh_handle)); + fh.fh_size = qword_get(&bp, (char *)fh.fh_handle, NFS3_FHSIZE); + return &fh; +} + +/* Wait for all worker child processes to exit and reap them */ +void +cache_wait_for_workers(char *prog) +{ + int status; + pid_t pid; + + for (;;) { + + pid = waitpid(0, &status, 0); + + if (pid < 0) { + if (errno == ECHILD) + return; /* no more children */ + xlog(L_FATAL, "%s: can't wait: %s\n", prog, + strerror(errno)); + } + + /* Note: because we SIG_IGN'd SIGCHLD earlier, this + * does not happen on 2.6 kernels, and waitpid() blocks + * until all the children are dead then returns with + * -ECHILD. But, we don't need to do anything on the + * death of individual workers, so we don't care. */ + xlog(L_NOTICE, "%s: reaped child %d, status %d\n", + prog, (int)pid, status); + } +} + +/* Fork num_threads worker children and wait for them */ +int +cache_fork_workers(char *prog, int num_threads) +{ + int i; + pid_t pid; + + if (num_threads <= 1) + return 1; + + xlog(L_NOTICE, "%s: starting %d threads\n", prog, num_threads); + + for (i = 0 ; i < num_threads ; i++) { + pid = fork(); + if (pid < 0) { + xlog(L_FATAL, "%s: cannot fork: %s\n", prog, + strerror(errno)); + } + if (pid == 0) { + /* worker child */ + + /* Re-enable the default action on SIGTERM et al + * so that workers die naturally when sent them. + * Only the parent unregisters with pmap and + * hence needs to do special SIGTERM handling. */ + struct sigaction sa; + sa.sa_handler = SIG_DFL; + sa.sa_flags = 0; + sigemptyset(&sa.sa_mask); + sigaction(SIGHUP, &sa, NULL); + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + + /* fall into my_svc_run in caller */ + return 1; + } + } + + /* in parent */ + cache_wait_for_workers(prog); + return 0; +} diff --git a/support/export/client.c b/support/export/client.c new file mode 100644 index 0000000..79164fe --- /dev/null +++ b/support/export/client.c @@ -0,0 +1,800 @@ +/* + * support/export/client.c + * + * Maintain list of nfsd clients. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/types.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> +#include <netdb.h> +#include <errno.h> + +#include "sockaddr.h" +#include "misc.h" +#include "nfslib.h" +#include "exportfs.h" + +/* netgroup stuff never seems to be defined in any header file. Linux is + * not alone in this. + */ +#if !defined(__GLIBC__) || __GLIBC__ < 2 +extern int innetgr(char *netgr, char *host, char *, char *); +#endif + +static char *add_name(char *old, const char *add); + +nfs_client *clientlist[MCL_MAXTYPES] = { NULL, }; + + +static void +init_addrlist(nfs_client *clp, const struct addrinfo *ai) +{ + int i; + + if (ai == NULL) + return; + + for (i = 0; (ai != NULL) && (i < NFSCLNT_ADDRMAX); i++) { + set_addrlist(clp, i, ai->ai_addr); + ai = ai->ai_next; + } + + clp->m_naddr = i; +} + +static void +client_free(nfs_client *clp) +{ + free(clp->m_hostname); + free(clp); +} + +static int +init_netmask4(nfs_client *clp, const char *slash) +{ + struct sockaddr_in sin = { + .sin_family = AF_INET, + }; + uint32_t shift; + + /* + * Decide what kind of netmask was specified. If there's + * no '/' present, assume the netmask is all ones. If + * there is a '/' and at least one '.', look for a spelled- + * out netmask. Otherwise, assume it was a prefixlen. + */ + if (slash == NULL) + shift = 0; + else { + unsigned long prefixlen; + + if (strchr(slash + 1, '.') != NULL) { + if (inet_pton(AF_INET, slash + 1, + &sin.sin_addr.s_addr) == 0) + goto out_badmask; + set_addrlist_in(clp, 1, &sin); + return 1; + } else { + char *endptr; + + prefixlen = strtoul(slash + 1, &endptr, 10); + if (*endptr != '\0' && prefixlen != ULONG_MAX && + errno != ERANGE) + goto out_badprefix; + } + if (prefixlen > 32) + goto out_badprefix; + shift = 32 - (uint32_t)prefixlen; + } + + /* + * Now construct the full netmask bitmask in a sockaddr_in, + * and plant it in the nfs_client record. + */ + sin.sin_addr.s_addr = htonl((uint32_t)~0 << shift); + set_addrlist_in(clp, 1, &sin); + + return 1; + +out_badmask: + xlog(L_ERROR, "Invalid netmask `%s' for %s", slash + 1, clp->m_hostname); + return 0; + +out_badprefix: + xlog(L_ERROR, "Invalid prefix `%s' for %s", slash + 1, clp->m_hostname); + return 0; +} + +#ifdef IPV6_SUPPORTED +static int +init_netmask6(nfs_client *clp, const char *slash) +{ + struct sockaddr_in6 sin6 = { + .sin6_family = AF_INET6, + }; + unsigned long prefixlen; + uint32_t shift; + int i; + + /* + * Decide what kind of netmask was specified. If there's + * no '/' present, assume the netmask is all ones. If + * there is a '/' and at least one ':', look for a spelled- + * out netmask. Otherwise, assume it was a prefixlen. + */ + if (slash == NULL) + prefixlen = 128; + else { + if (strchr(slash + 1, ':') != NULL) { + if (!inet_pton(AF_INET6, slash + 1, &sin6.sin6_addr)) + goto out_badmask; + set_addrlist_in6(clp, 1, &sin6); + return 1; + } else { + char *endptr; + + prefixlen = strtoul(slash + 1, &endptr, 10); + if (*endptr != '\0' && prefixlen != ULONG_MAX && + errno != ERANGE) + goto out_badprefix; + } + if (prefixlen > 128) + goto out_badprefix; + } + + /* + * Now construct the full netmask bitmask in a sockaddr_in6, + * and plant it in the nfs_client record. + */ + for (i = 0; prefixlen > 32; i++) { + sin6.sin6_addr.s6_addr32[i] = 0xffffffff; + prefixlen -= 32; + } + shift = 32 - (uint32_t)prefixlen; + sin6.sin6_addr.s6_addr32[i] = htonl((uint32_t)~0 << shift); + set_addrlist_in6(clp, 1, &sin6); + + return 1; + +out_badmask: + xlog(L_ERROR, "Invalid netmask `%s' for %s", slash + 1, clp->m_hostname); + return 0; + +out_badprefix: + xlog(L_ERROR, "Invalid prefix `%s' for %s", slash + 1, clp->m_hostname); + return 0; +} +#else /* IPV6_SUPPORTED */ +static int +init_netmask6(nfs_client *UNUSED(clp), const char *UNUSED(slash)) +{ + return 0; +} +#endif /* IPV6_SUPPORTED */ + +/* + * Parse the network mask for M_SUBNETWORK type clients. + * + * Return TRUE if successful, or FALSE if some error occurred. + */ +static int +init_subnetwork(nfs_client *clp) +{ + struct addrinfo *ai; + sa_family_t family; + int result = 0; + char *slash; + + slash = strchr(clp->m_hostname, '/'); + if (slash != NULL) { + *slash = '\0'; + ai = host_pton(clp->m_hostname); + *slash = '/'; + } else + ai = host_pton(clp->m_hostname); + if (ai == NULL) { + xlog(L_ERROR, "Invalid IP address %s", clp->m_hostname); + return result; + } + + set_addrlist(clp, 0, ai->ai_addr); + family = ai->ai_addr->sa_family; + + nfs_freeaddrinfo(ai); + + switch (family) { + case AF_INET: + result = init_netmask4(clp, slash); + break; + case AF_INET6: + result = init_netmask6(clp, slash); + break; + default: + xlog(L_ERROR, "Unsupported address family for %s", + clp->m_hostname); + } + + return result; +} + +static int +client_init(nfs_client *clp, const char *hname, const struct addrinfo *ai) +{ + clp->m_hostname = strdup(hname); + if (clp->m_hostname == NULL) + return 0; + + clp->m_exported = 0; + clp->m_count = 0; + clp->m_naddr = 0; + + if (clp->m_type == MCL_SUBNETWORK) + return init_subnetwork(clp); + + init_addrlist(clp, ai); + return 1; +} + +static void +client_add(nfs_client *clp) +{ + nfs_client **cpp; + + cpp = &clientlist[clp->m_type]; + while (*cpp != NULL) + cpp = &((*cpp)->m_next); + clp->m_next = NULL; + *cpp = clp; +} + +/** + * client_lookup - look for @hname in our list of cached nfs_clients + * @hname: '\0'-terminated ASCII string containing hostname to look for + * @canonical: if set, @hname is known to be canonical DNS name + * + * Returns pointer to a matching or freshly created nfs_client. NULL + * is returned if some problem occurs. + */ +nfs_client * +client_lookup(char *hname, int canonical) +{ + nfs_client *clp = NULL; + int htype; + struct addrinfo *ai = NULL; + + htype = client_gettype(hname); + + if (htype == MCL_FQDN && !canonical) { + ai = host_addrinfo(hname); + if (!ai) { + xlog(L_WARNING, "Failed to resolve %s", hname); + goto out; + } + hname = ai->ai_canonname; + + for (clp = clientlist[htype]; clp; clp = clp->m_next) + if (client_check(clp, ai)) + break; + } else { + for (clp = clientlist[htype]; clp; clp = clp->m_next) { + if (strcasecmp(hname, clp->m_hostname)==0) + break; + } + } + + if (clp == NULL) { + clp = calloc(1, sizeof(*clp)); + if (clp == NULL) + goto out; + clp->m_type = htype; + if (!client_init(clp, hname, NULL)) { + client_free(clp); + clp = NULL; + goto out; + } + client_add(clp); + } + + if (htype == MCL_FQDN && clp->m_naddr == 0) + init_addrlist(clp, ai); + +out: + nfs_freeaddrinfo(ai); + return clp; +} + +/** + * client_dup - create a copy of an nfs_client + * @clp: pointer to nfs_client to copy + * @ai: pointer to addrinfo used to initialize the new client's addrlist + * + * Returns a dynamically allocated nfs_client if successful, or + * NULL if some problem occurs. Caller must free the returned + * nfs_client with free(3). + */ +nfs_client * +client_dup(const nfs_client *clp, const struct addrinfo *ai) +{ + nfs_client *new; + + new = (nfs_client *)malloc(sizeof(*new)); + if (new == NULL) + return NULL; + memcpy(new, clp, sizeof(*new)); + new->m_type = MCL_FQDN; + new->m_hostname = NULL; + + if (!client_init(new, ai->ai_canonname, ai)) { + client_free(new); + return NULL; + } + client_add(new); + return new; +} + +/** + * client_release - drop a reference to an nfs_client record + * + */ +void +client_release(nfs_client *clp) +{ + if (clp->m_count <= 0) + xlog(L_FATAL, "client_free: m_count <= 0!"); + clp->m_count--; +} + +/** + * client_freeall - deallocate all nfs_client records + * + */ +void +client_freeall(void) +{ + nfs_client *clp, **head; + int i; + + for (i = 0; i < MCL_MAXTYPES; i++) { + head = clientlist + i; + while (*head) { + *head = (clp = *head)->m_next; + client_free(clp); + } + } +} + +/** + * client_resolve - look up an IP address + * @sap: pointer to socket address to resolve + * + * Returns an addrinfo structure, or NULL if some problem occurred. + * Caller must free the result with freeaddrinfo(3). + */ +struct addrinfo * +client_resolve(const struct sockaddr *sap) +{ + struct addrinfo *ai = NULL; + + if (clientlist[MCL_WILDCARD] || clientlist[MCL_NETGROUP]) + ai = host_reliable_addrinfo(sap); + if (ai == NULL) + ai = host_numeric_addrinfo(sap); + + return ai; +} + +/** + * client_compose - Make a list of cached hostnames that match an IP address + * @ai: pointer to addrinfo containing IP address information to match + * + * Gather all known client hostnames that match the IP address, and sort + * the result into a comma-separated list. + * + * Returns a '\0'-terminated ASCII string containing a comma-separated + * sorted list of client hostnames, or NULL if no client records matched + * the IP address or memory could not be allocated. Caller must free the + * returned string with free(3). + */ +char * +client_compose(const struct addrinfo *ai) +{ + char *name = NULL; + int i; + + for (i = 0 ; i < MCL_MAXTYPES; i++) { + nfs_client *clp; + for (clp = clientlist[i]; clp ; clp = clp->m_next) { + if (!client_check(clp, ai)) + continue; + name = add_name(name, clp->m_hostname); + } + } + return name; +} + +/** + * client_member - check if @name is contained in the list @client + * @client: '\0'-terminated ASCII string containing + * comma-separated list of hostnames + * @name: '\0'-terminated ASCII string containing hostname to look for + * + * Returns 1 if @name was found in @client, otherwise zero is returned. + */ +int +client_member(const char *client, const char *name) +{ + size_t l = strlen(name); + + while (*client) { + if (strncmp(client, name, l) == 0 && + (client[l] == ',' || client[l] == '\0')) + return 1; + client = strchr(client, ','); + if (client == NULL) + return 0; + client++; + } + return 0; +} + +static int +name_cmp(const char *a, const char *b) +{ + /* compare strings a and b, but only upto ',' in a */ + while (*a && *b && *a != ',' && *a == *b) + a++, b++; + if (!*b && (!*a || *a == ',')) + return 0; + if (!*b) return 1; + if (!*a || *a == ',') return -1; + return *a - *b; +} + +static char * +add_name(char *old, const char *add) +{ + size_t len = strlen(add) + 2; + char *new; + char *cp; + if (old) len += strlen(old); + + new = malloc(len); + if (!new) { + free(old); + return NULL; + } + cp = old; + while (cp && *cp && name_cmp(cp, add) < 0) { + /* step cp forward over a name */ + char *e = strchr(cp, ','); + if (e) + cp = e+1; + else + cp = cp + strlen(cp); + } + len = cp-old; + if (old && len > 0) { + strncpy(new, old, len); + new[cp-old] = 0; + } else { + new[0] = 0; + } + if (cp != old && !*cp) + strcat(new, ","); + strcat(new, add); + if (cp && *cp) { + strcat(new, ","); + strcat(new, cp); + } + free(old); + return new; +} + +/* + * Check each address listed in @ai against each address + * stored in @clp. Return 1 if a match is found, otherwise + * zero. + */ +static int +check_fqdn(const nfs_client *clp, const struct addrinfo *ai) +{ + int i; + + for (; ai; ai = ai->ai_next) + for (i = 0; i < clp->m_naddr; i++) + if (nfs_compare_sockaddr(ai->ai_addr, + get_addrlist(clp, i))) + return 1; + + return 0; +} + +static _Bool +mask_match(const uint32_t a, const uint32_t b, const uint32_t m) +{ + return ((a ^ b) & m) == 0; +} + +static int +check_subnet_v4(const struct sockaddr_in *address, + const struct sockaddr_in *mask, const struct addrinfo *ai) +{ + for (; ai; ai = ai->ai_next) { + struct sockaddr_in *sin = (struct sockaddr_in *)ai->ai_addr; + + if (sin->sin_family != AF_INET) + continue; + + if (mask_match(address->sin_addr.s_addr, + sin->sin_addr.s_addr, + mask->sin_addr.s_addr)) + return 1; + } + return 0; +} + +#ifdef IPV6_SUPPORTED +static int +check_subnet_v6(const struct sockaddr_in6 *address, + const struct sockaddr_in6 *mask, const struct addrinfo *ai) +{ + for (; ai; ai = ai->ai_next) { + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ai->ai_addr; + + if (sin6->sin6_family != AF_INET6) + continue; + + if (mask_match(address->sin6_addr.s6_addr32[0], + sin6->sin6_addr.s6_addr32[0], + mask->sin6_addr.s6_addr32[0]) && + mask_match(address->sin6_addr.s6_addr32[1], + sin6->sin6_addr.s6_addr32[1], + mask->sin6_addr.s6_addr32[1]) && + mask_match(address->sin6_addr.s6_addr32[2], + sin6->sin6_addr.s6_addr32[2], + mask->sin6_addr.s6_addr32[2]) && + mask_match(address->sin6_addr.s6_addr32[3], + sin6->sin6_addr.s6_addr32[3], + mask->sin6_addr.s6_addr32[3])) + return 1; + } + return 0; +} +#else /* !IPV6_SUPPORTED */ +static int +check_subnet_v6(const struct sockaddr_in6 *UNUSED(address), + const struct sockaddr_in6 *UNUSED(mask), + const struct addrinfo *UNUSED(ai)) +{ + return 0; +} +#endif /* !IPV6_SUPPORTED */ + +/* + * Check each address listed in @ai against the subnetwork or + * host address stored in @clp. Return 1 if an address in @hp + * matches the host address stored in @clp, otherwise zero. + */ +static int +check_subnetwork(const nfs_client *clp, const struct addrinfo *ai) +{ + switch (get_addrlist(clp, 0)->sa_family) { + case AF_INET: + return check_subnet_v4(get_addrlist_in(clp, 0), + get_addrlist_in(clp, 1), ai); + case AF_INET6: + return check_subnet_v6(get_addrlist_in6(clp, 0), + get_addrlist_in6(clp, 1), ai); + } + + return 0; +} + +/* + * Check if a wildcard nfs_client record matches the canonical name + * or the aliases of a host. Return 1 if a match is found, otherwise + * zero. + */ +static int +check_wildcard(const nfs_client *clp, const struct addrinfo *ai) +{ + char *hname, *cname = clp->m_hostname; + struct hostent *hp; + char **ap; + int match; + + match = 0; + + hname = host_canonname(ai->ai_addr); + if (hname == NULL) + goto out; + + if (wildmat(hname, cname)) { + match = 1; + goto out; + } + + /* See if hname aliases listed in /etc/hosts or nis[+] + * match the requested wildcard */ + hp = gethostbyname(hname); + if (hp != NULL) { + for (ap = hp->h_aliases; *ap; ap++) + if (wildmat(*ap, cname)) { + match = 1; + goto out; + } + } + +out: + free(hname); + return match; +} + +/* + * Check if @ai's hostname or aliases fall in a given netgroup. + * Return 1 if @ai represents a host in the netgroup, otherwise + * zero. + */ +#ifdef HAVE_INNETGR +static int +check_netgroup(const nfs_client *clp, const struct addrinfo *ai) +{ + const char *netgroup = clp->m_hostname + 1; + struct addrinfo *tmp = NULL; + struct hostent *hp; + char *dot, *hname, *ip; + int i, match; + + match = 0; + + hname = host_canonname(ai->ai_addr); + if (hname == NULL) + goto out; + + /* First, try to match the hostname without + * splitting off the domain */ + if (innetgr(netgroup, hname, NULL, NULL)) { + match = 1; + goto out; + } + + /* See if hname aliases listed in /etc/hosts or nis[+] + * match the requested netgroup */ + hp = gethostbyname(hname); + if (hp != NULL) { + for (i = 0; hp->h_aliases[i]; i++) + if (innetgr(netgroup, hp->h_aliases[i], NULL, NULL)) { + match = 1; + goto out; + } + } + + /* If hname happens to be an IP address, convert it + * to a the canonical DNS name bound to this address. */ + tmp = host_pton(hname); + if (tmp != NULL) { + char *cname = host_canonname(tmp->ai_addr); + nfs_freeaddrinfo(tmp); + + /* The resulting FQDN may be in our netgroup. */ + if (cname != NULL) { + free(hname); + hname = cname; + if (innetgr(netgroup, hname, NULL, NULL)) { + match = 1; + goto out; + } + } + } + + /* check whether the IP itself is in the netgroup */ + ip = calloc(INET6_ADDRSTRLEN, 1); + if (ip == NULL) + goto out; + + if (inet_ntop(ai->ai_family, &(((struct sockaddr_in *)ai->ai_addr)->sin_addr), ip, INET6_ADDRSTRLEN) == ip) { + if (innetgr(netgroup, ip, NULL, NULL)) { + free(hname); + hname = ip; + match = 1; + goto out; + } + } + free(ip); + + /* Okay, strip off the domain (if we have one) */ + dot = strchr(hname, '.'); + if (dot == NULL) + goto out; + + *dot = '\0'; + match = innetgr(netgroup, hname, NULL, NULL); + +out: + free(hname); + return match; +} +#else /* !HAVE_INNETGR */ +static int +check_netgroup(__attribute__((unused)) const nfs_client *clp, + __attribute__((unused)) const struct addrinfo *ai) +{ + return 0; +} +#endif /* !HAVE_INNETGR */ + +/** + * client_check - check if IP address information matches a cached nfs_client + * @clp: pointer to a cached nfs_client record + * @ai: pointer to addrinfo to compare it with + * + * Returns 1 if the address information matches the cached nfs_client, + * otherwise zero. + */ +int +client_check(const nfs_client *clp, const struct addrinfo *ai) +{ + switch (clp->m_type) { + case MCL_FQDN: + return check_fqdn(clp, ai); + case MCL_SUBNETWORK: + return check_subnetwork(clp, ai); + case MCL_WILDCARD: + return check_wildcard(clp, ai); + case MCL_NETGROUP: + return check_netgroup(clp, ai); + case MCL_ANONYMOUS: + return 1; + case MCL_GSS: + return 0; + default: + xlog(D_GENERAL, "%s: unrecognized client type: %d", + __func__, clp->m_type); + } + + return 0; +} + +/** + * client_gettype - determine type of nfs_client given an identifier + * @ident: '\0'-terminated ASCII string containing a client identifier + * + * Returns the type of nfs_client record that would be used for + * this client. + */ +int +client_gettype(char *ident) +{ + char *sp; + + if (ident[0] == '\0' || strcmp(ident, "*")==0) + return MCL_ANONYMOUS; + if (strncmp(ident, "gss/", 4) == 0) + return MCL_GSS; + if (ident[0] == '@') { +#ifndef HAVE_INNETGR + xlog(L_WARNING, "netgroup support not compiled in"); +#endif + return MCL_NETGROUP; + } + for (sp = ident; *sp; sp++) { + if (*sp == '*' || *sp == '?' || *sp == '[') + return MCL_WILDCARD; + if (*sp == '/') + return MCL_SUBNETWORK; + if (*sp == '\\' && sp[1]) + sp++; + } + + return MCL_FQDN; +} diff --git a/support/export/export.c b/support/export/export.c new file mode 100644 index 0000000..3e48c42 --- /dev/null +++ b/support/export/export.c @@ -0,0 +1,471 @@ +/* + * support/export/export.c + * + * Maintain list of exported file systems. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <unistd.h> +#include <string.h> +#include <sys/types.h> +#include <sys/param.h> +#include <fcntl.h> +#include <netinet/in.h> +#include <limits.h> +#include <stdlib.h> +#include <dirent.h> +#include <errno.h> +#include "xmalloc.h" +#include "nfslib.h" +#include "exportfs.h" +#include "nfsd_path.h" +#include "xlog.h" +#include "reexport.h" + +exp_hash_table exportlist[MCL_MAXTYPES] = {{NULL, {{NULL,NULL}, }}, }; +static int export_hash(char *); + +static void export_init(nfs_export *exp, nfs_client *clp, + struct exportent *nep); +static void export_add(nfs_export *exp); +static int export_check(const nfs_export *exp, const struct addrinfo *ai, + const char *path); + +/* Return a real path for the export. */ +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; +} + +char * +exportent_realpath(struct exportent *eep) +{ + if (!eep->e_realpath) + exportent_mkrealpath(eep); + return eep->e_realpath; +} + +void +exportent_release(struct exportent *eep) +{ + xfree(eep->e_squids); + xfree(eep->e_sqgids); + free(eep->e_mountpoint); + free(eep->e_fslocdata); + free(eep->e_uuid); + xfree(eep->e_hostname); + xfree(eep->e_realpath); +} + +static void +export_free(nfs_export *exp) +{ + exportent_release(&exp->m_export); + xfree(exp); +} + +static void warn_duplicated_exports(nfs_export *exp, struct exportent *eep) +{ + if (exp->m_export.e_flags != eep->e_flags) { + xlog(L_ERROR, "incompatible duplicated export entries:"); + xlog(L_ERROR, "\t%s:%s (0x%x) [IGNORED]", eep->e_hostname, + eep->e_path, eep->e_flags); + xlog(L_ERROR, "\t%s:%s (0x%x)", exp->m_export.e_hostname, + exp->m_export.e_path, exp->m_export.e_flags); + } else { + xlog(L_ERROR, "duplicated export entries:"); + xlog(L_ERROR, "\t%s:%s", eep->e_hostname, eep->e_path); + xlog(L_ERROR, "\t%s:%s", exp->m_export.e_hostname, + exp->m_export.e_path); + } +} + +/** + * export_read - read entries from /etc/exports + * @fname: name of file to read from + * @ignore_hosts: don't check validity of host names + * + * Returns number of read entries. + * @ignore_hosts can be set when the host names won't be used + * and when getting delays or errors due to problems with + * hostname looking is not acceptable. + */ +int +export_read(char *fname, int ignore_hosts) +{ + struct exportent *eep; + nfs_export *exp; + + int volumes = 0; + int reexport_found = 0; + + setexportent(fname, "r"); + while ((eep = getexportent(0,1)) != NULL) { + exp = export_lookup(eep->e_hostname, eep->e_path, ignore_hosts); + if (!exp) { + if (export_create(eep, 0)) + /* possible complaints already logged */ + volumes++; + } + else + warn_duplicated_exports(exp, eep); + + if (eep->e_reexport) + reexport_found = 1; + } + + if (reexport_found) { + for (int i = 0; i < MCL_MAXTYPES; i++) { + for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { + if (exp->m_export.e_reexport) + continue; + + if (exp->m_export.e_flags & NFSEXP_FSID) { + xlog(L_ERROR, "When a reexport= option is present no manully assigned numerical fsid= options are allowed"); + return -1; + } + } + } + } + + endexportent(); + + return volumes; +} + +/** + * export_d_read - read entries from /etc/exports. + * @fname: name of directory to read from + * @ignore_hosts: don't check validity of host names + * + * Returns number of read entries. + * Based on mnt_table_parse_dir() in + * util-linux-ng/shlibs/mount/src/tab_parse.c + */ +int +export_d_read(const char *dname, int ignore_hosts) +{ + int n = 0, i; + struct dirent **namelist = NULL; + int volumes = 0; + + + n = scandir(dname, &namelist, NULL, versionsort); + if (n < 0) { + if (errno == ENOENT) + /* Silently return */ + return volumes; + xlog(L_NOTICE, "scandir %s: %s", dname, strerror(errno)); + } else if (n == 0) + return volumes; + + for (i = 0; i < n; i++) { + struct dirent *d = namelist[i]; + size_t namesz; + char fname[PATH_MAX + 1]; + int fname_len; + + + if (d->d_type != DT_UNKNOWN + && d->d_type != DT_REG + && d->d_type != DT_LNK) + continue; + if (*d->d_name == '.') + continue; + +#define _EXT_EXPORT_SIZ (sizeof(_EXT_EXPORT) - 1) + namesz = strlen(d->d_name); + if (!namesz + || namesz < _EXT_EXPORT_SIZ + 1 + || strcmp(d->d_name + (namesz - _EXT_EXPORT_SIZ), + _EXT_EXPORT)) + continue; + + fname_len = snprintf(fname, PATH_MAX +1, "%s/%s", dname, d->d_name); + if (fname_len > PATH_MAX) { + xlog(L_WARNING, "Too long file name: %s in %s", d->d_name, dname); + continue; + } + + volumes += export_read(fname, ignore_hosts); + } + + for (i = 0; i < n; i++) + free(namelist[i]); + free(namelist); + + return volumes; +} + +/** + * export_create - create an in-core nfs_export record from an export entry + * @xep: export entry to lookup + * @canonical: if set, e_hostname is known to be canonical DNS name + * + * Returns a freshly instantiated export record, or NULL if + * a problem occurred. + */ +nfs_export * +export_create(struct exportent *xep, int canonical) +{ + nfs_client *clp; + nfs_export *exp; + + if (!(clp = client_lookup(xep->e_hostname, canonical))) { + /* bad export entry; complaint already logged */ + return NULL; + } + exp = (nfs_export *) xmalloc(sizeof(*exp)); + export_init(exp, clp, xep); + export_add(exp); + + return exp; +} + +static void +export_init(nfs_export *exp, nfs_client *clp, struct exportent *nep) +{ + struct exportent *e = &exp->m_export; + + dupexportent(e, nep); + if (nep->e_hostname) + e->e_hostname = xstrdup(nep->e_hostname); + + exp->m_exported = 0; + exp->m_xtabent = 0; + exp->m_mayexport = 0; + exp->m_changed = 0; + exp->m_warned = 0; + exp->m_client = clp; + clp->m_count++; +} + +/* + * Duplicate exports data. The in-core export struct retains the + * original hostname from /etc/exports, while the in-core client struct + * gets the newly found FQDN. + */ +static nfs_export * +export_dup(nfs_export *exp, const struct addrinfo *ai) +{ + nfs_export *new; + nfs_client *clp; + + new = (nfs_export *) xmalloc(sizeof(*new)); + memcpy(new, exp, sizeof(*new)); + dupexportent(&new->m_export, &exp->m_export); + if (exp->m_export.e_hostname) + new->m_export.e_hostname = xstrdup(exp->m_export.e_hostname); + clp = client_dup(exp->m_client, ai); + if (clp == NULL) { + export_free(new); + return NULL; + } + clp->m_count++; + new->m_client = clp; + new->m_mayexport = exp->m_mayexport; + new->m_exported = 0; + new->m_xtabent = 0; + new->m_changed = 0; + new->m_warned = 0; + export_add(new); + + return new; +} + +static void +export_add(nfs_export *exp) +{ + exp_hash_table *p_tbl; + exp_hash_entry *p_hen; + nfs_export *p_next; + + int type = exp->m_client->m_type; + int pos; + + pos = export_hash(exp->m_export.e_path); + p_tbl = &(exportlist[type]); /* pointer to hash table */ + p_hen = &(p_tbl->entries[pos]); /* pointer to hash table entry */ + + if (!(p_hen->p_first)) { /* hash table entry is empty */ + p_hen->p_first = exp; + p_hen->p_last = exp; + + exp->m_next = p_tbl->p_head; + p_tbl->p_head = exp; + } else { /* hash table entry is NOT empty */ + p_next = p_hen->p_last->m_next; + p_hen->p_last->m_next = exp; + exp->m_next = p_next; + p_hen->p_last = exp; + } +} + +/** + * export_find - find or create a suitable nfs_export for @ai and @path + * @ai: pointer to addrinfo for client + * @path: '\0'-terminated ASCII string containing export path + * + * Returns a pointer to nfs_export data matching @ai and @path, + * or NULL if an error occurs. + */ +nfs_export * +export_find(const struct addrinfo *ai, const char *path) +{ + nfs_export *exp; + int i; + + for (i = 0; i < MCL_MAXTYPES; i++) { + for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { + if (!export_check(exp, ai, path)) + continue; + if (exp->m_client->m_type == MCL_FQDN) + return exp; + return export_dup(exp, ai); + } + } + + return NULL; +} + +/** + * export_lookup - search hash table for export entry + * @hname: '\0'-terminated ASCII string containing client hostname to look for + * @path: '\0'-terminated ASCII string containing export path to look for + * @canonical: if set, @hname is known to be canonical DNS name + * + * Returns a pointer to nfs_export record matching @hname and @path, + * or NULL if the export was not found. + */ +nfs_export * +export_lookup(char *hname, char *path, int canonical) +{ + nfs_client *clp; + nfs_export *exp; + exp_hash_entry *p_hen; + + int pos; + + clp = client_lookup(hname, canonical); + if(clp == NULL) + return NULL; + + pos = export_hash(path); + p_hen = &(exportlist[clp->m_type].entries[pos]); + for(exp = p_hen->p_first; exp && (exp != p_hen->p_last->m_next); + exp = exp->m_next) { + if (exp->m_client == clp && !strcmp(exp->m_export.e_path, path)) { + return exp; + } + } + return NULL; +} + +static int +export_check(const nfs_export *exp, const struct addrinfo *ai, const char *path) +{ + if (strcmp(path, exp->m_export.e_path)) + return 0; + + return client_check(exp->m_client, ai); +} + +/** + * export_freeall - deallocate all nfs_export records + * + */ +void +export_freeall(void) +{ + nfs_export *exp, *nxt; + int i, j; + + for (i = 0; i < MCL_MAXTYPES; i++) { + for (exp = exportlist[i].p_head; exp; exp = nxt) { + nxt = exp->m_next; + client_release(exp->m_client); + export_free(exp); + } + for (j = 0; j < HASH_TABLE_SIZE; j++) { + exportlist[i].entries[j].p_first = NULL; + exportlist[i].entries[j].p_last = NULL; + } + exportlist[i].p_head = NULL; + } + client_freeall(); +} + +/* + * Compute and returns integer from string. + * Note: Its understood the smae integers can be same for + * different strings, but it should not matter. + */ +static unsigned int +strtoint(char *str) +{ + int i = 0; + unsigned int n = 0; + + while ( str[i] != '\0') { + n+=((int)str[i])*i; + i++; + } + return n; +} + +/* + * Hash function + */ +static int +export_hash(char *str) +{ + unsigned int num = strtoint(str); + + return num % HASH_TABLE_SIZE; +} + +int export_test(struct exportent *eep, int with_fsid) +{ + char *path = eep->e_path; + int flags = eep->e_flags | (with_fsid ? NFSEXP_FSID : 0); + /* beside max path, buf size should take protocol str into account */ + char buf[NFS_MAXPATHLEN+1+64] = { 0 }; + char *bp = buf; + int len = sizeof(buf); + int fd, n; + + n = snprintf(buf, len, "-test-client- "); + bp += n; + len -= n; + qword_add(&bp, &len, path); + if (len < 1) + return 0; + snprintf(bp, len, " 3 %d 65534 65534 0\n", flags); + fd = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY); + if (fd < 0) + return 0; + n = nfsd_path_write(fd, buf, strlen(buf)); + close(fd); + if (n < 0) + return 0; + return 1; +} diff --git a/support/export/export.h b/support/export/export.h new file mode 100644 index 0000000..e2009cc --- /dev/null +++ b/support/export/export.h @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2021 Red Hat <nfs@redhat.com> + * + * support/export/export.h + * + * Declarations for export support + */ + +#ifndef EXPORT_H +#define EXPORT_H + +#include "nfslib.h" +#include "exportfs.h" + +unsigned int auth_reload(void); +nfs_export * auth_authenticate(const char *what, + const struct sockaddr *caller, + const char *path); + +void cache_open(void); +void cache_set_fds(fd_set *fdset); +int cache_process_req(fd_set *readfds); +void cache_process_loop(void); + +void v4clients_init(void); +void v4clients_set_fds(fd_set *fdset); +int v4clients_process(fd_set *fdset); + +struct nfs_fh_len * + cache_get_filehandle(nfs_export *exp, int len, char *p); +int cache_export(nfs_export *exp, char *path); +int cache_fork_workers(char *prog, int num_threads); +void cache_wait_for_workers(char *prog); +int cache_process(fd_set *readfds); + +bool ipaddr_client_matches(nfs_export *exp, struct addrinfo *ai); +bool namelist_client_matches(nfs_export *exp, char *dom); +bool client_matches(nfs_export *exp, char *dom, struct addrinfo *ai); + +static inline bool is_ipaddr_client(char *dom) +{ + return dom[0] == '$'; +} +#endif /* EXPORT__H */ diff --git a/support/export/fsloc.c b/support/export/fsloc.c new file mode 100644 index 0000000..1b869b6 --- /dev/null +++ b/support/export/fsloc.c @@ -0,0 +1,203 @@ +/* + * COPYRIGHT (c) 2006 + * THE REGENTS OF THE UNIVERSITY OF MICHIGAN + * ALL RIGHTS RESERVED + * + * Permission is granted to use, copy, create derivative works + * and redistribute this software and such derivative works + * for any purpose, so long as the name of The University of + * Michigan is not used in any advertising or publicity + * pertaining to the use of distribution of this software + * without specific, written prior authorization. If the + * above copyright notice or any other identification of the + * University of Michigan is included in any copy of any + * portion of this software, then the disclaimer below must + * also be included. + * + * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION + * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY + * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF + * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING + * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE + * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING + * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN + * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + */ + +#include <stdlib.h> +#include <string.h> +#include <syslog.h> + +#include "fsloc.h" +#include "exportfs.h" + +/* Debugging tool: prints out @servers info to syslog */ +static void replicas_print(struct servers *sp) +{ + int i; + if (!sp) { + xlog(L_NOTICE, "NULL replicas pointer"); + return; + } + xlog(L_NOTICE, "replicas listsize=%i", sp->h_num); + for (i=0; i<sp->h_num; i++) { + xlog(L_NOTICE, " %s:%s", + sp->h_mp[i]->h_host, sp->h_mp[i]->h_path); + } +} + +#ifdef DEBUG +/* Called by setting 'Method = stub' in config file. Just returns + * some syntactically correct gibberish for testing purposes. + */ +static struct servers *method_stub(char *key) +{ + struct servers *sp; + struct mount_point *mp; + + xlog(L_NOTICE, "called method_stub\n"); + sp = malloc(sizeof(struct servers)); + if (!sp) + return NULL; + mp = calloc(1, sizeof(struct mount_point)); + if (!mp) { + free(sp); + return NULL; + } + sp->h_num = 1; + sp->h_mp[0] = mp; + mp->h_host = strdup("stub_server"); + mp->h_path = strdup("/my/test/path"); + sp->h_referral = 1; + return sp; +} +#endif /* DEBUG */ + +/* Scan @list, which is a NULL-terminated array of strings of the + * form path@host[+host], and return corresponding servers structure. + */ +static struct servers *parse_list(char **list) +{ + int i; + struct servers *res; + struct mount_point *mp; + char *cp; + + res = malloc(sizeof(struct servers)); + if (!res) + return NULL; + res->h_num = 0; + + /* parse each of the answers in sucession. */ + for (i=0; list[i] && i<FSLOC_MAX_LIST; i++) { + mp = calloc(1, sizeof(struct mount_point)); + if (!mp) { + release_replicas(res); + return NULL; + } + cp = strchr(list[i], '@'); + if ((!cp) || list[i][0] != '/') { + xlog(L_WARNING, "invalid entry '%s'", list[i]); + free(mp); + continue; /* XXX Need better error handling */ + } + res->h_mp[i] = mp; + res->h_num++; + mp->h_path = strndup(list[i], cp - list[i]); + cp++; + mp->h_host = strdup(cp); + /* hosts are '+' separated, kernel expects ':' separated */ + while ( (cp = strchr(mp->h_host, '+')) ) + *cp = ':'; + } + return res; +} + +/* @data is a string of form path@host[+host][:path@host[+host]] + */ +static struct servers *method_list(char *data) +{ + char *copy, *ptr=data, *p; + char **list; + int i, listsize; + struct servers *rv=NULL; + bool v6esc = false; + + xlog(L_NOTICE, "method_list(%s)", data); + for (ptr--, listsize=1; ptr; ptr=strchr(ptr, ':'), listsize++) + ptr++; + list = malloc(listsize * sizeof(char *)); + copy = strdup(data); + if (copy) + xlog(L_NOTICE, "converted to %s", copy); + if (list && copy) { + ptr = copy; + for (p = ptr, i = 0; *p && i < listsize; p++) { + if (*p == '[') + v6esc = true; + else if (*p == ']') + v6esc = false; + + if (!v6esc && *p == ':') { + *p = '\0'; + if (*ptr) + list[i++] = ptr; + ptr = p + 1; + } + } + if (*ptr) + list[i++] = ptr; + list[i] = NULL; + rv = parse_list(list); + } + free(copy); + free(list); + replicas_print(rv); + return rv; +} + +/* Returns appropriately filled struct servers, or NULL if had a problem */ +struct servers *replicas_lookup(int method, char *data) +{ + struct servers *sp=NULL; + switch(method) { + case FSLOC_NONE: + break; + case FSLOC_REFER: + sp = method_list(data); + if (sp) + sp->h_referral = 1; + break; + case FSLOC_REPLICA: + sp = method_list(data); + if (sp) + sp->h_referral = 0; + break; +#ifdef DEBUG + case FSLOC_STUB: + sp = method_stub(data); + break; +#endif + default: + xlog(L_WARNING, "Unknown method = %i", method); + } + replicas_print(sp); + return sp; +} + +void release_replicas(struct servers *server) +{ + int i; + + if (!server) return; + for (i = 0; i < server->h_num; i++) { + free(server->h_mp[i]->h_host); + free(server->h_mp[i]->h_path); + free(server->h_mp[i]); + } + free(server); +} diff --git a/support/export/hostname.c b/support/export/hostname.c new file mode 100644 index 0000000..be4d7f6 --- /dev/null +++ b/support/export/hostname.c @@ -0,0 +1,366 @@ +/* + * Copyright 2010 Oracle. All rights reserved. + * + * This file is part of nfs-utils. + * + * nfs-utils is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * nfs-utils is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with nfs-utils. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include <stdlib.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <errno.h> + +#include "sockaddr.h" +#include "exportfs.h" + +/** + * host_ntop - generate presentation address given a sockaddr + * @sap: pointer to socket address + * @buf: working storage + * @buflen: size of @buf in bytes + * + * Returns a pointer to a @buf. + */ +#ifdef HAVE_GETNAMEINFO +char * +host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen) +{ + socklen_t salen = nfs_sockaddr_length(sap); + int error; + + memset(buf, 0, buflen); + + if (salen == 0) { + (void)strncpy(buf, "bad family", buflen - 1); + return buf; + } + + error = getnameinfo(sap, salen, buf, (socklen_t)buflen, + NULL, 0, NI_NUMERICHOST); + if (error != 0) { + buf[0] = '\0'; + (void)strncpy(buf, "bad address", buflen - 1); + } + + return buf; +} +#else /* !HAVE_GETNAMEINFO */ +char * +host_ntop(const struct sockaddr *sap, char *buf, const size_t buflen) +{ + const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap; + + memset(buf, 0, buflen); + + if (sin->sin_family != AF_INET) { + (void)strncpy(buf, "bad family", buflen - 1); + return buf; + } + + if (inet_ntop(AF_INET, &sin->sin_addr.s_addr, buf, buflen) != NULL) + return buf; + + buf[0] = '\0'; + (void)strncpy(buf, "bad address", buflen - 1); + return buf; +} +#endif /* !HAVE_GETNAMEINFO */ + +/** + * host_pton - return addrinfo for a given presentation address + * @paddr: pointer to a '\0'-terminated ASCII string containing an + * IP presentation address + * + * Returns address info structure, or NULL if an error occurs. Caller + * must free the returned structure with freeaddrinfo(3). + */ +__attribute__((__malloc__)) +struct addrinfo * +host_pton(const char *paddr) +{ + struct addrinfo *ai = NULL; + struct addrinfo hint = { + /* don't return duplicates */ + .ai_protocol = (int)IPPROTO_UDP, + .ai_flags = AI_NUMERICHOST, + .ai_family = AF_UNSPEC, + }; + struct sockaddr_in sin; + int error, inet4; + + /* + * Although getaddrinfo(3) is easier to use and supports + * IPv6, it recognizes incomplete addresses like "10.4" + * as valid AF_INET addresses. It also accepts presentation + * addresses that end with a blank. + * + * inet_pton(3) is much stricter. Use it to be certain we + * have a real AF_INET presentation address, before invoking + * getaddrinfo(3) to generate the full addrinfo list. + */ + if (paddr == NULL) { + xlog(D_GENERAL, "%s: passed a NULL presentation address", + __func__); + return NULL; + } + inet4 = 1; + if (inet_pton(AF_INET, paddr, &sin.sin_addr) == 0) + inet4 = 0; + + error = getaddrinfo(paddr, NULL, &hint, &ai); + switch (error) { + case 0: + if (!inet4 && ai->ai_addr->sa_family == AF_INET) { + xlog(D_GENERAL, "%s: failed to convert %s", + __func__, paddr); + nfs_freeaddrinfo(ai); + break; + } + return ai; + case EAI_NONAME: + break; + case EAI_SYSTEM: + xlog(L_WARNING, "%s: failed to convert %s: (%d) %m", + __func__, paddr, errno); + break; + default: + xlog(L_WARNING, "%s: failed to convert %s: %s", + __func__, paddr, gai_strerror(error)); + break; + } + + return NULL; +} + +/** + * host_addrinfo - return addrinfo for a given hostname + * @hostname: pointer to a '\0'-terminated ASCII string containing a hostname + * + * Returns address info structure with ai_canonname filled in, or NULL + * if no information is available for @hostname. Caller must free the + * returned structure with freeaddrinfo(3). + */ +__attribute__((__malloc__)) +struct addrinfo * +host_addrinfo(const char *hostname) +{ + struct addrinfo *ai = NULL; + struct addrinfo hint = { +#ifdef IPV6_SUPPORTED + .ai_family = AF_UNSPEC, +#else + .ai_family = AF_INET, +#endif + /* don't return duplicates */ + .ai_protocol = (int)IPPROTO_UDP, + .ai_flags = AI_CANONNAME, + }; + int error; + + error = getaddrinfo(hostname, NULL, &hint, &ai); + switch (error) { + case 0: + return ai; + case EAI_SYSTEM: + xlog(D_PARSE, "%s: failed to resolve %s: (%d) %m", + __func__, hostname, errno); + break; + default: + xlog(D_PARSE, "%s: failed to resolve %s: %s", + __func__, hostname, gai_strerror(error)); + break; + } + + return NULL; +} + +/** + * host_canonname - return canonical hostname bound to an address + * @sap: pointer to socket address to look up + * + * Discover the canonical hostname associated with the given socket + * address. The host's reverse mapping is verified in the process. + * + * Returns a '\0'-terminated ASCII string containing a hostname, or + * NULL if no hostname can be found for @sap. Caller must free + * the string. + */ +#ifdef HAVE_GETNAMEINFO +__attribute__((__malloc__)) +char * +host_canonname(const struct sockaddr *sap) +{ + socklen_t salen = nfs_sockaddr_length(sap); + char buf[NI_MAXHOST]; + int error; + + if (salen == 0) { + xlog(D_GENERAL, "%s: unsupported address family %d", + __func__, sap->sa_family); + return NULL; + } + + memset(buf, 0, sizeof(buf)); + error = getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf), + NULL, 0, NI_NAMEREQD); + switch (error) { + case 0: + break; + case EAI_SYSTEM: + xlog(D_GENERAL, "%s: getnameinfo(3) failed: (%d) %m", + __func__, errno); + return NULL; + default: + (void)getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf), + NULL, 0, NI_NUMERICHOST); + xlog(D_PARSE, "%s: failed to resolve %s: %s", + __func__, buf, gai_strerror(error)); + return NULL; + } + + return strdup(buf); +} +#else /* !HAVE_GETNAMEINFO */ +__attribute__((__malloc__)) +char * +host_canonname(const struct sockaddr *sap) +{ + const struct sockaddr_in *sin = (const struct sockaddr_in *)(char *)sap; + const struct in_addr *addr = &sin->sin_addr; + struct hostent *hp; + + if (sap->sa_family != AF_INET) + return NULL; + + hp = gethostbyaddr(addr, (socklen_t)sizeof(addr), AF_INET); + if (hp == NULL) + return NULL; + + return strdup(hp->h_name); +} +#endif /* !HAVE_GETNAMEINFO */ + +/** + * host_reliable_addrinfo - return addrinfo for a given address + * @sap: pointer to socket address to look up + * + * Reverse and forward lookups are performed to ensure the address has + * matching forward and reverse mappings. + * + * Returns addrinfo structure with just the provided address. If there + * is a problem with resolution or the resolved records don't match up + * properly then returns NULL. + * + * Caller must free the returned structure with freeaddrinfo(3). + */ +__attribute__((__malloc__)) +struct addrinfo * +host_reliable_addrinfo(const struct sockaddr *sap) +{ + struct addrinfo *ai, *a; + char *hostname; + + ai = NULL; + hostname = host_canonname(sap); + if (hostname == NULL) + goto out; + + ai = host_addrinfo(hostname); + free(hostname); + if (!ai) + goto out; + + /* make sure there's a matching address in the list */ + for (a = ai; a; a = a->ai_next) + if (nfs_compare_sockaddr(a->ai_addr, sap)) + break; + + nfs_freeaddrinfo(ai); + ai = NULL; + if (!a) + goto out; + + /* get addrinfo with just the original address */ + ai = host_numeric_addrinfo(sap); + +out: + return ai; +} + +/** + * host_numeric_addrinfo - return addrinfo without doing DNS queries + * @sap: pointer to socket address + * + * Returns address info structure, or NULL if an error occurred. + * Caller must free the returned structure with freeaddrinfo(3). + */ +#ifdef HAVE_GETNAMEINFO +__attribute__((__malloc__)) +struct addrinfo * +host_numeric_addrinfo(const struct sockaddr *sap) +{ + socklen_t salen = nfs_sockaddr_length(sap); + char buf[INET6_ADDRSTRLEN]; + int error; + + if (salen == 0) { + xlog(D_GENERAL, "%s: unsupported address family %d", + __func__, sap->sa_family); + return NULL; + } + + memset(buf, 0, sizeof(buf)); + error = getnameinfo(sap, salen, buf, (socklen_t)sizeof(buf), + NULL, 0, NI_NUMERICHOST); + switch (error) { + case 0: + break; + case EAI_SYSTEM: + xlog(D_GENERAL, "%s: getnameinfo(3) failed: (%d) %m", + __func__, errno); + return NULL; + default: + xlog(D_GENERAL, "%s: getnameinfo(3) failed: %s", + __func__, gai_strerror(error)); + return NULL; + } + + return host_pton(buf); +} +#else /* !HAVE_GETNAMEINFO */ +__attribute__((__malloc__)) +struct addrinfo * +host_numeric_addrinfo(const struct sockaddr *sap) +{ + const struct sockaddr_in *sin = (const struct sockaddr_in *)sap; + const struct in_addr *addr = &sin->sin_addr; + char buf[INET_ADDRSTRLEN]; + + if (sap->sa_family != AF_INET) + return NULL; + + memset(buf, 0, sizeof(buf)); + if (inet_ntop(AF_INET, (char *)addr, buf, + (socklen_t)sizeof(buf)) == NULL) + return NULL; + + return host_pton(buf); +} +#endif /* !HAVE_GETNAMEINFO */ diff --git a/support/export/mount.x b/support/export/mount.x new file mode 100644 index 0000000..12fd841 --- /dev/null +++ b/support/export/mount.x @@ -0,0 +1,343 @@ +%/* +% * Copyright (c) 2009, Sun Microsystems, Inc. +% * All rights reserved. +% * +% * Redistribution and use in source and binary forms, with or without +% * modification, are permitted provided that the following conditions are met: +% * - Redistributions of source code must retain the above copyright notice, +% * this list of conditions and the following disclaimer. +% * - Redistributions in binary form must reproduce the above copyright notice, +% * this list of conditions and the following disclaimer in the documentation +% * and/or other materials provided with the distribution. +% * - Neither the name of Sun Microsystems, Inc. nor the names of its +% * contributors may be used to endorse or promote products derived +% * from this software without specific prior written permission. +% * +% * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +% * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +% * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +% * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +% * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +% * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +% * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +% * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +% * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +% * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +% * POSSIBILITY OF SUCH DAMAGE. +% */ + +%/* +% * Copyright (c) 1985, 1990 by Sun Microsystems, Inc. +% */ +% +%/* from @(#)mount.x 1.3 91/03/11 TIRPC 1.0 */ + +/* + * Protocol description for the mount program + */ + +#ifdef RPC_HDR +%#ifndef _rpcsvc_mount_h +%#define _rpcsvc_mount_h +%#include <memory.h> +#endif + +const MNTPATHLEN = 1024; /* maximum bytes in a pathname argument */ +const MNTNAMLEN = 255; /* maximum bytes in a name argument */ +const FHSIZE = 32; /* size in bytes of a file handle */ + +/* + * The fhandle is the file handle that the server passes to the client. + * All file operations are done using the file handles to refer to a file + * or a directory. The file handle can contain whatever information the + * server needs to distinguish an individual file. + */ +typedef opaque fhandle[FHSIZE]; + +/* + * If a status of zero is returned, the call completed successfully, and + * a file handle for the directory follows. A non-zero status indicates + * some sort of error. The status corresponds with UNIX error numbers. + */ +union fhstatus switch (unsigned fhs_status) { +case 0: + fhandle fhs_fhandle; +default: + void; +}; + +/* + * The type dirpath is the pathname of a directory + */ +typedef string dirpath<MNTPATHLEN>; + +/* + * The type name is used for arbitrary names (hostnames, groupnames) + */ +typedef string name<MNTNAMLEN>; + +/* + * A list of who has what mounted + */ +typedef struct mountbody *mountlist; +struct mountbody { + name ml_hostname; + dirpath ml_directory; + mountlist ml_next; +}; + +/* + * A list of netgroups + */ +typedef struct groupnode *groups; +struct groupnode { + name gr_name; + groups gr_next; +}; + +/* + * A list of what is exported and to whom + */ +typedef struct exportnode *exports; +struct exportnode { + dirpath ex_dir; + groups ex_groups; + exports ex_next; +}; + +/* + * POSIX pathconf information + */ +struct ppathcnf { + int pc_link_max; /* max links allowed */ + short pc_max_canon; /* max line len for a tty */ + short pc_max_input; /* input a tty can eat all at once */ + short pc_name_max; /* max file name length (dir entry) */ + short pc_path_max; /* max path name length (/x/y/x/.. ) */ + short pc_pipe_buf; /* size of a pipe (bytes) */ + u_char pc_vdisable; /* safe char to turn off c_cc[i] */ + char pc_xxx; /* alignment padding; cc_t == char */ + short pc_mask[2]; /* validity and boolean bits */ +}; + +/* + * NFSv3 file handle + */ +const FHSIZE3 = 64; /* max size of NFSv3 file handle in bytes */ +typedef opaque fhandle3<FHSIZE3>; + +/* + * NFSv3 mount status + */ +enum mountstat3 { + MNT_OK = 0, /* no error */ + MNT3ERR_PERM = 1, /* not owner */ + MNT3ERR_NOENT = 2, /* no such file or directory */ + MNT3ERR_IO = 5, /* I/O error */ + MNT3ERR_ACCES = 13, /* Permission denied */ + MNT3ERR_NOTDIR = 20, /* Not a directory */ + MNT3ERR_INVAL = 22, /* Invalid argument */ + MNT3ERR_NAMETOOLONG = 63, /* File name too long */ + MNT3ERR_NOTSUPP = 10004,/* Operation not supported */ + MNT3ERR_SERVERFAULT = 10006 /* A failure on the server */ +}; + +/* + * NFSv3 mount result + */ +struct mountres3_ok { + fhandle3 fhandle; + int auth_flavors<>; +}; + +union mountres3 switch (mountstat3 fhs_status) { +case MNT_OK: + mountres3_ok mountinfo; /* File handle and supported flavors */ +default: + void; +}; + +program MOUNTPROG { + /* + * Version one of the mount protocol communicates with version two + * of the NFS protocol. The only connecting point is the fhandle + * structure, which is the same for both protocols. + */ + version MOUNTVERS { + /* + * Does no work. It is made available in all RPC services + * to allow server reponse testing and timing + */ + void + MOUNTPROC_NULL(void) = 0; + + /* + * If fhs_status is 0, then fhs_fhandle contains the + * file handle for the directory. This file handle may + * be used in the NFS protocol. This procedure also adds + * a new entry to the mount list for this client mounting + * the directory. + * Unix authentication required. + */ + fhstatus + MOUNTPROC_MNT(dirpath) = 1; + + /* + * Returns the list of remotely mounted filesystems. The + * mountlist contains one entry for each hostname and + * directory pair. + */ + mountlist + MOUNTPROC_DUMP(void) = 2; + + /* + * Removes the mount list entry for the directory + * Unix authentication required. + */ + void + MOUNTPROC_UMNT(dirpath) = 3; + + /* + * Removes all of the mount list entries for this client + * Unix authentication required. + */ + void + MOUNTPROC_UMNTALL(void) = 4; + + /* + * Returns a list of all the exported filesystems, and which + * machines are allowed to import it. + */ + exports + MOUNTPROC_EXPORT(void) = 5; + + /* + * Identical to MOUNTPROC_EXPORT above + */ + exports + MOUNTPROC_EXPORTALL(void) = 6; + } = 1; + + /* + * Version two of the mount protocol communicates with version two + * of the NFS protocol. + * The only difference from version one is the addition of a POSIX + * pathconf call. + */ + version MOUNTVERS_POSIX { + /* + * Does no work. It is made available in all RPC services + * to allow server reponse testing and timing + */ + void + MOUNTPROC_NULL(void) = 0; + + /* + * If fhs_status is 0, then fhs_fhandle contains the + * file handle for the directory. This file handle may + * be used in the NFS protocol. This procedure also adds + * a new entry to the mount list for this client mounting + * the directory. + * Unix authentication required. + */ + fhstatus + MOUNTPROC_MNT(dirpath) = 1; + + /* + * Returns the list of remotely mounted filesystems. The + * mountlist contains one entry for each hostname and + * directory pair. + */ + mountlist + MOUNTPROC_DUMP(void) = 2; + + /* + * Removes the mount list entry for the directory + * Unix authentication required. + */ + void + MOUNTPROC_UMNT(dirpath) = 3; + + /* + * Removes all of the mount list entries for this client + * Unix authentication required. + */ + void + MOUNTPROC_UMNTALL(void) = 4; + + /* + * Returns a list of all the exported filesystems, and which + * machines are allowed to import it. + */ + exports + MOUNTPROC_EXPORT(void) = 5; + + /* + * Identical to MOUNTPROC_EXPORT above + */ + exports + MOUNTPROC_EXPORTALL(void) = 6; + + /* + * POSIX pathconf info (Sun hack) + */ + ppathcnf + MOUNTPROC_PATHCONF(dirpath) = 7; + } = 2; + + /* + * Version 3 of the protocol is for NFSv3 + */ + version MOUNTVERS_NFSV3 { + /* + * Does no work. It is made available in all RPC services + * to allow server reponse testing and timing + */ + void + MOUNTPROC3_NULL(void) = 0; + + /* + * If fhs_status is 0, then fhs_fhandle contains the + * file handle for the directory. This file handle may + * be used in the NFS protocol. This procedure also adds + * a new entry to the mount list for this client mounting + * the directory. + * Unix authentication required. + */ + mountres3 + MOUNTPROC3_MNT(dirpath) = 1; + + /* + * Returns the list of remotely mounted filesystems. The + * mountlist contains one entry for each hostname and + * directory pair. + */ + mountlist + MOUNTPROC3_DUMP(void) = 2; + + /* + * Removes the mount list entry for the directory + * Unix authentication required. + */ + void + MOUNTPROC3_UMNT(dirpath) = 3; + + /* + * Removes all of the mount list entries for this client + * Unix authentication required. + */ + void + MOUNTPROC3_UMNTALL(void) = 4; + + /* + * Returns a list of all the exported filesystems, and which + * machines are allowed to import it. + */ + exports + MOUNTPROC3_EXPORT(void) = 5; + } = 3; +} = 100005; + +#ifdef RPC_HDR +%#endif /*!_rpcsvc_mount_h*/ +#endif diff --git a/support/export/v4clients.c b/support/export/v4clients.c new file mode 100644 index 0000000..3230251 --- /dev/null +++ b/support/export/v4clients.c @@ -0,0 +1,233 @@ +/* + * support/export/v4clients.c + * + * Montior clients appearing in, and disappearing from, /proc/fs/nfsd/clients + * and log relevant information. + */ + +#include <unistd.h> +#include <stdlib.h> +#include <sys/inotify.h> +#include <sys/stat.h> +#include <errno.h> +#include "export.h" + +/* search.h declares 'struct entry' and nfs_prot.h + * does too. Easiest fix is to trick search.h into + * calling its struct "struct Entry". + */ +#define entry Entry +#include <search.h> +#undef entry + +static int clients_fd = -1; + +void v4clients_init(void) +{ + struct stat sb; + + if (stat("/proc/fs/nfsd/clients", &sb) != 0 || + !S_ISDIR(sb.st_mode)) + return; + if (clients_fd >= 0) + return; + clients_fd = inotify_init1(IN_NONBLOCK); + if (clients_fd < 0) { + xlog_err("Unable to initialise v4clients watcher: %s\n", + strerror(errno)); + return; + } + if (inotify_add_watch(clients_fd, "/proc/fs/nfsd/clients", + IN_CREATE | IN_DELETE) < 0) { + xlog_err("Unable to watch /proc/fs/nfsd/clients: %s\n", + strerror(errno)); + close(clients_fd); + clients_fd = -1; + return; + } +} + +void v4clients_set_fds(fd_set *fdset) +{ + if (clients_fd >= 0) + FD_SET(clients_fd, fdset); +} + +static void *tree_root; +static int have_unconfirmed; + +struct ent { + unsigned long num; + char *clientid; + char *addr; + int vers; + int unconfirmed; + int wid; +}; + +static int ent_cmp(const void *av, const void *bv) +{ + const struct ent *a = av; + const struct ent *b = bv; + + if (a->num < b->num) + return -1; + if (a->num > b->num) + return 1; + return 0; +} + +static void free_ent(struct ent *ent) +{ + free(ent->clientid); + free(ent->addr); + free(ent); +} + +static char *dup_line(char *line) +{ + char *ret; + char *e = strchr(line, '\n'); + if (!e) + e = line + strlen(line); + ret = malloc(e - line + 1); + if (ret) { + memcpy(ret, line, e - line); + ret[e-line] = 0; + } + return ret; +} + +static void read_info(struct ent *key) +{ + char buf[2048]; + char *path; + int was_unconfirmed = key->unconfirmed; + FILE *f; + + if (asprintf(&path, "/proc/fs/nfsd/clients/%lu/info", key->num) < 0) + return; + + f = fopen(path, "r"); + if (!f) { + free(path); + return; + } + if (key->wid < 0) + key->wid = inotify_add_watch(clients_fd, path, IN_MODIFY); + + while (fgets(buf, sizeof(buf), f)) { + if (strncmp(buf, "clientid: ", 10) == 0) { + free(key->clientid); + key->clientid = dup_line(buf+10); + } + if (strncmp(buf, "address: ", 9) == 0) { + free(key->addr); + key->addr = dup_line(buf+9); + } + if (strncmp(buf, "minor version: ", 15) == 0) + key->vers = atoi(buf+15); + if (strncmp(buf, "status: ", 8) == 0 && + strstr(buf, " unconfirmed") != NULL) { + key->unconfirmed = 1; + have_unconfirmed = 1; + } + if (strncmp(buf, "status: ", 8) == 0 && + strstr(buf, " confirmed") != NULL) + key->unconfirmed = 0; + } + fclose(f); + free(path); + + if (was_unconfirmed && !key->unconfirmed) + xlog(L_NOTICE, "v4.%d client attached: %s from %s", + key->vers, key->clientid ?: "-none-", + key->addr ?: "-none-"); + if (!key->unconfirmed && key->wid >= 0) { + inotify_rm_watch(clients_fd, key->wid); + key->wid = -1; + } +} + +static void add_id(int id) +{ + struct ent **ent; + struct ent *key; + + key = calloc(1, sizeof(*key)); + if (!key) { + return; + } + key->num = id; + key->wid = -1; + + ent = tsearch(key, &tree_root, ent_cmp); + + if (!ent || *ent != key) + /* Already existed, or insertion failed */ + free_ent(key); + else + read_info(key); +} + +static void del_id(unsigned long id) +{ + struct ent key = {.num = id}; + struct ent **e, *ent; + + e = tfind(&key, &tree_root, ent_cmp); + if (!e || !*e) + return; + ent = *e; + tdelete(ent, &tree_root, ent_cmp); + if (!ent->unconfirmed) + xlog(L_NOTICE, "v4.%d client detached: %s from %s", + ent->vers, ent->clientid, ent->addr); + if (ent->wid >= 0) + inotify_rm_watch(clients_fd, ent->wid); + free_ent(ent); +} + +static void check_id(unsigned long id) +{ + struct ent key = {.num = id}; + struct ent **e, *ent; + + e = tfind(&key, &tree_root, ent_cmp); + if (!e || !*e) + return; + ent = *e; + if (ent->unconfirmed) + read_info(ent); +} + +int v4clients_process(fd_set *fdset) +{ + char buf[4096] __attribute__((aligned(__alignof__(struct inotify_event)))); + const struct inotify_event *ev; + ssize_t len; + char *ptr; + + if (clients_fd < 0 || + !FD_ISSET(clients_fd, fdset)) + return 0; + + while ((len = read(clients_fd, buf, sizeof(buf))) > 0) { + for (ptr = buf; ptr < buf + len; + ptr += sizeof(struct inotify_event) + ev->len) { + int id; + ev = (const struct inotify_event *)ptr; + + id = atoi(ev->name); + if (id <= 0) + continue; + if (ev->mask & IN_CREATE) + add_id(id); + if (ev->mask & IN_DELETE) + del_id(id); + if (ev->mask & IN_MODIFY) + check_id(id); + } + } + return 1; +} diff --git a/support/export/v4root.c b/support/export/v4root.c new file mode 100644 index 0000000..03805dc --- /dev/null +++ b/support/export/v4root.c @@ -0,0 +1,233 @@ +/* + * Copyright (C) 2009 Red Hat <nfs@redhat.com> + * + * support/export/v4root.c + * + * Routines used to support NFSv4 pseudo roots + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/queue.h> +#include <stdio.h> +#include <stdlib.h> +#include <ctype.h> + +#include <unistd.h> +#include <errno.h> +#include <uuid/uuid.h> + +#include "xlog.h" +#include "exportfs.h" +#include "nfslib.h" +#include "misc.h" +#include "v4root.h" +#include "pseudoflavors.h" + +static nfs_export pseudo_root = { + .m_next = NULL, + .m_client = NULL, + .m_export = { + .e_hostname = "*", + .e_path = "/", + .e_flags = NFSEXP_READONLY + | NFSEXP_NOSUBTREECHECK | NFSEXP_FSID + | NFSEXP_V4ROOT | NFSEXP_INSECURE_PORT, + .e_anonuid = 65534, + .e_anongid = 65534, + .e_squids = NULL, + .e_nsquids = 0, + .e_sqgids = NULL, + .e_nsqgids = 0, + .e_fsid = 0, + .e_mountpoint = NULL, + .e_ttl = 0, + }, + .m_exported = 0, + .m_xtabent = 1, + .m_mayexport = 1, + .m_changed = 0, + .m_warned = 0, +}; + +static void +set_pseudofs_security(struct exportent *pseudo) +{ + struct flav_info *flav; + int i; + + for (flav = flav_map; flav < flav_map + flav_map_size; flav++) { + struct sec_entry *new; + + if (!flav->fnum) + continue; + if (flav->need_krb5 && access("/etc/krb5.keytab", F_OK) != 0) + continue; + + i = secinfo_addflavor(flav, pseudo); + new = &pseudo->e_secinfo[i]; + + new->flags |= NFSEXP_INSECURE_PORT; + } +} + +/* + * Create a pseudo export + */ +static struct exportent * +v4root_create(char *path, nfs_export *export) +{ + nfs_export *exp; + struct exportent eep; + struct exportent *curexp = &export->m_export; + + dupexportent(&eep, &pseudo_root.m_export); + eep.e_ttl = default_ttl; + eep.e_hostname = curexp->e_hostname; + strncpy(eep.e_path, path, sizeof(eep.e_path)-1); + if (strcmp(path, "/") != 0) + eep.e_flags &= ~NFSEXP_FSID; + + if (strcmp(path, "/") != 0 && + !export_test(&eep, 0)) { + /* Need a uuid - base it on path using a fixed seed that + * was generated randomly. + */ + const char seed_s[] = "39c6b5c1-3f24-4f4e-977c-7fe6546b8a25"; + uuid_t seed, uuid; + char uuid_s[UUID_STR_LEN]; + unsigned int i, j; + + uuid_parse(seed_s, seed); + uuid_generate_sha1(uuid, seed, path, strlen(path)); + uuid_unparse_upper(uuid, uuid_s); + /* strip hyhens */ + for (i = j = 0; uuid_s[i]; i++) + if (uuid_s[i] != '-') + uuid_s[j++] = uuid_s[i]; + eep.e_uuid = uuid_s; + } + set_pseudofs_security(&eep); + exp = export_create(&eep, 0); + if (exp == NULL) + return NULL; + xlog(D_CALL, "v4root_create: path '%s' flags 0x%x", + exp->m_export.e_path, exp->m_export.e_flags); + return &exp->m_export; +} + +/* + * Make sure the kernel has pseudo root support. + */ +static int +v4root_support(void) +{ + struct export_features *ef; + static int warned = 0; + + ef = get_export_features(); + + if (ef->flags & NFSEXP_V4ROOT) + return 1; + if (!warned) { + xlog(L_WARNING, "Kernel does not have pseudo root support."); + xlog(L_WARNING, "NFS v4 mounts will be disabled unless fsid=0"); + xlog(L_WARNING, "is specfied in /etc/exports file."); + warned++; + } + return 0; +} + +static int +pseudofs_update(char *hostname, char *path, nfs_export *source) +{ + nfs_export *exp; + + exp = export_lookup(hostname, path, 0); + if (exp && !(exp->m_export.e_flags & NFSEXP_V4ROOT)) + return 0; + if (!exp) { + if (v4root_create(path, source) == NULL) { + xlog(L_WARNING, "v4root_set: Unable to create " + "pseudo export for '%s'", path); + return -ENOMEM; + } + return 0; + } + /* Update an existing V4ROOT export: */ + set_pseudofs_security(&exp->m_export); + return 0; +} + +static int v4root_add_parents(nfs_export *exp) +{ + char *hostname = exp->m_export.e_hostname; + char *path; + char *ptr; + int ret = 0; + + path = strdup(exp->m_export.e_path); + if (!path) { + xlog(L_WARNING, "v4root_add_parents: Unable to create " + "pseudo export for '%s'", exp->m_export.e_path); + return -ENOMEM; + } + for (ptr = path; ptr; ptr = strchr(ptr, '/')) { + char saved; + + saved = *ptr; + *ptr = '\0'; + ret = pseudofs_update(hostname, *path ? path : "/", exp); + if (ret) + break; + *ptr = saved; + ptr++; + } + free(path); + return ret; +} + +/* + * Create pseudo exports by running through the real export + * looking at the components of the path that make up the export. + * Those path components, if not exported, will become pseudo + * exports allowing them to be found when the kernel does an upcall + * looking for components of the v4 mount. + */ +void +v4root_set(void) +{ + nfs_export *exp; + int i; + + if (!v4root_needed) + return; + if (!v4root_support()) + return; + + for (i = 0; i < MCL_MAXTYPES; i++) { + for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { + if (exp->m_export.e_flags & NFSEXP_V4ROOT) + /* + * We just added this one, so its + * parents are already dealt with! + */ + continue; + + if (strcmp(exp->m_export.e_path, "/") == 0 && + !(exp->m_export.e_flags & NFSEXP_FSID)) { + /* Force '/' to be exported as fsid == 0*/ + exp->m_export.e_flags |= NFSEXP_FSID; + exp->m_export.e_fsid = 0; + } + + v4root_add_parents(exp); + /* XXX: error handling! */ + } + } +} diff --git a/support/export/xtab.c b/support/export/xtab.c new file mode 100644 index 0000000..e210ca9 --- /dev/null +++ b/support/export/xtab.c @@ -0,0 +1,256 @@ +/* + * support/export/xtab.c + * + * Interface to the etab/exports file. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <fcntl.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <errno.h> +#include <libgen.h> + +#include "nfslib.h" +#include "exportfs.h" +#include "xio.h" +#include "xlog.h" +#include "v4root.h" +#include "misc.h" + +static char state_base_dirname[PATH_MAX] = NFS_STATEDIR; +struct state_paths etab; + +int v4root_needed; +static void cond_rename(char *newfile, char *oldfile); + +static int +xtab_read(char *xtab, char *lockfn, int is_export) +{ + /* is_export == 0 => reading /proc/fs/nfs/exports - we know these things are exported to kernel + * is_export == 1 => reading /var/lib/nfs/etab - these things are allowed to be exported + */ + struct exportent *xp; + nfs_export *exp; + int lockid; + + if ((lockid = xflock(lockfn, "r")) < 0) + return 0; + setexportent(xtab, "r"); + if (is_export == 1) + v4root_needed = 1; + while ((xp = getexportent(is_export==0, 0)) != NULL) { + if (!(exp = export_lookup(xp->e_hostname, xp->e_path, is_export != 1)) && + !(exp = export_create(xp, is_export!=1))) { + if(xp->e_hostname) { + free(xp->e_hostname); + xp->e_hostname=NULL; + } + if(xp->e_uuid) { + free(xp->e_uuid); + xp->e_uuid=NULL; + } + continue; + } + switch (is_export) { + case 0: + exp->m_exported = 1; + break; + case 1: + exp->m_xtabent = 1; + exp->m_mayexport = 1; + if ((xp->e_flags & NFSEXP_FSID) && xp->e_fsid == 0) + v4root_needed = 0; + break; + } + if(xp->e_hostname) { + free(xp->e_hostname); + xp->e_hostname=NULL; + } + if(xp->e_uuid) { + free(xp->e_uuid); + xp->e_uuid=NULL; + } + + } + endexportent(); + xfunlock(lockid); + + return 0; +} + +int +xtab_export_read(void) +{ + return xtab_read(etab.statefn, etab.lockfn, 1); +} + +/* + * mountd now keeps an open fd for the etab at all times to make sure that the + * inode number changes when the xtab_export_write is done. If you change the + * routine below such that the files are edited in place, then you'll need to + * fix the auth_reload logic as well... + */ +static int +xtab_write(char *xtab, char *xtabtmp, char *lockfn, int is_export) +{ + struct exportent xe; + nfs_export *exp; + int lockid, i; + + if ((lockid = xflock(lockfn, "w")) < 0) { + xlog(L_ERROR, "can't lock %s for writing", xtab); + return 0; + } + setexportent(xtabtmp, "w"); + + for (i = 0; i < MCL_MAXTYPES; i++) { + for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { + if (is_export && !exp->m_xtabent) + continue; + if (!is_export && ! exp->m_exported) + continue; + + /* write out the export entry using the FQDN */ + xe = exp->m_export; + xe.e_hostname = exp->m_client->m_hostname; + putexportent(&xe); + } + } + endexportent(); + + cond_rename(xtabtmp, xtab); + + xfunlock(lockid); + + return 1; +} + +int +xtab_export_write(void) +{ + return xtab_write(etab.statefn, etab.tmpfn, etab.lockfn, 1); +} + +/* + * rename newfile onto oldfile unless + * they are identical + */ +static void cond_rename(char *newfile, char *oldfile) +{ + int nfd, ofd; + char nbuf[4096], obuf[4096]; + int ncnt, ocnt; + + nfd = open(newfile, 0); + if (nfd < 0) + return; + ofd = open(oldfile, 0); + if (ofd < 0) { + close(nfd); + rename(newfile, oldfile); + return; + } + + do { + ncnt = read(nfd, nbuf, sizeof(nbuf)); + if (ncnt < 0) + break; + ocnt = read(ofd, obuf, sizeof(obuf)); + if (ocnt < 0) + break; + if (ncnt != ocnt) + break; + if (ncnt == 0) { + close(nfd); + close(ofd); + unlink(newfile); + return; + } + } while (memcmp(obuf, nbuf, ncnt) == 0); + + /* some mis-match */ + close(nfd); + close(ofd); + rename(newfile, oldfile); + return; +} + +/* + * Returns a dynamically allocated, '\0'-terminated buffer + * containing an appropriate pathname, or NULL if an error + * occurs. Caller must free the returned result with free(3). + */ +static char * +state_make_pathname(const char *tabname) +{ + return generic_make_pathname(state_base_dirname, tabname); +} + +/** + * state_setup_basedir - set up basedir + * @progname: C string containing name of program, for error messages + * @parentdir: C string containing pathname to on-disk state, or NULL + * + * This runs before logging is set up, so error messages are directed + * to stderr. + * + * Returns true and sets up our basedir, if @parentdir was valid + * and usable; otherwise false is returned. + */ +_Bool +state_setup_basedir(const char *progname, const char *parentdir) +{ + return generic_setup_basedir(progname, parentdir, state_base_dirname, + PATH_MAX); +} + +int +setup_state_path_names(const char *progname, const char *statefn, + const char *tmpfn, const char *lockfn, + struct state_paths *paths) +{ + paths->statefn = state_make_pathname(statefn); + if (!paths->statefn) { + fprintf(stderr, "%s: state_make_pathname(%s) failed\n", + progname, statefn); + goto out_err; + } + paths->tmpfn = state_make_pathname(tmpfn); + if (!paths->tmpfn) { + fprintf(stderr, "%s: state_make_pathname(%s) failed\n", + progname, tmpfn); + goto out_free_statefn; + } + paths->lockfn = state_make_pathname(lockfn); + if (!paths->lockfn) { + fprintf(stderr, "%s: state_make_pathname(%s) failed\n", + progname, lockfn); + goto out_free_tmpfn; + } + return 1; + +out_free_tmpfn: + free(paths->tmpfn); +out_free_statefn: + free(paths->statefn); +out_err: + return 0; + +} + +void +free_state_path_names(struct state_paths *paths) +{ + free(paths->statefn); + free(paths->tmpfn); + free(paths->lockfn); +} diff --git a/support/include/Makefile.am b/support/include/Makefile.am new file mode 100644 index 0000000..1373891 --- /dev/null +++ b/support/include/Makefile.am @@ -0,0 +1,31 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = nfs rpcsvc sys + +noinst_HEADERS = \ + cld.h \ + exportfs.h \ + ha-callout.h \ + junction.h \ + misc.h \ + nfs_mntent.h \ + nfs_paths.h \ + nfsd_path.h \ + nfslib.h \ + nfsrpc.h \ + nls.h \ + nsm.h \ + pseudoflavors.h \ + rpcmisc.h \ + sockaddr.h \ + tcpwrapper.h \ + v4root.h \ + workqueue.h \ + xio.h \ + xlog.h \ + xmalloc.h \ + xcommon.h \ + xstat.h \ + conffile.h + +MAINTAINERCLEANFILES = Makefile.in diff --git a/support/include/Makefile.in b/support/include/Makefile.in new file mode 100644 index 0000000..9dc7624 --- /dev/null +++ b/support/include/Makefile.in @@ -0,0 +1,760 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = support/include +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ax_gcc_func_attribute.m4 \ + $(top_srcdir)/aclocal/bsdsignals.m4 \ + $(top_srcdir)/aclocal/getrandom.m4 \ + $(top_srcdir)/aclocal/ipv6.m4 \ + $(top_srcdir)/aclocal/kerberos5.m4 \ + $(top_srcdir)/aclocal/keyutils.m4 \ + $(top_srcdir)/aclocal/libblkid.m4 \ + $(top_srcdir)/aclocal/libcap.m4 \ + $(top_srcdir)/aclocal/libevent.m4 \ + $(top_srcdir)/aclocal/libpthread.m4 \ + $(top_srcdir)/aclocal/libsqlite3.m4 \ + $(top_srcdir)/aclocal/libtirpc.m4 \ + $(top_srcdir)/aclocal/libxml2.m4 \ + $(top_srcdir)/aclocal/nfs-utils.m4 \ + $(top_srcdir)/aclocal/rpcsec_vers.m4 \ + $(top_srcdir)/aclocal/tcp-wrappers.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) \ + config.h.in +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GREP = @GREP@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GSSD = @GSSD@ +GSSGLUE_CFLAGS = @GSSGLUE_CFLAGS@ +GSSGLUE_LIBS = @GSSGLUE_LIBS@ +GSSKRB_CFLAGS = @GSSKRB_CFLAGS@ +GSSKRB_LIBS = @GSSKRB_LIBS@ +HAVE_GETRANDOM = @HAVE_GETRANDOM@ +HAVE_LIBWRAP = @HAVE_LIBWRAP@ +HAVE_TCP_WRAPPER = @HAVE_TCP_WRAPPER@ +IDMAPD = @IDMAPD@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +K5VERS = @K5VERS@ +KRBCFLAGS = @KRBCFLAGS@ +KRBDIR = @KRBDIR@ +KRBLDFLAGS = @KRBLDFLAGS@ +KRBLIBS = @KRBLIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ +LIBBLKID = @LIBBLKID@ +LIBBSD = @LIBBSD@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBEVENT = @LIBEVENT@ +LIBKEYUTILS = @LIBKEYUTILS@ +LIBMOUNT = @LIBMOUNT@ +LIBMOUNT_CFLAGS = @LIBMOUNT_CFLAGS@ +LIBMOUNT_LIBS = @LIBMOUNT_LIBS@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPTHREAD = @LIBPTHREAD@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSQLITE = @LIBSQLITE@ +LIBTIRPC = @LIBTIRPC@ +LIBTOOL = @LIBTOOL@ +LIBWRAP = @LIBWRAP@ +LIBXML2 = @LIBXML2@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_PLUGINS = @PATH_PLUGINS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +RELEASE = @RELEASE@ +RPCGEN_PATH = @RPCGEN_PATH@ +RPCSECGSS_CFLAGS = @RPCSECGSS_CFLAGS@ +RPCSECGSS_LIBS = @RPCSECGSS_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SVCGSSD = @SVCGSSD@ +TIRPC_CFLAGS = @TIRPC_CFLAGS@ +TIRPC_LIBS = @TIRPC_LIBS@ +VERSION = @VERSION@ +XML2_CFLAGS = @XML2_CFLAGS@ +XML2_LIBS = @XML2_LIBS@ +_rpc_pipefsmount = @_rpc_pipefsmount@ +_statedir = @_statedir@ +_sysconfdir = @_sysconfdir@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_gss = @enable_gss@ +enable_ipv6 = @enable_ipv6@ +enable_mountconfig = @enable_mountconfig@ +enable_nfsv4 = @enable_nfsv4@ +enable_nfsv41 = @enable_nfsv41@ +enable_svcgss = @enable_svcgss@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +kprefix = @kprefix@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +mountfile = @mountfile@ +nfsconfig = @nfsconfig@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rpc_pipefsmount = @rpc_pipefsmount@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +startstatd = @startstatd@ +statdpath = @statdpath@ +statduser = @statduser@ +statedir = @statedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +unitdir = @unitdir@ +SUBDIRS = nfs rpcsvc sys +noinst_HEADERS = \ + cld.h \ + exportfs.h \ + ha-callout.h \ + junction.h \ + misc.h \ + nfs_mntent.h \ + nfs_paths.h \ + nfsd_path.h \ + nfslib.h \ + nfsrpc.h \ + nls.h \ + nsm.h \ + pseudoflavors.h \ + rpcmisc.h \ + sockaddr.h \ + tcpwrapper.h \ + v4root.h \ + workqueue.h \ + xio.h \ + xlog.h \ + xmalloc.h \ + xcommon.h \ + xstat.h \ + conffile.h + +MAINTAINERCLEANFILES = Makefile.in +all: config.h + $(MAKE) $(AM_MAKEFLAGS) all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu support/include/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu support/include/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +config.h: stamp-h1 + @test -f $@ || rm -f stamp-h1 + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1 + +stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status + @rm -f stamp-h1 + cd $(top_builddir) && $(SHELL) ./config.status support/include/config.h +$(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + ($(am__cd) $(top_srcdir) && $(AUTOHEADER)) + rm -f stamp-h1 + touch $@ + +distclean-hdr: + -rm -f config.h stamp-h1 + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(HEADERS) config.h +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-hdr distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(am__recursive_targets) all install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-generic distclean-hdr \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/support/include/cld.h b/support/include/cld.h new file mode 100644 index 0000000..88d3b63 --- /dev/null +++ b/support/include/cld.h @@ -0,0 +1,94 @@ +/* + * Upcall description for nfsdcld communication + * + * Copyright (c) 2012 Red Hat, Inc. + * Author(s): Jeff Layton <jlayton@redhat.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + */ + +#ifndef _NFSD_CLD_H +#define _NFSD_CLD_H + +/* latest upcall version available */ +#define CLD_UPCALL_VERSION 2 + +/* defined by RFC3530 */ +#define NFS4_OPAQUE_LIMIT 1024 + +#ifndef SHA256_DIGEST_SIZE +#define SHA256_DIGEST_SIZE 32 +#endif + +enum cld_command { + Cld_Create, /* create a record for this cm_id */ + Cld_Remove, /* remove record of this cm_id */ + Cld_Check, /* is this cm_id allowed? */ + Cld_GraceDone, /* grace period is complete */ + Cld_GraceStart, /* grace start (upload client records) */ + Cld_GetVersion, /* query max supported upcall version */ +}; + +/* representation of long-form NFSv4 client ID */ +struct cld_name { + uint16_t cn_len; /* length of cm_id */ + unsigned char cn_id[NFS4_OPAQUE_LIMIT]; /* client-provided */ +} __attribute__((packed)); + +/* sha256 hash of the kerberos principal */ +struct cld_princhash { + uint8_t cp_len; /* length of cp_data */ + unsigned char cp_data[SHA256_DIGEST_SIZE]; /* hash of principal */ +} __attribute__((packed)); + +struct cld_clntinfo { + struct cld_name cc_name; + struct cld_princhash cc_princhash; +} __attribute__((packed)); + +/* message struct for communication with userspace */ +struct cld_msg { + uint8_t cm_vers; /* upcall version */ + uint8_t cm_cmd; /* upcall command */ + int16_t cm_status; /* return code */ + uint32_t cm_xid; /* transaction id */ + union { + int64_t cm_gracetime; /* grace period start time */ + struct cld_name cm_name; + uint8_t cm_version; /* for getting max version */ + } __attribute__((packed)) cm_u; +} __attribute__((packed)); + +/* version 2 message can include hash of kerberos principal */ +struct cld_msg_v2 { + uint8_t cm_vers; /* upcall version */ + uint8_t cm_cmd; /* upcall command */ + int16_t cm_status; /* return code */ + uint32_t cm_xid; /* transaction id */ + union { + struct cld_name cm_name; + uint8_t cm_version; /* for getting max version */ + struct cld_clntinfo cm_clntinfo; /* name & princ hash */ + } __attribute__((packed)) cm_u; +} __attribute__((packed)); + +struct cld_msg_hdr { + uint8_t cm_vers; /* upcall version */ + uint8_t cm_cmd; /* upcall command */ + int16_t cm_status; /* return code */ + uint32_t cm_xid; /* transaction id */ +} __attribute__((packed)); + +#endif /* !_NFSD_CLD_H */ diff --git a/support/include/conffile.h b/support/include/conffile.h new file mode 100644 index 0000000..c4a3ca6 --- /dev/null +++ b/support/include/conffile.h @@ -0,0 +1,87 @@ +/* $OpenBSD: conf.h,v 1.30 2004/06/25 20:25:34 hshoexer Exp $ */ +/* $EOM: conf.h,v 1.13 2000/09/18 00:01:47 ho Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2000, 2003 Håkan Olsson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This code was written under funding by Ericsson Radio Systems. + */ + +#ifndef _CONFFILE_H_ +#define _CONFFILE_H_ + +#include <sys/queue.h> +#include <ctype.h> +#include <stdint.h> +#include <stdbool.h> +#include <stdio.h> + +struct conf_list_node { + TAILQ_ENTRY(conf_list_node) link; + char *field; +}; + +struct conf_list { + size_t cnt; + TAILQ_HEAD(conf_list_fields_head, conf_list_node) fields; +}; + +extern int conf_begin(void); +extern int conf_decode_base64(uint8_t *, uint32_t *, const unsigned char *); +extern int conf_end(int, int); +extern void conf_free_list(struct conf_list *); +extern struct sockaddr *conf_get_address(const char *, const char *); +extern struct conf_list *conf_get_list(const char *, const char *); +extern struct conf_list *conf_get_tag_list(const char *, const char *); +extern int conf_get_num(const char *, const char *, int); +extern _Bool conf_get_bool(const char *, const char *, _Bool); +extern char *conf_get_str(const char *, const char *); +extern char *conf_get_str_with_def(const char *, const char *, char *); +extern char *conf_get_section(const char *, const char *, const char *); +extern char *conf_get_entry(const char *, const char *, const char *); +extern int conf_init_file(const char *); +extern void conf_cleanup(void); +extern int conf_match_num(const char *, const char *, int); +extern int conf_remove(int, const char *, const char *); +extern int conf_remove_section(int, const char *); +extern void conf_report(FILE *); +extern int conf_write(const char *, const char *, const char *, const char *, const char *); + +extern const char *modified_by; + +/* + * Convert letter from upper case to lower case + */ +static inline void upper2lower(char *str) +{ + char c; + + while ((c = tolower(*str))) + *str++ = c; +} + + +#endif /* _CONFFILE_H_ */ diff --git a/support/include/config.h.in b/support/include/config.h.in new file mode 100644 index 0000000..54d6211 --- /dev/null +++ b/support/include/config.h.in @@ -0,0 +1,653 @@ +/* support/include/config.h.in. Generated from configure.ac by autoheader. */ + +/* Define to 1 if the `closedir' function returns void instead of int. */ +#undef CLOSEDIR_VOID + +/* Define to 1 if using 'alloca.c'. */ +#undef C_ALLOCA + +/* Enable GUMS mapping library support */ +#undef ENABLE_GUMS + +/* Enable LDAP Support */ +#undef ENABLE_LDAP + +/* Enable LDAP SASL support */ +#undef ENABLE_LDAP_SASL + +/* Define to the type of elements in the array set by `getgroups'. Usually + this is either `int' or `gid_t'. */ +#undef GETGROUPS_T + +/* Define to 1 if you have the `alarm' function. */ +#undef HAVE_ALARM + +/* Define to 1 if you have 'alloca', as a function or macro. */ +#undef HAVE_ALLOCA + +/* Define to 1 if <alloca.h> works. */ +#undef HAVE_ALLOCA_H + +/* Define to 1 if you have the <arpa/inet.h> header file. */ +#undef HAVE_ARPA_INET_H + +/* Define to 1 if you have the `atexit' function. */ +#undef HAVE_ATEXIT + +/* Define to 1 if your rpcsec library provides authgss_free_private_data */ +#undef HAVE_AUTHGSS_FREE_PRIVATE_DATA + +/* Define this if you want to use BSD signal semantics */ +#undef HAVE_BSD_SIGNALS + +/* Define to 1 if you have the <com_err.h> header file. */ +#undef HAVE_COM_ERR_H + +/* Define to 1 if you have the <dirent.h> header file, and it defines `DIR'. + */ +#undef HAVE_DIRENT_H + +/* Define to 1 if you have the <dlfcn.h> header file. */ +#undef HAVE_DLFCN_H + +/* Define to 1 if you don't have `vprintf' but do have `_doprnt.' */ +#undef HAVE_DOPRNT + +/* Define to 1 if you have the `dup2' function. */ +#undef HAVE_DUP2 + +/* Define to 1 if you have the <et/com_err.h> header file. */ +#undef HAVE_ET_COM_ERR_H + +/* Define to 1 if you have the <event2/event.h> header file. */ +#undef HAVE_EVENT2_EVENT_H + +/* Define to 1 if you have the <fcntl.h> header file. */ +#undef HAVE_FCNTL_H + +/* Define to 1 if you have the `fdatasync' function. */ +#undef HAVE_FDATASYNC + +/* Define to 1 if you have the `find_key_by_type_and_desc' function. */ +#undef HAVE_FIND_KEY_BY_TYPE_AND_DESC + +/* Define to 1 if you have the `fork' function. */ +#undef HAVE_FORK + +/* Define to 1 if you have the `fstatat' function. */ +#undef HAVE_FSTATAT + +/* Define to 1 if you have the `ftruncate' function. */ +#undef HAVE_FTRUNCATE + +/* Define to 1 if the system has the `format' function attribute */ +#undef HAVE_FUNC_ATTRIBUTE_FORMAT + +/* Define to 1 if you have the `getcwd' function. */ +#undef HAVE_GETCWD + +/* Define to 1 if your system has a working `getgroups' function. */ +#undef HAVE_GETGROUPS + +/* Define to 1 if you have the `gethostbyaddr' function. */ +#undef HAVE_GETHOSTBYADDR + +/* Define to 1 if you have the `gethostbyname' function. */ +#undef HAVE_GETHOSTBYNAME + +/* Define to 1 if you have the `gethostname' function. */ +#undef HAVE_GETHOSTNAME + +/* Define to 1 if you have the `getifaddrs' function. */ +#undef HAVE_GETIFADDRS + +/* Define to 1 if you have the `getmntent' function. */ +#undef HAVE_GETMNTENT + +/* Define to 1 if you have the `getnameinfo' function. */ +#undef HAVE_GETNAMEINFO + +/* Define to 1 if you have the `getrandom' function. */ +#undef HAVE_GETRANDOM + +/* Define to 1 if you have the `getrpcbyname' function. */ +#undef HAVE_GETRPCBYNAME + +/* Define to 1 if you have the `getrpcbynumber' function. */ +#undef HAVE_GETRPCBYNUMBER + +/* Define to 1 if you have the `getrpcbynumber_r' function. */ +#undef HAVE_GETRPCBYNUMBER_R + +/* Define to 1 if you have the `gettimeofday' function. */ +#undef HAVE_GETTIMEOFDAY + +/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */ +#undef HAVE_GSSAPI_GSSAPI_GENERIC_H + +/* Define to 1 if you have the <gssapi/gssapi.h> header file. */ +#undef HAVE_GSSAPI_GSSAPI_H + +/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */ +#undef HAVE_GSSAPI_GSSAPI_KRB5_H + +/* Define to 1 if you have the <gssapi.h> header file. */ +#undef HAVE_GSSAPI_H + +/* Define to 1 if you have the <gsssasl.h> header file. */ +#undef HAVE_GSSSASL_H + +/* Has gss_krb5_ccache_name function */ +#undef HAVE_GSS_KRB5_CCACHE_NAME + +/* Define this if the Kerberos GSS library supports + gss_krb5_free_lucid_sec_context */ +#undef HAVE_GSS_KRB5_FREE_LUCID_SEC_CONTEXT + +/* Define to 1 if you have the `hasmntopt' function. */ +#undef HAVE_HASMNTOPT + +/* Define this if you have Heimdal Kerberos libraries */ +#undef HAVE_HEIMDAL + +/* Define to 1 if you have the <ifaddrs.h> header file. */ +#undef HAVE_IFADDRS_H + +/* Define to 1 if you have the `inet_ntoa' function. */ +#undef HAVE_INET_NTOA + +/* Define to 1 if you have the `innetgr' function. */ +#undef HAVE_INNETGR + +/* Define to 1 if you have the <inttypes.h> header file. */ +#undef HAVE_INTTYPES_H + +/* Define this if you want junction support compiled in */ +#undef HAVE_JUNCTION_SUPPORT + +/* Define to 1 if you have the <keyutils.h> header file. */ +#undef HAVE_KEYUTILS_H + +/* Define this if you have MIT Kerberos libraries */ +#undef HAVE_KRB5 + +/* Define this if the function krb5_get_error_message is available */ +#undef HAVE_KRB5_GET_ERROR_MESSAGE + +/* Define this if the function krb5_get_init_creds_opt_set_addressless is + available */ +#undef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS + +/* Define to 1 if you have the <krb5.h> header file. */ +#undef HAVE_KRB5_H + +/* Has ldap_sasl_interactive_bind_s function */ +#undef HAVE_LDAP_SASL_INTERACTIVE_BIND_S + +/* Define to 1 if you have the <libgen.h> header file. */ +#undef HAVE_LIBGEN_H + +/* Define to 1 if you have the `gssglue' library (-lgssglue). */ +#undef HAVE_LIBGSSGLUE + +/* Define to 1 if you have the <libintl.h> header file. */ +#undef HAVE_LIBINTL_H + +/* Define to 1 if you have libpthread. */ +#undef HAVE_LIBPTHREAD + +/* Define to 1 if you have the `resolv' library (-lresolv). */ +#undef HAVE_LIBRESOLV + +/* Define to 1 if you have and wish to use libtirpc. */ +#undef HAVE_LIBTIRPC + +/* Define to 1 if your tirpc library provides libtirpc_set_debug */ +#undef HAVE_LIBTIRPC_SET_DEBUG + +/* tcp-wrapper */ +#undef HAVE_LIBWRAP + +/* Define to 1 if you have and wish to use libxml2. */ +#undef HAVE_LIBXML2 + +/* Define to 1 if you have the <limits.h> header file. */ +#undef HAVE_LIMITS_H + +/* Define to 1 if `lstat' has the bug that it succeeds when given the + zero-length file name argument. */ +#undef HAVE_LSTAT_EMPTY_STRING_BUG + +/* Define this if the Kerberos GSS library supports + gss_krb5_export_lucid_sec_context */ +#undef HAVE_LUCID_CONTEXT_SUPPORT + +/* Define to 1 if you have the <malloc.h> header file. */ +#undef HAVE_MALLOC_H + +/* Define to 1 if you have the <memory.h> header file. */ +#undef HAVE_MEMORY_H + +/* Define to 1 if you have the `memset' function. */ +#undef HAVE_MEMSET + +/* Define to 1 if you have the <minix/config.h> header file. */ +#undef HAVE_MINIX_CONFIG_H + +/* Define to 1 if you have the `mkdir' function. */ +#undef HAVE_MKDIR + +/* Define to 1 if you have the `name_to_handle_at' function. */ +#undef HAVE_NAME_TO_HANDLE_AT + +/* Define to 1 if you have the <ndir.h> header file, and it defines `DIR'. */ +#undef HAVE_NDIR_H + +/* Define to 1 if you have the <netdb.h> header file. */ +#undef HAVE_NETDB_H + +/* Define to 1 if you have the <netinet/in.h> header file. */ +#undef HAVE_NETINET_IN_H + +/* Bundled lib always has the `nfs4_set_debug' function. */ +#undef HAVE_NFS4_SET_DEBUG + +/* Define this if you want NFSv4 server only support compiled in */ +#undef HAVE_NFSV4SERVER_SUPPORT + +/* Define to 1 if you have the `pathconf' function. */ +#undef HAVE_PATHCONF + +/* Define to 1 if you have the <paths.h> header file. */ +#undef HAVE_PATHS_H + +/* Define to 1 if you have the `ppoll' function. */ +#undef HAVE_PPOLL + +/* Define to 1 if you have the <pthread.h> header file. */ +#undef HAVE_PTHREAD_H + +/* Define to 1 if you have the `realpath' function. */ +#undef HAVE_REALPATH + +/* Define to 1 if you have the `rmdir' function. */ +#undef HAVE_RMDIR + +/* Define to 1 if you have the <sasl.h> header file. */ +#undef HAVE_SASL_H + +/* Define to 1 if you have the <sasl/sasl.h> header file. */ +#undef HAVE_SASL_SASL_H + +/* Define to 1 if you have the <sched.h> header file. */ +#undef HAVE_SCHED_H + +/* Define to 1 if you have the `select' function. */ +#undef HAVE_SELECT + +/* Define this if the Kerberos GSS library supports + gss_krb5_set_allowable_enctypes */ +#undef HAVE_SET_ALLOWABLE_ENCTYPES + +/* Define to 1 if you have the `sigprocmask' function. */ +#undef HAVE_SIGPROCMASK + +/* Define to 1 if you have the `socket' function. */ +#undef HAVE_SOCKET + +/* Define to 1 if you have the <sqlite3.h> header file. */ +#undef HAVE_SQLITE3_H + +/* Define to 1 if you have the `statx' function. */ +#undef HAVE_STATX + +/* Define to 1 if `stat' has the bug that it succeeds when given the + zero-length file name argument. */ +#undef HAVE_STAT_EMPTY_STRING_BUG + +/* Define to 1 if you have the <stdint.h> header file. */ +#undef HAVE_STDINT_H + +/* Define to 1 if you have the <stdio.h> header file. */ +#undef HAVE_STDIO_H + +/* Define to 1 if you have the <stdlib.h> header file. */ +#undef HAVE_STDLIB_H + +/* Define to 1 if you have the `strcasecmp' function. */ +#undef HAVE_STRCASECMP + +/* Define to 1 if you have the `strchr' function. */ +#undef HAVE_STRCHR + +/* Define to 1 if you have the `strdup' function. */ +#undef HAVE_STRDUP + +/* Define to 1 if you have the `strerror' function. */ +#undef HAVE_STRERROR + +/* Define to 1 if you have the <strings.h> header file. */ +#undef HAVE_STRINGS_H + +/* Define to 1 if you have the <string.h> header file. */ +#undef HAVE_STRING_H + +/* Define to 1 if you have the `strrchr' function. */ +#undef HAVE_STRRCHR + +/* Define to 1 if you have the `strtol' function. */ +#undef HAVE_STRTOL + +/* Define to 1 if you have the `strtoul' function. */ +#undef HAVE_STRTOUL + +/* Define to 1 if the system has the type `struct file_handle'. */ +#undef HAVE_STRUCT_FILE_HANDLE + +/* Define to 1 if you have the <syslog.h> header file. */ +#undef HAVE_SYSLOG_H + +/* Define to 1 if you have the <sys/capability.h> header file. */ +#undef HAVE_SYS_CAPABILITY_H + +/* Define to 1 if you have the <sys/dir.h> header file, and it defines `DIR'. + */ +#undef HAVE_SYS_DIR_H + +/* Define to 1 if you have the <sys/file.h> header file. */ +#undef HAVE_SYS_FILE_H + +/* Define to 1 if you have the <sys/inotify.h> header file. */ +#undef HAVE_SYS_INOTIFY_H + +/* Define to 1 if you have the <sys/ioctl.h> header file. */ +#undef HAVE_SYS_IOCTL_H + +/* Define to 1 if you have the <sys/mount.h> header file. */ +#undef HAVE_SYS_MOUNT_H + +/* Define to 1 if you have the <sys/ndir.h> header file, and it defines `DIR'. + */ +#undef HAVE_SYS_NDIR_H + +/* Define to 1 if you have the <sys/param.h> header file. */ +#undef HAVE_SYS_PARAM_H + +/* Define to 1 if you have the <sys/select.h> header file. */ +#undef HAVE_SYS_SELECT_H + +/* Define to 1 if you have the <sys/socket.h> header file. */ +#undef HAVE_SYS_SOCKET_H + +/* Define to 1 if you have the <sys/stat.h> header file. */ +#undef HAVE_SYS_STAT_H + +/* Define to 1 if you have the <sys/time.h> header file. */ +#undef HAVE_SYS_TIME_H + +/* Define to 1 if you have the <sys/types.h> header file. */ +#undef HAVE_SYS_TYPES_H + +/* Define to 1 if you have the <sys/vfs.h> header file. */ +#undef HAVE_SYS_VFS_H + +/* tcp-wrapper */ +#undef HAVE_TCP_WRAPPER + +/* Define to 1 if you have the <unistd.h> header file. */ +#undef HAVE_UNISTD_H + +/* Define to 1 if you have the `unshare' function. */ +#undef HAVE_UNSHARE + +/* Define to 1 if you have the `vfork' function. */ +#undef HAVE_VFORK + +/* Define to 1 if you have the <vfork.h> header file. */ +#undef HAVE_VFORK_H + +/* Define to 1 if you have the `vprintf' function. */ +#undef HAVE_VPRINTF + +/* Define to 1 if you have the <wchar.h> header file. */ +#undef HAVE_WCHAR_H + +/* Define to 1 if `fork' works. */ +#undef HAVE_WORKING_FORK + +/* Define to 1 if `vfork' works. */ +#undef HAVE_WORKING_VFORK + +/* Define this if you want IPv6 support compiled in */ +#undef IPV6_SUPPORTED + +/* Define this as the Kerberos version number */ +#undef KRB5_VERSION + +/* tcp-wrapper */ +#undef LIBWRAP + +/* Define to 1 if `lstat' dereferences a symlink specified with a trailing + slash. */ +#undef LSTAT_FOLLOWS_SLASHED_SYMLINK + +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#undef LT_OBJDIR + +/* Define to 1 if `major', `minor', and `makedev' are declared in <mkdev.h>. + */ +#undef MAJOR_IN_MKDEV + +/* Define to 1 if `major', `minor', and `makedev' are declared in + <sysmacros.h>. */ +#undef MAJOR_IN_SYSMACROS + +/* This defines the location of the NFS mount configuration file */ +#undef MOUNTOPTS_CONFFILE + +/* Define this if you want mount to read a configuration file */ +#undef MOUNT_CONFIG + +/* This defines the location of NFS daemon config file */ +#undef NFS_CONFFILE + +/* This defines the location of the NFS state files. Warning: this must match + definitions in config.mk! */ +#undef NFS_STATEDIR + +/* Define this to the pathname where statd keeps its state file */ +#undef NSM_DEFAULT_STATEDIR + +/* Name of package */ +#undef PACKAGE + +/* Define to the address where bug reports for this package should be sent. */ +#undef PACKAGE_BUGREPORT + +/* Define to the full name of this package. */ +#undef PACKAGE_NAME + +/* Define to the full name and version of this package. */ +#undef PACKAGE_STRING + +/* Define to the one symbol short name of this package. */ +#undef PACKAGE_TARNAME + +/* Define to the home page for this package. */ +#undef PACKAGE_URL + +/* Define to the version of this package. */ +#undef PACKAGE_VERSION + +/* Define this to change the plugins path */ +#undef PATH_PLUGINS + +/* Define to the type of arg 1 for `select'. */ +#undef SELECT_TYPE_ARG1 + +/* Define to the type of args 2, 3 and 4 for `select'. */ +#undef SELECT_TYPE_ARG234 + +/* Define to the type of arg 5 for `select'. */ +#undef SELECT_TYPE_ARG5 + +/* The size of `int', as computed by sizeof. */ +#undef SIZEOF_INT + +/* The size of `long', as computed by sizeof. */ +#undef SIZEOF_LONG + +/* The size of `short', as computed by sizeof. */ +#undef SIZEOF_SHORT + +/* The size of `size_t', as computed by sizeof. */ +#undef SIZEOF_SIZE_T + +/* The size of `socklen_t', as computed by sizeof. */ +#undef SIZEOF_SOCKLEN_T + +/* If using the C implementation of alloca, define if you know the + direction of stack growth for your system; otherwise it will be + automatically deduced at runtime. + STACK_DIRECTION > 0 => grows toward higher addresses + STACK_DIRECTION < 0 => grows toward lower addresses + STACK_DIRECTION = 0 => direction of growth unknown */ +#undef STACK_DIRECTION + +/* Define this to a script which can start statd on mount */ +#undef START_STATD + +/* Define to 1 if all of the C90 standard headers exist (not just the ones + required in a freestanding environment). This macro is provided for + backward compatibility; new code need not use it. */ +#undef STDC_HEADERS + +/* Define to 1 if your <sys/time.h> declares `struct tm'. */ +#undef TM_IN_SYS_TIME + +/* Define if you want to use blkid to find uuid of filesystems */ +#undef USE_BLKID + +/* Enable extensions on AIX 3, Interix. */ +#ifndef _ALL_SOURCE +# undef _ALL_SOURCE +#endif +/* Enable general extensions on macOS. */ +#ifndef _DARWIN_C_SOURCE +# undef _DARWIN_C_SOURCE +#endif +/* Enable general extensions on Solaris. */ +#ifndef __EXTENSIONS__ +# undef __EXTENSIONS__ +#endif +/* Enable GNU extensions on systems that have them. */ +#ifndef _GNU_SOURCE +# undef _GNU_SOURCE +#endif +/* Enable X/Open compliant socket functions that do not require linking + with -lxnet on HP-UX 11.11. */ +#ifndef _HPUX_ALT_XOPEN_SOCKET_API +# undef _HPUX_ALT_XOPEN_SOCKET_API +#endif +/* Identify the host operating system as Minix. + This macro does not affect the system headers' behavior. + A future release of Autoconf may stop defining this macro. */ +#ifndef _MINIX +# undef _MINIX +#endif +/* Enable general extensions on NetBSD. + Enable NetBSD compatibility extensions on Minix. */ +#ifndef _NETBSD_SOURCE +# undef _NETBSD_SOURCE +#endif +/* Enable OpenBSD compatibility extensions on NetBSD. + Oddly enough, this does nothing on OpenBSD. */ +#ifndef _OPENBSD_SOURCE +# undef _OPENBSD_SOURCE +#endif +/* Define to 1 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_SOURCE +# undef _POSIX_SOURCE +#endif +/* Define to 2 if needed for POSIX-compatible behavior. */ +#ifndef _POSIX_1_SOURCE +# undef _POSIX_1_SOURCE +#endif +/* Enable POSIX-compatible threading on Solaris. */ +#ifndef _POSIX_PTHREAD_SEMANTICS +# undef _POSIX_PTHREAD_SEMANTICS +#endif +/* Enable extensions specified by ISO/IEC TS 18661-5:2014. */ +#ifndef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ +# undef __STDC_WANT_IEC_60559_ATTRIBS_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TS 18661-1:2014. */ +#ifndef __STDC_WANT_IEC_60559_BFP_EXT__ +# undef __STDC_WANT_IEC_60559_BFP_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TS 18661-2:2015. */ +#ifndef __STDC_WANT_IEC_60559_DFP_EXT__ +# undef __STDC_WANT_IEC_60559_DFP_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TS 18661-4:2015. */ +#ifndef __STDC_WANT_IEC_60559_FUNCS_EXT__ +# undef __STDC_WANT_IEC_60559_FUNCS_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TS 18661-3:2015. */ +#ifndef __STDC_WANT_IEC_60559_TYPES_EXT__ +# undef __STDC_WANT_IEC_60559_TYPES_EXT__ +#endif +/* Enable extensions specified by ISO/IEC TR 24731-2:2010. */ +#ifndef __STDC_WANT_LIB_EXT2__ +# undef __STDC_WANT_LIB_EXT2__ +#endif +/* Enable extensions specified by ISO/IEC 24747:2009. */ +#ifndef __STDC_WANT_MATH_SPEC_FUNCS__ +# undef __STDC_WANT_MATH_SPEC_FUNCS__ +#endif +/* Enable extensions on HP NonStop. */ +#ifndef _TANDEM_SOURCE +# undef _TANDEM_SOURCE +#endif +/* Enable X/Open extensions. Define to 500 only if necessary + to make mbstate_t available. */ +#ifndef _XOPEN_SOURCE +# undef _XOPEN_SOURCE +#endif + + +/* Version number of package */ +#undef VERSION + +/* Number of bits in a file offset, on hosts where this is settable. */ +#undef _FILE_OFFSET_BITS + +/* Define for large files, on AIX-style hosts. */ +#undef _LARGE_FILES + +/* Define to empty if `const' does not conform to ANSI C. */ +#undef const + +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef gid_t + +/* Define to `__inline__' or `__inline' if that's what the C compiler + calls it, or to nothing if 'inline' is not supported under any name. */ +#ifndef __cplusplus +#undef inline +#endif + +/* Define to `long int' if <sys/types.h> does not define. */ +#undef off_t + +/* Define as a signed integer type capable of holding a process identifier. */ +#undef pid_t + +/* Define to `unsigned int' if <sys/types.h> does not define. */ +#undef size_t + +/* Define to `int' if <sys/types.h> doesn't define. */ +#undef uid_t + +/* Define as `fork' if `vfork' does not work. */ +#undef vfork diff --git a/support/include/exportfs.h b/support/include/exportfs.h new file mode 100644 index 0000000..9edf0d0 --- /dev/null +++ b/support/include/exportfs.h @@ -0,0 +1,179 @@ +/* + * support/include/exportfs.h + * + * Declarations for exportfs and mountd + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#ifndef EXPORTFS_H +#define EXPORTFS_H + +#include <netdb.h> +#include <string.h> + +#include "sockaddr.h" +#include "nfslib.h" + +enum { + MCL_FQDN = 0, + MCL_SUBNETWORK, + MCL_IPADDR = MCL_SUBNETWORK, + MCL_WILDCARD, + MCL_NETGROUP, + MCL_ANONYMOUS, + MCL_GSS, + MCL_MAXTYPES +}; + +enum { + FSLOC_NONE = 0, + FSLOC_REFER, + FSLOC_REPLICA, + FSLOC_STUB +}; + +#ifndef EXP_LOCKFILE +#define EXP_LOCKFILE "/var/lib/nfs/export-lock" +#endif + +typedef struct mclient { + struct mclient * m_next; + char * m_hostname; + int m_type; + int m_naddr; + union nfs_sockaddr m_addrlist[NFSCLNT_ADDRMAX]; + int m_exported; /* exported to nfsd */ + int m_count; +} nfs_client; + +static inline const struct sockaddr * +get_addrlist(const nfs_client *clp, const int i) +{ + return &clp->m_addrlist[i].sa; +} + +static inline const struct sockaddr_in * +get_addrlist_in(const nfs_client *clp, const int i) +{ + return &clp->m_addrlist[i].s4; +} + +static inline const struct sockaddr_in6 * +get_addrlist_in6(const nfs_client *clp, const int i) +{ + return &clp->m_addrlist[i].s6; +} + +static inline void +set_addrlist_in(nfs_client *clp, const int i, const struct sockaddr_in *sin) +{ + memcpy(&clp->m_addrlist[i].s4, sin, sizeof(*sin)); +} + +static inline void +set_addrlist_in6(nfs_client *clp, const int i, const struct sockaddr_in6 *sin6) +{ + memcpy(&clp->m_addrlist[i].s6, sin6, sizeof(*sin6)); +} + +static inline void +set_addrlist(nfs_client *clp, const int i, const struct sockaddr *sap) +{ + switch (sap->sa_family) { + case AF_INET: + memcpy(&clp->m_addrlist[i].s4, sap, sizeof(struct sockaddr_in)); + break; +#ifdef IPV6_SUPPORTED + case AF_INET6: + memcpy(&clp->m_addrlist[i].s6, sap, sizeof(struct sockaddr_in6)); + break; +#endif + } +} + +typedef struct mexport { + struct mexport * m_next; + struct mclient * m_client; + struct exportent m_export; + int m_exported; /* known to knfsd. */ + unsigned int m_xtabent : 1, /* xtab entry exists */ + m_mayexport: 1, /* derived from xtabbed */ + m_changed : 1, /* options (may) have changed */ + m_warned : 1; /* warned about multiple exports + * matching one client */ +} nfs_export; + +#define HASH_TABLE_SIZE 1021 + +extern int default_ttl; + +typedef struct _exp_hash_entry { + nfs_export * p_first; + nfs_export * p_last; +} exp_hash_entry; + +typedef struct _exp_hash_table { + nfs_export * p_head; + exp_hash_entry entries[HASH_TABLE_SIZE]; +} exp_hash_table; + +extern exp_hash_table exportlist[MCL_MAXTYPES]; + +extern nfs_client * clientlist[MCL_MAXTYPES]; + +nfs_client * client_lookup(char *hname, int canonical); +nfs_client * client_dup(const nfs_client *clp, + const struct addrinfo *ai); +int client_gettype(char *hname); +int client_check(const nfs_client *clp, + const struct addrinfo *ai); +void client_release(nfs_client *); +void client_freeall(void); +char * client_compose(const struct addrinfo *ai); +struct addrinfo * client_resolve(const struct sockaddr *sap); +int client_member(const char *client, + const char *name); + +int export_read(char *fname, int ignore_hosts); +int export_d_read(const char *dname, int ignore_hosts); +void export_reset(nfs_export *); +nfs_export * export_lookup(char *hname, char *path, int caconical); +nfs_export * export_find(const struct addrinfo *ai, + const char *path); +nfs_export * export_create(struct exportent *, int canonical); +void exportent_release(struct exportent *); +void export_freeall(void); + +extern struct state_paths etab; +int xtab_export_read(void); +int xtab_export_write(void); + +int secinfo_addflavor(struct flav_info *, struct exportent *); + +char * host_ntop(const struct sockaddr *sap, + char *buf, const size_t buflen); +__attribute__((__malloc__)) +struct addrinfo * host_pton(const char *paddr); +__attribute__((__malloc__)) +struct addrinfo * host_addrinfo(const char *hostname); +__attribute__((__malloc__)) +char * host_canonname(const struct sockaddr *sap); +__attribute__((__malloc__)) +struct addrinfo * host_reliable_addrinfo(const struct sockaddr *sap); +__attribute__((__malloc__)) +struct addrinfo * host_numeric_addrinfo(const struct sockaddr *sap); + +struct nfskey * key_lookup(char *hname); + +struct export_features { + unsigned int flags; + unsigned int secinfo_flags; +}; + +struct export_features *get_export_features(void); +void fix_pseudoflavor_flags(struct exportent *ep); +char *exportent_realpath(struct exportent *eep); +int export_test(struct exportent *eep, int with_fsid); + +#endif /* EXPORTFS_H */ diff --git a/support/include/fsloc.h b/support/include/fsloc.h new file mode 100644 index 0000000..1605df4 --- /dev/null +++ b/support/include/fsloc.h @@ -0,0 +1,50 @@ +/* + * COPYRIGHT (c) 2006 + * THE REGENTS OF THE UNIVERSITY OF MICHIGAN + * ALL RIGHTS RESERVED + * + * Permission is granted to use, copy, create derivative works + * and redistribute this software and such derivative works + * for any purpose, so long as the name of The University of + * Michigan is not used in any advertising or publicity + * pertaining to the use of distribution of this software + * without specific, written prior authorization. If the + * above copyright notice or any other identification of the + * University of Michigan is included in any copy of any + * portion of this software, then the disclaimer below must + * also be included. + * + * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION + * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY + * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF + * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING + * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE + * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE + * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR + * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING + * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN + * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGES. + */ + +#ifndef FSLOC_H +#define FSLOC_H + +#define FSLOC_MAX_LIST 40 + +struct mount_point { + char *h_host; + char *h_path; +}; + +struct servers { + int h_num; + struct mount_point *h_mp[FSLOC_MAX_LIST]; + int h_referral; /* 0=replica, 1=referral */ +}; + +struct servers *replicas_lookup(int method, char *data); +void release_replicas(struct servers *server); + +#endif /* FSLOC_H */ diff --git a/support/include/ha-callout.h b/support/include/ha-callout.h new file mode 100644 index 0000000..a454bdb --- /dev/null +++ b/support/include/ha-callout.h @@ -0,0 +1,59 @@ +/* + * support/include/ha-callout.h + * + * High Availability NFS Callout support routines + * + * Copyright (c) 2004, Paul Clements, SteelEye Technology + * + * In order to implement HA NFS, we need several callouts at key + * points in statd and mountd. These callouts all come to ha_callout(), + * which, in turn, calls out to an ha-callout script (not part of nfs-utils; + * defined by -H argument to rpc.statd and rpc.mountd). + */ +#ifndef HA_CALLOUT_H +#define HA_CALLOUT_H + +#include <sys/wait.h> +#include <signal.h> + +extern char *ha_callout_prog; + +static inline void +ha_callout(char *event, char *arg1, char *arg2, int arg3) +{ + char buf[16]; /* should be plenty */ + pid_t pid; + int ret = -1; + struct sigaction oldact, newact; + + if (!ha_callout_prog) /* HA callout is not enabled */ + return; + + sprintf(buf, "%d", arg3); + + /* many daemons ignore SIGCHLD as tcpwrappers will + * fork a child to do logging. We need to wait + * for a child here, so we need to un-ignore + * SIGCHLD temporarily + */ + newact.sa_handler = SIG_DFL; + newact.sa_flags = 0; + sigemptyset(&newact.sa_mask); + sigaction(SIGCHLD, &newact, &oldact); + pid = fork(); + switch (pid) { + case 0: execl(ha_callout_prog, ha_callout_prog, + event, arg1, arg2, + arg3 < 0 ? NULL : buf, + NULL); + perror("execl"); + _exit(2); + case -1: perror("fork"); + break; + default: pid = waitpid(pid, &ret, 0); + } + sigaction(SIGCHLD, &oldact, &newact); + xlog(D_GENERAL, "ha callout returned %d\n", WEXITSTATUS(ret)); +} + +#endif diff --git a/support/include/junction.h b/support/include/junction.h new file mode 100644 index 0000000..7257d80 --- /dev/null +++ b/support/include/junction.h @@ -0,0 +1,167 @@ +/* + * @file support/include/junction.h + * @brief Declarations for libjunction.a + */ + +/* + * Copyright 2010, 2018 Oracle. All rights reserved. + * + * This file is part of nfs-utils. + * + * nfs-utils is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 as + * published by the Free Software Foundation. + * + * nfs-utils is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2.0 for more details. + * + * You should have received a copy of the GNU General Public License + * version 2.0 along with nfs-utils. If not, see: + * + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + */ + +#ifndef _NFS_JUNCTION_H_ +#define _NFS_JUNCTION_H_ + +#include <stdint.h> + +/* + * The libjunction APIs use the status codes from the FedFS ADMIN + * protocol, which includes non-errno codes like FEDFS_ERR_NOTJUNCT. + */ +enum FedFsStatus { + FEDFS_OK = 0, + FEDFS_ERR_ACCESS = 1, + FEDFS_ERR_BADCHAR = 2, + FEDFS_ERR_BADNAME = 3, + FEDFS_ERR_NAMETOOLONG = 4, + FEDFS_ERR_LOOP = 5, + FEDFS_ERR_BADXDR = 6, + FEDFS_ERR_EXIST = 7, + FEDFS_ERR_INVAL = 8, + FEDFS_ERR_IO = 9, + FEDFS_ERR_NOSPC = 10, + FEDFS_ERR_NOTJUNCT = 11, + FEDFS_ERR_NOTLOCAL = 12, + FEDFS_ERR_PERM = 13, + FEDFS_ERR_ROFS = 14, + FEDFS_ERR_SVRFAULT = 15, + FEDFS_ERR_NOTSUPP = 16, + FEDFS_ERR_NSDB_ROUTE = 17, + FEDFS_ERR_NSDB_DOWN = 18, + FEDFS_ERR_NSDB_CONN = 19, + FEDFS_ERR_NSDB_AUTH = 20, + FEDFS_ERR_NSDB_LDAP = 21, + FEDFS_ERR_NSDB_LDAP_VAL = 22, + FEDFS_ERR_NSDB_NONCE = 23, + FEDFS_ERR_NSDB_NOFSN = 24, + FEDFS_ERR_NSDB_NOFSL = 25, + FEDFS_ERR_NSDB_RESPONSE = 26, + FEDFS_ERR_NSDB_FAULT = 27, + FEDFS_ERR_NSDB_PARAMS = 28, + FEDFS_ERR_NSDB_LDAP_REFERRAL = 29, + FEDFS_ERR_NSDB_LDAP_REFERRAL_VAL = 30, + FEDFS_ERR_NSDB_LDAP_REFERRAL_NOTFOLLOWED = 31, + FEDFS_ERR_NSDB_PARAMS_LDAP_REFERRAL = 32, + FEDFS_ERR_PATH_TYPE_UNSUPP = 33, + FEDFS_ERR_DELAY = 34, + FEDFS_ERR_NO_CACHE = 35, + FEDFS_ERR_UNKNOWN_CACHE = 36, + FEDFS_ERR_NO_CACHE_UPDATE = 37, +}; +typedef enum FedFsStatus FedFsStatus; + +/** + * Contains NFS fileset location information + * + * Each of these represents one server:/rootpath pair. The NFS + * implementation can coalesce multiple pairs into a single + * fs_location4 result if jfl_rootpath is the same across + * multiple servers. + * + * The nfl_server field can contain either one presentation format + * IP address or one DNS hostname. + * + * See Section 11.9 and 11.10 of RFC 5661 or section 4.2.2.3 and + * 4.2.2.4 of the NSDB protocol draft for details. + */ + +struct nfs_fsloc { + struct nfs_fsloc *nfl_next; + + char *nfl_hostname; + uint16_t nfl_hostport; + char **nfl_rootpath; + + struct { + _Bool nfl_varsub; + } nfl_flags; + int32_t nfl_currency; + int32_t nfl_validfor; + + struct { + _Bool nfl_writable, nfl_going, nfl_split; + } nfl_genflags; + struct { + _Bool nfl_rdma; + } nfl_transflags; + struct { + uint8_t nfl_simul, nfl_handle, nfl_fileid; + uint8_t nfl_writever, nfl_change, nfl_readdir; + uint8_t nfl_readrank, nfl_writerank; + uint8_t nfl_readorder, nfl_writeorder; + } nfl_info; +}; + + +/** + ** NFS location data management functions + **/ + +void nfs_free_location(struct nfs_fsloc *location); +void nfs_free_locations(struct nfs_fsloc *locations); +struct nfs_fsloc *nfs_new_location(void); + +__attribute_malloc__ +char **nfs_dup_string_array(char **array); +void nfs_free_string_array(char **array); + + +/** + ** NFS junction management functions + **/ + +FedFsStatus nfs_delete_junction(const char *pathname); +FedFsStatus nfs_add_junction(const char *pathname, + struct nfs_fsloc *locations); +FedFsStatus nfs_get_locations(const char *pathname, + struct nfs_fsloc **locations); +FedFsStatus nfs_is_prejunction(const char *pathname); +FedFsStatus nfs_is_junction(const char *pathname); + + +/** + ** Flush kernel NFS server's export cache + **/ +FedFsStatus junction_flush_exports_cache(void); + +/** + ** Pathname conversion helpers + **/ +void nsdb_free_string_array(char **strings); +FedFsStatus nsdb_path_array_to_posix(char * const *path_array, + char **pathname); +FedFsStatus nsdb_posix_to_path_array(const char *pathname, + char ***path_array); + +/** + ** Readability helpers + **/ + +const char *nsdb_display_fedfsstatus(const FedFsStatus status); +void nsdb_print_fedfsstatus(const FedFsStatus status); + +#endif /* !_NFS_JUNCTION_H_ */ diff --git a/support/include/misc.h b/support/include/misc.h new file mode 100644 index 0000000..2b0fef2 --- /dev/null +++ b/support/include/misc.h @@ -0,0 +1,31 @@ +/* + * misc.h All that didn't fit elsewhere. + * + * Copyright (C) 1995 Olaf Kirch <okir@monad.swb.de> + */ + +#ifndef MISC_H +#define MISC_H + +/* + * Generate random key, returning the length of the result. Currently, + * weakrandomkey generates a maximum of 20 bytes are generated, but this + * may change with future implementations. + */ +int randomkey(unsigned char *keyout, int len); +int weakrandomkey(unsigned char *keyout, int len); + +char *generic_make_pathname(const char *, const char *); +_Bool generic_setup_basedir(const char *, const char *, char *, const size_t); + +struct stat; + +extern int check_is_mountpoint(const char *path, + int (mystat)(const char *, struct stat *)); +#define is_mountpoint(path) \ + check_is_mountpoint(path, NULL) + +/* size of the file pointer buffers for rpc procfs files */ +#define RPC_CHAN_BUF_SIZE 32768 + +#endif /* MISC_H */ diff --git a/support/include/nfs/Makefile.am b/support/include/nfs/Makefile.am new file mode 100644 index 0000000..9903ba1 --- /dev/null +++ b/support/include/nfs/Makefile.am @@ -0,0 +1,5 @@ +## Process this file with automake to produce Makefile.in + +noinst_HEADERS = debug.h export.h nfs.h + +MAINTAINERCLEANFILES = Makefile.in diff --git a/support/include/nfs/Makefile.in b/support/include/nfs/Makefile.in new file mode 100644 index 0000000..00cbc35 --- /dev/null +++ b/support/include/nfs/Makefile.in @@ -0,0 +1,601 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = support/include/nfs +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ax_gcc_func_attribute.m4 \ + $(top_srcdir)/aclocal/bsdsignals.m4 \ + $(top_srcdir)/aclocal/getrandom.m4 \ + $(top_srcdir)/aclocal/ipv6.m4 \ + $(top_srcdir)/aclocal/kerberos5.m4 \ + $(top_srcdir)/aclocal/keyutils.m4 \ + $(top_srcdir)/aclocal/libblkid.m4 \ + $(top_srcdir)/aclocal/libcap.m4 \ + $(top_srcdir)/aclocal/libevent.m4 \ + $(top_srcdir)/aclocal/libpthread.m4 \ + $(top_srcdir)/aclocal/libsqlite3.m4 \ + $(top_srcdir)/aclocal/libtirpc.m4 \ + $(top_srcdir)/aclocal/libxml2.m4 \ + $(top_srcdir)/aclocal/nfs-utils.m4 \ + $(top_srcdir)/aclocal/rpcsec_vers.m4 \ + $(top_srcdir)/aclocal/tcp-wrappers.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/support/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GREP = @GREP@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GSSD = @GSSD@ +GSSGLUE_CFLAGS = @GSSGLUE_CFLAGS@ +GSSGLUE_LIBS = @GSSGLUE_LIBS@ +GSSKRB_CFLAGS = @GSSKRB_CFLAGS@ +GSSKRB_LIBS = @GSSKRB_LIBS@ +HAVE_GETRANDOM = @HAVE_GETRANDOM@ +HAVE_LIBWRAP = @HAVE_LIBWRAP@ +HAVE_TCP_WRAPPER = @HAVE_TCP_WRAPPER@ +IDMAPD = @IDMAPD@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +K5VERS = @K5VERS@ +KRBCFLAGS = @KRBCFLAGS@ +KRBDIR = @KRBDIR@ +KRBLDFLAGS = @KRBLDFLAGS@ +KRBLIBS = @KRBLIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ +LIBBLKID = @LIBBLKID@ +LIBBSD = @LIBBSD@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBEVENT = @LIBEVENT@ +LIBKEYUTILS = @LIBKEYUTILS@ +LIBMOUNT = @LIBMOUNT@ +LIBMOUNT_CFLAGS = @LIBMOUNT_CFLAGS@ +LIBMOUNT_LIBS = @LIBMOUNT_LIBS@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPTHREAD = @LIBPTHREAD@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSQLITE = @LIBSQLITE@ +LIBTIRPC = @LIBTIRPC@ +LIBTOOL = @LIBTOOL@ +LIBWRAP = @LIBWRAP@ +LIBXML2 = @LIBXML2@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_PLUGINS = @PATH_PLUGINS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +RELEASE = @RELEASE@ +RPCGEN_PATH = @RPCGEN_PATH@ +RPCSECGSS_CFLAGS = @RPCSECGSS_CFLAGS@ +RPCSECGSS_LIBS = @RPCSECGSS_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SVCGSSD = @SVCGSSD@ +TIRPC_CFLAGS = @TIRPC_CFLAGS@ +TIRPC_LIBS = @TIRPC_LIBS@ +VERSION = @VERSION@ +XML2_CFLAGS = @XML2_CFLAGS@ +XML2_LIBS = @XML2_LIBS@ +_rpc_pipefsmount = @_rpc_pipefsmount@ +_statedir = @_statedir@ +_sysconfdir = @_sysconfdir@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_gss = @enable_gss@ +enable_ipv6 = @enable_ipv6@ +enable_mountconfig = @enable_mountconfig@ +enable_nfsv4 = @enable_nfsv4@ +enable_nfsv41 = @enable_nfsv41@ +enable_svcgss = @enable_svcgss@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +kprefix = @kprefix@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +mountfile = @mountfile@ +nfsconfig = @nfsconfig@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rpc_pipefsmount = @rpc_pipefsmount@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +startstatd = @startstatd@ +statdpath = @statdpath@ +statduser = @statduser@ +statedir = @statedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +unitdir = @unitdir@ +noinst_HEADERS = debug.h export.h nfs.h +MAINTAINERCLEANFILES = Makefile.in +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu support/include/nfs/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu support/include/nfs/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libtool cscopelist-am ctags ctags-am distclean \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/support/include/nfs/debug.h b/support/include/nfs/debug.h new file mode 100644 index 0000000..80a1b1d --- /dev/null +++ b/support/include/nfs/debug.h @@ -0,0 +1,85 @@ +#ifndef _NFS_DEBUG_H +#define _NFS_DEBUG_H + +/* + * RPC debug facilities + */ +#define RPCDBG_XPRT 0x0001 +#define RPCDBG_CALL 0x0002 +#define RPCDBG_DEBUG 0x0004 +#define RPCDBG_NFS 0x0008 +#define RPCDBG_AUTH 0x0010 +#define RPCDBG_BIND 0x0020 +#define RPCDBG_SCHED 0x0040 +#define RPCDBG_TRANS 0x0080 +#define RPCDBG_SVCSOCK 0x0100 +#define RPCDBG_SVCDSP 0x0200 +#define RPCDBG_MISC 0x0400 +#define RPCDBG_CACHE 0x0800 +#define RPCDBG_ALL 0x7fff + +/* + * Declarations for the sysctl debug interface, which allows to read or + * change the debug flags for rpc, nfs, nfsd, and lockd. Since the sunrpc + * module currently registers its sysctl table dynamically, the sysctl path + * for module FOO is <CTL_SUNRPC, CTL_FOODEBUG>. + */ +#define CTL_SUNRPC 7249 /* arbitrary and hopefully unused */ + +enum { + CTL_RPCDEBUG = 1, + CTL_NFSDEBUG, + CTL_NFSDDEBUG, + CTL_NLMDEBUG, +}; + + +/* + * knfsd debug flags + */ +#define NFSDDBG_SOCK 0x0001 +#define NFSDDBG_FH 0x0002 +#define NFSDDBG_EXPORT 0x0004 +#define NFSDDBG_SVC 0x0008 +#define NFSDDBG_PROC 0x0010 +#define NFSDDBG_FILEOP 0x0020 +#define NFSDDBG_AUTH 0x0040 +#define NFSDDBG_REPCACHE 0x0080 +#define NFSDDBG_XDR 0x0100 +#define NFSDDBG_LOCKD 0x0200 +#define NFSDDBG_ALL 0x7FFF +#define NFSDDBG_NOCHANGE 0xFFFF + +/* + * Debug flags + */ +#define NLMDBG_SVC 0x0001 +#define NLMDBG_CLIENT 0x0002 +#define NLMDBG_CLNTLOCK 0x0004 +#define NLMDBG_SVCLOCK 0x0008 +#define NLMDBG_MONITOR 0x0010 +#define NLMDBG_CLNTSUBS 0x0020 +#define NLMDBG_SVCSUBS 0x0040 +#define NLMDBG_HOSTCACHE 0x0080 +#define NLMDBG_XDR 0x0100 +#define NLMDBG_ALL 0x7fff + + +#define NFSDBG_VFS 0x0001 +#define NFSDBG_DIRCACHE 0x0002 +#define NFSDBG_LOOKUPCACHE 0x0004 +#define NFSDBG_PAGECACHE 0x0008 +#define NFSDBG_PROC 0x0010 +#define NFSDBG_XDR 0x0020 +#define NFSDBG_FILE 0x0040 +#define NFSDBG_ROOT 0x0080 +#define NFSDBG_CALLBACK 0x0100 +#define NFSDBG_CLIENT 0x0200 +#define NFSDBG_MOUNT 0x0400 +#define NFSDBG_FSCACHE 0x0800 +#define NFSDBG_PNFS 0x1000 +#define NFSDBG_PNFS_LD 0x2000 +#define NFSDBG_STATE 0x4000 +#define NFSDBG_ALL 0xFFFF + +#endif /* _NFS_DEBUG_H */ diff --git a/support/include/nfs/export.h b/support/include/nfs/export.h new file mode 100644 index 0000000..be5867c --- /dev/null +++ b/support/include/nfs/export.h @@ -0,0 +1,57 @@ +#ifndef _NSF_EXPORT_H +#define _NSF_EXPORT_H + +/* + * Important limits for the exports stuff. + */ +#define NFSCLNT_IDMAX 1024 +#define NFSCLNT_ADDRMAX 16 +#define NFSCLNT_KEYMAX 32 + +/* + * Export flags. + */ +#define NFSEXP_READONLY 0x0001 +#define NFSEXP_INSECURE_PORT 0x0002 +#define NFSEXP_ROOTSQUASH 0x0004 +#define NFSEXP_ALLSQUASH 0x0008 +#define NFSEXP_ASYNC 0x0010 +#define NFSEXP_GATHERED_WRITES 0x0020 +#define NFSEXP_NOREADDIRPLUS 0x0040 +#define NFSEXP_SECURITY_LABEL 0x0080 +/* 0x100 unused */ +#define NFSEXP_NOHIDE 0x0200 +#define NFSEXP_NOSUBTREECHECK 0x0400 +#define NFSEXP_NOAUTHNLM 0x0800 +#define NFSEXP_FSID 0x2000 +#define NFSEXP_CROSSMOUNT 0x4000 +#define NFSEXP_NOACL 0x8000 /* reserved for possible ACL related use */ +#define NFSEXP_V4ROOT 0x10000 +#define NFSEXP_PNFS 0x20000 +/* + * All flags supported by the kernel before addition of the + * export_features interface: + */ +#define NFSEXP_OLDFLAGS 0x7E3F +/* + * Flags that can vary per flavor, for kernels before addition of the + * export_features interface: + */ +#define NFSEXP_OLD_SECINFO_FLAGS (NFSEXP_READONLY | NFSEXP_ROOTSQUASH \ + | NFSEXP_ALLSQUASH) + +/* + * Transport layer security policies that are permitted to access + * an export + */ +#define NFSEXP_XPRTSEC_NONE 0x0001 +#define NFSEXP_XPRTSEC_TLS 0x0002 +#define NFSEXP_XPRTSEC_MTLS 0x0004 + +#define NFSEXP_XPRTSEC_NUM (3) + +#define NFSEXP_XPRTSEC_ALL (NFSEXP_XPRTSEC_NONE | \ + NFSEXP_XPRTSEC_TLS | \ + NFSEXP_XPRTSEC_MTLS) + +#endif /* _NSF_EXPORT_H */ diff --git a/support/include/nfs/nfs.h b/support/include/nfs/nfs.h new file mode 100644 index 0000000..b7d9e06 --- /dev/null +++ b/support/include/nfs/nfs.h @@ -0,0 +1,51 @@ +#ifndef _NFS_NFS_H +#define _NFS_NFS_H + +#include <config.h> + +#include <linux/posix_types.h> +#include <sys/types.h> +#include <netinet/in.h> +#include <rpcsvc/nfs_prot.h> +#include <nfs/export.h> +#include <limits.h> + +#define NFS3_FHSIZE 64 +#define NFS_FHSIZE 32 + +#define NFSD_MINVERS 2 +#define NFSD_MAXVERS 4 + +#define NFS4_MINMINOR 0 +#define NFS4_MAXMINOR (WORD_BIT-1) + +struct nfs_fh_len { + int fh_size; + u_int8_t fh_handle[NFS3_FHSIZE]; +}; + + +#define NFSCTL_UDPBIT (1 << (17 - 1)) +#define NFSCTL_TCPBIT (1 << (18 - 1)) +#define NFSCTL_PROTODEFAULT (NFSCTL_TCPBIT) + +#define NFSCTL_VERUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << ((_v) - 1))) +#define NFSCTL_MINORUNSET(_cltbits, _v) ((_cltbits) &= ~(1 << (_v))) +#define NFSCTL_UDPUNSET(_cltbits) ((_cltbits) &= ~NFSCTL_UDPBIT) +#define NFSCTL_TCPUNSET(_cltbits) ((_cltbits) &= ~NFSCTL_TCPBIT) + +#define NFSCTL_VERISSET(_cltbits, _v) ((_cltbits) & (1 << ((_v) - 1))) +#define NFSCTL_MINORISSET(_cltbits, _v) ((_cltbits) & (1 << (_v))) +#define NFSCTL_UDPISSET(_cltbits) ((_cltbits) & NFSCTL_UDPBIT) +#define NFSCTL_TCPISSET(_cltbits) ((_cltbits) & NFSCTL_TCPBIT) + +#define NFSCTL_VERDEFAULT (0xc) /* versions 3 and 4 */ +#define NFSCTL_MINDEFAULT (0x7) /* minor versions 4.1 and 4.2 */ +#define NFSCTL_VERSET(_cltbits, _v) ((_cltbits) |= (1 << ((_v) - 1))) +#define NFSCTL_MINORSET(_cltbits, _v) ((_cltbits) |= (1 << (_v))) +#define NFSCTL_UDPSET(_cltbits) ((_cltbits) |= NFSCTL_UDPBIT) +#define NFSCTL_TCPSET(_cltbits) ((_cltbits) |= NFSCTL_TCPBIT) + +#define NFSCTL_ANYPROTO(_cltbits) ((_cltbits) & (NFSCTL_UDPBIT | NFSCTL_TCPBIT)) + +#endif /* _NFS_NFS_H */ diff --git a/support/include/nfs_mntent.h b/support/include/nfs_mntent.h new file mode 100644 index 0000000..010df24 --- /dev/null +++ b/support/include/nfs_mntent.h @@ -0,0 +1,26 @@ +/* + * 2006-06-08 Amit Gud <agud@redhat.com> + * - Moved code snippets here from util-linux/mount/my_mntent.h + */ + +#ifndef _NFS_MNTENT_H +#define _NFS_MNTENT_H +#include <mntent.h> + +#define ERR_MAX 5 + +typedef struct mntFILEstruct { + FILE *mntent_fp; + char *mntent_file; + int mntent_lineno; + int mntent_errs; + int mntent_softerrs; +} mntFILE; + +mntFILE *nfs_setmntent (const char *file, char *mode); +void nfs_endmntent (mntFILE *mfp); +int nfs_addmntent (mntFILE *mfp, struct mntent *mnt); +struct nfs_mntent *my_getmntent (mntFILE *mfp); +struct mntent *nfs_getmntent (mntFILE *mfp); + +#endif /* _NFS_MNTENT_H */ diff --git a/support/include/nfs_paths.h b/support/include/nfs_paths.h new file mode 100644 index 0000000..de4ac19 --- /dev/null +++ b/support/include/nfs_paths.h @@ -0,0 +1,11 @@ +#ifndef _NFS_PATHS_H +#define _NFS_PATHS_H + +#ifndef _PATH_MOUNTED +#define _PATH_MOUNTED "/etc/fstab" +#endif +#define MOUNTED_LOCK _PATH_MOUNTED "~" +#define MOUNTED_TEMP _PATH_MOUNTED ".tmp" + +#endif /* _NFS_PATHS_H */ + diff --git a/support/include/nfsd_path.h b/support/include/nfsd_path.h new file mode 100644 index 0000000..aa1e1dd --- /dev/null +++ b/support/include/nfsd_path.h @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2019 Trond Myklebust <trond.myklebust@hammerspace.com> + */ +#ifndef NFSD_PATH_H +#define NFSD_PATH_H + +#include <sys/stat.h> + +struct file_handle; +struct statfs; + +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); + +int nfsd_path_statfs(const char *pathname, + struct statfs *statbuf); + +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); + +int nfsd_name_to_handle_at(int fd, const char *path, + struct file_handle *fh, + int *mount_id, int flags); +#endif diff --git a/support/include/nfslib.h b/support/include/nfslib.h new file mode 100644 index 0000000..bdbde78 --- /dev/null +++ b/support/include/nfslib.h @@ -0,0 +1,187 @@ +/* + * support/include/nfslib.h + * + * General support functions for NFS user-space programs. + * + * Copyright (C) 1995 Olaf Kirch <okir@monad.swb.de> + */ + +#ifndef NFSLIB_H +#define NFSLIB_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <stdio.h> +#include <stdbool.h> +#include <paths.h> +#include <rpcsvc/nfs_prot.h> +#include <nfs/nfs.h> +#include "xlog.h" + +#ifndef _PATH_EXPORTS +#define _PATH_EXPORTS "/etc/exports" +#endif +#ifndef _PATH_EXPORTS_D +#define _PATH_EXPORTS_D "/etc/exports.d" +#endif +#ifndef _EXT_EXPORT +#define _EXT_EXPORT ".exports" +#endif +#ifndef _PATH_IDMAPDCONF +#define _PATH_IDMAPDCONF "/etc/idmapd.conf" +#endif +#ifndef _PATH_PROC_EXPORTS +#define _PATH_PROC_EXPORTS "/proc/fs/nfs/exports" +#define _PATH_PROC_EXPORTS_ALT "/proc/fs/nfsd/exports" +#endif + +#define ETAB "etab" +#define ETABTMP "etab.tmp" +#define ETABLCK ".etab.lock" +#define RMTAB "rmtab" +#define RMTABTMP "rmtab.tmp" +#define RMTABLCK ".rmtab.lock" + +struct state_paths { + char *statefn; + char *tmpfn; + char *lockfn; +}; + +/* Maximum number of security flavors on an export: */ +#define SECFLAVOR_COUNT 8 + +struct sec_entry { + struct flav_info *flav; + int flags; +}; + +#define XPRTSECMODE_COUNT 3 + +struct xprtsec_info { + const char *name; + int number; +}; + +struct xprtsec_entry { + const struct xprtsec_info *info; + int flags; +}; + +/* + * Data related to a single exports entry as returned by getexportent. + * FIXME: export options should probably be parsed at a later time to + * allow overrides when using exportfs. + */ +struct exportent { + char * e_hostname; + char e_path[NFS_MAXPATHLEN+1]; + int e_flags; + int e_anonuid; + int e_anongid; + int * e_squids; + int e_nsquids; + int * e_sqgids; + int e_nsqgids; + unsigned int e_fsid; + char * e_mountpoint; + int e_fslocmethod; + char * e_fslocdata; + char * e_uuid; + struct sec_entry e_secinfo[SECFLAVOR_COUNT+1]; + struct xprtsec_entry e_xprtsec[XPRTSECMODE_COUNT + 1]; + unsigned int e_ttl; + char * e_realpath; + int e_reexport; +}; + +struct rmtabent { + char r_client[NFSCLNT_IDMAX+1]; + char r_path[NFS_MAXPATHLEN+1]; + int r_count; +}; + +/* + * configuration file parsing + */ +void setexportent(char *fname, char *type); +struct exportent * getexportent(int,int); +void secinfo_show(FILE *fp, struct exportent *ep); +void xprtsecinfo_show(FILE *fp, struct exportent *ep); +void putexportent(struct exportent *xep); +void endexportent(void); +struct exportent * mkexportent(char *hname, char *path, char *opts); +void dupexportent(struct exportent *dst, + struct exportent *src); +int updateexportent(struct exportent *eep, char *options); + +extern struct state_paths rmtab; +int setrmtabent(char *type); +struct rmtabent * getrmtabent(int log, long *pos); +void putrmtabent(struct rmtabent *xep, long *pos); +void endrmtabent(void); +void rewindrmtabent(void); +FILE * fsetrmtabent(char *fname, char *type); +struct rmtabent * fgetrmtabent(FILE *fp, int log, long *pos); +void fputrmtabent(FILE *fp, struct rmtabent *xep, long *pos); +void fendrmtabent(FILE *fp); +void frewindrmtabent(FILE *fp); + +_Bool state_setup_basedir(const char *, const char *); +int setup_state_path_names(const char *, const char *, const char *, const char *, struct state_paths *); +void free_state_path_names(struct state_paths *); + +/* mydaemon */ +void daemon_init(bool fg); +void daemon_ready(void); + +/* + * wildmat borrowed from INN + */ +int wildmat(char *text, char *pattern); + +int qword_get(char **bpp, char *dest, int bufsize); +int qword_get_int(char **bpp, int *anint); +void cache_flush(void); +void qword_add(char **bpp, int *lp, char *str); +void qword_addhex(char **bpp, int *lp, char *buf, int blen); +void qword_addint(char **bpp, int *lp, int n); +void qword_adduint(char **bpp, int *lp, unsigned int n); +void qword_addeol(char **bpp, int *lp); +int qword_get_uint(char **bpp, unsigned int *anint); + +void closeall(int min); + +int svctcp_socket (u_long __number, int __reuse); +int svcudp_socket (u_long __number); +int svcsock_nonblock (int __sock); + +/* Misc shared code prototypes */ +size_t strlcat(char *, const char *, size_t); +size_t strlcpy(char *, const char *, size_t); +ssize_t atomicio(ssize_t (*f) (int, void*, size_t), + int, void *, size_t); + +#ifdef HAVE_LIBTIRPC_SET_DEBUG +void libtirpc_set_debug(char *name, int level, int use_stderr); +#endif + +#define UNUSED(x) UNUSED_ ## x __attribute__((unused)) + +/* + * Some versions of freeaddrinfo(3) do not tolerate being + * passed a NULL pointer. + */ +static inline void nfs_freeaddrinfo(struct addrinfo *ai) +{ + if (ai) { + freeaddrinfo(ai); + } +} +#endif /* NFSLIB_H */ diff --git a/support/include/nfsrpc.h b/support/include/nfsrpc.h new file mode 100644 index 0000000..fbbdb6a --- /dev/null +++ b/support/include/nfsrpc.h @@ -0,0 +1,178 @@ +/* + * nfsrpc.h -- RPC client APIs provided by support/nfs + * + * Copyright (C) 2008 Oracle Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA + * + */ + +#ifndef __NFS_UTILS_NFSRPC_H +#define __NFS_UTILS_NFSRPC_H + +#include <string.h> +#include <rpc/types.h> +#include <rpc/clnt.h> + +/* + * IANA does not define an IP protocol number for RDMA transports. + * Choose an arbitrary value we can use locally. + */ +#define NFSPROTO_RDMA (3939) + +/* + * Conventional RPC program numbers + */ +#ifndef RPCBPROG +#define RPCBPROG ((rpcprog_t)100000) +#endif +#ifndef PMAPPROG +#define PMAPPROG ((rpcprog_t)100000) +#endif + +#ifndef NFSPROG +#define NFSPROG ((rpcprog_t)100003) +#endif +#ifndef MOUNTPROG +#define MOUNTPROG ((rpcprog_t)100005) +#endif +#ifndef NLMPROG +#define NLMPROG ((rpcprog_t)100021) +#endif +#ifndef NSMPROG +#define NSMPROG ((rpcprog_t)100024) +#endif + +/** + * nfs_clear_rpc_createerr - zap all error reporting fields + * + */ +static inline void nfs_clear_rpc_createerr(void) +{ + memset(&rpc_createerr, 0, sizeof(rpc_createerr)); +} + +/* + * Look up an RPC program name in /etc/rpc + */ +extern rpcprog_t nfs_getrpcbyname(const rpcprog_t, const char *table[]); + +/* + * Acquire an RPC CLIENT * with an ephemeral source port + */ +extern CLIENT *nfs_get_rpcclient(const struct sockaddr *, + const socklen_t, const unsigned short, + const rpcprog_t, const rpcvers_t, + struct timeval *); + +/* + * Acquire an RPC CLIENT * with a privileged source port + */ +extern CLIENT *nfs_get_priv_rpcclient( const struct sockaddr *, + const socklen_t, const unsigned short, + const rpcprog_t, const rpcvers_t, + struct timeval *); + +/* + * Convert a netid to a protocol number and protocol family + */ +extern int nfs_get_proto(const char *netid, sa_family_t *family, + unsigned long *protocol); + +/* + * Convert a protocol family and protocol name to a netid + */ +extern char *nfs_get_netid(const sa_family_t family, + const unsigned long protocol); + +/* + * Convert a socket address to a universal address + */ +extern char *nfs_sockaddr2universal(const struct sockaddr *); + +/* + * Extract port number from a universal address + */ +extern int nfs_universal2port(const char *); + +/* + * Generic function that maps an RPC service tuple to an IP port + * number of the service on a remote post, and sends a NULL + * request to determine if the service is responding to requests + */ +extern int nfs_getport_ping(struct sockaddr *sap, + const socklen_t salen, + const rpcprog_t program, + const rpcvers_t version, + const unsigned short protocol); + +/* + * Generic function that maps an RPC service tuple to an IP port + * number of the service on a remote host + */ +extern unsigned short nfs_getport(const struct sockaddr *, + const socklen_t, const rpcprog_t, + const rpcvers_t, const unsigned short); + +/* + * Generic function that maps an RPC service tuple to an IP port + * number of the service on the local host + */ +extern unsigned short nfs_getlocalport(const rpcprot_t, + const rpcvers_t, const unsigned short); + +/* + * Function to invoke an rpcbind v3/v4 GETADDR request + */ +extern unsigned short nfs_rpcb_getaddr(const struct sockaddr *, + const socklen_t, + const unsigned short, + const struct sockaddr *, + const rpcprog_t, + const rpcvers_t, + const unsigned short, + const struct timeval *); + +/* + * Function to invoke a portmap GETPORT request + */ +extern unsigned long nfs_pmap_getport(const struct sockaddr_in *, + const unsigned short, + const unsigned long, + const unsigned long, + const unsigned long, + const struct timeval *); + +/* + * Use nfs_pmap_getport to see if statd is running locally + */ +extern int nfs_probe_statd(void); + +/* + * Contact a remote RPC service to discover whether it is responding + * to requests. + */ +extern int nfs_rpc_ping(const struct sockaddr *sap, + const socklen_t salen, + const rpcprog_t program, + const rpcvers_t version, + const unsigned short protocol, + const struct timeval *timeout); + +/* create AUTH_SYS handle with no supplemental groups */ +extern AUTH * nfs_authsys_create(void); + +#endif /* !__NFS_UTILS_NFSRPC_H */ diff --git a/support/include/nls.h b/support/include/nls.h new file mode 100644 index 0000000..899e8d7 --- /dev/null +++ b/support/include/nls.h @@ -0,0 +1,27 @@ +/* + * 2006-06-08 Amit Gud <agud@redhat.com> + * - Copied to nfs-utils/support/include from util-linux/mount + */ + +#ifndef LOCALEDIR +#define LOCALEDIR "/usr/share/locale" +#endif + +#ifdef ENABLE_NLS +# include <libintl.h> +# define _(Text) gettext (Text) +# ifdef gettext_noop +# define N_(String) gettext_noop (String) +# else +# define N_(String) (String) +# endif +#else +# undef bindtextdomain +# define bindtextdomain(Domain, Directory) /* empty */ +# undef textdomain +# define textdomain(Domain) /* empty */ +# define _(Text) (Text) +# define N_(Text) (Text) +#endif + + diff --git a/support/include/nsm.h b/support/include/nsm.h new file mode 100644 index 0000000..080d176 --- /dev/null +++ b/support/include/nsm.h @@ -0,0 +1,94 @@ +/* + * Copyright 2009 Oracle. All rights reserved. + * + * This file is part of nfs-utils. + * + * nfs-utils is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * nfs-utils is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with nfs-utils. If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * NSM for Linux. + */ + +#ifndef NFS_UTILS_SUPPORT_NSM_H +#define NFS_UTILS_SUPPORT_NSM_H + +#include <sys/types.h> +#include <sys/socket.h> +#include <stdbool.h> + +#include <netdb.h> +#include <time.h> + +#include "sm_inter.h" + +typedef unsigned int + (*nsm_populate_t)(const char *hostname, + const struct sockaddr *sap, + const struct mon *mon, + const time_t timestamp); + +/* file.c */ + +extern _Bool nsm_setup_pathnames(const char *progname, + const char *parentdir); +extern _Bool nsm_is_default_parentdir(void); +extern _Bool nsm_drop_privileges(const int pidfd); + +extern int nsm_get_state(_Bool update); +extern void nsm_update_kernel_state(const int state); + +extern unsigned int + nsm_retire_monitored_hosts(void); +extern unsigned int + nsm_load_monitor_list(nsm_populate_t func); +extern unsigned int + nsm_load_notify_list(nsm_populate_t func); + +extern _Bool nsm_insert_monitored_host(const char *hostname, + const struct sockaddr *sap, const struct mon *m); +extern void nsm_delete_monitored_host(const char *hostname, + const char *mon_name, const char *my_name, + const int chatty); +extern void nsm_delete_notified_host(const char *hostname, + const char *mon_name, const char *my_name); +extern size_t nsm_priv_to_hex(const char *priv, char *buf, + const size_t buflen); + +/* rpc.c */ + +#define NSM_MAXMSGSIZE (2048u) + +extern uint32_t nsm_xmit_getport(const int sock, + const struct sockaddr_in *sin, + const unsigned long program, + const unsigned long version); +extern uint32_t nsm_xmit_getaddr(const int sock, + const struct sockaddr_in6 *sin6, + const rpcprog_t program, const rpcvers_t version); +extern uint32_t nsm_xmit_rpcbind(const int sock, const struct sockaddr *sap, + const rpcprog_t program, const rpcvers_t version); +extern uint32_t nsm_xmit_notify(const int sock, const struct sockaddr *sap, + const socklen_t salen, const rpcprog_t program, + const char *mon_name, const int state); +extern uint32_t nsm_xmit_nlmcall(const int sock, const struct sockaddr *sap, + const socklen_t salen, const struct mon *m, + const int state); +extern uint32_t nsm_parse_reply(XDR *xdrs); +extern unsigned long + nsm_recv_getport(XDR *xdrs); +extern uint16_t nsm_recv_getaddr(XDR *xdrs); +extern uint16_t nsm_recv_rpcbind(const sa_family_t family, XDR *xdrs); + +#endif /* !NFS_UTILS_SUPPORT_NSM_H */ diff --git a/support/include/pseudoflavors.h b/support/include/pseudoflavors.h new file mode 100644 index 0000000..1f16f3f --- /dev/null +++ b/support/include/pseudoflavors.h @@ -0,0 +1,15 @@ +#define RPC_AUTH_GSS_KRB5 390003 +#define RPC_AUTH_GSS_KRB5I 390004 +#define RPC_AUTH_GSS_KRB5P 390005 +#define RPC_AUTH_GSS_LKEY 390006 +#define RPC_AUTH_GSS_LKEYI 390007 +#define RPC_AUTH_GSS_LKEYP 390008 + +struct flav_info { + char *flavour; + int fnum; + int need_krb5; +}; + +extern struct flav_info flav_map[]; +extern const int flav_map_size; diff --git a/support/include/rpcmisc.h b/support/include/rpcmisc.h new file mode 100644 index 0000000..31c8e5d --- /dev/null +++ b/support/include/rpcmisc.h @@ -0,0 +1,72 @@ +/* + * rpcmisc Support for RPC startup, dispatching and logging. + * + * Copyright (C) 1995 Olaf Kirch <okir@monad.swb.de> + */ + +#ifndef RPCMISC_H +#define RPCMISC_H + +#include <rpc/rpc.h> +#include <rpc/pmap_clnt.h> + +#ifdef __STDC__ +# define CONCAT(a,b) a##b +# define STRING(a) #a +#else +# define CONCAT(a,b) a/**/b +# define STRING(a) "a" +#endif + +typedef bool_t (*rpcsvc_fn_t)(struct svc_req *, void *argp, void *resp); + +struct rpc_dentry { + const char *name; + rpcsvc_fn_t func; + xdrproc_t xdr_arg_fn; /* argument XDR */ + size_t xdr_arg_size; + xdrproc_t xdr_res_fn; /* result XDR */ + size_t xdr_res_size; +}; + +struct rpc_dtable { + struct rpc_dentry *entries; + rpcproc_t nproc; +}; + +#define dtable_ent(func, vers, arg_type, res_type) \ + { STRING(func), \ + (rpcsvc_fn_t)func##_##vers##_svc, \ + (xdrproc_t)xdr_##arg_type, sizeof(arg_type), \ + (xdrproc_t)xdr_##res_type, sizeof(res_type), \ + } + +void nfs_svc_unregister(const rpcprog_t program, + const rpcvers_t version); +unsigned int nfs_svc_create(char *name, const rpcprog_t program, + const rpcvers_t version, + void (*dispatch)(struct svc_req *, SVCXPRT *), + const uint16_t port); +void rpc_init(char *name, int prog, int vers, + void (*dispatch)(struct svc_req *, SVCXPRT *), + int defport); +void rpc_dispatch(struct svc_req *rq, SVCXPRT *xprt, + struct rpc_dtable *dtable, int nvers, + void *argp, void *resp); +int getservport(u_long number, const char *proto); + +extern int _rpcpmstart; +extern unsigned int _rpcprotobits; +extern int _rpcsvcdirty; + +static inline struct sockaddr_in *nfs_getrpccaller_in(SVCXPRT *xprt) +{ + return (struct sockaddr_in *)(char *)svc_getcaller(xprt); +} + +static inline struct sockaddr *nfs_getrpccaller(SVCXPRT *xprt) +{ + return (struct sockaddr *)(char *)svc_getcaller(xprt); +} + +#endif /* RPCMISC_H */ diff --git a/support/include/rpcsvc/Makefile.am b/support/include/rpcsvc/Makefile.am new file mode 100644 index 0000000..252bf8f --- /dev/null +++ b/support/include/rpcsvc/Makefile.am @@ -0,0 +1,5 @@ +## Process this file with automake to produce Makefile.in + +noinst_HEADERS = nfs_prot.h + +MAINTAINERCLEANFILES = Makefile.in diff --git a/support/include/rpcsvc/Makefile.in b/support/include/rpcsvc/Makefile.in new file mode 100644 index 0000000..cc215d5 --- /dev/null +++ b/support/include/rpcsvc/Makefile.in @@ -0,0 +1,601 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = support/include/rpcsvc +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ax_gcc_func_attribute.m4 \ + $(top_srcdir)/aclocal/bsdsignals.m4 \ + $(top_srcdir)/aclocal/getrandom.m4 \ + $(top_srcdir)/aclocal/ipv6.m4 \ + $(top_srcdir)/aclocal/kerberos5.m4 \ + $(top_srcdir)/aclocal/keyutils.m4 \ + $(top_srcdir)/aclocal/libblkid.m4 \ + $(top_srcdir)/aclocal/libcap.m4 \ + $(top_srcdir)/aclocal/libevent.m4 \ + $(top_srcdir)/aclocal/libpthread.m4 \ + $(top_srcdir)/aclocal/libsqlite3.m4 \ + $(top_srcdir)/aclocal/libtirpc.m4 \ + $(top_srcdir)/aclocal/libxml2.m4 \ + $(top_srcdir)/aclocal/nfs-utils.m4 \ + $(top_srcdir)/aclocal/rpcsec_vers.m4 \ + $(top_srcdir)/aclocal/tcp-wrappers.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/support/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GREP = @GREP@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GSSD = @GSSD@ +GSSGLUE_CFLAGS = @GSSGLUE_CFLAGS@ +GSSGLUE_LIBS = @GSSGLUE_LIBS@ +GSSKRB_CFLAGS = @GSSKRB_CFLAGS@ +GSSKRB_LIBS = @GSSKRB_LIBS@ +HAVE_GETRANDOM = @HAVE_GETRANDOM@ +HAVE_LIBWRAP = @HAVE_LIBWRAP@ +HAVE_TCP_WRAPPER = @HAVE_TCP_WRAPPER@ +IDMAPD = @IDMAPD@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +K5VERS = @K5VERS@ +KRBCFLAGS = @KRBCFLAGS@ +KRBDIR = @KRBDIR@ +KRBLDFLAGS = @KRBLDFLAGS@ +KRBLIBS = @KRBLIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ +LIBBLKID = @LIBBLKID@ +LIBBSD = @LIBBSD@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBEVENT = @LIBEVENT@ +LIBKEYUTILS = @LIBKEYUTILS@ +LIBMOUNT = @LIBMOUNT@ +LIBMOUNT_CFLAGS = @LIBMOUNT_CFLAGS@ +LIBMOUNT_LIBS = @LIBMOUNT_LIBS@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPTHREAD = @LIBPTHREAD@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSQLITE = @LIBSQLITE@ +LIBTIRPC = @LIBTIRPC@ +LIBTOOL = @LIBTOOL@ +LIBWRAP = @LIBWRAP@ +LIBXML2 = @LIBXML2@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_PLUGINS = @PATH_PLUGINS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +RELEASE = @RELEASE@ +RPCGEN_PATH = @RPCGEN_PATH@ +RPCSECGSS_CFLAGS = @RPCSECGSS_CFLAGS@ +RPCSECGSS_LIBS = @RPCSECGSS_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SVCGSSD = @SVCGSSD@ +TIRPC_CFLAGS = @TIRPC_CFLAGS@ +TIRPC_LIBS = @TIRPC_LIBS@ +VERSION = @VERSION@ +XML2_CFLAGS = @XML2_CFLAGS@ +XML2_LIBS = @XML2_LIBS@ +_rpc_pipefsmount = @_rpc_pipefsmount@ +_statedir = @_statedir@ +_sysconfdir = @_sysconfdir@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_gss = @enable_gss@ +enable_ipv6 = @enable_ipv6@ +enable_mountconfig = @enable_mountconfig@ +enable_nfsv4 = @enable_nfsv4@ +enable_nfsv41 = @enable_nfsv41@ +enable_svcgss = @enable_svcgss@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +kprefix = @kprefix@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +mountfile = @mountfile@ +nfsconfig = @nfsconfig@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rpc_pipefsmount = @rpc_pipefsmount@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +startstatd = @startstatd@ +statdpath = @statdpath@ +statduser = @statduser@ +statedir = @statedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +unitdir = @unitdir@ +noinst_HEADERS = nfs_prot.h +MAINTAINERCLEANFILES = Makefile.in +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu support/include/rpcsvc/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu support/include/rpcsvc/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libtool cscopelist-am ctags ctags-am distclean \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/support/include/rpcsvc/nfs_prot.h b/support/include/rpcsvc/nfs_prot.h new file mode 100644 index 0000000..9311341 --- /dev/null +++ b/support/include/rpcsvc/nfs_prot.h @@ -0,0 +1,661 @@ +/* + * Please do not edit this file. + * It was generated using rpcgen. + */ + +#ifndef _NFS_PROT_H_RPCGEN +#define _NFS_PROT_H_RPCGEN + +#include <rpc/rpc.h> + +#define NFS_PORT 2049 +#define NFS_MAXDATA 8192 +#define NFS_MAXPATHLEN 1024 +#define NFS_MAXNAMLEN 255 +#define NFS_FHSIZE 32 +#define NFS_COOKIESIZE 4 +#define NFS_FIFO_DEV -1 +#define NFSMODE_FMT 0170000 +#define NFSMODE_DIR 0040000 +#define NFSMODE_CHR 0020000 +#define NFSMODE_BLK 0060000 +#define NFSMODE_REG 0100000 +#define NFSMODE_LNK 0120000 +#define NFSMODE_SOCK 0140000 +#define NFSMODE_FIFO 0010000 + +enum nfsstat { + NFS_OK = 0, + NFSERR_PERM = 1, + NFSERR_NOENT = 2, + NFSERR_IO = 5, + NFSERR_NXIO = 6, + NFSERR_ACCES = 13, + NFSERR_EXIST = 17, + NFSERR_NODEV = 19, + NFSERR_NOTDIR = 20, + NFSERR_ISDIR = 21, + NFSERR_FBIG = 27, + NFSERR_NOSPC = 28, + NFSERR_ROFS = 30, + NFSERR_NAMETOOLONG = 63, + NFSERR_NOTEMPTY = 66, + NFSERR_DQUOT = 69, + NFSERR_STALE = 70, + NFSERR_WFLUSH = 99, +}; +typedef enum nfsstat nfsstat; +#ifdef __cplusplus +extern "C" bool_t xdr_nfsstat(XDR *, nfsstat*); +#elif __STDC__ +extern bool_t xdr_nfsstat(XDR *, nfsstat*); +#else /* Old Style C */ +bool_t xdr_nfsstat(); +#endif /* Old Style C */ + + +enum ftype { + NFNON = 0, + NFREG = 1, + NFDIR = 2, + NFBLK = 3, + NFCHR = 4, + NFLNK = 5, + NFSOCK = 6, + NFBAD = 7, + NFFIFO = 8, +}; +typedef enum ftype ftype; +#ifdef __cplusplus +extern "C" bool_t xdr_ftype(XDR *, ftype*); +#elif __STDC__ +extern bool_t xdr_ftype(XDR *, ftype*); +#else /* Old Style C */ +bool_t xdr_ftype(); +#endif /* Old Style C */ + + +struct nfs_fh { + char data[NFS_FHSIZE]; +}; +typedef struct nfs_fh nfs_fh; +#ifdef __cplusplus +extern "C" bool_t xdr_nfs_fh(XDR *, nfs_fh*); +#elif __STDC__ +extern bool_t xdr_nfs_fh(XDR *, nfs_fh*); +#else /* Old Style C */ +bool_t xdr_nfs_fh(); +#endif /* Old Style C */ + + +struct nfstime { + u_int seconds; + u_int useconds; +}; +typedef struct nfstime nfstime; +#ifdef __cplusplus +extern "C" bool_t xdr_nfstime(XDR *, nfstime*); +#elif __STDC__ +extern bool_t xdr_nfstime(XDR *, nfstime*); +#else /* Old Style C */ +bool_t xdr_nfstime(); +#endif /* Old Style C */ + + +struct fattr { + ftype type; + u_int mode; + u_int nlink; + u_int uid; + u_int gid; + u_int size; + u_int blocksize; + u_int rdev; + u_int blocks; + u_int fsid; + u_int fileid; + nfstime atime; + nfstime mtime; + nfstime ctime; +}; +typedef struct fattr fattr; +#ifdef __cplusplus +extern "C" bool_t xdr_fattr(XDR *, fattr*); +#elif __STDC__ +extern bool_t xdr_fattr(XDR *, fattr*); +#else /* Old Style C */ +bool_t xdr_fattr(); +#endif /* Old Style C */ + + +struct sattr { + u_int mode; + u_int uid; + u_int gid; + u_int size; + nfstime atime; + nfstime mtime; +}; +typedef struct sattr sattr; +#ifdef __cplusplus +extern "C" bool_t xdr_sattr(XDR *, sattr*); +#elif __STDC__ +extern bool_t xdr_sattr(XDR *, sattr*); +#else /* Old Style C */ +bool_t xdr_sattr(); +#endif /* Old Style C */ + + +typedef char *filename; +#ifdef __cplusplus +extern "C" bool_t xdr_filename(XDR *, filename*); +#elif __STDC__ +extern bool_t xdr_filename(XDR *, filename*); +#else /* Old Style C */ +bool_t xdr_filename(); +#endif /* Old Style C */ + + +typedef char *nfspath; +#ifdef __cplusplus +extern "C" bool_t xdr_nfspath(XDR *, nfspath*); +#elif __STDC__ +extern bool_t xdr_nfspath(XDR *, nfspath*); +#else /* Old Style C */ +bool_t xdr_nfspath(); +#endif /* Old Style C */ + + +struct attrstat { + nfsstat status; + union { + fattr attributes; + } attrstat_u; +}; +typedef struct attrstat attrstat; +#ifdef __cplusplus +extern "C" bool_t xdr_attrstat(XDR *, attrstat*); +#elif __STDC__ +extern bool_t xdr_attrstat(XDR *, attrstat*); +#else /* Old Style C */ +bool_t xdr_attrstat(); +#endif /* Old Style C */ + + +struct sattrargs { + nfs_fh file; + sattr attributes; +}; +typedef struct sattrargs sattrargs; +#ifdef __cplusplus +extern "C" bool_t xdr_sattrargs(XDR *, sattrargs*); +#elif __STDC__ +extern bool_t xdr_sattrargs(XDR *, sattrargs*); +#else /* Old Style C */ +bool_t xdr_sattrargs(); +#endif /* Old Style C */ + + +struct diropargs { + nfs_fh dir; + filename name; +}; +typedef struct diropargs diropargs; +#ifdef __cplusplus +extern "C" bool_t xdr_diropargs(XDR *, diropargs*); +#elif __STDC__ +extern bool_t xdr_diropargs(XDR *, diropargs*); +#else /* Old Style C */ +bool_t xdr_diropargs(); +#endif /* Old Style C */ + + +struct diropokres { + nfs_fh file; + fattr attributes; +}; +typedef struct diropokres diropokres; +#ifdef __cplusplus +extern "C" bool_t xdr_diropokres(XDR *, diropokres*); +#elif __STDC__ +extern bool_t xdr_diropokres(XDR *, diropokres*); +#else /* Old Style C */ +bool_t xdr_diropokres(); +#endif /* Old Style C */ + + +struct diropres { + nfsstat status; + union { + diropokres diropres; + } diropres_u; +}; +typedef struct diropres diropres; +#ifdef __cplusplus +extern "C" bool_t xdr_diropres(XDR *, diropres*); +#elif __STDC__ +extern bool_t xdr_diropres(XDR *, diropres*); +#else /* Old Style C */ +bool_t xdr_diropres(); +#endif /* Old Style C */ + + +struct readlinkres { + nfsstat status; + union { + nfspath data; + } readlinkres_u; +}; +typedef struct readlinkres readlinkres; +#ifdef __cplusplus +extern "C" bool_t xdr_readlinkres(XDR *, readlinkres*); +#elif __STDC__ +extern bool_t xdr_readlinkres(XDR *, readlinkres*); +#else /* Old Style C */ +bool_t xdr_readlinkres(); +#endif /* Old Style C */ + + +struct readargs { + nfs_fh file; + u_int offset; + u_int count; + u_int totalcount; +}; +typedef struct readargs readargs; +#ifdef __cplusplus +extern "C" bool_t xdr_readargs(XDR *, readargs*); +#elif __STDC__ +extern bool_t xdr_readargs(XDR *, readargs*); +#else /* Old Style C */ +bool_t xdr_readargs(); +#endif /* Old Style C */ + + +struct readokres { + fattr attributes; + struct { + u_int data_len; + char *data_val; + } data; +}; +typedef struct readokres readokres; +#ifdef __cplusplus +extern "C" bool_t xdr_readokres(XDR *, readokres*); +#elif __STDC__ +extern bool_t xdr_readokres(XDR *, readokres*); +#else /* Old Style C */ +bool_t xdr_readokres(); +#endif /* Old Style C */ + + +struct readres { + nfsstat status; + union { + readokres reply; + } readres_u; +}; +typedef struct readres readres; +#ifdef __cplusplus +extern "C" bool_t xdr_readres(XDR *, readres*); +#elif __STDC__ +extern bool_t xdr_readres(XDR *, readres*); +#else /* Old Style C */ +bool_t xdr_readres(); +#endif /* Old Style C */ + + +struct writeargs { + nfs_fh file; + u_int beginoffset; + u_int offset; + u_int totalcount; + struct { + u_int data_len; + char *data_val; + } data; +}; +typedef struct writeargs writeargs; +#ifdef __cplusplus +extern "C" bool_t xdr_writeargs(XDR *, writeargs*); +#elif __STDC__ +extern bool_t xdr_writeargs(XDR *, writeargs*); +#else /* Old Style C */ +bool_t xdr_writeargs(); +#endif /* Old Style C */ + + +struct createargs { + diropargs where; + sattr attributes; +}; +typedef struct createargs createargs; +#ifdef __cplusplus +extern "C" bool_t xdr_createargs(XDR *, createargs*); +#elif __STDC__ +extern bool_t xdr_createargs(XDR *, createargs*); +#else /* Old Style C */ +bool_t xdr_createargs(); +#endif /* Old Style C */ + + +struct renameargs { + diropargs from; + diropargs to; +}; +typedef struct renameargs renameargs; +#ifdef __cplusplus +extern "C" bool_t xdr_renameargs(XDR *, renameargs*); +#elif __STDC__ +extern bool_t xdr_renameargs(XDR *, renameargs*); +#else /* Old Style C */ +bool_t xdr_renameargs(); +#endif /* Old Style C */ + + +struct linkargs { + nfs_fh from; + diropargs to; +}; +typedef struct linkargs linkargs; +#ifdef __cplusplus +extern "C" bool_t xdr_linkargs(XDR *, linkargs*); +#elif __STDC__ +extern bool_t xdr_linkargs(XDR *, linkargs*); +#else /* Old Style C */ +bool_t xdr_linkargs(); +#endif /* Old Style C */ + + +struct symlinkargs { + diropargs from; + nfspath to; + sattr attributes; +}; +typedef struct symlinkargs symlinkargs; +#ifdef __cplusplus +extern "C" bool_t xdr_symlinkargs(XDR *, symlinkargs*); +#elif __STDC__ +extern bool_t xdr_symlinkargs(XDR *, symlinkargs*); +#else /* Old Style C */ +bool_t xdr_symlinkargs(); +#endif /* Old Style C */ + + +typedef char nfscookie[NFS_COOKIESIZE]; +#ifdef __cplusplus +extern "C" bool_t xdr_nfscookie(XDR *, nfscookie); +#elif __STDC__ +extern bool_t xdr_nfscookie(XDR *, nfscookie); +#else /* Old Style C */ +bool_t xdr_nfscookie(); +#endif /* Old Style C */ + + +struct readdirargs { + nfs_fh dir; + nfscookie cookie; + u_int count; +}; +typedef struct readdirargs readdirargs; +#ifdef __cplusplus +extern "C" bool_t xdr_readdirargs(XDR *, readdirargs*); +#elif __STDC__ +extern bool_t xdr_readdirargs(XDR *, readdirargs*); +#else /* Old Style C */ +bool_t xdr_readdirargs(); +#endif /* Old Style C */ + + +struct entry { + u_int fileid; + filename name; + nfscookie cookie; + struct entry *nextentry; +}; +typedef struct entry entry; +#ifdef __cplusplus +extern "C" bool_t xdr_entry(XDR *, entry*); +#elif __STDC__ +extern bool_t xdr_entry(XDR *, entry*); +#else /* Old Style C */ +bool_t xdr_entry(); +#endif /* Old Style C */ + + +struct dirlist { + entry *entries; + bool_t eof; +}; +typedef struct dirlist dirlist; +#ifdef __cplusplus +extern "C" bool_t xdr_dirlist(XDR *, dirlist*); +#elif __STDC__ +extern bool_t xdr_dirlist(XDR *, dirlist*); +#else /* Old Style C */ +bool_t xdr_dirlist(); +#endif /* Old Style C */ + + +struct readdirres { + nfsstat status; + union { + dirlist reply; + } readdirres_u; +}; +typedef struct readdirres readdirres; +#ifdef __cplusplus +extern "C" bool_t xdr_readdirres(XDR *, readdirres*); +#elif __STDC__ +extern bool_t xdr_readdirres(XDR *, readdirres*); +#else /* Old Style C */ +bool_t xdr_readdirres(); +#endif /* Old Style C */ + + +struct statfsokres { + u_int tsize; + u_int bsize; + u_int blocks; + u_int bfree; + u_int bavail; +}; +typedef struct statfsokres statfsokres; +#ifdef __cplusplus +extern "C" bool_t xdr_statfsokres(XDR *, statfsokres*); +#elif __STDC__ +extern bool_t xdr_statfsokres(XDR *, statfsokres*); +#else /* Old Style C */ +bool_t xdr_statfsokres(); +#endif /* Old Style C */ + + +struct statfsres { + nfsstat status; + union { + statfsokres reply; + } statfsres_u; +}; +typedef struct statfsres statfsres; +#ifdef __cplusplus +extern "C" bool_t xdr_statfsres(XDR *, statfsres*); +#elif __STDC__ +extern bool_t xdr_statfsres(XDR *, statfsres*); +#else /* Old Style C */ +bool_t xdr_statfsres(); +#endif /* Old Style C */ + + +#define NFS_PROGRAM ((u_long)100003) +#define NFS_VERSION ((u_long)2) + +#ifdef __cplusplus +#define NFSPROC_NULL ((u_long)0) +extern "C" void * nfsproc_null_2(void *, CLIENT *); +extern "C" void * nfsproc_null_2_svc(void *, struct svc_req *); +#define NFSPROC_GETATTR ((u_long)1) +extern "C" attrstat * nfsproc_getattr_2(nfs_fh *, CLIENT *); +extern "C" attrstat * nfsproc_getattr_2_svc(nfs_fh *, struct svc_req *); +#define NFSPROC_SETATTR ((u_long)2) +extern "C" attrstat * nfsproc_setattr_2(sattrargs *, CLIENT *); +extern "C" attrstat * nfsproc_setattr_2_svc(sattrargs *, struct svc_req *); +#define NFSPROC_ROOT ((u_long)3) +extern "C" void * nfsproc_root_2(void *, CLIENT *); +extern "C" void * nfsproc_root_2_svc(void *, struct svc_req *); +#define NFSPROC_LOOKUP ((u_long)4) +extern "C" diropres * nfsproc_lookup_2(diropargs *, CLIENT *); +extern "C" diropres * nfsproc_lookup_2_svc(diropargs *, struct svc_req *); +#define NFSPROC_READLINK ((u_long)5) +extern "C" readlinkres * nfsproc_readlink_2(nfs_fh *, CLIENT *); +extern "C" readlinkres * nfsproc_readlink_2_svc(nfs_fh *, struct svc_req *); +#define NFSPROC_READ ((u_long)6) +extern "C" readres * nfsproc_read_2(readargs *, CLIENT *); +extern "C" readres * nfsproc_read_2_svc(readargs *, struct svc_req *); +#define NFSPROC_WRITECACHE ((u_long)7) +extern "C" void * nfsproc_writecache_2(void *, CLIENT *); +extern "C" void * nfsproc_writecache_2_svc(void *, struct svc_req *); +#define NFSPROC_WRITE ((u_long)8) +extern "C" attrstat * nfsproc_write_2(writeargs *, CLIENT *); +extern "C" attrstat * nfsproc_write_2_svc(writeargs *, struct svc_req *); +#define NFSPROC_CREATE ((u_long)9) +extern "C" diropres * nfsproc_create_2(createargs *, CLIENT *); +extern "C" diropres * nfsproc_create_2_svc(createargs *, struct svc_req *); +#define NFSPROC_REMOVE ((u_long)10) +extern "C" nfsstat * nfsproc_remove_2(diropargs *, CLIENT *); +extern "C" nfsstat * nfsproc_remove_2_svc(diropargs *, struct svc_req *); +#define NFSPROC_RENAME ((u_long)11) +extern "C" nfsstat * nfsproc_rename_2(renameargs *, CLIENT *); +extern "C" nfsstat * nfsproc_rename_2_svc(renameargs *, struct svc_req *); +#define NFSPROC_LINK ((u_long)12) +extern "C" nfsstat * nfsproc_link_2(linkargs *, CLIENT *); +extern "C" nfsstat * nfsproc_link_2_svc(linkargs *, struct svc_req *); +#define NFSPROC_SYMLINK ((u_long)13) +extern "C" nfsstat * nfsproc_symlink_2(symlinkargs *, CLIENT *); +extern "C" nfsstat * nfsproc_symlink_2_svc(symlinkargs *, struct svc_req *); +#define NFSPROC_MKDIR ((u_long)14) +extern "C" diropres * nfsproc_mkdir_2(createargs *, CLIENT *); +extern "C" diropres * nfsproc_mkdir_2_svc(createargs *, struct svc_req *); +#define NFSPROC_RMDIR ((u_long)15) +extern "C" nfsstat * nfsproc_rmdir_2(diropargs *, CLIENT *); +extern "C" nfsstat * nfsproc_rmdir_2_svc(diropargs *, struct svc_req *); +#define NFSPROC_READDIR ((u_long)16) +extern "C" readdirres * nfsproc_readdir_2(readdirargs *, CLIENT *); +extern "C" readdirres * nfsproc_readdir_2_svc(readdirargs *, struct svc_req *); +#define NFSPROC_STATFS ((u_long)17) +extern "C" statfsres * nfsproc_statfs_2(nfs_fh *, CLIENT *); +extern "C" statfsres * nfsproc_statfs_2_svc(nfs_fh *, struct svc_req *); + +#elif __STDC__ +#define NFSPROC_NULL ((u_long)0) +extern void * nfsproc_null_2(void *, CLIENT *); +extern void * nfsproc_null_2_svc(void *, struct svc_req *); +#define NFSPROC_GETATTR ((u_long)1) +extern attrstat * nfsproc_getattr_2(nfs_fh *, CLIENT *); +extern attrstat * nfsproc_getattr_2_svc(nfs_fh *, struct svc_req *); +#define NFSPROC_SETATTR ((u_long)2) +extern attrstat * nfsproc_setattr_2(sattrargs *, CLIENT *); +extern attrstat * nfsproc_setattr_2_svc(sattrargs *, struct svc_req *); +#define NFSPROC_ROOT ((u_long)3) +extern void * nfsproc_root_2(void *, CLIENT *); +extern void * nfsproc_root_2_svc(void *, struct svc_req *); +#define NFSPROC_LOOKUP ((u_long)4) +extern diropres * nfsproc_lookup_2(diropargs *, CLIENT *); +extern diropres * nfsproc_lookup_2_svc(diropargs *, struct svc_req *); +#define NFSPROC_READLINK ((u_long)5) +extern readlinkres * nfsproc_readlink_2(nfs_fh *, CLIENT *); +extern readlinkres * nfsproc_readlink_2_svc(nfs_fh *, struct svc_req *); +#define NFSPROC_READ ((u_long)6) +extern readres * nfsproc_read_2(readargs *, CLIENT *); +extern readres * nfsproc_read_2_svc(readargs *, struct svc_req *); +#define NFSPROC_WRITECACHE ((u_long)7) +extern void * nfsproc_writecache_2(void *, CLIENT *); +extern void * nfsproc_writecache_2_svc(void *, struct svc_req *); +#define NFSPROC_WRITE ((u_long)8) +extern attrstat * nfsproc_write_2(writeargs *, CLIENT *); +extern attrstat * nfsproc_write_2_svc(writeargs *, struct svc_req *); +#define NFSPROC_CREATE ((u_long)9) +extern diropres * nfsproc_create_2(createargs *, CLIENT *); +extern diropres * nfsproc_create_2_svc(createargs *, struct svc_req *); +#define NFSPROC_REMOVE ((u_long)10) +extern nfsstat * nfsproc_remove_2(diropargs *, CLIENT *); +extern nfsstat * nfsproc_remove_2_svc(diropargs *, struct svc_req *); +#define NFSPROC_RENAME ((u_long)11) +extern nfsstat * nfsproc_rename_2(renameargs *, CLIENT *); +extern nfsstat * nfsproc_rename_2_svc(renameargs *, struct svc_req *); +#define NFSPROC_LINK ((u_long)12) +extern nfsstat * nfsproc_link_2(linkargs *, CLIENT *); +extern nfsstat * nfsproc_link_2_svc(linkargs *, struct svc_req *); +#define NFSPROC_SYMLINK ((u_long)13) +extern nfsstat * nfsproc_symlink_2(symlinkargs *, CLIENT *); +extern nfsstat * nfsproc_symlink_2_svc(symlinkargs *, struct svc_req *); +#define NFSPROC_MKDIR ((u_long)14) +extern diropres * nfsproc_mkdir_2(createargs *, CLIENT *); +extern diropres * nfsproc_mkdir_2_svc(createargs *, struct svc_req *); +#define NFSPROC_RMDIR ((u_long)15) +extern nfsstat * nfsproc_rmdir_2(diropargs *, CLIENT *); +extern nfsstat * nfsproc_rmdir_2_svc(diropargs *, struct svc_req *); +#define NFSPROC_READDIR ((u_long)16) +extern readdirres * nfsproc_readdir_2(readdirargs *, CLIENT *); +extern readdirres * nfsproc_readdir_2_svc(readdirargs *, struct svc_req *); +#define NFSPROC_STATFS ((u_long)17) +extern statfsres * nfsproc_statfs_2(nfs_fh *, CLIENT *); +extern statfsres * nfsproc_statfs_2_svc(nfs_fh *, struct svc_req *); + +#else /* Old Style C */ +#define NFSPROC_NULL ((u_long)0) +extern void * nfsproc_null_2(); +extern void * nfsproc_null_2_svc(); +#define NFSPROC_GETATTR ((u_long)1) +extern attrstat * nfsproc_getattr_2(); +extern attrstat * nfsproc_getattr_2_svc(); +#define NFSPROC_SETATTR ((u_long)2) +extern attrstat * nfsproc_setattr_2(); +extern attrstat * nfsproc_setattr_2_svc(); +#define NFSPROC_ROOT ((u_long)3) +extern void * nfsproc_root_2(); +extern void * nfsproc_root_2_svc(); +#define NFSPROC_LOOKUP ((u_long)4) +extern diropres * nfsproc_lookup_2(); +extern diropres * nfsproc_lookup_2_svc(); +#define NFSPROC_READLINK ((u_long)5) +extern readlinkres * nfsproc_readlink_2(); +extern readlinkres * nfsproc_readlink_2_svc(); +#define NFSPROC_READ ((u_long)6) +extern readres * nfsproc_read_2(); +extern readres * nfsproc_read_2_svc(); +#define NFSPROC_WRITECACHE ((u_long)7) +extern void * nfsproc_writecache_2(); +extern void * nfsproc_writecache_2_svc(); +#define NFSPROC_WRITE ((u_long)8) +extern attrstat * nfsproc_write_2(); +extern attrstat * nfsproc_write_2_svc(); +#define NFSPROC_CREATE ((u_long)9) +extern diropres * nfsproc_create_2(); +extern diropres * nfsproc_create_2_svc(); +#define NFSPROC_REMOVE ((u_long)10) +extern nfsstat * nfsproc_remove_2(); +extern nfsstat * nfsproc_remove_2_svc(); +#define NFSPROC_RENAME ((u_long)11) +extern nfsstat * nfsproc_rename_2(); +extern nfsstat * nfsproc_rename_2_svc(); +#define NFSPROC_LINK ((u_long)12) +extern nfsstat * nfsproc_link_2(); +extern nfsstat * nfsproc_link_2_svc(); +#define NFSPROC_SYMLINK ((u_long)13) +extern nfsstat * nfsproc_symlink_2(); +extern nfsstat * nfsproc_symlink_2_svc(); +#define NFSPROC_MKDIR ((u_long)14) +extern diropres * nfsproc_mkdir_2(); +extern diropres * nfsproc_mkdir_2_svc(); +#define NFSPROC_RMDIR ((u_long)15) +extern nfsstat * nfsproc_rmdir_2(); +extern nfsstat * nfsproc_rmdir_2_svc(); +#define NFSPROC_READDIR ((u_long)16) +extern readdirres * nfsproc_readdir_2(); +extern readdirres * nfsproc_readdir_2_svc(); +#define NFSPROC_STATFS ((u_long)17) +extern statfsres * nfsproc_statfs_2(); +extern statfsres * nfsproc_statfs_2_svc(); +#endif /* Old Style C */ + +#endif /* !_NFS_PROT_H_RPCGEN */ diff --git a/support/include/sockaddr.h b/support/include/sockaddr.h new file mode 100644 index 0000000..eeebcdf --- /dev/null +++ b/support/include/sockaddr.h @@ -0,0 +1,244 @@ +/* + * Copyright 2009 Oracle. All rights reserved. + * + * This file is part of nfs-utils. + * + * nfs-utils is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * nfs-utils is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with nfs-utils. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef NFS_UTILS_SOCKADDR_H +#define NFS_UTILS_SOCKADDR_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <stdbool.h> +#include <sys/socket.h> +#include <netinet/in.h> + +/* + * This type is for defining buffers that contain network socket + * addresses. + * + * Casting a "struct sockaddr *" to the address of a "struct + * sockaddr_storage" breaks C aliasing rules. The "union + * nfs_sockaddr" type follows C aliasing rules yet specifically + * allows converting pointers to it between "struct sockaddr *" + * and a few other network sockaddr-related pointer types. + * + * Note that this union is much smaller than a sockaddr_storage. + * It should be used only for AF_INET or AF_INET6 socket addresses. + * An AF_LOCAL sockaddr_un, for example, will clearly not fit into + * a buffer of this type. + */ +union nfs_sockaddr { + struct sockaddr sa; + struct sockaddr_in s4; + struct sockaddr_in6 s6; +}; + +#if SIZEOF_SOCKLEN_T - 0 == 0 +#define socklen_t unsigned int +#endif + +#define SIZEOF_SOCKADDR_UNKNOWN (socklen_t)0 +#define SIZEOF_SOCKADDR_IN (socklen_t)sizeof(struct sockaddr_in) + +#ifdef IPV6_SUPPORTED +#define SIZEOF_SOCKADDR_IN6 (socklen_t)sizeof(struct sockaddr_in6) +#else /* !IPV6_SUPPORTED */ +#define SIZEOF_SOCKADDR_IN6 SIZEOF_SOCKADDR_UNKNOWN +#endif /* !IPV6_SUPPORTED */ + +/** + * nfs_sockaddr_length - return the size in bytes of a socket address + * @sap: pointer to socket address + * + * Returns the size in bytes of @sap, or zero if the family is + * not recognized. + */ +static inline socklen_t +nfs_sockaddr_length(const struct sockaddr *sap) +{ + switch (sap->sa_family) { + case AF_INET: + return SIZEOF_SOCKADDR_IN; + case AF_INET6: + return SIZEOF_SOCKADDR_IN6; + } + return SIZEOF_SOCKADDR_UNKNOWN; +} + +static inline uint16_t +get_port4(const struct sockaddr *sap) +{ + const struct sockaddr_in *sin = (const struct sockaddr_in *)sap; + return ntohs(sin->sin_port); +} + +#ifdef IPV6_SUPPORTED +static inline uint16_t +get_port6(const struct sockaddr *sap) +{ + const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap; + return ntohs(sin6->sin6_port); +} +#else /* !IPV6_SUPPORTED */ +static inline uint16_t +get_port6(__attribute__ ((unused)) const struct sockaddr *sap) +{ + return 0; +} +#endif /* !IPV6_SUPPORTED */ + +/** + * nfs_get_port - extract port value from a socket address + * @sap: pointer to socket address + * + * Returns port value in host byte order, or zero if the + * socket address contains an unrecognized family. + */ +static inline uint16_t +nfs_get_port(const struct sockaddr *sap) +{ + switch (sap->sa_family) { + case AF_INET: + return get_port4(sap); + case AF_INET6: + return get_port6(sap); + } + return 0; +} + +static inline void +set_port4(struct sockaddr *sap, const uint16_t port) +{ + struct sockaddr_in *sin = (struct sockaddr_in *)sap; + sin->sin_port = htons(port); +} + +#ifdef IPV6_SUPPORTED +static inline void +set_port6(struct sockaddr *sap, const uint16_t port) +{ + struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap; + sin6->sin6_port = htons(port); +} +#else /* !IPV6_SUPPORTED */ +static inline void +set_port6(__attribute__ ((unused)) struct sockaddr *sap, + __attribute__ ((unused)) const uint16_t port) +{ +} +#endif /* !IPV6_SUPPORTED */ + +/** + * nfs_set_port - set port value in a socket address + * @sap: pointer to socket address + * @port: port value to set + * + */ +static inline void +nfs_set_port(struct sockaddr *sap, const uint16_t port) +{ + switch (sap->sa_family) { + case AF_INET: + set_port4(sap, port); + break; + case AF_INET6: + set_port6(sap, port); + break; + } +} + +/** + * nfs_is_v4_loopback - test to see if socket address is AF_INET loopback + * @sap: pointer to socket address + * + * Returns true if the socket address is the standard IPv4 loopback + * address; otherwise false is returned. + */ +static inline _Bool +nfs_is_v4_loopback(const struct sockaddr *sap) +{ + const struct sockaddr_in *sin = (const struct sockaddr_in *)sap; + + if (sin->sin_family != AF_INET) + return false; + if (sin->sin_addr.s_addr != htonl(INADDR_LOOPBACK)) + return false; + return true; +} + +static inline _Bool +compare_sockaddr4(const struct sockaddr *sa1, const struct sockaddr *sa2) +{ + const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1; + const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2; + return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr; +} + +#ifdef IPV6_SUPPORTED +static inline _Bool +compare_sockaddr6(const struct sockaddr *sa1, const struct sockaddr *sa2) +{ + const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1; + const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2; + const struct in6_addr *saddr1 = &sin1->sin6_addr; + const struct in6_addr *saddr2 = &sin2->sin6_addr; + + if (IN6_IS_ADDR_LINKLOCAL(saddr1) && IN6_IS_ADDR_LINKLOCAL(saddr2)) + if (sin1->sin6_scope_id != sin2->sin6_scope_id) + return false; + + return IN6_ARE_ADDR_EQUAL(saddr1, saddr2); +} +#else /* !IPV6_SUPPORTED */ +static inline _Bool +compare_sockaddr6(__attribute__ ((unused)) const struct sockaddr *sa1, + __attribute__ ((unused)) const struct sockaddr *sa2) +{ + return false; +} +#endif /* !IPV6_SUPPORTED */ + +/** + * nfs_compare_sockaddr - compare two socket addresses for equality + * @sa1: pointer to a socket address + * @sa2: pointer to a socket address + * + * Returns true if the two socket addresses contain equivalent + * network addresses; otherwise false is returned. + */ +static inline _Bool +nfs_compare_sockaddr(const struct sockaddr *sa1, const struct sockaddr *sa2) +{ + if (sa1 == NULL || sa2 == NULL) + return false; + + if (sa1->sa_family == sa2->sa_family) + switch (sa1->sa_family) { + case AF_INET: + return compare_sockaddr4(sa1, sa2); + case AF_INET6: + return compare_sockaddr6(sa1, sa2); + } + + return false; +} + +#endif /* !NFS_UTILS_SOCKADDR_H */ diff --git a/support/include/sys/Makefile.am b/support/include/sys/Makefile.am new file mode 100644 index 0000000..aead11d --- /dev/null +++ b/support/include/sys/Makefile.am @@ -0,0 +1,5 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = fs + +MAINTAINERCLEANFILES = Makefile.in diff --git a/support/include/sys/Makefile.in b/support/include/sys/Makefile.in new file mode 100644 index 0000000..0f3e008 --- /dev/null +++ b/support/include/sys/Makefile.in @@ -0,0 +1,713 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = support/include/sys +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ax_gcc_func_attribute.m4 \ + $(top_srcdir)/aclocal/bsdsignals.m4 \ + $(top_srcdir)/aclocal/getrandom.m4 \ + $(top_srcdir)/aclocal/ipv6.m4 \ + $(top_srcdir)/aclocal/kerberos5.m4 \ + $(top_srcdir)/aclocal/keyutils.m4 \ + $(top_srcdir)/aclocal/libblkid.m4 \ + $(top_srcdir)/aclocal/libcap.m4 \ + $(top_srcdir)/aclocal/libevent.m4 \ + $(top_srcdir)/aclocal/libpthread.m4 \ + $(top_srcdir)/aclocal/libsqlite3.m4 \ + $(top_srcdir)/aclocal/libtirpc.m4 \ + $(top_srcdir)/aclocal/libxml2.m4 \ + $(top_srcdir)/aclocal/nfs-utils.m4 \ + $(top_srcdir)/aclocal/rpcsec_vers.m4 \ + $(top_srcdir)/aclocal/tcp-wrappers.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/support/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GREP = @GREP@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GSSD = @GSSD@ +GSSGLUE_CFLAGS = @GSSGLUE_CFLAGS@ +GSSGLUE_LIBS = @GSSGLUE_LIBS@ +GSSKRB_CFLAGS = @GSSKRB_CFLAGS@ +GSSKRB_LIBS = @GSSKRB_LIBS@ +HAVE_GETRANDOM = @HAVE_GETRANDOM@ +HAVE_LIBWRAP = @HAVE_LIBWRAP@ +HAVE_TCP_WRAPPER = @HAVE_TCP_WRAPPER@ +IDMAPD = @IDMAPD@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +K5VERS = @K5VERS@ +KRBCFLAGS = @KRBCFLAGS@ +KRBDIR = @KRBDIR@ +KRBLDFLAGS = @KRBLDFLAGS@ +KRBLIBS = @KRBLIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ +LIBBLKID = @LIBBLKID@ +LIBBSD = @LIBBSD@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBEVENT = @LIBEVENT@ +LIBKEYUTILS = @LIBKEYUTILS@ +LIBMOUNT = @LIBMOUNT@ +LIBMOUNT_CFLAGS = @LIBMOUNT_CFLAGS@ +LIBMOUNT_LIBS = @LIBMOUNT_LIBS@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPTHREAD = @LIBPTHREAD@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSQLITE = @LIBSQLITE@ +LIBTIRPC = @LIBTIRPC@ +LIBTOOL = @LIBTOOL@ +LIBWRAP = @LIBWRAP@ +LIBXML2 = @LIBXML2@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_PLUGINS = @PATH_PLUGINS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +RELEASE = @RELEASE@ +RPCGEN_PATH = @RPCGEN_PATH@ +RPCSECGSS_CFLAGS = @RPCSECGSS_CFLAGS@ +RPCSECGSS_LIBS = @RPCSECGSS_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SVCGSSD = @SVCGSSD@ +TIRPC_CFLAGS = @TIRPC_CFLAGS@ +TIRPC_LIBS = @TIRPC_LIBS@ +VERSION = @VERSION@ +XML2_CFLAGS = @XML2_CFLAGS@ +XML2_LIBS = @XML2_LIBS@ +_rpc_pipefsmount = @_rpc_pipefsmount@ +_statedir = @_statedir@ +_sysconfdir = @_sysconfdir@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_gss = @enable_gss@ +enable_ipv6 = @enable_ipv6@ +enable_mountconfig = @enable_mountconfig@ +enable_nfsv4 = @enable_nfsv4@ +enable_nfsv41 = @enable_nfsv41@ +enable_svcgss = @enable_svcgss@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +kprefix = @kprefix@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +mountfile = @mountfile@ +nfsconfig = @nfsconfig@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rpc_pipefsmount = @rpc_pipefsmount@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +startstatd = @startstatd@ +statdpath = @statdpath@ +statduser = @statduser@ +statedir = @statedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +unitdir = @unitdir@ +SUBDIRS = fs +MAINTAINERCLEANFILES = Makefile.in +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu support/include/sys/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu support/include/sys/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-recursive + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-recursive + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \ + check-am clean clean-generic clean-libtool cscopelist-am ctags \ + ctags-am distclean distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \ + ps ps-am tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/support/include/sys/fs/Makefile.am b/support/include/sys/fs/Makefile.am new file mode 100644 index 0000000..9d5fa43 --- /dev/null +++ b/support/include/sys/fs/Makefile.am @@ -0,0 +1,5 @@ +## Process this file with automake to produce Makefile.in + +noinst_HEADERS = ext2fs.h + +MAINTAINERCLEANFILES = Makefile.in diff --git a/support/include/sys/fs/Makefile.in b/support/include/sys/fs/Makefile.in new file mode 100644 index 0000000..99152a1 --- /dev/null +++ b/support/include/sys/fs/Makefile.in @@ -0,0 +1,601 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = support/include/sys/fs +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ax_gcc_func_attribute.m4 \ + $(top_srcdir)/aclocal/bsdsignals.m4 \ + $(top_srcdir)/aclocal/getrandom.m4 \ + $(top_srcdir)/aclocal/ipv6.m4 \ + $(top_srcdir)/aclocal/kerberos5.m4 \ + $(top_srcdir)/aclocal/keyutils.m4 \ + $(top_srcdir)/aclocal/libblkid.m4 \ + $(top_srcdir)/aclocal/libcap.m4 \ + $(top_srcdir)/aclocal/libevent.m4 \ + $(top_srcdir)/aclocal/libpthread.m4 \ + $(top_srcdir)/aclocal/libsqlite3.m4 \ + $(top_srcdir)/aclocal/libtirpc.m4 \ + $(top_srcdir)/aclocal/libxml2.m4 \ + $(top_srcdir)/aclocal/nfs-utils.m4 \ + $(top_srcdir)/aclocal/rpcsec_vers.m4 \ + $(top_srcdir)/aclocal/tcp-wrappers.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/support/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +am__DIST_COMMON = $(srcdir)/Makefile.in +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GREP = @GREP@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GSSD = @GSSD@ +GSSGLUE_CFLAGS = @GSSGLUE_CFLAGS@ +GSSGLUE_LIBS = @GSSGLUE_LIBS@ +GSSKRB_CFLAGS = @GSSKRB_CFLAGS@ +GSSKRB_LIBS = @GSSKRB_LIBS@ +HAVE_GETRANDOM = @HAVE_GETRANDOM@ +HAVE_LIBWRAP = @HAVE_LIBWRAP@ +HAVE_TCP_WRAPPER = @HAVE_TCP_WRAPPER@ +IDMAPD = @IDMAPD@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +K5VERS = @K5VERS@ +KRBCFLAGS = @KRBCFLAGS@ +KRBDIR = @KRBDIR@ +KRBLDFLAGS = @KRBLDFLAGS@ +KRBLIBS = @KRBLIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ +LIBBLKID = @LIBBLKID@ +LIBBSD = @LIBBSD@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBEVENT = @LIBEVENT@ +LIBKEYUTILS = @LIBKEYUTILS@ +LIBMOUNT = @LIBMOUNT@ +LIBMOUNT_CFLAGS = @LIBMOUNT_CFLAGS@ +LIBMOUNT_LIBS = @LIBMOUNT_LIBS@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPTHREAD = @LIBPTHREAD@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSQLITE = @LIBSQLITE@ +LIBTIRPC = @LIBTIRPC@ +LIBTOOL = @LIBTOOL@ +LIBWRAP = @LIBWRAP@ +LIBXML2 = @LIBXML2@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_PLUGINS = @PATH_PLUGINS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +RELEASE = @RELEASE@ +RPCGEN_PATH = @RPCGEN_PATH@ +RPCSECGSS_CFLAGS = @RPCSECGSS_CFLAGS@ +RPCSECGSS_LIBS = @RPCSECGSS_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SVCGSSD = @SVCGSSD@ +TIRPC_CFLAGS = @TIRPC_CFLAGS@ +TIRPC_LIBS = @TIRPC_LIBS@ +VERSION = @VERSION@ +XML2_CFLAGS = @XML2_CFLAGS@ +XML2_LIBS = @XML2_LIBS@ +_rpc_pipefsmount = @_rpc_pipefsmount@ +_statedir = @_statedir@ +_sysconfdir = @_sysconfdir@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_gss = @enable_gss@ +enable_ipv6 = @enable_ipv6@ +enable_mountconfig = @enable_mountconfig@ +enable_nfsv4 = @enable_nfsv4@ +enable_nfsv41 = @enable_nfsv41@ +enable_svcgss = @enable_svcgss@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +kprefix = @kprefix@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +mountfile = @mountfile@ +nfsconfig = @nfsconfig@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rpc_pipefsmount = @rpc_pipefsmount@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +startstatd = @startstatd@ +statdpath = @statdpath@ +statduser = @statduser@ +statedir = @statedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +unitdir = @unitdir@ +noinst_HEADERS = ext2fs.h +MAINTAINERCLEANFILES = Makefile.in +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu support/include/sys/fs/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu support/include/sys/fs/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \ + clean-libtool cscopelist-am ctags ctags-am distclean \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/support/include/sys/fs/ext2fs.h b/support/include/sys/fs/ext2fs.h new file mode 100644 index 0000000..93b3e2b --- /dev/null +++ b/support/include/sys/fs/ext2fs.h @@ -0,0 +1,42 @@ +#ifndef _SYS_FS_EXT2FS_H +#define _SYS_FS_EXT2FS_H + +/* + * ioctl commands + */ +#define EXT2_IOC_GETFLAGS _IOR('f', 1, long) +#define EXT2_IOC_SETFLAGS _IOW('f', 2, long) +#define EXT2_IOC_GETVERSION _IOR('v', 1, long) +#define EXT2_IOC_SETVERSION _IOW('v', 2, long) + +/* + * File system states + */ +#define EXT2_VALID_FS 0x0001 /* Unmounted cleanly */ +#define EXT2_ERROR_FS 0x0002 /* Errors detected */ + +/* + * Mount flags + */ +#define EXT2_MOUNT_CHECK_NORMAL 0x0001 /* Do some more checks */ +#define EXT2_MOUNT_CHECK_STRICT 0x0002 /* Do again more checks */ +#define EXT2_MOUNT_CHECK (EXT2_MOUNT_CHECK_NORMAL | \ + EXT2_MOUNT_CHECK_STRICT) +#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */ +#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */ +#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */ +#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */ +#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */ +#define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */ + +#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt +#define set_opt(o, opt) o |= EXT2_MOUNT_##opt +#define test_opt(sb, opt) ((sb)->u.ext2_sb.s_mount_opt & \ + EXT2_MOUNT_##opt) +/* + * Maximal mount counts between two filesystem checks + */ +#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */ +#define EXT2_DFL_CHECKINTERVAL 0 /* Don't use interval check */ + +#endif /* _SYS_FS_EXT2FS_H */ diff --git a/support/include/tcpwrapper.h b/support/include/tcpwrapper.h new file mode 100644 index 0000000..f735106 --- /dev/null +++ b/support/include/tcpwrapper.h @@ -0,0 +1,12 @@ +#ifndef TCP_WRAPPER_H +#define TCP_WRAPPER_H + +#include <sys/socket.h> +#include <netinet/in.h> +#include <arpa/inet.h> + +extern int from_local(const struct sockaddr *sap); +extern int check_default(char *name, struct sockaddr *sap, + const unsigned long program); + +#endif /* TCP_WRAPPER_H */ diff --git a/support/include/v4root.h b/support/include/v4root.h new file mode 100644 index 0000000..706c15c --- /dev/null +++ b/support/include/v4root.h @@ -0,0 +1,15 @@ +/* + * Copyright (C) 2009 Red Hat <nfs@redhat.com> + * support/include/v4root.h + * + * Support routines for dynamic pseudo roots. + * + */ + +#ifndef V4ROOT_H +#define V4ROOT_H + +extern int v4root_needed; +extern void v4root_set(void); + +#endif /* V4ROOT_H */ diff --git a/support/include/version.h b/support/include/version.h new file mode 100644 index 0000000..d7cf680 --- /dev/null +++ b/support/include/version.h @@ -0,0 +1,53 @@ +/* + * version.h -- get running kernel version + * + * Copyright (C) 2008 Oracle. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA + * + */ + +#ifndef _NFS_UTILS_MOUNT_VERSION_H +#define _NFS_UTILS_MOUNT_VERSION_H + +#include <stdio.h> +#include <limits.h> + +#include <sys/utsname.h> + +static inline unsigned int MAKE_VERSION(unsigned int p, unsigned int q, + unsigned int r) +{ + return (65536 * p) + (256 * q) + r; +} + +static inline unsigned int linux_version_code(void) +{ + struct utsname my_utsname; + unsigned int p, q = 0, r = 0; + + /* UINT_MAX as backward compatibility code should not be run */ + if (uname(&my_utsname)) + return UINT_MAX; + + /* UINT_MAX as future versions might not start with an integer */ + if (sscanf(my_utsname.release, "%u.%u.%u", &p, &q, &r) < 1) + return UINT_MAX; + + return MAKE_VERSION(p, q, r); +} + +#endif /* _NFS_UTILS_MOUNT_VERSION_H */ diff --git a/support/include/workqueue.h b/support/include/workqueue.h new file mode 100644 index 0000000..518be82 --- /dev/null +++ b/support/include/workqueue.h @@ -0,0 +1,18 @@ +/* + * Copyright (C) 2019 Trond Myklebust <trond.myklebust@hammerspace.com> + */ +#ifndef WORKQUEUE_H +#define WORKQUEUE_H + +struct xthread_workqueue; + +struct xthread_workqueue *xthread_workqueue_alloc(void); +void xthread_workqueue_shutdown(struct xthread_workqueue *wq); + +void xthread_work_run_sync(struct xthread_workqueue *wq, + void (*fn)(void *), void *data); + +void xthread_workqueue_chroot(struct xthread_workqueue *wq, + const char *path); + +#endif diff --git a/support/include/xcommon.h b/support/include/xcommon.h new file mode 100644 index 0000000..efde83c --- /dev/null +++ b/support/include/xcommon.h @@ -0,0 +1,65 @@ +/* + * xcommon.h -- Support function prototypes. Functions are in xcommon.c. + * + * 2006-06-06 Amit Gud <agud@redhat.com> + * - Moved code snippets from mount/sundries.h of util-linux + * and merged code from support/nfs/xmalloc.c by Olaf Kirch <okir@monad.swb.de> here. + */ + +#ifndef _XMALLOC_H +#define _XMALLOC_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/types.h> +#include <fcntl.h> +#include <limits.h> +#include <signal.h> +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +#ifdef MAJOR_IN_MKDEV +#include <sys/mkdev.h> +#elif defined(MAJOR_IN_SYSMACROS) +#include <sys/sysmacros.h> +#endif + +#define streq(s, t) (strcmp ((s), (t)) == 0) + +#ifdef HAVE_FUNC_ATTRIBUTE_FORMAT +#define X_FORMAT(_x) __attribute__((__format__ _x)) +#else +#define X_FORMAT(_x) +#endif + +/* Functions in sundries.c that are used in mount.c and umount.c */ +char *canonicalize (const char *path); +void nfs_error (const char *fmt, ...) X_FORMAT((printf, 1, 2)); +void *xmalloc (size_t size); +void *xrealloc(void *p, size_t size); +void xfree(void *); +char *xstrdup (const char *s); +char *xstrndup (const char *s, int n); +char *xstrconcat2 (const char *, const char *); +char *xstrconcat3 (const char *, const char *, const char *); +char *xstrconcat4 (const char *, const char *, const char *, const char *); +void die (int errcode, const char *fmt, ...) X_FORMAT((printf, 2, 3)); + +extern void die(int err, const char *fmt, ...) X_FORMAT((printf, 2, 3)); +extern void (*at_die)(void); + +/* exit status - bits below are ORed */ +#define EX_SUCCESS 0 /* no failure occurred */ +#define EX_USAGE 1 /* incorrect invocation or permission */ +#define EX_SYSERR 2 /* out of memory, cannot fork, ... */ +#define EX_SOFTWARE 4 /* internal mount bug or wrong version */ +#define EX_USER 8 /* user interrupt */ +#define EX_FILEIO 16 /* problems writing, locking, ... mtab/fstab */ +#define EX_FAIL 32 /* mount failure */ +#define EX_SOMEOK 64 /* some mount succeeded */ +#define EX_BG 256 /* retry in background (internal only) */ + +#endif /* XMALLOC_H */ diff --git a/support/include/xio.h b/support/include/xio.h new file mode 100644 index 0000000..a8e288e --- /dev/null +++ b/support/include/xio.h @@ -0,0 +1,26 @@ +/* + * xio.h Declarations for simple parsing functions. + * + */ + +#ifndef XIO_H +#define XIO_H + +#include <stdio.h> + +typedef struct XFILE { + FILE *x_fp; + int x_line; +} XFILE; + +XFILE *xfopen(char *fname, char *type); +int xflock(char *fname, char *type); +void xfunlock(int lockid); +void xfclose(XFILE *xfp); +int xgettok(XFILE *xfp, char sepa, char *tok, int len); +int xgetc(XFILE *xfp); +void xungetc(int c, XFILE *xfp); +void xskip(XFILE *xfp, char *str); +char xskipcomment(XFILE *xfp); + +#endif /* XIO_H */ diff --git a/support/include/xlog.h b/support/include/xlog.h new file mode 100644 index 0000000..69cdf61 --- /dev/null +++ b/support/include/xlog.h @@ -0,0 +1,62 @@ +/* + * xlog Logging functionality + * + * Copyright (C) 1995 Olaf Kirch <okir@monad.swb.de> + */ + +#ifndef XLOG_H +#define XLOG_H + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdarg.h> + +/* These are logged always. L_FATAL also does exit(1) */ +#define L_FATAL 0x0100 +#define L_ERROR 0x0200 +#define L_WARNING 0x0400 +#define L_NOTICE 0x0800 +#define L_ALL 0xFF00 + +/* These are logged if enabled with xlog_[s]config */ +/* NB: code does not expect ORing together D_ and L_ */ +#define D_GENERAL 0x0001 /* general debug info */ +#define D_CALL 0x0002 +#define D_AUTH 0x0004 +#define D_FAC3 0x0008 +#define D_FAC4 0x0010 +#define D_FAC5 0x0020 +#define D_PARSE 0x0040 +#define D_FAC7 0x0080 +#define D_ALL 0x00FF + +/* This can be used to define symbolic log names that can be passed to + * xlog_config. */ +struct xlog_debugfac { + char *df_name; + int df_fac; +}; + +#ifdef HAVE_FUNC_ATTRIBUTE_FORMAT +#define XLOG_FORMAT(_x) __attribute__((__format__ _x)) +#else +#define XLOG_FORMAT(_x) +#endif + +extern int export_errno; +void xlog_open(char *progname); +void xlog_stderr(int on); +void xlog_syslog(int on); +void xlog_config(int fac, int on); +void xlog_sconfig(char *, int on); +void xlog_set_debug(char *); +int xlog_enabled(int fac); +void xlog(int fac, const char *fmt, ...) XLOG_FORMAT((printf, 2, 3)); +void xlog_warn(const char *fmt, ...) XLOG_FORMAT((printf, 1, 2)); +void xlog_err(const char *fmt, ...) XLOG_FORMAT((printf, 1, 2)); +void xlog_errno(int err, const char *fmt, ...) XLOG_FORMAT((printf, 2, 3)); +void xlog_backend(int fac, const char *fmt, va_list args) XLOG_FORMAT((printf, 2, 0)); + +#endif /* XLOG_H */ diff --git a/support/include/xmalloc.h b/support/include/xmalloc.h new file mode 100644 index 0000000..8b82800 --- /dev/null +++ b/support/include/xmalloc.h @@ -0,0 +1 @@ +#include "xcommon.h" diff --git a/support/include/xstat.h b/support/include/xstat.h new file mode 100644 index 0000000..f1241bb --- /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/junction/Makefile.am b/support/junction/Makefile.am new file mode 100644 index 0000000..be6958b --- /dev/null +++ b/support/junction/Makefile.am @@ -0,0 +1,32 @@ +## +## @file support/junction/Makefile.am +## @brief Process this file with automake to produce src/libjunction/Makefile.in +## + +## +## Copyright 2010, 2018 Oracle. All rights reserved. +## +## This file is part of nfs-utils. +## +## nfs-utils is free software; you can redistribute it and/or modify +## it under the terms of the GNU General Public License version 2.0 as +## published by the Free Software Foundation. +## +## nfs-utils is distributed in the hope that it will be useful, but +## WITHOUT ANY WARRANTY; without even the implied warranty of +## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +## GNU General Public License version 2.0 for more details. +## +## You should have received a copy of the GNU General Public License +## version 2.0 along with nfs-utils. If not, see: +## +## http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt +## + +noinst_HEADERS = junction-internal.h + +noinst_LTLIBRARIES = libjunction.la +libjunction_la_SOURCES = display.c export-cache.c junction.c \ + locations.c nfs.c path.c xml.c + +MAINTAINERCLEANFILES = Makefile.in diff --git a/support/junction/Makefile.in b/support/junction/Makefile.in new file mode 100644 index 0000000..8ca8ad3 --- /dev/null +++ b/support/junction/Makefile.in @@ -0,0 +1,715 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = support/junction +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ax_gcc_func_attribute.m4 \ + $(top_srcdir)/aclocal/bsdsignals.m4 \ + $(top_srcdir)/aclocal/getrandom.m4 \ + $(top_srcdir)/aclocal/ipv6.m4 \ + $(top_srcdir)/aclocal/kerberos5.m4 \ + $(top_srcdir)/aclocal/keyutils.m4 \ + $(top_srcdir)/aclocal/libblkid.m4 \ + $(top_srcdir)/aclocal/libcap.m4 \ + $(top_srcdir)/aclocal/libevent.m4 \ + $(top_srcdir)/aclocal/libpthread.m4 \ + $(top_srcdir)/aclocal/libsqlite3.m4 \ + $(top_srcdir)/aclocal/libtirpc.m4 \ + $(top_srcdir)/aclocal/libxml2.m4 \ + $(top_srcdir)/aclocal/nfs-utils.m4 \ + $(top_srcdir)/aclocal/rpcsec_vers.m4 \ + $(top_srcdir)/aclocal/tcp-wrappers.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(noinst_HEADERS) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/support/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LTLIBRARIES = $(noinst_LTLIBRARIES) +libjunction_la_LIBADD = +am_libjunction_la_OBJECTS = display.lo export-cache.lo junction.lo \ + locations.lo nfs.lo path.lo xml.lo +libjunction_la_OBJECTS = $(am_libjunction_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/support/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/display.Plo \ + ./$(DEPDIR)/export-cache.Plo ./$(DEPDIR)/junction.Plo \ + ./$(DEPDIR)/locations.Plo ./$(DEPDIR)/nfs.Plo \ + ./$(DEPDIR)/path.Plo ./$(DEPDIR)/xml.Plo +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libjunction_la_SOURCES) +DIST_SOURCES = $(libjunction_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +HEADERS = $(noinst_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GREP = @GREP@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GSSD = @GSSD@ +GSSGLUE_CFLAGS = @GSSGLUE_CFLAGS@ +GSSGLUE_LIBS = @GSSGLUE_LIBS@ +GSSKRB_CFLAGS = @GSSKRB_CFLAGS@ +GSSKRB_LIBS = @GSSKRB_LIBS@ +HAVE_GETRANDOM = @HAVE_GETRANDOM@ +HAVE_LIBWRAP = @HAVE_LIBWRAP@ +HAVE_TCP_WRAPPER = @HAVE_TCP_WRAPPER@ +IDMAPD = @IDMAPD@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +K5VERS = @K5VERS@ +KRBCFLAGS = @KRBCFLAGS@ +KRBDIR = @KRBDIR@ +KRBLDFLAGS = @KRBLDFLAGS@ +KRBLIBS = @KRBLIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ +LIBBLKID = @LIBBLKID@ +LIBBSD = @LIBBSD@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBEVENT = @LIBEVENT@ +LIBKEYUTILS = @LIBKEYUTILS@ +LIBMOUNT = @LIBMOUNT@ +LIBMOUNT_CFLAGS = @LIBMOUNT_CFLAGS@ +LIBMOUNT_LIBS = @LIBMOUNT_LIBS@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPTHREAD = @LIBPTHREAD@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSQLITE = @LIBSQLITE@ +LIBTIRPC = @LIBTIRPC@ +LIBTOOL = @LIBTOOL@ +LIBWRAP = @LIBWRAP@ +LIBXML2 = @LIBXML2@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_PLUGINS = @PATH_PLUGINS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +RELEASE = @RELEASE@ +RPCGEN_PATH = @RPCGEN_PATH@ +RPCSECGSS_CFLAGS = @RPCSECGSS_CFLAGS@ +RPCSECGSS_LIBS = @RPCSECGSS_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SVCGSSD = @SVCGSSD@ +TIRPC_CFLAGS = @TIRPC_CFLAGS@ +TIRPC_LIBS = @TIRPC_LIBS@ +VERSION = @VERSION@ +XML2_CFLAGS = @XML2_CFLAGS@ +XML2_LIBS = @XML2_LIBS@ +_rpc_pipefsmount = @_rpc_pipefsmount@ +_statedir = @_statedir@ +_sysconfdir = @_sysconfdir@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_gss = @enable_gss@ +enable_ipv6 = @enable_ipv6@ +enable_mountconfig = @enable_mountconfig@ +enable_nfsv4 = @enable_nfsv4@ +enable_nfsv41 = @enable_nfsv41@ +enable_svcgss = @enable_svcgss@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +kprefix = @kprefix@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +mountfile = @mountfile@ +nfsconfig = @nfsconfig@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rpc_pipefsmount = @rpc_pipefsmount@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +startstatd = @startstatd@ +statdpath = @statdpath@ +statduser = @statduser@ +statedir = @statedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +unitdir = @unitdir@ +noinst_HEADERS = junction-internal.h +noinst_LTLIBRARIES = libjunction.la +libjunction_la_SOURCES = display.c export-cache.c junction.c \ + locations.c nfs.c path.c xml.c + +MAINTAINERCLEANFILES = Makefile.in +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu support/junction/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu support/junction/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libjunction.la: $(libjunction_la_OBJECTS) $(libjunction_la_DEPENDENCIES) $(EXTRA_libjunction_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libjunction_la_OBJECTS) $(libjunction_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/display.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/export-cache.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/junction.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/locations.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nfs.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/path.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xml.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/display.Plo + -rm -f ./$(DEPDIR)/export-cache.Plo + -rm -f ./$(DEPDIR)/junction.Plo + -rm -f ./$(DEPDIR)/locations.Plo + -rm -f ./$(DEPDIR)/nfs.Plo + -rm -f ./$(DEPDIR)/path.Plo + -rm -f ./$(DEPDIR)/xml.Plo + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/display.Plo + -rm -f ./$(DEPDIR)/export-cache.Plo + -rm -f ./$(DEPDIR)/junction.Plo + -rm -f ./$(DEPDIR)/locations.Plo + -rm -f ./$(DEPDIR)/nfs.Plo + -rm -f ./$(DEPDIR)/path.Plo + -rm -f ./$(DEPDIR)/xml.Plo + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-noinstLTLIBRARIES \ + cscopelist-am ctags ctags-am distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/support/junction/display.c b/support/junction/display.c new file mode 100644 index 0000000..e1e1af1 --- /dev/null +++ b/support/junction/display.c @@ -0,0 +1,139 @@ +/** + * @file support/junction/display.c + * @brief Shared display helper functions + */ + +/* + * Copyright 2010, 2018 Oracle. All rights reserved. + * + * This file is part of nfs-utils. + * + * nfs-utils is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 as + * published by the Free Software Foundation. + * + * nfs-utils is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2.0 for more details. + * + * You should have received a copy of the GNU General Public License + * version 2.0 along with nfs-utils. If not, see: + * + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + */ + +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "junction.h" + +/** + * Return human-readable equivalent of a FedFsStatus value + * + * @param status FedFsStatus code + * @return a static NUL-terminated C string + */ +const char * +nsdb_display_fedfsstatus(const FedFsStatus status) +{ + switch (status) { + case FEDFS_OK: + return "FEDFS_OK"; + case FEDFS_ERR_ACCESS: + return "FEDFS_ERR_ACCESS"; + case FEDFS_ERR_BADCHAR: + return "FEDFS_ERR_BADCHAR"; + case FEDFS_ERR_BADNAME: + return "FEDFS_ERR_BADNAME"; + case FEDFS_ERR_NAMETOOLONG: + return "FEDFS_ERR_NAMETOOLONG"; + case FEDFS_ERR_LOOP: + return "FEDFS_ERR_LOOP"; + case FEDFS_ERR_BADXDR: + return "FEDFS_ERR_BADXDR"; + case FEDFS_ERR_EXIST: + return "FEDFS_ERR_EXIST"; + case FEDFS_ERR_INVAL: + return "FEDFS_ERR_INVAL"; + case FEDFS_ERR_IO: + return "FEDFS_ERR_IO"; + case FEDFS_ERR_NOSPC: + return "FEDFS_ERR_NOSPC"; + case FEDFS_ERR_NOTJUNCT: + return "FEDFS_ERR_NOTJUNCT"; + case FEDFS_ERR_NOTLOCAL: + return "FEDFS_ERR_NOTLOCAL"; + case FEDFS_ERR_PERM: + return "FEDFS_ERR_PERM"; + case FEDFS_ERR_ROFS: + return "FEDFS_ERR_ROFS"; + case FEDFS_ERR_SVRFAULT: + return "FEDFS_ERR_SVRFAULT"; + case FEDFS_ERR_NOTSUPP: + return "FEDFS_ERR_NOTSUPP"; + case FEDFS_ERR_NSDB_ROUTE: + return "FEDFS_ERR_NSDB_ROUTE"; + case FEDFS_ERR_NSDB_DOWN: + return "FEDFS_ERR_NSDB_DOWN"; + case FEDFS_ERR_NSDB_CONN: + return "FEDFS_ERR_NSDB_CONN"; + case FEDFS_ERR_NSDB_AUTH: + return "FEDFS_ERR_NSDB_AUTH"; + case FEDFS_ERR_NSDB_LDAP: + return "FEDFS_ERR_NSDB_LDAP"; + case FEDFS_ERR_NSDB_LDAP_VAL: + return "FEDFS_ERR_NSDB_LDAP_VAL"; + case FEDFS_ERR_NSDB_NONCE: + return "FEDFS_ERR_NSDB_NONCE"; + case FEDFS_ERR_NSDB_NOFSN: + return "FEDFS_ERR_NSDB_NOFSN"; + case FEDFS_ERR_NSDB_NOFSL: + return "FEDFS_ERR_NSDB_NOFSL"; + case FEDFS_ERR_NSDB_RESPONSE: + return "FEDFS_ERR_NSDB_RESPONSE"; + case FEDFS_ERR_NSDB_FAULT: + return "FEDFS_ERR_NSDB_FAULT"; + case FEDFS_ERR_NSDB_PARAMS: + return "FEDFS_ERR_NSDB_PARAMS"; + case FEDFS_ERR_NSDB_LDAP_REFERRAL: + return "FEDFS_ERR_NSDB_LDAP_REFERRAL"; + case FEDFS_ERR_NSDB_LDAP_REFERRAL_VAL: + return "FEDFS_ERR_NSDB_LDAP_REFERRAL_VAL"; + case FEDFS_ERR_NSDB_PARAMS_LDAP_REFERRAL: + return "FEDFS_ERR_NSDB_PARAMS_LDAP_REFERRAL"; + case FEDFS_ERR_PATH_TYPE_UNSUPP: + return "FEDFS_ERR_PATH_TYPE_UNSUPP"; + case FEDFS_ERR_DELAY: + return "FEDFS_ERR_DELAY"; + case FEDFS_ERR_NO_CACHE: + return "FEDFS_ERR_NO_CACHE"; + case FEDFS_ERR_UNKNOWN_CACHE: + return "FEDFS_ERR_UNKNOWN_CACHE"; + case FEDFS_ERR_NO_CACHE_UPDATE: + return "FEDFS_ERR_NO_CACHE_UPDATE"; + default: + break; + } + return "an unrecognized error code"; +} + +/** + * Display human-readable FedFsStatus on stderr + * + * @param status FedFsStatus value to display + */ +void +nsdb_print_fedfsstatus(const FedFsStatus status) +{ + if (status == FEDFS_OK) { + printf("Call completed successfully\n"); + return; + } + + fprintf(stderr, "Server returned %s\n", + nsdb_display_fedfsstatus(status)); +} diff --git a/support/junction/export-cache.c b/support/junction/export-cache.c new file mode 100644 index 0000000..4e578c9 --- /dev/null +++ b/support/junction/export-cache.c @@ -0,0 +1,118 @@ +/** + * @file support/junction/export-cache.c + * @brief Try to flush NFSD's exports cache + */ + +/* + * Copyright 2011, 2018 Oracle. All rights reserved. + * + * This file is part of nfs-utils. + * + * nfs-utils is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 as + * published by the Free Software Foundation. + * + * nfs-utils is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2.0 for more details. + * + * You should have received a copy of the GNU General Public License + * version 2.0 along with nfs-utils. If not, see: + * + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + */ + +#include <sys/types.h> +#include <sys/stat.h> + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <time.h> + + +#include "junction.h" +#include "xlog.h" + +/** + * Ordered list of proc files to poke when requesting an NFSD cache flush + */ +static const char *junction_proc_files[] = { + "/proc/net/rpc/auth.unix.ip/flush", + "/proc/net/rpc/auth.unix.gid/flush", + "/proc/net/rpc/nfsd.fh/flush", + "/proc/net/rpc/nfsd.export/flush", + NULL, +}; + +/** + * Write time into one file + * + * @param pathname NUL-terminated C string containing POSIX pathname of file to write + * @param flushtime NUL-terminated C string containing current time in seconds since the Epoch + * @return a FedFsStatus code + */ +static FedFsStatus +junction_write_time(const char *pathname, const char *flushtime) +{ + FedFsStatus retval; + ssize_t len; + int fd; + + fd = open(pathname, O_RDWR); + if (fd == -1) { + xlog(D_GENERAL, "%s: Failed to open %s: %m", + __func__, pathname); + /* If the proc files don't exist, no server + * is running on this system */ + return FEDFS_ERR_NO_CACHE_UPDATE; + } + + len = write(fd, flushtime, strlen(flushtime)); + if (len != (ssize_t)strlen(flushtime)) { + xlog(D_GENERAL, "%s: Failed to write %s: %m", + __func__, pathname); + /* If the proc files exist but the update failed, + * we don't know the state of the cache */ + retval = FEDFS_ERR_UNKNOWN_CACHE; + } else + /* Cache flush succeeded */ + retval = FEDFS_OK; + + (void)close(fd); + return retval; +} + +/** + * Flush the kernel NFSD's exports cache + * + * @return a FedFsStatus code + */ +FedFsStatus +junction_flush_exports_cache(void) +{ + FedFsStatus retval; + char flushtime[20]; + unsigned int i; + time_t now; + + xlog(D_CALL, "%s: Flushing NFSD caches...", __func__); + + now = time(NULL); + if (now == -1) { + xlog(D_GENERAL, "%s: time(3) failed", __func__); + return FEDFS_ERR_SVRFAULT; + } + snprintf(flushtime, sizeof(flushtime), "%ld\n", now); + + for (i = 0; junction_proc_files[i] != NULL; i++) { + retval = junction_write_time(junction_proc_files[i], flushtime); + if (retval != FEDFS_OK) + return retval; + } + return FEDFS_OK; +} diff --git a/support/junction/junction-internal.h b/support/junction/junction-internal.h new file mode 100644 index 0000000..3dff4cc --- /dev/null +++ b/support/junction/junction-internal.h @@ -0,0 +1,121 @@ +/* + * @file support/junction/junction-internal.h + * @brief Internal declarations for libjunction.a + */ + +/* + * Copyright 2011, 2018 Oracle. All rights reserved. + * + * This file is part of nfs-utils. + * + * nfs-utils is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 as + * published by the Free Software Foundation. + * + * nfs-utils is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2.0 for more details. + * + * You should have received a copy of the GNU General Public License + * version 2.0 along with nfs-utils. If not, see: + * + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + */ + +#ifndef _FEDFS_JUNCTION_INTERNAL_H_ +#define _FEDFS_JUNCTION_INTERNAL_H_ + +#include <libxml/tree.h> +#include <libxml/xpath.h> + +/** + ** Names of extended attributes that store junction data + **/ + +/** + * Name of extended attribute containing saved mode bits + */ +#define JUNCTION_XATTR_NAME_MODE "trusted.junction.mode" + +/** + * Name of extended attribute containing NFS-related junction data + */ +#define JUNCTION_XATTR_NAME_NFS "trusted.junction.nfs" + + +/** + ** Names of XML elements and attributes that represent junction data + **/ + +/** + * Tag name of root element of a junction XML document + */ +#define JUNCTION_XML_ROOT_TAG (const xmlChar *)"junction" + +/** + * Tag name of fileset element of a junction XML document + */ +#define JUNCTION_XML_FILESET_TAG (const xmlChar *)"fileset" + +/** + * Tag name of savedmode element of a junction XML document + */ +#define JUNCTION_XML_SAVEDMODE_TAG (const xmlChar *)"savedmode" + +/** + * Name of mode bits attribute on a savedmode element + */ +#define JUNCTION_XML_MODEBITS_ATTR (const xmlChar *)"bits" + +/** + ** Junction helper functions + **/ + +FedFsStatus junction_open_path(const char *pathname, int *fd); +FedFsStatus junction_is_directory(int fd, const char *path); +FedFsStatus junction_is_sticky_bit_set(int fd, const char *path); +FedFsStatus junction_set_sticky_bit(int fd, const char *path); +FedFsStatus junction_is_xattr_present(int fd, const char *path, + const char *name); +FedFsStatus junction_read_xattr(int fd, const char *path, const char *name, + char **contents); +FedFsStatus junction_get_xattr(int fd, const char *path, const char *name, + void **contents, size_t *contentlen); +FedFsStatus junction_set_xattr(int fd, const char *path, const char *name, + const void *contents, const size_t contentlen); +FedFsStatus junction_remove_xattr(int fd, const char *pathname, + const char *name); +FedFsStatus junction_get_mode(const char *pathname, mode_t *mode); +FedFsStatus junction_save_mode(const char *pathname); +FedFsStatus junction_restore_mode(const char *pathname); + + +/** + ** XML helper functions + **/ + +_Bool junction_xml_is_empty(const xmlChar *content); +_Bool junction_xml_match_node_name(xmlNodePtr node, + const xmlChar *name); +xmlNodePtr junction_xml_find_child_by_name(xmlNodePtr parent, + const xmlChar *name); +_Bool junction_xml_get_bool_attribute(xmlNodePtr node, + const xmlChar *attrname, _Bool *value); +void junction_xml_set_bool_attribute(xmlNodePtr node, + const xmlChar *attrname, _Bool value); +_Bool junction_xml_get_u8_attribute(xmlNodePtr node, + const xmlChar *attrname, uint8_t *value); +_Bool junction_xml_get_int_attribute(xmlNodePtr node, + const xmlChar *attrname, int *value); +void junction_xml_set_int_attribute(xmlNodePtr node, + const xmlChar *attrname, int value); +_Bool junction_xml_get_int_content(xmlNodePtr node, int *value); +xmlNodePtr junction_xml_set_int_content(xmlNodePtr parent, + const xmlChar *name, int value); +FedFsStatus junction_xml_parse(const char *pathname, const char *name, + xmlDocPtr *doc); +FedFsStatus junction_xml_write(const char *pathname, const char *name, + xmlDocPtr doc); + +#endif /* !_FEDFS_JUNCTION_INTERNAL_H_ */ diff --git a/support/junction/junction.c b/support/junction/junction.c new file mode 100644 index 0000000..c1ec8ff --- /dev/null +++ b/support/junction/junction.c @@ -0,0 +1,498 @@ +/** + * @file support/junction/junction.c + * @brief Common utilities for managing junctions on the local file system + */ + +/* + * Copyright 2010, 2018 Oracle. All rights reserved. + * + * This file is part of nfs-utils. + * + * nfs-utils is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 as + * published by the Free Software Foundation. + * + * nfs-utils is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2.0 for more details. + * + * You should have received a copy of the GNU General Public License + * version 2.0 along with nfs-utils. If not, see: + * + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/types.h> +#include <sys/stat.h> + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> +#include <wchar.h> +#include <memory.h> +#include <signal.h> +#include <errno.h> +#include <dirent.h> + +#include <sys/xattr.h> + +#include "junction.h" +#include "junction-internal.h" +#include "xlog.h" + +/** + * Open a file system object + * + * @param pathname NUL-terminated C string containing pathname of an object + * @param fd OUT: a file descriptor number is filled in + * @return a FedFsStatus code + */ +FedFsStatus +junction_open_path(const char *pathname, int *fd) +{ + int tmp; + + if (pathname == NULL || fd == NULL) + return FEDFS_ERR_INVAL; + + tmp = open(pathname, O_DIRECTORY); + if (tmp == -1) { + switch (errno) { + case EPERM: + return FEDFS_ERR_ACCESS; + case EACCES: + return FEDFS_ERR_PERM; + default: + xlog(D_GENERAL, "%s: Failed to open path %s: %m", + __func__, pathname); + return FEDFS_ERR_INVAL; + } + } + + *fd = tmp; + return FEDFS_OK; +} + +/** + * Predicate: is object a directory? + * + * @param fd an open file descriptor + * @param path NUL-terminated C string containing pathname of a directory + * @return a FedFsStatus code + */ +FedFsStatus +junction_is_directory(int fd, const char *path) +{ + struct stat stb; + + if (fstatat(fd, "", &stb, AT_NO_AUTOMOUNT|AT_EMPTY_PATH) == -1) { + xlog(D_GENERAL, "%s: failed to stat %s: %m", + __func__, path); + return FEDFS_ERR_ACCESS; + } + + if (!S_ISDIR(stb.st_mode)) { + xlog(D_CALL, "%s: %s is not a directory", + __func__, path); + return FEDFS_ERR_INVAL; + } + + xlog(D_CALL, "%s: %s is a directory", __func__, path); + return FEDFS_OK; +} + +/** + * Predicate: is a directory's sticky bit set? + * + * @param fd an open file descriptor + * @param path NUL-terminated C string containing pathname of a directory + * @return a FedFsStatus code + */ +FedFsStatus +junction_is_sticky_bit_set(int fd, const char *path) +{ + struct stat stb; + + if (fstatat(fd, "", &stb, AT_NO_AUTOMOUNT|AT_EMPTY_PATH) == -1) { + xlog(D_GENERAL, "%s: failed to stat %s: %m", + __func__, path); + return FEDFS_ERR_ACCESS; + } + + if (stb.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)) { + xlog(D_CALL, "%s: execute bit set on %s", + __func__, path); + return FEDFS_ERR_NOTJUNCT; + } + + if (!(stb.st_mode & S_ISVTX)) { + xlog(D_CALL, "%s: sticky bit not set on %s", + __func__, path); + return FEDFS_ERR_NOTJUNCT; + } + + xlog(D_CALL, "%s: sticky bit is set on %s", __func__, path); + return FEDFS_OK; +} + +/** + * Set just a directory's sticky bit + * + * @param fd an open file descriptor + * @param path NUL-terminated C string containing pathname of a directory + * @return a FedFsStatus code + */ +FedFsStatus +junction_set_sticky_bit(int fd, const char *path) +{ + struct stat stb; + + if (fstatat(fd, "", &stb, AT_NO_AUTOMOUNT|AT_EMPTY_PATH) == -1) { + xlog(D_GENERAL, "%s: failed to stat %s: %m", + __func__, path); + return FEDFS_ERR_ACCESS; + } + + stb.st_mode &= (unsigned int)~ALLPERMS; + stb.st_mode |= S_ISVTX; + + if (fchmod(fd, stb.st_mode) == -1) { + xlog(D_GENERAL, "%s: failed to set sticky bit on %s: %m", + __func__, path); + return FEDFS_ERR_ROFS; + } + + xlog(D_CALL, "%s: set sticky bit on %s", __func__, path); + return FEDFS_OK; +} + +/** + * Predicate: does a directory have an xattr named "name"? + * + * @param fd an open file descriptor + * @param path NUL-terminated C string containing pathname of a directory + * @param name NUL-terminated C string containing name of xattr to check + * @return a FedFsStatus code + * + * @note Access to trusted attributes requires CAP_SYS_ADMIN. + */ +FedFsStatus +junction_is_xattr_present(int fd, const char *path, const char *name) +{ + ssize_t rc; + + /* + * Do not assume the total number of extended attributes + * this object may have. + */ + rc = fgetxattr(fd, name, NULL, 0); + if (rc == -1) { + switch (errno) { + case EPERM: + xlog(D_CALL, "%s: no access to xattr %s on %s", + __func__, name, path); + return FEDFS_ERR_PERM; + case ENODATA: + xlog(D_CALL, "%s: no xattr %s present on %s", + __func__, name, path); + return FEDFS_ERR_NOTJUNCT; + default: + xlog(D_CALL, "%s: xattr %s not found on %s: %m", + __func__, name, path); + return FEDFS_ERR_IO; + } + } + + xlog(D_CALL, "%s: xattr %s found on %s", + __func__, name, path); + return FEDFS_OK; +} + +/** + * Read the contents of xattr "name" + * + * @param fd an open file descriptor + * @param path NUL-terminated C string containing pathname of a directory + * @param name NUL-terminated C string containing name of xattr to retrieve + * @param contents OUT: NUL-terminated C string containing contents of xattr + * @return a FedFsStatus code + * + * If junction_read_xattr() returns FEDFS_OK, the caller must free "*contents" + * with free(3). + * + * @note Access to trusted attributes requires CAP_SYS_ADMIN. + */ +FedFsStatus +junction_read_xattr(int fd, const char *path, const char *name, char **contents) +{ + char *xattrbuf = NULL; + ssize_t len; + + len = fgetxattr(fd, name, xattrbuf, 0); + if (len < 0) { + xlog(D_GENERAL, "%s: failed to get size of xattr %s on %s: %m", + __func__, name, path); + return FEDFS_ERR_ACCESS; + } + + xattrbuf = malloc((size_t)len + 1); + if (xattrbuf == NULL) { + xlog(D_GENERAL, "%s: failed to get buffer for xattr %s on %s", + __func__, name, path); + return FEDFS_ERR_SVRFAULT; + } + + if (fgetxattr(fd, name, xattrbuf, (size_t)len) == -1) { + xlog(D_GENERAL, "%s: failed to get xattr %s on %s: %m", + __func__, name, path); + free(xattrbuf); + return FEDFS_ERR_ACCESS; + } + xattrbuf[len] = '\0'; + + xlog(D_CALL, "%s: read xattr %s from path %s", + __func__, name, path); + *contents = xattrbuf; + return FEDFS_OK; +} + +/** + * Retrieve the contents of xattr "name" + * + * @param fd an open file descriptor + * @param path NUL-terminated C string containing pathname of a directory + * @param name NUL-terminated C string containing name of xattr to retrieve + * @param contents OUT: opaque byte array containing contents of xattr + * @param contentlen OUT: size of "contents" + * @return a FedFsStatus code + * + * If junction_get_xattr() returns FEDFS_OK, the caller must free "*contents" + * with free(3). + * + * @note Access to trusted attributes requires CAP_SYS_ADMIN. + */ +FedFsStatus +junction_get_xattr(int fd, const char *path, const char *name, void **contents, + size_t *contentlen) +{ + void *xattrbuf = NULL; + ssize_t len; + + len = fgetxattr(fd, name, xattrbuf, 0); + if (len < 0) { + xlog(D_GENERAL, "%s: failed to get size of xattr %s on %s: %m", + __func__, name, path); + return FEDFS_ERR_ACCESS; + } + + xattrbuf = malloc((size_t)len); + if (xattrbuf == NULL) { + xlog(D_GENERAL, "%s: failed to get buffer for xattr %s on %s", + __func__, name, path); + return FEDFS_ERR_SVRFAULT; + } + + if (fgetxattr(fd, name, xattrbuf, (size_t)len) == -1) { + xlog(D_GENERAL, "%s: failed to get xattr %s on %s: %m", + __func__, name, path); + free(xattrbuf); + return FEDFS_ERR_ACCESS; + } + + xlog(D_CALL, "%s: read xattr %s from path %s", + __func__, name, path); + *contents = xattrbuf; + *contentlen = (size_t)len; + return FEDFS_OK; +} + +/** + * Update the contents of an xattr + * + * @param fd an open file descriptor + * @param path NUL-terminated C string containing pathname of a directory + * @param name NUL-terminated C string containing name of xattr to set + * @param contents opaque byte array containing contents of xattr + * @param contentlen size of "contents" + * @return a FedFsStatus code + * + * The extended attribute is created if it does not exist. + * Its contents are replaced if it does. + * + * @note Access to trusted attributes requires CAP_SYS_ADMIN. + */ +FedFsStatus +junction_set_xattr(int fd, const char *path, const char *name, + const void *contents, const size_t contentlen) +{ + /* + * XXX: Eventually should distinguish among several errors: + * object isn't there, no root access, some other issue + */ + if (fsetxattr(fd, name, contents, contentlen, 0) == -1) { + xlog(D_GENERAL, "%s: Failed to set xattr %s on %s: %m", + __func__, name, path); + return FEDFS_ERR_IO; + } + + xlog(D_CALL, "%s: Wrote xattr %s from path %s", + __func__, name, path); + return FEDFS_OK; +} + +/** + * Remove one xattr + * + * @param fd an open file descriptor + * @param pathname NUL-terminated C string containing pathname of a directory + * @param name NUL-terminated C string containing name of xattr to set + * @return a FedFsStatus code + * + * @note Access to trusted attributes requires CAP_SYS_ADMIN. + */ +FedFsStatus +junction_remove_xattr(int fd, const char *pathname, const char *name) +{ + /* + * XXX: Eventually should distinguish among several errors: + * object isn't there, no root access, some other issue + */ + if (fremovexattr(fd, name) == -1) { + xlog(D_GENERAL, "%s: failed to remove xattr %s from %s: %m", + __func__, name, pathname); + return FEDFS_ERR_ACCESS; + } + xlog(D_CALL, "%s: removed xattr %s from path %s", + __func__, name, pathname); + return FEDFS_OK; +} + +/** + * Retrieve object's mode bits. + * + * @param pathname NUL-terminated C string containing pathname of a directory + * @param mode OUT: mode bits + * @return a FedFsStatus code + */ +FedFsStatus +junction_get_mode(const char *pathname, mode_t *mode) +{ + FedFsStatus retval; + struct stat stb; + int fd; + + retval = junction_open_path(pathname, &fd); + if (retval != FEDFS_OK) + return retval; + + if (fstatat(fd, "", &stb, AT_NO_AUTOMOUNT|AT_EMPTY_PATH) == -1) { + xlog(D_GENERAL, "%s: failed to stat %s: %m", + __func__, pathname); + (void)close(fd); + return FEDFS_ERR_ACCESS; + } + (void)close(fd); + + xlog(D_CALL, "%s: pathname %s has mode %o", + __func__, pathname, stb.st_mode); + *mode = stb.st_mode; + return FEDFS_OK; + +} + +/** + * Save the object's mode in an xattr. Saved mode is human-readable. + * + * @param pathname NUL-terminated C string containing pathname of a directory + * @return a FedFsStatus code + */ +FedFsStatus +junction_save_mode(const char *pathname) +{ + FedFsStatus retval; + mode_t mode; + char buf[8]; + int fd; + + retval = junction_get_mode(pathname, &mode); + if (retval != FEDFS_OK) + return retval; + (void)snprintf(buf, sizeof(buf), "%o", ALLPERMS & mode); + + retval = junction_open_path(pathname, &fd); + if (retval != FEDFS_OK) + return retval; + + retval = junction_set_xattr(fd, pathname, JUNCTION_XATTR_NAME_MODE, + buf, strlen(buf)); + if (retval != FEDFS_OK) + goto out; + + retval = junction_set_sticky_bit(fd, pathname); + if (retval != FEDFS_OK) { + (void)junction_remove_xattr(fd, pathname, + JUNCTION_XATTR_NAME_MODE); + goto out; + } + + xlog(D_CALL, "%s: saved mode %o to %s", __func__, mode, pathname); + retval = FEDFS_OK; + +out: + (void)close(fd); + return retval; + +} + +/** + * Restore an object's mode bits + * + * @param pathname NUL-terminated C string containing pathname of a directory + * @return a FedFsStatus code + */ +FedFsStatus +junction_restore_mode(const char *pathname) +{ + FedFsStatus retval; + char *buf = NULL; + mode_t mode; + int fd; + + retval = junction_open_path(pathname, &fd); + if (retval != FEDFS_OK) + return retval; + + retval = junction_read_xattr(fd, pathname, JUNCTION_XATTR_NAME_MODE, &buf); + if (retval != FEDFS_OK) + goto out; + + retval = FEDFS_ERR_SVRFAULT; + if (sscanf((char *)buf, "%o", &mode) != 1) { + xlog(D_GENERAL, "%s: failed to parse saved mode on %s", + __func__, pathname); + goto out; + } + + retval = FEDFS_ERR_ROFS; + if (fchmod(fd, mode) == -1) { + xlog(D_GENERAL, "%s: failed to set mode of %s to %o: %m", + __func__, pathname, mode); + goto out; + } + + xlog(D_CALL, "%s: restored mode %o to %s", __func__, mode, pathname); + retval = FEDFS_OK; + +out: + free(buf); + (void)close(fd); + return retval; +} diff --git a/support/junction/locations.c b/support/junction/locations.c new file mode 100644 index 0000000..c577981 --- /dev/null +++ b/support/junction/locations.c @@ -0,0 +1,131 @@ +/** + * @file support/junction/locations.c + * @brief Utility functions to manage NFS locations data + */ + +/* + * Copyright 2011, 2018 Oracle. All rights reserved. + * + * This file is part of nfs-utils. + * + * nfs-utils is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 as + * published by the Free Software Foundation. + * + * nfs-utils is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2.0 for more details. + * + * You should have received a copy of the GNU General Public License + * version 2.0 along with nfs-utils. If not, see: + * + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + */ + +#include <sys/types.h> +#include <sys/stat.h> + +#include <stdbool.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> + +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> + +#include "junction.h" + +/** + * Free an array of NUL-terminated C strings + * + * @param array array of pointers to C strings + */ +void +nfs_free_string_array(char **array) +{ + unsigned int i; + + if (array == NULL) + return; + for (i = 0; array[i] != NULL; i++) + free(array[i]); + free(array); +} + +/** + * Duplicate an array of NUL-terminated C strings + * + * @param array array of pointers to C strings + * @return freshly allocated array of points to C strings, or NULL + * + * Caller must free the returned array with nfs_free_string_array() + */ +__attribute_malloc__ char ** +nfs_dup_string_array(char **array) +{ + unsigned int size, i; + char **result; + + if (array == NULL) + return NULL; + + for (size = 0; array[size] != NULL; size++); + + result = calloc(size + 1, sizeof(char *)); + if (result == NULL) + return NULL; + for (i = 0; i < size; i++) { + result[i] = strdup(array[i]); + if (result[i] == NULL) { + nfs_free_string_array(result); + return NULL; + } + } + return result; +} + +/** + * Free a single NFS location + * + * @param location pointer to nfs_fsloc data + */ +void +nfs_free_location(struct nfs_fsloc *location) +{ + nfs_free_string_array(location->nfl_rootpath); + free(location->nfl_hostname); + free(location); +} + +/** + * Free a list of NFS locations + * + * @param locations pointer to list of one or more locations + */ +void +nfs_free_locations(struct nfs_fsloc *locations) +{ + struct nfs_fsloc *fsloc; + + while (locations != NULL) { + fsloc = locations; + locations = fsloc->nfl_next; + nfs_free_location(fsloc); + } +} + +/** + * Allocate a fresh nfs_fsloc structure + * + * @return pointer to new empty nfs_fsloc data structure + * + * Caller must free returned locations with nfs_free_location(). + */ +struct nfs_fsloc * +nfs_new_location(void) +{ + return calloc(1, sizeof(struct nfs_fsloc)); +} diff --git a/support/junction/nfs.c b/support/junction/nfs.c new file mode 100644 index 0000000..73e3533 --- /dev/null +++ b/support/junction/nfs.c @@ -0,0 +1,1564 @@ +/** + * @file support/junction/nfs.c + * @brief Create, delete, and read NFS junctions on the local file system + */ + +/* + * Copyright 2011, 2018 Oracle. All rights reserved. + * + * This file is part of nfs-utils. + * + * nfs-utils is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 as + * published by the Free Software Foundation. + * + * nfs-utils is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2.0 for more details. + * + * You should have received a copy of the GNU General Public License + * version 2.0 along with nfs-utils. If not, see: + * + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + */ + +/* + * An NFS junction is a list of NFS FSLs, represented in a well-formed XML + * document: + * + * <?xml version="1.0" encoding="UTF-8"?> + * <junction> + * <savedmode bits="1777" /> + * <fileset> + * <location> + * <host name="fileserver.example.net" port="2049" /> + * <path> + * <component>foo</component> + * <component>bar</component> + * <component>baz</component> + * </path> + * <currency>-1</currency> + * <genflags writable="false" going="false" split="true" /> + * <transflags rdma="true" /> + * <class simul="0" handle="0" fileid="0" + * writever="0" change="0" readdir="0" /> + * <read rank="0" order="0" /> + * <write rank="0" order="0" /> + * <flags varsub="false" /> + * <validfor>0</validfor> + * </location> + * + * .... + * + * </fileset> + * </junction> + * + * NFS junction XML is stored in an extended attribute called + * "trusted.junction.nfs". The parent object is a directory. + * + * To help file servers discover junctions efficiently, the directory + * has no execute bits, and the sticky bit is set. In addition, an + * extended attribute called "trusted.junction.type" is added. The + * contents are ignored in user space. + * + * Finally, for pre-existing directories that are converted to + * junctions, their mode bits are saved in an extended attribute called + * "trusted.junction.mode". When the junction data is removed, the + * directory's mode bits are restored from this information. + */ + +#include <sys/types.h> +#include <sys/stat.h> + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <rpcsvc/nfs_prot.h> + +#include "junction.h" +#include "junction-internal.h" +#include "xlog.h" + +/** + * Tag name of NFS location element of a junction XML document + */ +#define NFS_XML_LOCATION_TAG (const xmlChar *)"location" + +/** + * Tag name of host child element of an NFS location element + */ +#define NFS_XML_HOST_TAG (const xmlChar *)"host" + +/** + * Name of hostname attribute of a host element + */ +#define NFS_XML_HOST_NAME_ATTR (const xmlChar *)"name" + +/** + * Name of IP port attribute of a host element + */ +#define NFS_XML_HOST_PORT_ATTR (const xmlChar *)"port" + +/** + * Tag name of path child element of an NFS location element + */ +#define NFS_XML_PATH_TAG (const xmlChar *)"path" + +/** + * Tag name of component child element of a path element + */ +#define NFS_XML_COMPONENT_TAG (const xmlChar *)"component" + +/** + * Tag name of currency child element of an NFS location element + */ +#define NFS_XML_CURRENCY_TAG (const xmlChar *)"currency" + +/** + * Tag name of genflags child element of an NFS location element + */ +#define NFS_XML_GENFLAGS_TAG (const xmlChar *)"genflags" + +/** + * Name of writable attribute of a genflags element + */ +#define NFS_XML_GENFLAGS_WRITABLE_ATTR (const xmlChar *)"writable" + +/** + * Name of going attribute of a genflags element + */ +#define NFS_XML_GENFLAGS_GOING_ATTR (const xmlChar *)"going" + +/** + * Name of split attribute of a genflags element + */ +#define NFS_XML_GENFLAGS_SPLIT_ATTR (const xmlChar *)"split" + +/** + * Tag name of transflags child element of an NFS location element + */ +#define NFS_XML_TRANSFLAGS_TAG (const xmlChar *)"transflags" + +/** + * Name of rdma attribute of a transflags element + */ +#define NFS_XML_TRANSFLAGS_RDMA_ATTR (const xmlChar *)"rdma" + +/** + * Tag name of class child element of an NFS location element + */ +#define NFS_XML_CLASS_TAG (const xmlChar *)"class" + +/** + * Name of simul attribute of a class element + */ +#define NFS_XML_CLASS_SIMUL_ATTR (const xmlChar *)"simul" + +/** + * Name of handle attribute of a class element + */ +#define NFS_XML_CLASS_HANDLE_ATTR (const xmlChar *)"handle" + +/** + * Name of fileid attribute of a class element + */ +#define NFS_XML_CLASS_FILEID_ATTR (const xmlChar *)"fileid" + +/** + * Name of writever attribute of a class element + */ +#define NFS_XML_CLASS_WRITEVER_ATTR (const xmlChar *)"writever" + +/** + * Name of change attribute of a class element + */ +#define NFS_XML_CLASS_CHANGE_ATTR (const xmlChar *)"change" + +/** + * Name of readdir attribute of a class element + */ +#define NFS_XML_CLASS_READDIR_ATTR (const xmlChar *)"readdir" + +/** + * Tag name of read child element of an NFS location element + */ +#define NFS_XML_READ_TAG (const xmlChar *)"read" + +/** + * Name of rank attribute of a read element + */ +#define NFS_XML_READ_RANK_ATTR (const xmlChar *)"rank" + +/** + * Name of order attribute of a read element + */ +#define NFS_XML_READ_ORDER_ATTR (const xmlChar *)"order" + +/** + * Tag name of write attribute of an NFS location element + */ +#define NFS_XML_WRITE_TAG (const xmlChar *)"write" + +/** + * Name of rank attribute of a write element + */ +#define NFS_XML_WRITE_RANK_ATTR (const xmlChar *)"rank" + +/** + * Name of order attribute of a write element + */ +#define NFS_XML_WRITE_ORDER_ATTR (const xmlChar *)"order" + +/** + * Tag name of flags child element of an NFS location element + */ +#define NFS_XML_FLAGS_TAG (const xmlChar *)"flags" + +/** + * Name of varsub attribute of a flags element + */ +#define NFS_XML_FLAGS_VARSUB_ATTR (const xmlChar *)"varsub" + +/** + * Tag name of a validfor child element of an NFS location element + */ +#define NFS_XML_VALIDFOR_TAG (const xmlChar *)"validfor" + +/** + * XPath path to NFS location elements in a junction document + */ +#define NFS_XML_LOCATION_XPATH (const xmlChar *) \ + "/junction/fileset/location" + + +/** + * Remove all NFS-related xattrs from a directory + * + * @param pathname NUL-terminated C string containing pathname of a directory + * @return a FedFsStatus code + * + * @note Access to trusted attributes requires CAP_SYS_ADMIN. + */ +static FedFsStatus +nfs_remove_locations(const char *pathname) +{ + FedFsStatus retval; + int fd; + + retval = junction_open_path(pathname, &fd); + if (retval != FEDFS_OK) + return retval; + + retval = junction_remove_xattr(fd, pathname, JUNCTION_XATTR_NAME_NFS); + + (void)close(fd); + return retval; +} + +/** + * Add a "host" child to a "location" element + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param parent parent element to which to add "host" child + * @param fsloc NFS location containing host information to add + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_location_host_xml(const char *pathname, xmlNodePtr parent, + struct nfs_fsloc *fsloc) +{ + uint16_t port = fsloc->nfl_hostport; + xmlNodePtr new; + + new = xmlNewTextChild(parent, NULL, NFS_XML_HOST_TAG, NULL); + if (new == NULL) { + xlog(D_GENERAL, "%s: Failed to add host element for %s", + __func__, pathname); + return FEDFS_ERR_SVRFAULT; + } + + xmlSetProp(new, NFS_XML_HOST_NAME_ATTR, + (const xmlChar *)fsloc->nfl_hostname); + if (port != NFS_PORT && port != 0) + junction_xml_set_int_attribute(new, NFS_XML_HOST_PORT_ATTR, + port); + + return FEDFS_OK; +} + +/** + * Add a "path" child to a "location" element + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param parent parent element to which to add "host" child + * @param fsloc NFS location containing host information to add + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_location_path_xml(const char *pathname, xmlNodePtr parent, + struct nfs_fsloc *fsloc) +{ + xmlNodePtr new; + int i; + + new = xmlNewTextChild(parent, NULL, NFS_XML_PATH_TAG, NULL); + if (new == NULL) { + xlog(D_GENERAL, "%s: Failed to add path element for %s", + __func__, pathname); + return FEDFS_ERR_SVRFAULT; + } + + for (i = 0; fsloc->nfl_rootpath[i] != NULL; i++) { + xmlNodePtr component; + + component = xmlNewTextChild(new , NULL, + NFS_XML_COMPONENT_TAG, + (const xmlChar *) + fsloc->nfl_rootpath[i]); + if (component == NULL) { + xlog(D_GENERAL, "%s: Failed to add component " + "element for %s", + __func__, pathname); + return FEDFS_ERR_SVRFAULT; + } + } + + return FEDFS_OK; +} + +/** + * Add a "currency" child to a "location" element + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param parent parent element to which to add "host" child + * @param fsloc NFS location containing host information to add + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_location_currency_xml(__attribute__((unused)) const char *pathname, + xmlNodePtr parent, struct nfs_fsloc *fsloc) +{ + if (junction_xml_set_int_content(parent, NFS_XML_CURRENCY_TAG, + fsloc->nfl_currency) == NULL) + return FEDFS_ERR_SVRFAULT; + return FEDFS_OK; +} + +/** + * Add a "genflags" child to a "location" element + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param parent parent element to which to add "host" child + * @param fsloc NFS location containing host information to add + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_location_genflags_xml(const char *pathname, xmlNodePtr parent, + struct nfs_fsloc *fsloc) +{ + xmlNodePtr new; + + new = xmlNewTextChild(parent, NULL, NFS_XML_GENFLAGS_TAG, NULL); + if (new == NULL) { + xlog(D_GENERAL, "%s: Failed to add genflags element for %s", + __func__, pathname); + return FEDFS_ERR_SVRFAULT; + } + + junction_xml_set_bool_attribute(new, NFS_XML_GENFLAGS_WRITABLE_ATTR, + fsloc->nfl_genflags.nfl_writable); + junction_xml_set_bool_attribute(new, NFS_XML_GENFLAGS_GOING_ATTR, + fsloc->nfl_genflags.nfl_going); + junction_xml_set_bool_attribute(new, NFS_XML_GENFLAGS_SPLIT_ATTR, + fsloc->nfl_genflags.nfl_split); + + return FEDFS_OK; +} + +/** + * Add a "transflags" child to a "location" element + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param parent parent element to which to add "host" child + * @param fsloc NFS location containing host information to add + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_location_transflags_xml(const char *pathname, xmlNodePtr parent, + struct nfs_fsloc *fsloc) +{ + xmlNodePtr new; + + new = xmlNewTextChild(parent, NULL, NFS_XML_TRANSFLAGS_TAG, NULL); + if (new == NULL) { + xlog(D_GENERAL, "%s: Failed to add transflags element for %s", + __func__, pathname); + return FEDFS_ERR_SVRFAULT; + } + + junction_xml_set_bool_attribute(new, NFS_XML_TRANSFLAGS_RDMA_ATTR, + fsloc->nfl_transflags.nfl_rdma); + + return FEDFS_OK; +} + +/** + * Add a "class" child to a "location" element + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param parent parent element to which to add "host" child + * @param fsloc NFS location containing host information to add + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_location_class_xml(const char *pathname, xmlNodePtr parent, + struct nfs_fsloc *fsloc) +{ + xmlNodePtr new; + + new = xmlNewTextChild(parent, NULL, NFS_XML_CLASS_TAG, NULL); + if (new == NULL) { + xlog(D_GENERAL, "%s: Failed to add class element for %s", + __func__, pathname); + return FEDFS_ERR_SVRFAULT; + } + + junction_xml_set_int_attribute(new, NFS_XML_CLASS_SIMUL_ATTR, + fsloc->nfl_info.nfl_simul); + junction_xml_set_int_attribute(new, NFS_XML_CLASS_HANDLE_ATTR, + fsloc->nfl_info.nfl_handle); + junction_xml_set_int_attribute(new, NFS_XML_CLASS_FILEID_ATTR, + fsloc->nfl_info.nfl_fileid); + junction_xml_set_int_attribute(new, NFS_XML_CLASS_WRITEVER_ATTR, + fsloc->nfl_info.nfl_writever); + junction_xml_set_int_attribute(new, NFS_XML_CLASS_CHANGE_ATTR, + fsloc->nfl_info.nfl_change); + junction_xml_set_int_attribute(new, NFS_XML_CLASS_READDIR_ATTR, + fsloc->nfl_info.nfl_readdir); + + return FEDFS_OK; +} + +/** + * Add a "read" child to a "location" element + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param parent parent element to which to add "host" child + * @param fsloc NFS location containing host information to add + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_location_read_xml(const char *pathname, xmlNodePtr parent, + struct nfs_fsloc *fsloc) +{ + xmlNodePtr new; + + new = xmlNewTextChild(parent, NULL, NFS_XML_READ_TAG, NULL); + if (new == NULL) { + xlog(D_GENERAL, "%s: Failed to add read element for %s", + __func__, pathname); + return FEDFS_ERR_SVRFAULT; + } + + junction_xml_set_int_attribute(new, NFS_XML_READ_RANK_ATTR, + fsloc->nfl_info.nfl_readrank); + junction_xml_set_int_attribute(new, NFS_XML_READ_ORDER_ATTR, + fsloc->nfl_info.nfl_readorder); + + return FEDFS_OK; +} + +/** + * Add a "write" child to a "location" element + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param parent parent element to which to add "host" child + * @param fsloc NFS location containing host information to add + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_location_write_xml(const char *pathname, xmlNodePtr parent, + struct nfs_fsloc *fsloc) +{ + xmlNodePtr new; + + new = xmlNewTextChild(parent, NULL, NFS_XML_WRITE_TAG, NULL); + if (new == NULL) { + xlog(D_GENERAL, "%s: Failed to add write element for %s", + __func__, pathname); + return FEDFS_ERR_SVRFAULT; + } + + junction_xml_set_int_attribute(new, NFS_XML_WRITE_RANK_ATTR, + fsloc->nfl_info.nfl_writerank); + junction_xml_set_int_attribute(new, NFS_XML_WRITE_ORDER_ATTR, + fsloc->nfl_info.nfl_writeorder); + + return FEDFS_OK; +} + +/** + * Add a "flags" child to a "location" element + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param parent parent element to which to add "host" child + * @param fsloc NFS location containing host information to add + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_location_flags_xml(const char *pathname, xmlNodePtr parent, + struct nfs_fsloc *fsloc) +{ + xmlNodePtr new; + + new = xmlNewTextChild(parent, NULL, NFS_XML_FLAGS_TAG, NULL); + if (new == NULL) { + xlog(D_GENERAL, "%s: Failed to add flags element for %s", + __func__, pathname); + return FEDFS_ERR_SVRFAULT; + } + + junction_xml_set_bool_attribute(new, NFS_XML_FLAGS_VARSUB_ATTR, + fsloc->nfl_flags.nfl_varsub); + + return FEDFS_OK; +} + +/** + * Add a "validfor" child to a "location" element + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param parent parent element to which to add "host" child + * @param fsloc NFS location containing host information to add + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_location_validfor_xml(__attribute__((unused)) const char *pathname, + xmlNodePtr parent, struct nfs_fsloc *fsloc) +{ + if (junction_xml_set_int_content(parent, NFS_XML_VALIDFOR_TAG, + fsloc->nfl_validfor) == NULL) + return FEDFS_ERR_SVRFAULT; + return FEDFS_OK; +} + +/** + * Construct and add one "location" element to a "fileset" + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param fileset fileset element of junction XML parse tree + * @param fsloc one NFS location to add + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_location_xml(const char *pathname, xmlNodePtr fileset, + struct nfs_fsloc *fsloc) +{ + FedFsStatus retval; + xmlNodePtr new; + + new = xmlNewTextChild(fileset, NULL, NFS_XML_LOCATION_TAG, NULL); + if (new == NULL) { + xlog(D_GENERAL, "%s: Failed to add location element for %s", + __func__, pathname); + return FEDFS_ERR_SVRFAULT; + } + + retval = nfs_location_host_xml(pathname, new, fsloc); + if (retval != FEDFS_OK) + return retval; + retval = nfs_location_path_xml(pathname, new, fsloc); + if (retval != FEDFS_OK) + return retval; + retval = nfs_location_currency_xml(pathname, new, fsloc); + if (retval != FEDFS_OK) + return retval; + retval = nfs_location_genflags_xml(pathname, new, fsloc); + if (retval != FEDFS_OK) + return retval; + retval = nfs_location_transflags_xml(pathname, new, fsloc); + if (retval != FEDFS_OK) + return retval; + retval = nfs_location_class_xml(pathname, new, fsloc); + if (retval != FEDFS_OK) + return retval; + retval = nfs_location_read_xml(pathname, new, fsloc); + if (retval != FEDFS_OK) + return retval; + retval = nfs_location_write_xml(pathname, new, fsloc); + if (retval != FEDFS_OK) + return retval; + retval = nfs_location_flags_xml(pathname, new, fsloc); + if (retval != FEDFS_OK) + return retval; + return nfs_location_validfor_xml(pathname, new, fsloc); +} + +/** + * Construct and add a "fileset" element + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param root root element of junction XML parse tree + * @param fslocs list of NFS locations to add + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_fileset_xml(const char *pathname, xmlNodePtr root, + struct nfs_fsloc *fslocs) +{ + struct nfs_fsloc *next; + xmlNodePtr fileset; + FedFsStatus retval; + + fileset = xmlNewTextChild(root, NULL, JUNCTION_XML_FILESET_TAG, NULL); + if (fileset == NULL) { + xlog(D_GENERAL, "%s: Failed to add fileset element for %s", + __func__, pathname); + return FEDFS_ERR_SVRFAULT; + } + + for (next = fslocs; next != NULL; next = next->nfl_next) { + retval = nfs_location_xml(pathname, fileset, next); + if (retval != FEDFS_OK) + return retval; + } + + return FEDFS_OK; +} + +/** + * Construct a "savedmode" element + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param root root element of XML document tree + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_savedmode_xml(const char *pathname, xmlNodePtr root) +{ + xmlNodePtr savedmode; + FedFsStatus retval; + mode_t mode; + char buf[8]; + + retval = junction_get_mode(pathname, &mode); + if (retval != FEDFS_OK) + return retval; + + savedmode = xmlNewTextChild(root, NULL, JUNCTION_XML_SAVEDMODE_TAG, NULL); + if (savedmode == NULL) { + xlog(D_GENERAL, "%s: Failed to add savedmode element for %s\n", + __func__, pathname); + return FEDFS_ERR_SVRFAULT; + } + + (void)snprintf(buf, sizeof(buf), "%o", ALLPERMS & mode); + xmlSetProp(savedmode, JUNCTION_XML_MODEBITS_ATTR, (const xmlChar *)buf); + + return FEDFS_OK; +} + +/** + * Construct NFS junction XML document from list of NFS locations + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param doc an XML parse tree in which to construct the junction XML document + * @param fslocs list of NFS locations to add + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_junction_xml(const char *pathname, xmlDocPtr doc, + struct nfs_fsloc *fslocs) +{ + FedFsStatus retval; + xmlNodePtr root; + + root = xmlNewNode(NULL, JUNCTION_XML_ROOT_TAG); + if (root == NULL) { + xlog(D_GENERAL, "%s: Failed to create root element for %s", + __func__, pathname); + return FEDFS_ERR_SVRFAULT; + } + (void)xmlDocSetRootElement(doc, root); + + retval = nfs_savedmode_xml(pathname, root); + if (retval != FEDFS_OK) + return retval; + + return nfs_fileset_xml(pathname, root, fslocs); +} + +/** + * Write NFS locations information into an NFS junction extended attribute + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param doc an empty XML parse tree in which to construct the junction XML document + * @param fslocs list of NFS locations to add + * @return a FedFsStatus code + * + * @note Access to trusted attributes requires CAP_SYS_ADMIN. + */ +static FedFsStatus +nfs_write_junction(const char *pathname, xmlDocPtr doc, + struct nfs_fsloc *fslocs) +{ + FedFsStatus retval; + + retval = nfs_junction_xml(pathname, doc, fslocs); + if (retval != FEDFS_OK) + return retval; + + return junction_xml_write(pathname, JUNCTION_XATTR_NAME_NFS, doc); +} + +/** + * Store NFS locations information into a junction object + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param fslocs list of NFS locations to add + * @return a FedFsStatus code + * + * @note Access to trusted attributes requires CAP_SYS_ADMIN. + */ +static FedFsStatus +nfs_store_locations(const char *pathname, struct nfs_fsloc *fslocs) +{ + FedFsStatus retval; + xmlDocPtr doc; + + doc = xmlNewDoc((xmlChar *)"1.0"); + if (doc == NULL) { + xlog(D_GENERAL, "%s: Failed to create XML doc for %s", + __func__, pathname); + return FEDFS_ERR_SVRFAULT; + } + + retval = nfs_write_junction(pathname, doc, fslocs); + + xmlFreeDoc(doc); + return retval; +} + +/** + * Add NFS junction information to a pre-existing object + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param fslocs list of NFS locations to add + * @return a FedFsStatus code + * + * An error occurs if the object referred to by "pathname" does not + * exist or contains existing junction data. + */ +FedFsStatus +nfs_add_junction(const char *pathname, struct nfs_fsloc *fslocs) +{ + FedFsStatus retval; + + if (fslocs == NULL) + return FEDFS_ERR_INVAL; + + retval = nfs_is_prejunction(pathname); + if (retval != FEDFS_ERR_NOTJUNCT) + return retval; + + retval = nfs_store_locations(pathname, fslocs); + if (retval != FEDFS_OK) + goto out_err; + + retval = junction_save_mode(pathname); + if (retval != FEDFS_OK) + goto out_err; + + return retval; + +out_err: + (void)nfs_remove_locations(pathname); + return retval; +} + +/** + * Remove NFS junction information from an object + * + * @param pathname NUL-terminated C string containing pathname of a directory + * @return a FedFsStatus code + * + * An error occurs if the object referred to by "pathname" does not + * exist or does not contain NFS junction data. + */ +FedFsStatus +nfs_delete_junction(const char *pathname) +{ + FedFsStatus retval; + + retval = nfs_is_junction(pathname); + if (retval != FEDFS_OK) + return retval; + + retval = junction_restore_mode(pathname); + if (retval != FEDFS_OK) + return retval; + + return nfs_remove_locations(pathname); +} + +/** + * Parse the first "host" child of "location" + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param location XML parse tree containing fileset location element + * @param fsloc a blank nfs_fsloc to fill in + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_parse_location_host(const char *pathname, xmlNodePtr location, + struct nfs_fsloc *fsloc) +{ + FedFsStatus retval; + xmlChar *hostname; + xmlNodePtr node; + int hostport; + + retval = FEDFS_ERR_NOTJUNCT; + node = junction_xml_find_child_by_name(location, NFS_XML_HOST_TAG); + if (node == NULL) + return retval; + + hostname = xmlGetProp(node, NFS_XML_HOST_NAME_ATTR); + if (!junction_xml_get_int_attribute(node, NFS_XML_HOST_PORT_ATTR, + &hostport)) + fsloc->nfl_hostport = NFS_PORT; + else { + if (hostport < 1 || hostport > UINT16_MAX) { + xlog(D_GENERAL, "%s: Bad port attribute on %s", + __func__, pathname); + goto out; + } + fsloc->nfl_hostport = (uint16_t)hostport; + } + if (hostname == NULL) { + xlog(D_GENERAL, "%s: No hostname attribute on %s", + __func__, pathname); + goto out; + } + fsloc->nfl_hostname = strdup((const char *)hostname); + if (fsloc->nfl_hostname == NULL) { + retval = FEDFS_ERR_SVRFAULT; + goto out; + } + + retval = FEDFS_OK; + +out: + xmlFree(hostname); + return retval; +} + +/** + * Parse the first "path" child of "location" into a path array + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param location XML parse tree containing fileset location element + * @param fsloc a blank nfs_fsloc to fill in + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_parse_location_path(const char *pathname, xmlNodePtr location, + struct nfs_fsloc *fsloc) +{ + xmlNodePtr node, component; + unsigned int count; + xmlChar *value; + char **result; + + node = junction_xml_find_child_by_name(location, NFS_XML_PATH_TAG); + if (node == NULL) + return FEDFS_ERR_NOTJUNCT; + + count = 0; + for (component = node->children; + component != NULL; + component = component->next) { + if (!junction_xml_match_node_name(component, + NFS_XML_COMPONENT_TAG)) + continue; + value = xmlNodeGetContent(component); + if (junction_xml_is_empty(value)) { + xlog(D_GENERAL, "%s: Bad pathname component in %s", + __func__, pathname); + return FEDFS_ERR_NOTJUNCT; + } + xmlFree(value); + count++; + } + xlog(D_GENERAL, "%s: Found %u component(s)", __func__, count); + + if (count == 0) { + xlog(D_GENERAL, "%s: Zero-component pathname", __func__); + fsloc->nfl_rootpath = (char **)calloc(1, sizeof(char *)); + if (fsloc->nfl_rootpath == NULL) + return FEDFS_ERR_SVRFAULT; + fsloc->nfl_rootpath[0] = NULL; + return FEDFS_OK; + } + + result = calloc(count + 1, sizeof(char *)); + if (result == NULL) + return FEDFS_ERR_SVRFAULT; + + count = 0; + for (component = node->children; + component != NULL; + component = component->next) { + if (!junction_xml_match_node_name(component, + NFS_XML_COMPONENT_TAG)) + continue; + value = xmlNodeGetContent(component); + result[count] = strdup((const char *)value); + xmlFree(value); + if (result[count] == NULL) { + nfs_free_string_array(result); + return FEDFS_ERR_SVRFAULT; + } + count++; + } + + fsloc->nfl_rootpath = result; + return FEDFS_OK; +} + +/** + * Parse the first "currency" child of "location" + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param location XML parse tree containing fileset location element + * @param fsloc a blank nfs_fsloc to fill in + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_parse_location_currency(const char *pathname, xmlNodePtr location, + struct nfs_fsloc *fsloc) +{ + xmlNodePtr node; + + node = junction_xml_find_child_by_name(location, NFS_XML_CURRENCY_TAG); + if (node == NULL) + goto out_err; + + if (!junction_xml_get_int_content(node, &fsloc->nfl_currency)) + goto out_err; + + return FEDFS_OK; + +out_err: + xlog(D_GENERAL, "%s: Missing or invalid currency element in %s", + __func__, pathname); + return FEDFS_ERR_NOTJUNCT; +} + +/** + * Parse the first "genflags" child of "location" + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param location XML parse tree containing fileset location element + * @param fsloc a blank nfs_fsloc to fill in + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_parse_location_genflags(const char *pathname, xmlNodePtr location, + struct nfs_fsloc *fsloc) +{ + xmlNodePtr node; + + node = junction_xml_find_child_by_name(location, NFS_XML_GENFLAGS_TAG); + if (node == NULL) + goto out_err; + + if (!junction_xml_get_bool_attribute(node, + NFS_XML_GENFLAGS_WRITABLE_ATTR, + &fsloc->nfl_genflags.nfl_writable)) + goto out_err; + if (!junction_xml_get_bool_attribute(node, + NFS_XML_GENFLAGS_GOING_ATTR, + &fsloc->nfl_genflags.nfl_going)) + goto out_err; + if (!junction_xml_get_bool_attribute(node, + NFS_XML_GENFLAGS_SPLIT_ATTR, + &fsloc->nfl_genflags.nfl_split)) + goto out_err; + + return FEDFS_OK; + +out_err: + xlog(D_GENERAL, "%s: Missing or invalid genflags element in %s", + __func__, pathname); + return FEDFS_ERR_NOTJUNCT; +} + +/** + * Parse the first "transflags" child of "location" + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param location XML parse tree containing fileset location element + * @param fsloc a blank nfs_fsloc to fill in + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_parse_location_transflags(const char *pathname, xmlNodePtr location, + struct nfs_fsloc *fsloc) +{ + xmlNodePtr node; + + node = junction_xml_find_child_by_name(location, NFS_XML_TRANSFLAGS_TAG); + if (node == NULL) + goto out_err; + + if (!junction_xml_get_bool_attribute(node, + NFS_XML_TRANSFLAGS_RDMA_ATTR, + &fsloc->nfl_transflags.nfl_rdma)) + goto out_err; + + return FEDFS_OK; + +out_err: + xlog(D_GENERAL, "%s: Missing or invalid transflags element in %s", + __func__, pathname); + return FEDFS_ERR_NOTJUNCT; +} + +/** + * Parse the first "class" child of "location" + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param location XML parse tree containing fileset location element + * @param fsloc a blank nfs_fsloc to fill in + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_parse_location_class(const char *pathname, xmlNodePtr location, + struct nfs_fsloc *fsloc) +{ + xmlNodePtr node; + + node = junction_xml_find_child_by_name(location, NFS_XML_CLASS_TAG); + if (node == NULL) + goto out_err; + + if (!junction_xml_get_u8_attribute(node, + NFS_XML_CLASS_SIMUL_ATTR, + &fsloc->nfl_info.nfl_simul)) + goto out_err; + if (!junction_xml_get_u8_attribute(node, + NFS_XML_CLASS_HANDLE_ATTR, + &fsloc->nfl_info.nfl_handle)) + goto out_err; + if (!junction_xml_get_u8_attribute(node, + NFS_XML_CLASS_FILEID_ATTR, + &fsloc->nfl_info.nfl_fileid)) + goto out_err; + if (!junction_xml_get_u8_attribute(node, + NFS_XML_CLASS_WRITEVER_ATTR, + &fsloc->nfl_info.nfl_writever)) + goto out_err; + if (!junction_xml_get_u8_attribute(node, + NFS_XML_CLASS_WRITEVER_ATTR, + &fsloc->nfl_info.nfl_writever)) + goto out_err; + if (!junction_xml_get_u8_attribute(node, + NFS_XML_CLASS_CHANGE_ATTR, + &fsloc->nfl_info.nfl_change)) + goto out_err; + if (!junction_xml_get_u8_attribute(node, + NFS_XML_CLASS_READDIR_ATTR, + &fsloc->nfl_info.nfl_readdir)) + goto out_err; + + return FEDFS_OK; + +out_err: + xlog(D_GENERAL, "%s: Missing or invalid class element in %s", + __func__, pathname); + return FEDFS_ERR_NOTJUNCT; +} + +/** + * Parse the first "read" child of "location" + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param location XML parse tree containing fileset location element + * @param fsloc a blank nfs_fsloc to fill in + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_parse_location_read(const char *pathname, xmlNodePtr location, + struct nfs_fsloc *fsloc) +{ + xmlNodePtr node; + + node = junction_xml_find_child_by_name(location, NFS_XML_READ_TAG); + if (node == NULL) + goto out_err; + + if (!junction_xml_get_u8_attribute(node, + NFS_XML_READ_RANK_ATTR, + &fsloc->nfl_info.nfl_readrank)) + goto out_err; + if (!junction_xml_get_u8_attribute(node, + NFS_XML_READ_ORDER_ATTR, + &fsloc->nfl_info.nfl_readorder)) + goto out_err; + + return FEDFS_OK; + +out_err: + xlog(D_GENERAL, "%s: Missing or invalid read element in %s", + __func__, pathname); + return FEDFS_ERR_NOTJUNCT; +} + +/** + * Parse the first "write" child of "location" + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param location XML parse tree containing fileset location element + * @param fsloc a blank nfs_fsloc to fill in + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_parse_location_write(const char *pathname, xmlNodePtr location, + struct nfs_fsloc *fsloc) +{ + xmlNodePtr node; + + node = junction_xml_find_child_by_name(location, NFS_XML_WRITE_TAG); + if (node == NULL) + goto out_err; + + if (!junction_xml_get_u8_attribute(node, + NFS_XML_WRITE_RANK_ATTR, + &fsloc->nfl_info.nfl_writerank)) + goto out_err; + if (!junction_xml_get_u8_attribute(node, + NFS_XML_WRITE_ORDER_ATTR, + &fsloc->nfl_info.nfl_writeorder)) + goto out_err; + + return FEDFS_OK; + +out_err: + xlog(D_GENERAL, "%s: Missing or invalid write element in %s", + __func__, pathname); + return FEDFS_ERR_NOTJUNCT; +} + +/** + * Parse the first "flags" child of "location" + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param location XML parse tree containing fileset location element + * @param fsloc a blank nfs_fsloc to fill in + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_parse_location_flags(const char *pathname, xmlNodePtr location, + struct nfs_fsloc *fsloc) +{ + xmlNodePtr node; + + node = junction_xml_find_child_by_name(location, NFS_XML_FLAGS_TAG); + if (node == NULL) + goto out_err; + + if (!junction_xml_get_bool_attribute(node, + NFS_XML_FLAGS_VARSUB_ATTR, + &fsloc->nfl_flags.nfl_varsub)) + goto out_err; + + return FEDFS_OK; + +out_err: + xlog(D_GENERAL, "%s: Missing or invalid flags element in %s", + __func__, pathname); + return FEDFS_ERR_NOTJUNCT; +} + +/** + * Parse the first "validfor" child of "location" + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param location XML parse tree containing fileset location element + * @param fsloc a blank nfs_fsloc to fill in + * @return a FedFsStatus code + */ +static FedFsStatus +nfs_parse_location_validfor(const char *pathname, xmlNodePtr location, + struct nfs_fsloc *fsloc) +{ + xmlNodePtr node; + + node = junction_xml_find_child_by_name(location, NFS_XML_VALIDFOR_TAG); + if (node == NULL) + goto out_err; + + if (!junction_xml_get_int_content(node, &fsloc->nfl_validfor)) + goto out_err; + + return FEDFS_OK; + +out_err: + xlog(D_GENERAL, "%s: Missing or invalid validfor element in %s", + __func__, pathname); + return FEDFS_ERR_NOTJUNCT; +} + +/** + * Parse children of NFS location element in an NFS junction + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param location XML parse tree containing fileset location element + * @param fsloc a blank nfs_fsloc to fill in + * @return a FedFsStatus code + * + * All children are required only-once elements, and may appear in any order. + * Extraneous or repeated elements are ignored for now. + */ +static FedFsStatus +nfs_parse_location_children(const char *pathname, xmlNodePtr location, + struct nfs_fsloc *fsloc) +{ + FedFsStatus retval; + + retval = nfs_parse_location_host(pathname, location, fsloc); + if (retval != FEDFS_OK) + return retval; + retval = nfs_parse_location_path(pathname, location, fsloc); + if (retval != FEDFS_OK) + return retval; + retval = nfs_parse_location_currency(pathname, location, fsloc); + if (retval != FEDFS_OK) + return retval; + retval = nfs_parse_location_genflags(pathname, location, fsloc); + if (retval != FEDFS_OK) + return retval; + retval = nfs_parse_location_transflags(pathname, location, fsloc); + if (retval != FEDFS_OK) + return retval; + retval = nfs_parse_location_class(pathname, location, fsloc); + if (retval != FEDFS_OK) + return retval; + retval = nfs_parse_location_read(pathname, location, fsloc); + if (retval != FEDFS_OK) + return retval; + retval = nfs_parse_location_write(pathname, location, fsloc); + if (retval != FEDFS_OK) + return retval; + retval = nfs_parse_location_flags(pathname, location, fsloc); + if (retval != FEDFS_OK) + return retval; + return nfs_parse_location_validfor(pathname, location, fsloc); +} + +/** + * Parse NFS location element in an NFS junction + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param location XML parse tree containing fileset location element + * @param fsloc OUT: a single NFS location item + * @return a FedFsStatus code + * + * If nfs_parse_location() returns FEDFS_OK, caller must free the returned + * location with nfs_free_location(). + */ +static FedFsStatus +nfs_parse_node(const char *pathname, xmlNodePtr location, + struct nfs_fsloc **fsloc) +{ + struct nfs_fsloc *tmp; + FedFsStatus retval; + + tmp = nfs_new_location(); + if (tmp == NULL) + return FEDFS_ERR_SVRFAULT; + + retval = nfs_parse_location_children(pathname, location, tmp); + if (retval != FEDFS_OK) + nfs_free_location(tmp); + else + *fsloc = tmp; + return retval; +} + +/** + * Build list of NFS locations from a nodeset + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param nodeset XML nodeset containing "location" elements + * @param fslocs OUT: pointer to a list of NFS locations + * @return a FedFsStatus code + * + * If nfs_parse_nodeset() returns FEDFS_OK, caller must free the returned + * list of locations with nfs_free_locations(). + */ +static FedFsStatus +nfs_parse_nodeset(const char *pathname, xmlNodeSetPtr nodeset, + struct nfs_fsloc **fslocs) +{ + struct nfs_fsloc *location, *result = NULL; + FedFsStatus retval; + int i; + + if (xmlXPathNodeSetIsEmpty(nodeset)) { + xlog(D_GENERAL, "%s: No fileset locations found in %s", + __func__, pathname); + return FEDFS_ERR_NOTJUNCT; + } + + for (i = 0; i < nodeset->nodeNr; i++) { + xmlNodePtr node = nodeset->nodeTab[i]; + + retval = nfs_parse_node(pathname, node, &location); + if (retval != FEDFS_OK) { + nfs_free_locations(result); + return retval; + } + + if (result == NULL) + result = location; + else + result->nfl_next = location; + } + + *fslocs = result; + return FEDFS_OK; +} + +/** + * Parse fileset location information from junction XML + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param context XML path context containing junction XML + * @param fslocs OUT: pointer to a list of NFS locations + * @return a FedFsStatus code + * + * If nfs_parse_context() returns FEDFS_OK, caller must free the returned + * list of locations with nfs_free_locations(). + */ +static FedFsStatus +nfs_parse_context(const char *pathname, xmlXPathContextPtr context, + struct nfs_fsloc **fslocs) +{ + xmlXPathObjectPtr object; + FedFsStatus retval; + + object = xmlXPathEvalExpression(NFS_XML_LOCATION_XPATH, context); + if (object == NULL) { + xlog(D_GENERAL, "%s: Failed to evaluate XML in %s", + __func__, pathname); + return FEDFS_ERR_NOTJUNCT; + } + + retval = nfs_parse_nodeset(pathname, object->nodesetval, fslocs); + + xmlXPathFreeObject(object); + return retval; +} + +/** + * Parse NFS locations information from junction XML + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param doc XML parse tree containing junction XML document + * @param fslocs OUT: pointer to a list of NFS locations + * @return a FedFsStatus code + * + * If nfs_parse_xml() returns FEDFS_OK, caller must free the returned + * list of locations with nfs_free_locations(). + */ +static FedFsStatus +nfs_parse_xml(const char *pathname, xmlDocPtr doc, struct nfs_fsloc **fslocs) +{ + xmlXPathContextPtr context; + FedFsStatus retval; + + context = xmlXPathNewContext(doc); + if (context == NULL) { + xlog(D_GENERAL, "%s: Failed to create XPath context from %s", + __func__, pathname); + return FEDFS_ERR_SVRFAULT; + } + + retval = nfs_parse_context(pathname, context, fslocs); + + xmlXPathFreeContext(context); + return retval; +} + +/** + * Retrieve list of NFS locations from an NFS junction + * + * @param pathname NUL-terminated C string containing pathname of a junction + * @param fslocs OUT: pointer to a list of NFS locations + * @return a FedFsStatus code + * + * If nfs_get_locations() returns FEDFS_OK, caller must free the returned + * list of locations with nfs_free_locations(). + */ +FedFsStatus +nfs_get_locations(const char *pathname, struct nfs_fsloc **fslocs) +{ + FedFsStatus retval; + xmlDocPtr doc; + + if (fslocs == NULL) + return FEDFS_ERR_INVAL; + + retval = junction_xml_parse(pathname, JUNCTION_XATTR_NAME_NFS, &doc); + if (retval != FEDFS_OK) + return retval; + + retval = nfs_parse_xml(pathname, doc, fslocs); + + xmlFreeDoc(doc); + return retval; +} + +/** + * Predicate: does "pathname" refer to an object that can become an NFS junction? + * + * @param pathname NUL-terminated C string containing pathname of a directory + * @return a FedFsStatus code + * + * Return values: + * FEDFS_ERR_NOTJUNCT: "pathname" refers to an object that can be + * made into a NFS junction + * FEDFS_ERR_EXIST: "pathname" refers to something that is + * already a junction + * FEDFS_ERR_INVAL: "pathname" does not exist + * Other: Some error occurred, "pathname" not + * investigated + */ +FedFsStatus +nfs_is_prejunction(const char *pathname) +{ + FedFsStatus retval; + int fd; + + retval = junction_open_path(pathname, &fd); + if (retval != FEDFS_OK) + return retval; + + retval = junction_is_directory(fd, pathname); + if (retval != FEDFS_OK) + goto out_close; + + retval = junction_is_sticky_bit_set(fd, pathname); + switch (retval) { + case FEDFS_ERR_NOTJUNCT: + break; + case FEDFS_OK: + goto out_exist; + default: + goto out_close; + } + + retval = junction_is_xattr_present(fd, pathname, JUNCTION_XATTR_NAME_NFS); + switch (retval) { + case FEDFS_ERR_NOTJUNCT: + break; + case FEDFS_OK: + goto out_exist; + default: + goto out_close; + } + +out_close: + (void)close(fd); + return retval; +out_exist: + retval = FEDFS_ERR_EXIST; + goto out_close; +} + +/** + * Verify that junction contains NFS junction XML + * + * @param pathname NUL-terminated C string containing pathname of a directory + * @return a FedFsStatus code + * + * Return values: + * FEDFS_OK: "pathname" refers to an NFS junction + * FEDFS_ERR_NOTJUNCT: "pathname" refers to something that is + * not an NFS junction + * FEDFS_ERR_INVAL: "pathname" does not exist + * Other: Some error occurred, "pathname" not + * investigated + * + * NB: This is an expensive test. However, it is only done if the object + * actually has a junction extended attribute, meaning it should be done + * rarely. If this is really a problem, we can make the XML test cheaper. + */ +static FedFsStatus +nfs_is_junction_xml(const char *pathname) +{ + struct nfs_fsloc *fslocs = NULL; + FedFsStatus retval; + xmlDocPtr doc; + + retval = junction_xml_parse(pathname, JUNCTION_XATTR_NAME_NFS, &doc); + if (retval != FEDFS_OK) + return retval; + + retval = nfs_parse_xml(pathname, doc, &fslocs); + nfs_free_locations(fslocs); + + xmlFreeDoc(doc); + return retval; +} + +/** + * Predicate: does "pathname" refer to an NFS junction? + * + * @param pathname NUL-terminated C string containing pathname of a directory + * @return a FedFsStatus code + * + * Return values: + * FEDFS_OK: "pathname" refers to an NFS junction + * FEDFS_ERR_NOTJUNCT: "pathname" refers to an object that is + * not a junction + * FEDFS_ERR_INVAL: "pathname" does not exist + * Other: Some error occurred, "pathname" not + * investigated + */ +FedFsStatus +nfs_is_junction(const char *pathname) +{ + FedFsStatus retval; + int fd; + + retval = junction_open_path(pathname, &fd); + if (retval != FEDFS_OK) + return retval; + + retval = junction_is_directory(fd, pathname); + if (retval != FEDFS_OK) + goto out_close; + + retval = junction_is_sticky_bit_set(fd, pathname); + if (retval != FEDFS_OK) + goto out_close; + + retval = junction_is_xattr_present(fd, pathname, JUNCTION_XATTR_NAME_NFS); + if (retval != FEDFS_OK) + goto out_close; + + (void)close(fd); + + return nfs_is_junction_xml(pathname); + +out_close: + (void)close(fd); + return retval; +} diff --git a/support/junction/path.c b/support/junction/path.c new file mode 100644 index 0000000..13a1438 --- /dev/null +++ b/support/junction/path.c @@ -0,0 +1,352 @@ +/** + * @file support/junction/path.c + * @brief Encode and decode FedFS pathnames + */ + +/* + * Copyright 2010, 2011, 2018 Oracle. All rights reserved. + * + * This file is part of nfs-utils. + * + * nfs-utils is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 as + * published by the Free Software Foundation. + * + * nfs-utils is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2.0 for more details. + * + * You should have received a copy of the GNU General Public License + * version 2.0 along with nfs-utils. If not, see: + * + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + */ + +#include <sys/types.h> +#include <sys/stat.h> + +#include <stdbool.h> +#include <unistd.h> +#include <stdint.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <dirent.h> + +#include <netinet/in.h> + +#include "junction.h" +#include "xlog.h" + +#define STRLEN_SLASH ((size_t)1) /* strlen("/") */ + +#define XDR_UINT_BYTES (sizeof(uint32_t)) + +/** + * Compute count of XDR 4-octet units from byte count + * + * @param bytes number of bytes to convert + * @return equivalent number of XDR 4-octet units + */ +static inline size_t +nsdb_quadlen(size_t bytes) +{ + return (bytes + 3) >> 2; +} + +/** + * Free array of NUL-terminated C strings + * + * @param strings array of char * to be released + */ +void +nsdb_free_string_array(char **strings) +{ + int i; + + if (strings == NULL) + return; + for (i = 0; strings[i] != NULL; i++) + free(strings[i]); + free(strings); +} + +static FedFsStatus +nsdb_alloc_zero_component_pathname(char ***path_array) +{ + char **result; + + xlog(D_GENERAL, "%s: Zero-component pathname", __func__); + + result = (char **)calloc(1, sizeof(char *)); + if (result == NULL) + return FEDFS_ERR_SVRFAULT; + result[0] = NULL; + *path_array = result; + return FEDFS_OK; +} + +/** + * Sanitize an incoming POSIX path + * + * @param pathname NUL-terminated C string containing a POSIX pathname + * @return NUL-terminated C string containing sanitized path + * + * Caller must free the returned pathname with free(3). + * + * Remove multiple sequential slashes and any trailing slashes, + * but leave "/" by itself alone. + */ +static __attribute_malloc__ char * +nsdb_normalize_path(const char *pathname) +{ + size_t i, j, len; + char *result; + + len = strlen(pathname); + if (len == 0) { + xlog(D_CALL, "%s: NULL pathname", __func__); + return NULL; + } + + result = malloc(len + 1); + if (result == NULL) + return NULL; + + for (i = 0, j = 0; i < len; i++) { + if (pathname[i] == '/' && pathname[i + 1] == '/') + continue; + result[j++] = pathname[i]; + } + result[j] = '\0'; + + if (j > 1 && result[j - 1] == '/') + result[j - 1] = '\0'; + + xlog(D_CALL, "%s: result = '%s'", __func__, result); + return result; +} + +/** + * Count the number of components in a POSIX pathname + * + * @param pathname NUL-terminated C string containing a POSIX pathname + * @param len OUT: number of bytes the encoded XDR stream will consume + * @param cnt OUT: component count + * @return true when successful + */ +static _Bool +nsdb_count_components(const char *pathname, size_t *len, + unsigned int *cnt) +{ + char *start, *component; + unsigned int count; + size_t length; + + /* strtok(3) will tromp on the string */ + start = strdup(pathname); + if (start == NULL) + return false; + + length = XDR_UINT_BYTES; + count = 0; + component = start; + for ( ;; ) { + char *next; + size_t tmp; + + if (*component == '/') + component++; + if (*component == '\0') + break; + next = strchrnul(component, '/'); + tmp = (size_t)(next - component); + if (tmp > 255) { + free(start); + return false; + } + length += XDR_UINT_BYTES + (nsdb_quadlen(tmp) << 2); + count++; + + if (*next == '\0') + break; + component = next; + } + + free(start); + + xlog(D_CALL, "%s: length = %zu, count = %u, path = '%s'", + __func__, length, count, pathname); + *len = length; + *cnt = count; + return true; +} + +/** + * Predicate: is input character set for a POSIX pathname valid UTF-8? + * + * @param pathname NUL-terminated C string containing a POSIX path + * @return true if the string is valid UTF-8 + * + * XXX: implement this + */ +static _Bool +nsdb_pathname_is_utf8(__attribute__((unused)) const char *pathname) +{ + return true; +} + +/** + * Construct a local POSIX-style pathname from an array of component strings + * + * @param path_array array of pointers to NUL-terminated C strings + * @param pathname OUT: pointer to NUL-terminated UTF-8 C string containing a POSIX-style path + * @return a FedFsStatus code + * + * Caller must free the returned pathname with free(3). + */ +FedFsStatus +nsdb_path_array_to_posix(char * const *path_array, char **pathname) +{ + char *component, *result; + unsigned int i, count; + size_t length, len; + + if (path_array == NULL || pathname == NULL) + return FEDFS_ERR_INVAL; + + if (path_array[0] == NULL) { + xlog(D_GENERAL, "%s: Zero-component pathname", __func__); + result = strdup("/"); + if (result == NULL) + return FEDFS_ERR_SVRFAULT; + *pathname = result; + return FEDFS_OK; + } + + for (length = 0, count = 0; + path_array[count] != NULL; + count++) { + component = path_array[count]; + len = strlen(component); + + if (len == 0) { + xlog(D_GENERAL, "%s: Zero-length component", __func__); + return FEDFS_ERR_BADNAME; + } + if (len > NAME_MAX) { + xlog(D_GENERAL, "%s: Component length too long", __func__); + return FEDFS_ERR_NAMETOOLONG; + } + if (strchr(component, '/') != NULL) { + xlog(D_GENERAL, "%s: Local separator character " + "found in component", __func__); + return FEDFS_ERR_BADNAME; + } + if (!nsdb_pathname_is_utf8(component)) { + xlog(D_GENERAL, "%s: Bad character in component", + __func__); + return FEDFS_ERR_BADCHAR; + } + + length += STRLEN_SLASH + len; + + if (length > PATH_MAX) { + xlog(D_GENERAL, "%s: Pathname too long", __func__); + return FEDFS_ERR_NAMETOOLONG; + } + } + + result = calloc(1, length + 1); + if (result == NULL) + return FEDFS_ERR_SVRFAULT; + + for (i = 0; i < count; i++) { + strcat(result, "/"); + strcat(result, path_array[i]); + } + *pathname = nsdb_normalize_path(result); + free(result); + if (*pathname == NULL) + return FEDFS_ERR_SVRFAULT; + return FEDFS_OK; +} + +/** + * Construct an array of component strings from a local POSIX-style pathname + * + * @param pathname NUL-terminated C string containing a POSIX-style pathname + * @param path_array OUT: pointer to array of pointers to NUL-terminated C strings + * @return a FedFsStatus code + * + * Caller must free "path_array" with nsdb_free_string_array(). + */ +FedFsStatus +nsdb_posix_to_path_array(const char *pathname, char ***path_array) +{ + char *normalized, *component, **result; + unsigned int i, count; + size_t length; + + if (pathname == NULL || path_array == NULL) + return FEDFS_ERR_INVAL; + + if (!nsdb_pathname_is_utf8(pathname)) { + xlog(D_GENERAL, "%s: Bad character in pathname", __func__); + return FEDFS_ERR_BADCHAR; + } + + normalized = nsdb_normalize_path(pathname); + if (normalized == NULL) + return FEDFS_ERR_SVRFAULT; + + if (!nsdb_count_components(normalized, &length, &count)) { + free(normalized); + return FEDFS_ERR_BADNAME; + } + + if (count == 0) { + free(normalized); + return nsdb_alloc_zero_component_pathname(path_array); + } + + result = (char **)calloc(count + 1, sizeof(char *)); + if (result == NULL) { + free(normalized); + return FEDFS_ERR_SVRFAULT; + } + + component = normalized; + for (i = 0; ; i++) { + char *next; + + if (*component == '/') + component++; + if (*component == '\0') + break; + next = strchrnul(component, '/'); + length = (size_t)(next - component); + if (length > 255) { + nsdb_free_string_array(result); + free(normalized); + return FEDFS_ERR_SVRFAULT; + } + + result[i] = strndup(component, length); + if (result[i] == NULL) { + free(normalized); + nsdb_free_string_array(result); + return FEDFS_ERR_SVRFAULT; + } + + if (*next == '\0') + break; + component = next; + } + + *path_array = result; + free(normalized); + return FEDFS_OK; +} diff --git a/support/junction/xml.c b/support/junction/xml.c new file mode 100644 index 0000000..813110b --- /dev/null +++ b/support/junction/xml.c @@ -0,0 +1,401 @@ +/** + * @file support/junction/xml.c + * @brief Common utilities for managing junction XML + */ + +/* + * Copyright 2011, 2018 Oracle. All rights reserved. + * + * This file is part of nfs-utils. + * + * nfs-utils is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2.0 as + * published by the Free Software Foundation. + * + * nfs-utils is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License version 2.0 for more details. + * + * You should have received a copy of the GNU General Public License + * version 2.0 along with nfs-utils. If not, see: + * + * http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt + */ + +#include <sys/types.h> +#include <sys/stat.h> + +#include <stdbool.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> + +#include "junction.h" +#include "junction-internal.h" +#include "xlog.h" + +/** + * Predicate: is element content empty? + * + * @param content element content to test + * @return true if content is empty + */ +_Bool +junction_xml_is_empty(const xmlChar *content) +{ + return content == NULL || *content == '\0'; +} + +/** + * Match an XML parse tree node by its name + * + * @param node pointer to a node in an XML parse tree + * @param name NUL-terminated C string containing name to match + * @return true if "node" is named "name" + */ +_Bool +junction_xml_match_node_name(xmlNodePtr node, const xmlChar *name) +{ + return (node->type == XML_ELEMENT_NODE) && + (xmlStrcmp(node->name, name) == 0); +} + +/** + * Find a first-level child of "parent" named "name" + * + * @param parent pointer to node whose children are to be searched + * @param name NUL-terminated C string containing name to match + * @return pointer to child of "parent" whose name is "name" + */ +xmlNodePtr +junction_xml_find_child_by_name(xmlNodePtr parent, const xmlChar *name) +{ + xmlNodePtr node; + + for (node = parent->children; node != NULL; node = node->next) + if (junction_xml_match_node_name(node, name)) + return node; + return NULL; +} + +/** + * Read attribute into a boolean + * + * @param node pointer to a node in an XML parse tree + * @param attrname NUL-terminated C string containing attribute name + * @param value OUT: attribute's value converted to an integer + * @return true if attribute "attrname" has a valid boolean value + */ +_Bool +junction_xml_get_bool_attribute(xmlNodePtr node, const xmlChar *attrname, + _Bool *value) +{ + xmlChar *prop; + _Bool retval; + + retval = false; + prop = xmlGetProp(node, attrname); + if (prop == NULL) + goto out; + + if (xmlStrcmp(prop, (const xmlChar *)"true") == 0) { + *value = true; + retval = true; + goto out; + } + + if (xmlStrcmp(prop, (const xmlChar *)"false") == 0) { + *value = false; + retval = true; + goto out; + } + +out: + xmlFree(prop); + return retval; +} + +/** + * Set attribute to a boolean + * + * @param node pointer to a node in an XML parse tree + * @param attrname NUL-terminated C string containing attribute name + * @param value boolean value to set + */ +void +junction_xml_set_bool_attribute(xmlNodePtr node, const xmlChar *attrname, + _Bool value) +{ + xmlSetProp(node, attrname, (const xmlChar *)(value ? "true" : "false")); +} + +/** + * Read attribute into an uint8_t + * + * @param node pointer to a node in an XML parse tree + * @param attrname NUL-terminated C string containing attribute name + * @param value OUT: attribute's value converted to an uint8_t + * @return true if attribute "attrname" has a valid uint8_t value + */ +_Bool +junction_xml_get_u8_attribute(xmlNodePtr node, const xmlChar *attrname, + uint8_t *value) +{ + char *endptr; + _Bool retval; + char *prop; + long tmp; + + retval = false; + prop = (char *)xmlGetProp(node, attrname); + if (prop == NULL) + goto out; + + errno = 0; + tmp = strtol(prop, &endptr, 10); + if (errno != 0 || *endptr != '\0' || tmp > 255 || tmp < 0) + goto out; + + *value = (uint8_t)tmp; + retval = true; + +out: + xmlFree(prop); + return retval; +} + +/** + * Read attribute into an integer + * + * @param node pointer to a node in an XML parse tree + * @param attrname NUL-terminated C string containing attribute name + * @param value OUT: attribute's value converted to an integer + * @return true if attribute "attrname" has a valid integer value + */ +_Bool +junction_xml_get_int_attribute(xmlNodePtr node, const xmlChar *attrname, + int *value) +{ + char *endptr; + _Bool retval; + char *prop; + long tmp; + + retval = false; + prop = (char *)xmlGetProp(node, attrname); + if (prop == NULL) + goto out; + + errno = 0; + tmp = strtol(prop, &endptr, 10); + if (errno != 0 || *endptr != '\0' || tmp > INT32_MAX || tmp < INT32_MIN) + goto out; + + *value = (int)tmp; + retval = true; + +out: + xmlFree(prop); + return retval; +} + +/** + * Set attribute to an integer + * + * @param node pointer to a node in an XML parse tree + * @param attrname NUL-terminated C string containing attribute name + * @param value integer value to set + */ +void +junction_xml_set_int_attribute(xmlNodePtr node, const xmlChar *attrname, + int value) +{ + char buf[16]; + + snprintf(buf, sizeof(buf), "%d", value); + xmlSetProp(node, attrname, (const xmlChar *)buf); +} + +/** + * Read node content into an integer + * + * @param node pointer to a node in an XML parse tree + * @param value OUT: node's content converted to an integer + * @return true if "node" has valid integer content + */ +_Bool +junction_xml_get_int_content(xmlNodePtr node, int *value) +{ + xmlChar *content; + char *endptr; + _Bool retval; + long tmp; + + retval = false; + content = xmlNodeGetContent(node); + if (content == NULL) + goto out; + + errno = 0; + tmp = strtol((const char *)content, &endptr, 10); + if (errno != 0 || *endptr != '\0' || tmp > INT32_MAX || tmp < INT32_MIN) + goto out; + + *value = (int)tmp; + retval = true; + +out: + xmlFree(content); + return retval; +} + +/** + * Add a child node with integer content + * + * @param parent pointer to a node in an XML parse tree + * @param name NUL-terminated C string containing name of child to add + * @param value set node content to this value + * @return pointer to new child node + */ +xmlNodePtr +junction_xml_set_int_content(xmlNodePtr parent, const xmlChar *name, int value) +{ + char buf[16]; + + snprintf(buf, sizeof(buf), "%d", value); + return xmlNewTextChild(parent, NULL, name, (const xmlChar *)buf); +} + +/** + * Parse XML document in a buffer into an XML document tree + * + * @param pathname NUL-terminated C string containing pathname of a directory + * @param name NUL-terminated C string containing name of xattr to replace + * @param buf opaque byte array containing XML to parse + * @param len size of "buf" in bytes + * @param doc OUT: an XML parse tree containing junction XML + * @return a FedFsStatus code + * + * If junction_parse_xml_buf() returns success, caller must free "*doc" + * using xmlFreeDoc(3). + * + * @note Access to trusted attributes requires CAP_SYS_ADMIN. + */ +static FedFsStatus +junction_parse_xml_buf(const char *pathname, const char *name, + void *buf, size_t len, xmlDocPtr *doc) +{ + xmlDocPtr tmp; + + tmp = xmlParseMemory(buf, (int)len); + if (tmp == NULL) { + xlog(D_GENERAL, "Failed to parse XML in %s(%s)\n", + pathname, name); + return FEDFS_ERR_SVRFAULT; + } + + *doc = tmp; + return FEDFS_OK; +} + +/** + * Read an XML document from an extended attribute into an XML document tree + * + * @param pathname NUL-terminated C string containing pathname of a directory + * @param fd an open file descriptor + * @param name NUL-terminated C string containing name of xattr to replace + * @param doc OUT: an XML parse tree containing junction XML + * @return a FedFsStatus code + * + * If junction_parse_xml_read() returns success, caller must free "*doc" + * using xmlFreeDoc(3). + * + * @note Access to trusted attributes requires CAP_SYS_ADMIN. + */ +static FedFsStatus +junction_parse_xml_read(const char *pathname, int fd, const char *name, + xmlDocPtr *doc) +{ + FedFsStatus retval; + void *buf = NULL; + size_t len; + + retval = junction_get_xattr(fd, pathname, name, &buf, &len); + if (retval != FEDFS_OK) + return retval; + + xlog(D_CALL, "%s: XML document contained in junction:\n%zu.%s", + __func__, len, (char *)buf); + + retval = junction_parse_xml_buf(pathname, name, buf, len, doc); + + free(buf); + return retval; +} + +/** + * Read an XML document from an extended attribute into an XML document tree + * + * @param pathname NUL-terminated C string containing pathname of a directory + * @param name NUL-terminated C string containing name of xattr to replace + * @param doc OUT: an XML parse tree containing junction XML + * @return a FedFsStatus code + * + * If junction_parse_xml() returns success, caller must free "*doc" + * using xmlFreeDoc(3). + * + * @note Access to trusted attributes requires CAP_SYS_ADMIN. + */ +FedFsStatus +junction_xml_parse(const char *pathname, const char *name, xmlDocPtr *doc) +{ + FedFsStatus retval; + int fd; + + retval = junction_open_path(pathname, &fd); + if (retval != FEDFS_OK) + return retval; + + retval = junction_parse_xml_read(pathname, fd, name, doc); + + (void)close(fd); + return retval; +} + +/** + * Write an XML document into an extended attribute + * + * @param pathname NUL-terminated C string containing pathname of a directory + * @param name NUL-terminated C string containing name of xattr to replace + * @param doc an XML parse tree containing junction XML + * @return a FedFsStatus code + * + * @note Access to trusted attributes requires CAP_SYS_ADMIN. + */ +FedFsStatus +junction_xml_write(const char *pathname, const char *name, xmlDocPtr doc) +{ + xmlChar *buf = NULL; + FedFsStatus retval; + int fd, len; + + retval = junction_open_path(pathname, &fd); + if (retval != FEDFS_OK) + return retval; + + retval = FEDFS_ERR_SVRFAULT; + xmlIndentTreeOutput = 1; + xmlDocDumpFormatMemoryEnc(doc, &buf, &len, "UTF-8", 1); + if (len < 0) + goto out; + + retval = junction_set_xattr(fd, pathname, name, buf, (size_t)len); + +out: + xmlFree(buf); + (void)close(fd); + return retval; +} diff --git a/support/misc/Makefile.am b/support/misc/Makefile.am new file mode 100644 index 0000000..f9993e3 --- /dev/null +++ b/support/misc/Makefile.am @@ -0,0 +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 \ + nfsd_path.c workqueue.c xstat.c + +MAINTAINERCLEANFILES = Makefile.in diff --git a/support/misc/Makefile.in b/support/misc/Makefile.in new file mode 100644 index 0000000..0636156 --- /dev/null +++ b/support/misc/Makefile.in @@ -0,0 +1,712 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = support/misc +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ax_gcc_func_attribute.m4 \ + $(top_srcdir)/aclocal/bsdsignals.m4 \ + $(top_srcdir)/aclocal/getrandom.m4 \ + $(top_srcdir)/aclocal/ipv6.m4 \ + $(top_srcdir)/aclocal/kerberos5.m4 \ + $(top_srcdir)/aclocal/keyutils.m4 \ + $(top_srcdir)/aclocal/libblkid.m4 \ + $(top_srcdir)/aclocal/libcap.m4 \ + $(top_srcdir)/aclocal/libevent.m4 \ + $(top_srcdir)/aclocal/libpthread.m4 \ + $(top_srcdir)/aclocal/libsqlite3.m4 \ + $(top_srcdir)/aclocal/libtirpc.m4 \ + $(top_srcdir)/aclocal/libxml2.m4 \ + $(top_srcdir)/aclocal/nfs-utils.m4 \ + $(top_srcdir)/aclocal/rpcsec_vers.m4 \ + $(top_srcdir)/aclocal/tcp-wrappers.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/support/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +AM_V_AR = $(am__v_AR_@AM_V@) +am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) +am__v_AR_0 = @echo " AR " $@; +am__v_AR_1 = +libmisc_a_AR = $(AR) $(ARFLAGS) +libmisc_a_LIBADD = +am_libmisc_a_OBJECTS = tcpwrapper.$(OBJEXT) from_local.$(OBJEXT) \ + mountpoint.$(OBJEXT) file.$(OBJEXT) nfsd_path.$(OBJEXT) \ + workqueue.$(OBJEXT) xstat.$(OBJEXT) +libmisc_a_OBJECTS = $(am_libmisc_a_OBJECTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/support/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/file.Po ./$(DEPDIR)/from_local.Po \ + ./$(DEPDIR)/mountpoint.Po ./$(DEPDIR)/nfsd_path.Po \ + ./$(DEPDIR)/tcpwrapper.Po ./$(DEPDIR)/workqueue.Po \ + ./$(DEPDIR)/xstat.Po +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libmisc_a_SOURCES) +DIST_SOURCES = $(libmisc_a_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GREP = @GREP@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GSSD = @GSSD@ +GSSGLUE_CFLAGS = @GSSGLUE_CFLAGS@ +GSSGLUE_LIBS = @GSSGLUE_LIBS@ +GSSKRB_CFLAGS = @GSSKRB_CFLAGS@ +GSSKRB_LIBS = @GSSKRB_LIBS@ +HAVE_GETRANDOM = @HAVE_GETRANDOM@ +HAVE_LIBWRAP = @HAVE_LIBWRAP@ +HAVE_TCP_WRAPPER = @HAVE_TCP_WRAPPER@ +IDMAPD = @IDMAPD@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +K5VERS = @K5VERS@ +KRBCFLAGS = @KRBCFLAGS@ +KRBDIR = @KRBDIR@ +KRBLDFLAGS = @KRBLDFLAGS@ +KRBLIBS = @KRBLIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ +LIBBLKID = @LIBBLKID@ +LIBBSD = @LIBBSD@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBEVENT = @LIBEVENT@ +LIBKEYUTILS = @LIBKEYUTILS@ +LIBMOUNT = @LIBMOUNT@ +LIBMOUNT_CFLAGS = @LIBMOUNT_CFLAGS@ +LIBMOUNT_LIBS = @LIBMOUNT_LIBS@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPTHREAD = @LIBPTHREAD@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSQLITE = @LIBSQLITE@ +LIBTIRPC = @LIBTIRPC@ +LIBTOOL = @LIBTOOL@ +LIBWRAP = @LIBWRAP@ +LIBXML2 = @LIBXML2@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_PLUGINS = @PATH_PLUGINS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +RELEASE = @RELEASE@ +RPCGEN_PATH = @RPCGEN_PATH@ +RPCSECGSS_CFLAGS = @RPCSECGSS_CFLAGS@ +RPCSECGSS_LIBS = @RPCSECGSS_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SVCGSSD = @SVCGSSD@ +TIRPC_CFLAGS = @TIRPC_CFLAGS@ +TIRPC_LIBS = @TIRPC_LIBS@ +VERSION = @VERSION@ +XML2_CFLAGS = @XML2_CFLAGS@ +XML2_LIBS = @XML2_LIBS@ +_rpc_pipefsmount = @_rpc_pipefsmount@ +_statedir = @_statedir@ +_sysconfdir = @_sysconfdir@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_gss = @enable_gss@ +enable_ipv6 = @enable_ipv6@ +enable_mountconfig = @enable_mountconfig@ +enable_nfsv4 = @enable_nfsv4@ +enable_nfsv41 = @enable_nfsv41@ +enable_svcgss = @enable_svcgss@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +kprefix = @kprefix@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +mountfile = @mountfile@ +nfsconfig = @nfsconfig@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rpc_pipefsmount = @rpc_pipefsmount@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +startstatd = @startstatd@ +statdpath = @statdpath@ +statduser = @statduser@ +statedir = @statedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +unitdir = @unitdir@ +noinst_LIBRARIES = libmisc.a +libmisc_a_SOURCES = tcpwrapper.c from_local.c mountpoint.c file.c \ + nfsd_path.c workqueue.c xstat.c + +MAINTAINERCLEANFILES = Makefile.in +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu support/misc/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu support/misc/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +libmisc.a: $(libmisc_a_OBJECTS) $(libmisc_a_DEPENDENCIES) $(EXTRA_libmisc_a_DEPENDENCIES) + $(AM_V_at)-rm -f libmisc.a + $(AM_V_AR)$(libmisc_a_AR) libmisc.a $(libmisc_a_OBJECTS) $(libmisc_a_LIBADD) + $(AM_V_at)$(RANLIB) libmisc.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/from_local.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mountpoint.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nfsd_path.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcpwrapper.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/workqueue.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xstat.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/file.Po + -rm -f ./$(DEPDIR)/from_local.Po + -rm -f ./$(DEPDIR)/mountpoint.Po + -rm -f ./$(DEPDIR)/nfsd_path.Po + -rm -f ./$(DEPDIR)/tcpwrapper.Po + -rm -f ./$(DEPDIR)/workqueue.Po + -rm -f ./$(DEPDIR)/xstat.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/file.Po + -rm -f ./$(DEPDIR)/from_local.Po + -rm -f ./$(DEPDIR)/mountpoint.Po + -rm -f ./$(DEPDIR)/nfsd_path.Po + -rm -f ./$(DEPDIR)/tcpwrapper.Po + -rm -f ./$(DEPDIR)/workqueue.Po + -rm -f ./$(DEPDIR)/xstat.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-noinstLIBRARIES \ + cscopelist-am ctags ctags-am distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/support/misc/file.c b/support/misc/file.c new file mode 100644 index 0000000..06f6bb2 --- /dev/null +++ b/support/misc/file.c @@ -0,0 +1,115 @@ +/* + * Copyright 2009 Oracle. All rights reserved. + * Copyright 2017 Red Hat, Inc. All rights reserved. + * + * This file is part of nfs-utils. + * + * nfs-utils is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * nfs-utils is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with nfs-utils. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/stat.h> + +#include <string.h> +#include <libgen.h> +#include <stdio.h> +#include <errno.h> +#include <dirent.h> +#include <stdlib.h> +#include <stdbool.h> +#include <limits.h> + +#include "xlog.h" +#include "misc.h" + +/* + * Returns a dynamically allocated, '\0'-terminated buffer + * containing an appropriate pathname, or NULL if an error + * occurs. Caller must free the returned result with free(3). + */ +__attribute__((__malloc__)) +char * +generic_make_pathname(const char *base, const char *leaf) +{ + size_t size; + char *path; + int len; + + size = strlen(base) + strlen(leaf) + 2; + if (size > PATH_MAX) + return NULL; + + path = malloc(size); + if (path == NULL) + return NULL; + + len = snprintf(path, size, "%s/%s", base, leaf); + if ((len < 0) || ((size_t)len >= size)) { + free(path); + return NULL; + } + + return path; +} + + +/** + * generic_setup_basedir - set up basedir + * @progname: C string containing name of program, for error messages + * @parentdir: C string containing pathname to on-disk state, or NULL + * @base: character buffer to contain the basedir that is set up + * @baselen: size of @base in bytes + * + * This runs before logging is set up, so error messages are directed + * to stderr. + * + * Returns true and sets up our basedir, if @parentdir was valid + * and usable; otherwise false is returned. + */ +_Bool +generic_setup_basedir(const char *progname, const char *parentdir, char *base, + const size_t baselen) +{ + static char buf[PATH_MAX]; + struct stat st; + char *path; + + /* First: test length of name and whether it exists */ + if ((strlen(parentdir) >= baselen) || (strlen(parentdir) >= PATH_MAX)) { + (void)fprintf(stderr, "%s: Directory name too long: %s", + progname, parentdir); + return false; + } + if (lstat(parentdir, &st) == -1) { + (void)fprintf(stderr, "%s: Failed to stat %s: %s", + progname, parentdir, strerror(errno)); + return false; + } + + /* Ensure we have a clean directory pathname */ + strncpy(buf, parentdir, sizeof(buf)-1); + path = dirname(buf); + if (*path == '.') { + (void)fprintf(stderr, "%s: Unusable directory %s", + progname, parentdir); + return false; + } + + xlog(D_CALL, "Using %s as the state directory", parentdir); + strcpy(base, parentdir); + return true; +} diff --git a/support/misc/from_local.c b/support/misc/from_local.c new file mode 100644 index 0000000..e2de969 --- /dev/null +++ b/support/misc/from_local.c @@ -0,0 +1,268 @@ + /* + * Check if an address belongs to the local system. Adapted from: + * + * @(#)pmap_svc.c 1.32 91/03/11 Copyright 1984,1990 Sun Microsystems, Inc. + * @(#)get_myaddress.c 2.1 88/07/29 4.0 RPCSRC. + */ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#if 0 +static char sccsid[] = "@(#) from_local.c 1.3 96/05/31 15:52:57"; +#endif + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/types.h> +#include <sys/socket.h> +#include <stdbool.h> +#include <stdio.h> +#include <unistd.h> +#include <netdb.h> +#include <netinet/in.h> +#include <net/if.h> +#include <sys/ioctl.h> +#include <stdlib.h> +#include <string.h> + +#include "sockaddr.h" +#include "tcpwrapper.h" +#include "xlog.h" + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +#ifdef HAVE_GETIFADDRS + +#include <ifaddrs.h> +#include <time.h> + +/** + * from_local - determine whether request comes from the local system + * @sap: pointer to socket address to check + * + * With virtual hosting, each hardware network interface can have + * multiple network addresses. On such machines the number of machine + * addresses can be surprisingly large. + * + * We also expect the local network configuration to change over time, + * so call getifaddrs(3) more than once, but not too often. + * + * Returns TRUE if the sockaddr contains an address of one of the local + * network interfaces. Otherwise FALSE is returned. + */ +int +from_local(const struct sockaddr *sap) +{ + static struct ifaddrs *ifaddr = NULL; + static time_t last_update = 0; + struct ifaddrs *ifa; + unsigned int count; + time_t now; + + if (time(&now) == ((time_t)-1)) { + xlog(L_ERROR, "%s: time(2): %m", __func__); + + /* If we don't know what time it is, use the + * existing ifaddr list, if one exists */ + now = last_update; + if (ifaddr == NULL) + now++; + } + if (now != last_update) { + xlog(D_GENERAL, "%s: updating local if addr list", __func__); + + if (ifaddr) + freeifaddrs(ifaddr); + + if (getifaddrs(&ifaddr) == -1) { + xlog(L_ERROR, "%s: getifaddrs(3): %m", __func__); + return FALSE; + } + + last_update = now; + } + + count = 0; + for (ifa = ifaddr; ifa; ifa = ifa->ifa_next) { + if ((ifa->ifa_flags & IFF_UP) && + nfs_compare_sockaddr(sap, ifa->ifa_addr)) { + xlog(D_GENERAL, "%s: incoming address matches " + "local interface address", __func__); + return TRUE; + } else + count++; + } + + xlog(D_GENERAL, "%s: checked %u local if addrs; " + "incoming address not found", __func__, count); + return FALSE; +} + +#else /* !HAVE_GETIFADDRS */ + +static int num_local; +static int num_addrs; +static struct in_addr *addrs; + +/* grow_addrs - extend list of local interface addresses */ + +static int grow_addrs(void) +{ + struct in_addr *new_addrs; + int new_num; + + /* + * Keep the previous result if we run out of memory. The system would + * really get hosed if we simply give up. + */ + new_num = (addrs == 0) ? 1 : num_addrs + num_addrs; + new_addrs = (struct in_addr *) malloc(sizeof(*addrs) * new_num); + if (new_addrs == 0) { + xlog_warn("%s: out of memory", __func__); + return (0); + } else { + if (addrs != 0) { + memcpy((char *) new_addrs, (char *) addrs, + sizeof(*addrs) * num_addrs); + free((char *) addrs); + } + num_addrs = new_num; + addrs = new_addrs; + return (1); + } +} + +/* find_local - find all IP addresses for this host */ +static int +find_local(void) +{ + struct ifconf ifc; + struct ifreq ifreq; + struct ifreq *ifr; + struct ifreq *the_end; + int sock; + char buf[BUFSIZ]; + + /* + * Get list of network interfaces. We use a huge buffer to allow for the + * presence of non-IP interfaces. + */ + + if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) < 0) { + xlog_warn("%s: socket(2): %m", __func__); + return (0); + } + ifc.ifc_len = sizeof(buf); + ifc.ifc_buf = buf; + if (ioctl(sock, SIOCGIFCONF, (char *) &ifc) < 0) { + xlog_warn("%s: ioctl(SIOCGIFCONF): %m", __func__); + (void) close(sock); + return (0); + } + /* Get IP address of each active IP network interface. */ + + the_end = (struct ifreq *) (ifc.ifc_buf + ifc.ifc_len); + num_local = 0; + for (ifr = ifc.ifc_req; ifr < the_end; ifr++) { + if (ifr->ifr_addr.sa_family == AF_INET) { /* IP net interface */ + ifreq = *ifr; + if (ioctl(sock, SIOCGIFFLAGS, (char *) &ifreq) < 0) { + xlog_warn("%s: ioctl(SIOCGIFFLAGS): %m", __func__); + } else if (ifreq.ifr_flags & IFF_UP) { /* active interface */ + if (ioctl(sock, SIOCGIFADDR, (char *) &ifreq) < 0) { + xlog_warn("%s: ioctl(SIOCGIFADDR): %m", __func__); + } else { + if (num_local >= num_addrs) + if (grow_addrs() == 0) + break; + addrs[num_local++] = ((struct sockaddr_in *) + & ifreq.ifr_addr)->sin_addr; + } + } + } + /* Support for variable-length addresses. */ +#ifdef HAS_SA_LEN + ifr = (struct ifreq *) ((caddr_t) ifr + + ifr->ifr_addr.sa_len - sizeof(struct sockaddr)); +#endif + } + (void) close(sock); + return (num_local); +} + +/** + * from_local - determine whether request comes from the local system + * @sap: pointer to socket address to check + * + * With virtual hosting, each hardware network interface can have + * multiple network addresses. On such machines the number of machine + * addresses can be surprisingly large. + * + * Returns TRUE if the sockaddr contains an address of one of the local + * network interfaces. Otherwise FALSE is returned. + */ +int +from_local(const struct sockaddr *sap) +{ + const struct sockaddr_in *addr = (const struct sockaddr_in *)sap; + int i; + + if (sap->sa_family != AF_INET) + return (FALSE); + + if (addrs == 0 && find_local() == 0) + xlog(L_ERROR, "Cannot find any active local network interfaces"); + + for (i = 0; i < num_local; i++) { + if (memcmp((char *) &(addr->sin_addr), (char *) &(addrs[i]), + sizeof(struct in_addr)) == 0) + return (TRUE); + } + return (FALSE); +} + +#ifdef TEST + +int main(void) +{ + int i; + + find_local(); + for (i = 0; i < num_local; i++) + printf("%s\n", inet_ntoa(addrs[i])); +} + +#endif /* TEST */ + +#endif /* !HAVE_GETIFADDRS */ diff --git a/support/misc/mountpoint.c b/support/misc/mountpoint.c new file mode 100644 index 0000000..14d6731 --- /dev/null +++ b/support/misc/mountpoint.c @@ -0,0 +1,46 @@ + +/* + * check if a given path is a mountpoint + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <string.h> +#include "xcommon.h" +#include <sys/stat.h> +#include "misc.h" + +int +check_is_mountpoint(const char *path, int (mystat)(const char *, struct stat *)) +{ + if (!mystat) + mystat = lstat; + /* Check if 'path' is a current mountpoint. + * Possibly we should also check it is the mountpoint of the + * filesystem holding the target directory, but there doesn't + * seem a lot of point. + * + * We deem it to be a mountpoint if appending a ".." gives a different + * device or the same inode number. + */ + char *dotdot; + struct stat stb, pstb; + int rv; + + dotdot = xmalloc(strlen(path)+4); + + strcat(strcpy(dotdot, path), "/.."); + if (mystat(path, &stb) != 0 || + mystat(dotdot, &pstb) != 0) + rv = 0; + else + if (stb.st_dev != pstb.st_dev || + stb.st_ino == pstb.st_ino) + rv = 1; + else + rv = 0; + free(dotdot); + return rv; +} diff --git a/support/misc/nfsd_path.c b/support/misc/nfsd_path.c new file mode 100644 index 0000000..c3dea4f --- /dev/null +++ b/support/misc/nfsd_path.c @@ -0,0 +1,409 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <sys/vfs.h> +#include <fcntl.h> +#include <limits.h> +#include <stdlib.h> +#include <unistd.h> + +#include "conffile.h" +#include "xmalloc.h" +#include "xlog.h" +#include "xstat.h" +#include "nfslib.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) +{ + 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; + + xlog(D_GENERAL, "%s: failed to resolve path %s: %m", __func__, dir); +out: + return pathname; +} + +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; + 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; +} + +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); +} + +struct nfsd_statfs_data { + const char *pathname; + struct statfs *statbuf; + int ret; + int err; +}; + +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) +{ + if (!nfsd_wq) + return statfs(pathname, statbuf); + return nfsd_run_statfs(nfsd_wq, pathname, statbuf); +} + +struct nfsd_realpath_data { + const char *pathname; + char *resolved; + int err; +}; + +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; +} + +char * +nfsd_realpath(const char *path, char *resolved_path) +{ + 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_read_data { + int fd; + char *buf; + size_t len; + ssize_t ret; + int err; +}; + +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; +} + +static ssize_t +nfsd_run_read(struct xthread_workqueue *wq, int fd, char *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; +} + +ssize_t +nfsd_path_read(int fd, char *buf, size_t len) +{ + if (!nfsd_wq) + return read(fd, buf, len); + return nfsd_run_read(nfsd_wq, 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; +} + +static ssize_t +nfsd_run_write(struct xthread_workqueue *wq, int fd, const char *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; +} + +ssize_t +nfsd_path_write(int fd, const char *buf, size_t len) +{ + if (!nfsd_wq) + return write(fd, buf, len); + return nfsd_run_write(nfsd_wq, fd, buf, len); +} + +#if defined(HAVE_NAME_TO_HANDLE_AT) +struct nfsd_handle_data { + int fd; + const char *path; + struct file_handle *fh; + 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; +} + +static int +nfsd_run_name_to_handle_at(struct xthread_workqueue *wq, + int fd, const char *path, struct file_handle *fh, + int *mount_id, int flags) +{ + struct nfsd_handle_data data = { + fd, + path, + fh, + mount_id, + flags, + 0, + 0 + }; + + xthread_work_run_sync(wq, nfsd_name_to_handle_func, &data); + if (data.ret < 0) + errno = data.err; + return data.ret; +} + +int +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); +} +#else +int +nfsd_name_to_handle_at(int UNUSED(fd), const char *UNUSED(path), + struct file_handle *UNUSED(fh), + int *UNUSED(mount_id), int UNUSED(flags)) +{ + errno = ENOSYS; + return -1; +} +#endif diff --git a/support/misc/tcpwrapper.c b/support/misc/tcpwrapper.c new file mode 100644 index 0000000..3128053 --- /dev/null +++ b/support/misc/tcpwrapper.c @@ -0,0 +1,270 @@ +/* This is copied from portmap 4.0-29 in RedHat. */ + + /* + * pmap_check - additional portmap security. + * + * Always reject non-local requests to update the portmapper tables. + * + * Refuse to forward mount requests to the nfs mount daemon. Otherwise, the + * requests would appear to come from the local system, and nfs export + * restrictions could be bypassed. + * + * Refuse to forward requests to the nfsd process. + * + * Refuse to forward requests to NIS (YP) daemons; The only exception is the + * YPPROC_DOMAIN_NONACK broadcast rpc call that is used to establish initial + * contact with the NIS server. + * + * Always allocate an unprivileged port when forwarding a request. + * + * If compiled with -DCHECK_PORT, require that requests to register or + * unregister a privileged port come from a privileged port. This makes it + * more difficult to replace a critical service by a trojan. + * + * If compiled with -DHOSTS_ACCESS, reject requests from hosts that are not + * authorized by the /etc/hosts.{allow,deny} files. The local system is + * always treated as an authorized host. The access control tables are never + * consulted for requests from the local system, and are always consulted + * for requests from other hosts. + * + * Author: Wietse Venema (wietse@wzv.win.tue.nl), dept. of Mathematics and + * Computing Science, Eindhoven University of Technology, The Netherlands. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef HAVE_LIBWRAP +#include <unistd.h> +#include <string.h> +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <netdb.h> +#include <pwd.h> +#include <sys/types.h> +#include <sys/signal.h> +#include <sys/queue.h> +#include <sys/stat.h> +#include <tcpd.h> + +#include "sockaddr.h" +#include "tcpwrapper.h" +#include "xlog.h" + +#ifdef SYSV40 +#include <netinet/in.h> +#include <rpc/rpcent.h> +#endif /* SYSV40 */ + +#define ALLOW 1 +#define DENY 0 + +#ifdef IPV6_SUPPORTED +static void +present_address(const struct sockaddr *sap, char *buf, const size_t buflen) +{ + const struct sockaddr_in *sin = (const struct sockaddr_in *)sap; + const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap; + socklen_t len = (socklen_t)buflen; + + switch (sap->sa_family) { + case AF_INET: + if (inet_ntop(AF_INET, &sin->sin_addr, buf, len) != 0) + return; + break; + case AF_INET6: + if (inet_ntop(AF_INET6, &sin6->sin6_addr, buf, len) != 0) + return; + } + + memset(buf, 0, buflen); + strncpy(buf, "unrecognized caller", buflen); +} +#else /* !IPV6_SUPPORTED */ +static void +present_address(const struct sockaddr *sap, char *buf, const size_t buflen) +{ + const struct sockaddr_in *sin = (const struct sockaddr_in *)sap; + socklen_t len = (socklen_t)buflen; + + if (sap->sa_family == AF_INET) + if (inet_ntop(AF_INET, &sin->sin_addr, buf, len) != 0) + return; + + memset(buf, 0, buflen); + strncpy(buf, "unrecognized caller", (size_t)buflen); +} +#endif /* !IPV6_SUPPORTED */ + +typedef struct _haccess_t { + TAILQ_ENTRY(_haccess_t) list; + int allowed; + union nfs_sockaddr address; +} haccess_t; + +#define HASH_TABLE_SIZE 1021 +typedef struct _hash_head { + TAILQ_HEAD(host_list, _haccess_t) h_head; +} hash_head; + +static hash_head haccess_tbl[HASH_TABLE_SIZE]; + +static unsigned long +strtoint(const char *str) +{ + unsigned long i, n = 0; + size_t len = strlen(str); + + for (i = 0; i < len; i++) + n += (unsigned char)str[i] * i; + + return n; +} + +static unsigned int +hashint(const unsigned long num) +{ + return (unsigned int)(num % HASH_TABLE_SIZE); +} + +static unsigned int +HASH(const char *addr, const unsigned long program) +{ + return hashint(strtoint(addr) + program); +} + +static void +haccess_add(const struct sockaddr *sap, const char *address, + const unsigned long program, const int allowed) +{ + hash_head *head; + haccess_t *hptr; + unsigned int hash; + + hptr = (haccess_t *)malloc(sizeof(haccess_t)); + if (hptr == NULL) + return; + + hash = HASH(address, program); + head = &(haccess_tbl[hash]); + + hptr->allowed = allowed; + memcpy(&hptr->address, sap, (size_t)nfs_sockaddr_length(sap)); + + if (TAILQ_EMPTY(&head->h_head)) + TAILQ_INSERT_HEAD(&head->h_head, hptr, list); + else + TAILQ_INSERT_TAIL(&head->h_head, hptr, list); +} + +static haccess_t * +haccess_lookup(const struct sockaddr *sap, const char *address, + const unsigned long program) +{ + hash_head *head; + haccess_t *hptr; + unsigned int hash; + + hash = HASH(address, program); + head = &(haccess_tbl[hash]); + + TAILQ_FOREACH(hptr, &head->h_head, list) { + if (nfs_compare_sockaddr(&hptr->address.sa, sap)) + return hptr; + } + return NULL; +} + +static void +logit(const char *address) +{ + xlog_warn("connect from %s denied: request from unauthorized host", + address); +} + +static int +good_client(char *name, struct sockaddr *sap) +{ + struct request_info req; + + request_init(&req, RQ_DAEMON, name, RQ_CLIENT_SIN, sap, 0); + sock_methods(&req); + + if (hosts_access(&req)) + return ALLOW; + + return DENY; +} + +static int +check_files(void) +{ + static time_t allow_mtime, deny_mtime; + struct stat astat, dstat; + int changed = 0; + + if (stat("/etc/hosts.allow", &astat) < 0) + astat.st_mtime = 0; + if (stat("/etc/hosts.deny", &dstat) < 0) + dstat.st_mtime = 0; + + if(!astat.st_mtime || !dstat.st_mtime) + return changed; + + if (astat.st_mtime != allow_mtime) + changed = 1; + else if (dstat.st_mtime != deny_mtime) + changed = 1; + + allow_mtime = astat.st_mtime; + deny_mtime = dstat.st_mtime; + + return changed; +} + +/** + * check_default - additional checks for NULL, DUMP, GETPORT and unknown + * @name: pointer to '\0'-terminated ASCII string containing name of the + * daemon requesting the access check + * @sap: pointer to sockaddr containing network address of caller + * @program: RPC program number caller is attempting to access + * + * Returns TRUE if the caller is allowed access; otherwise FALSE is returned. + */ +int +check_default(char *name, struct sockaddr *sap, const unsigned long program) +{ + haccess_t *acc = NULL; + int changed = check_files(); + char buf[INET6_ADDRSTRLEN]; + + present_address(sap, buf, sizeof(buf)); + + acc = haccess_lookup(sap, buf, program); + if (acc != NULL && changed == 0) { + xlog(D_GENERAL, "%s: access by %s %s (cached)", __func__, + buf, acc->allowed ? "ALLOWED" : "DENIED"); + return acc->allowed; + } + + if (!(from_local(sap) || good_client(name, sap))) { + logit(buf); + if (acc != NULL) + acc->allowed = FALSE; + else + haccess_add(sap, buf, program, FALSE); + xlog(D_GENERAL, "%s: access by %s DENIED", __func__, buf); + return (FALSE); + } + + if (acc != NULL) + acc->allowed = TRUE; + else + haccess_add(sap, buf, program, TRUE); + xlog(D_GENERAL, "%s: access by %s ALLOWED", __func__, buf); + + return (TRUE); +} + +#endif /* HAVE_LIBWRAP */ diff --git a/support/misc/workqueue.c b/support/misc/workqueue.c new file mode 100644 index 0000000..8043268 --- /dev/null +++ b/support/misc/workqueue.c @@ -0,0 +1,228 @@ +#include <stdlib.h> +#include <unistd.h> + +#include "config.h" +#include "workqueue.h" +#include "xlog.h" + +#if defined(HAVE_SCHED_H) && defined(HAVE_LIBPTHREAD) && defined(HAVE_UNSHARE) +#include <sched.h> +#include <pthread.h> + +struct xwork_struct { + struct xwork_struct *next; + void (*fn)(void *); + void *data; +}; + +struct xwork_queue { + struct xwork_struct *head; + struct xwork_struct **tail; + + unsigned char shutdown : 1; +}; + +static void xwork_queue_init(struct xwork_queue *queue) +{ + queue->head = NULL; + queue->tail = &queue->head; + queue->shutdown = 0; +} + +static void xwork_enqueue(struct xwork_queue *queue, + struct xwork_struct *entry) +{ + entry->next = NULL; + *queue->tail = entry; + queue->tail = &entry->next; +} + +static struct xwork_struct *xwork_dequeue(struct xwork_queue *queue) +{ + struct xwork_struct *entry = NULL; + if (queue->head) { + entry = queue->head; + queue->head = entry->next; + if (!queue->head) + queue->tail = &queue->head; + } + return entry; +} + +struct xthread_work { + struct xwork_struct work; + + pthread_cond_t cond; +}; + +struct xthread_workqueue { + struct xwork_queue queue; + + pthread_mutex_t mutex; + pthread_cond_t cond; +}; + +static void xthread_workqueue_init(struct xthread_workqueue *wq) +{ + xwork_queue_init(&wq->queue); + pthread_mutex_init(&wq->mutex, NULL); + pthread_cond_init(&wq->cond, NULL); +} + +static void xthread_workqueue_fini(struct xthread_workqueue *wq) +{ + pthread_cond_destroy(&wq->cond); + pthread_mutex_destroy(&wq->mutex); +} + +static int xthread_work_enqueue(struct xthread_workqueue *wq, + struct xthread_work *work) +{ + xwork_enqueue(&wq->queue, &work->work); + pthread_cond_signal(&wq->cond); + return 0; +} + +static struct xthread_work *xthread_work_dequeue(struct xthread_workqueue *wq) +{ + return (struct xthread_work *)xwork_dequeue(&wq->queue); +} + +static void xthread_workqueue_do_work(struct xthread_workqueue *wq) +{ + struct xthread_work *work; + + pthread_mutex_lock(&wq->mutex); + /* Signal the caller that we're up and running */ + pthread_cond_signal(&wq->cond); + for (;;) { + work = xthread_work_dequeue(wq); + if (work) { + work->work.fn(work->work.data); + pthread_cond_signal(&work->cond); + continue; + } + if (wq->queue.shutdown) + break; + pthread_cond_wait(&wq->cond, &wq->mutex); + } + pthread_mutex_unlock(&wq->mutex); +} + +void xthread_workqueue_shutdown(struct xthread_workqueue *wq) +{ + pthread_mutex_lock(&wq->mutex); + wq->queue.shutdown = 1; + pthread_cond_signal(&wq->cond); + pthread_mutex_unlock(&wq->mutex); +} + +static void xthread_workqueue_free(struct xthread_workqueue *wq) +{ + xthread_workqueue_fini(wq); + free(wq); +} + +static void xthread_workqueue_cleanup(void *data) +{ + xthread_workqueue_free(data); +} + +static void *xthread_workqueue_worker(void *data) +{ + pthread_cleanup_push(xthread_workqueue_cleanup, data); + xthread_workqueue_do_work(data); + pthread_cleanup_pop(1); + return NULL; +} + +struct xthread_workqueue *xthread_workqueue_alloc(void) +{ + struct xthread_workqueue *ret; + pthread_t thread; + + ret = malloc(sizeof(*ret)); + if (ret) { + xthread_workqueue_init(ret); + + pthread_mutex_lock(&ret->mutex); + if (pthread_create(&thread, NULL, + xthread_workqueue_worker, + ret) == 0) { + /* Wait for thread to start */ + pthread_cond_wait(&ret->cond, &ret->mutex); + pthread_mutex_unlock(&ret->mutex); + return ret; + } + pthread_mutex_unlock(&ret->mutex); + xthread_workqueue_free(ret); + ret = NULL; + } + return NULL; +} + +void xthread_work_run_sync(struct xthread_workqueue *wq, + void (*fn)(void *), void *data) +{ + struct xthread_work work = { + { + NULL, + fn, + data + }, + PTHREAD_COND_INITIALIZER, + }; + pthread_mutex_lock(&wq->mutex); + xthread_work_enqueue(wq, &work); + pthread_cond_wait(&work.cond, &wq->mutex); + pthread_mutex_unlock(&wq->mutex); + pthread_cond_destroy(&work.cond); +} + +static void xthread_workqueue_do_chroot(void *data) +{ + const char *path = data; + + if (unshare(CLONE_FS) != 0) { + xlog_err("unshare() failed: %m"); + return; + } + if (chroot(path) != 0) + xlog_err("chroot(%s) failed: %m", path); +} + +void xthread_workqueue_chroot(struct xthread_workqueue *wq, + const char *path) +{ + xthread_work_run_sync(wq, xthread_workqueue_do_chroot, (void *)path); +} + +#else + +struct xthread_workqueue { +}; + +static struct xthread_workqueue ret; + +struct xthread_workqueue *xthread_workqueue_alloc(void) +{ + return &ret; +} + +void xthread_workqueue_shutdown(struct xthread_workqueue *wq) +{ +} + +void xthread_work_run_sync(struct xthread_workqueue *wq, + void (*fn)(void *), void *data) +{ + fn(data); +} + +void xthread_workqueue_chroot(struct xthread_workqueue *wq, + const char *path) +{ + xlog_err("Unable to run as chroot"); +} + +#endif /* defined(HAVE_SCHED_H) && defined(HAVE_LIBPTHREAD) && defined(HAVE_UNSHARE) */ diff --git a/support/misc/xstat.c b/support/misc/xstat.c new file mode 100644 index 0000000..6f751f7 --- /dev/null +++ b/support/misc/xstat.c @@ -0,0 +1,114 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <sys/types.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <sys/sysmacros.h> +#include <unistd.h> + +#include "nfslib.h" +#include "xstat.h" + +#ifdef HAVE_FSTATAT +#ifdef HAVE_STATX + +static void +statx_copy(struct stat *stbuf, const struct statx *stxbuf) +{ + stbuf->st_dev = makedev(stxbuf->stx_dev_major, stxbuf->stx_dev_minor); + stbuf->st_ino = stxbuf->stx_ino; + stbuf->st_mode = stxbuf->stx_mode; + stbuf->st_nlink = stxbuf->stx_nlink; + stbuf->st_uid = stxbuf->stx_uid; + stbuf->st_gid = stxbuf->stx_gid; + stbuf->st_rdev = makedev(stxbuf->stx_rdev_major, stxbuf->stx_rdev_minor); + stbuf->st_size = stxbuf->stx_size; + stbuf->st_blksize = stxbuf->stx_blksize; + stbuf->st_blocks = stxbuf->stx_blocks; + stbuf->st_atim.tv_sec = stxbuf->stx_atime.tv_sec; + stbuf->st_atim.tv_nsec = stxbuf->stx_atime.tv_nsec; + stbuf->st_mtim.tv_sec = stxbuf->stx_mtime.tv_sec; + stbuf->st_mtim.tv_nsec = stxbuf->stx_mtime.tv_nsec; + stbuf->st_ctim.tv_sec = stxbuf->stx_ctime.tv_sec; + stbuf->st_ctim.tv_nsec = stxbuf->stx_ctime.tv_nsec; +} + +static int +statx_do_stat(int fd, const char *pathname, struct stat *statbuf, int flags) +{ + static int statx_supported = 1; + struct statx stxbuf; + int ret; + + if (statx_supported) { + ret = statx(fd, pathname, flags, + STATX_BASIC_STATS, + &stxbuf); + if (ret == 0) { + statx_copy(statbuf, &stxbuf); + return 0; + } + /* glibc emulation doesn't support AT_STATX_DONT_SYNC */ + if (errno == EINVAL) + errno = ENOSYS; + if (errno == ENOSYS) + statx_supported = 0; + } else + errno = ENOSYS; + return -1; +} + +static int +statx_stat_nosync(int fd, const char *pathname, struct stat *statbuf, int flags) +{ + return statx_do_stat(fd, pathname, statbuf, flags | AT_STATX_DONT_SYNC); +} + +#else + +static int +statx_stat_nosync(int UNUSED(fd), const char *UNUSED(pathname), struct stat *UNUSED(statbuf), int UNUSED(flags)) +{ + errno = ENOSYS; + return -1; +} + +#endif /* HAVE_STATX */ + +int xlstat(const char *pathname, struct stat *statbuf) +{ + if (statx_stat_nosync(AT_FDCWD, pathname, statbuf, AT_NO_AUTOMOUNT| + AT_SYMLINK_NOFOLLOW) == 0) + return 0; + else if (errno != ENOSYS) + return -1; + errno = 0; + return fstatat(AT_FDCWD, pathname, statbuf, AT_NO_AUTOMOUNT | + AT_SYMLINK_NOFOLLOW); +} + +int xstat(const char *pathname, struct stat *statbuf) +{ + if (statx_stat_nosync(AT_FDCWD, pathname, statbuf, AT_NO_AUTOMOUNT) == 0) + return 0; + else if (errno != ENOSYS) + return -1; + errno = 0; + 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 diff --git a/support/nfs/Makefile.am b/support/nfs/Makefile.am new file mode 100644 index 0000000..2e1577c --- /dev/null +++ b/support/nfs/Makefile.am @@ -0,0 +1,17 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = +noinst_LTLIBRARIES = libnfs.la libnfsconf.la + +libnfs_la_SOURCES = exports.c rmtab.c xio.c rpcmisc.c rpcdispatch.c \ + xcommon.c wildmat.c mydaemon.c \ + rpc_socket.c getport.c \ + svc_socket.c cacheio.c closeall.c nfs_mntent.c \ + svc_create.c atomicio.c strlcat.c strlcpy.c +libnfs_la_LIBADD = libnfsconf.la +libnfs_la_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) -I$(top_srcdir)/support/reexport + +libnfsconf_la_SOURCES = conffile.c xlog.c + +MAINTAINERCLEANFILES = Makefile.in + diff --git a/support/nfs/Makefile.in b/support/nfs/Makefile.in new file mode 100644 index 0000000..c4e2f8f --- /dev/null +++ b/support/nfs/Makefile.in @@ -0,0 +1,916 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = support/nfs +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ax_gcc_func_attribute.m4 \ + $(top_srcdir)/aclocal/bsdsignals.m4 \ + $(top_srcdir)/aclocal/getrandom.m4 \ + $(top_srcdir)/aclocal/ipv6.m4 \ + $(top_srcdir)/aclocal/kerberos5.m4 \ + $(top_srcdir)/aclocal/keyutils.m4 \ + $(top_srcdir)/aclocal/libblkid.m4 \ + $(top_srcdir)/aclocal/libcap.m4 \ + $(top_srcdir)/aclocal/libevent.m4 \ + $(top_srcdir)/aclocal/libpthread.m4 \ + $(top_srcdir)/aclocal/libsqlite3.m4 \ + $(top_srcdir)/aclocal/libtirpc.m4 \ + $(top_srcdir)/aclocal/libxml2.m4 \ + $(top_srcdir)/aclocal/nfs-utils.m4 \ + $(top_srcdir)/aclocal/rpcsec_vers.m4 \ + $(top_srcdir)/aclocal/tcp-wrappers.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/support/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +LTLIBRARIES = $(noinst_LTLIBRARIES) +libnfs_la_DEPENDENCIES = libnfsconf.la +am_libnfs_la_OBJECTS = libnfs_la-exports.lo libnfs_la-rmtab.lo \ + libnfs_la-xio.lo libnfs_la-rpcmisc.lo libnfs_la-rpcdispatch.lo \ + libnfs_la-xcommon.lo libnfs_la-wildmat.lo \ + libnfs_la-mydaemon.lo libnfs_la-rpc_socket.lo \ + libnfs_la-getport.lo libnfs_la-svc_socket.lo \ + libnfs_la-cacheio.lo libnfs_la-closeall.lo \ + libnfs_la-nfs_mntent.lo libnfs_la-svc_create.lo \ + libnfs_la-atomicio.lo libnfs_la-strlcat.lo \ + libnfs_la-strlcpy.lo +libnfs_la_OBJECTS = $(am_libnfs_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +libnfsconf_la_LIBADD = +am_libnfsconf_la_OBJECTS = conffile.lo xlog.lo +libnfsconf_la_OBJECTS = $(am_libnfsconf_la_OBJECTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/support/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/conffile.Plo \ + ./$(DEPDIR)/libnfs_la-atomicio.Plo \ + ./$(DEPDIR)/libnfs_la-cacheio.Plo \ + ./$(DEPDIR)/libnfs_la-closeall.Plo \ + ./$(DEPDIR)/libnfs_la-exports.Plo \ + ./$(DEPDIR)/libnfs_la-getport.Plo \ + ./$(DEPDIR)/libnfs_la-mydaemon.Plo \ + ./$(DEPDIR)/libnfs_la-nfs_mntent.Plo \ + ./$(DEPDIR)/libnfs_la-rmtab.Plo \ + ./$(DEPDIR)/libnfs_la-rpc_socket.Plo \ + ./$(DEPDIR)/libnfs_la-rpcdispatch.Plo \ + ./$(DEPDIR)/libnfs_la-rpcmisc.Plo \ + ./$(DEPDIR)/libnfs_la-strlcat.Plo \ + ./$(DEPDIR)/libnfs_la-strlcpy.Plo \ + ./$(DEPDIR)/libnfs_la-svc_create.Plo \ + ./$(DEPDIR)/libnfs_la-svc_socket.Plo \ + ./$(DEPDIR)/libnfs_la-wildmat.Plo \ + ./$(DEPDIR)/libnfs_la-xcommon.Plo \ + ./$(DEPDIR)/libnfs_la-xio.Plo ./$(DEPDIR)/xlog.Plo +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libnfs_la_SOURCES) $(libnfsconf_la_SOURCES) +DIST_SOURCES = $(libnfs_la_SOURCES) $(libnfsconf_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GREP = @GREP@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GSSD = @GSSD@ +GSSGLUE_CFLAGS = @GSSGLUE_CFLAGS@ +GSSGLUE_LIBS = @GSSGLUE_LIBS@ +GSSKRB_CFLAGS = @GSSKRB_CFLAGS@ +GSSKRB_LIBS = @GSSKRB_LIBS@ +HAVE_GETRANDOM = @HAVE_GETRANDOM@ +HAVE_LIBWRAP = @HAVE_LIBWRAP@ +HAVE_TCP_WRAPPER = @HAVE_TCP_WRAPPER@ +IDMAPD = @IDMAPD@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +K5VERS = @K5VERS@ +KRBCFLAGS = @KRBCFLAGS@ +KRBDIR = @KRBDIR@ +KRBLDFLAGS = @KRBLDFLAGS@ +KRBLIBS = @KRBLIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ +LIBBLKID = @LIBBLKID@ +LIBBSD = @LIBBSD@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBEVENT = @LIBEVENT@ +LIBKEYUTILS = @LIBKEYUTILS@ +LIBMOUNT = @LIBMOUNT@ +LIBMOUNT_CFLAGS = @LIBMOUNT_CFLAGS@ +LIBMOUNT_LIBS = @LIBMOUNT_LIBS@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPTHREAD = @LIBPTHREAD@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSQLITE = @LIBSQLITE@ +LIBTIRPC = @LIBTIRPC@ +LIBTOOL = @LIBTOOL@ +LIBWRAP = @LIBWRAP@ +LIBXML2 = @LIBXML2@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_PLUGINS = @PATH_PLUGINS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +RELEASE = @RELEASE@ +RPCGEN_PATH = @RPCGEN_PATH@ +RPCSECGSS_CFLAGS = @RPCSECGSS_CFLAGS@ +RPCSECGSS_LIBS = @RPCSECGSS_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SVCGSSD = @SVCGSSD@ +TIRPC_CFLAGS = @TIRPC_CFLAGS@ +TIRPC_LIBS = @TIRPC_LIBS@ +VERSION = @VERSION@ +XML2_CFLAGS = @XML2_CFLAGS@ +XML2_LIBS = @XML2_LIBS@ +_rpc_pipefsmount = @_rpc_pipefsmount@ +_statedir = @_statedir@ +_sysconfdir = @_sysconfdir@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_gss = @enable_gss@ +enable_ipv6 = @enable_ipv6@ +enable_mountconfig = @enable_mountconfig@ +enable_nfsv4 = @enable_nfsv4@ +enable_nfsv41 = @enable_nfsv41@ +enable_svcgss = @enable_svcgss@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +kprefix = @kprefix@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +mountfile = @mountfile@ +nfsconfig = @nfsconfig@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rpc_pipefsmount = @rpc_pipefsmount@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +startstatd = @startstatd@ +statdpath = @statdpath@ +statduser = @statduser@ +statedir = @statedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +unitdir = @unitdir@ +noinst_LIBRARIES = +noinst_LTLIBRARIES = libnfs.la libnfsconf.la +libnfs_la_SOURCES = exports.c rmtab.c xio.c rpcmisc.c rpcdispatch.c \ + xcommon.c wildmat.c mydaemon.c \ + rpc_socket.c getport.c \ + svc_socket.c cacheio.c closeall.c nfs_mntent.c \ + svc_create.c atomicio.c strlcat.c strlcpy.c + +libnfs_la_LIBADD = libnfsconf.la +libnfs_la_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) -I$(top_srcdir)/support/reexport +libnfsconf_la_SOURCES = conffile.c xlog.c +MAINTAINERCLEANFILES = Makefile.in +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu support/nfs/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu support/nfs/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +clean-noinstLTLIBRARIES: + -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES) + @list='$(noinst_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libnfs.la: $(libnfs_la_OBJECTS) $(libnfs_la_DEPENDENCIES) $(EXTRA_libnfs_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libnfs_la_OBJECTS) $(libnfs_la_LIBADD) $(LIBS) + +libnfsconf.la: $(libnfsconf_la_OBJECTS) $(libnfsconf_la_DEPENDENCIES) $(EXTRA_libnfsconf_la_DEPENDENCIES) + $(AM_V_CCLD)$(LINK) $(libnfsconf_la_OBJECTS) $(libnfsconf_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conffile.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnfs_la-atomicio.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnfs_la-cacheio.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnfs_la-closeall.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnfs_la-exports.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnfs_la-getport.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnfs_la-mydaemon.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnfs_la-nfs_mntent.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnfs_la-rmtab.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnfs_la-rpc_socket.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnfs_la-rpcdispatch.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnfs_la-rpcmisc.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnfs_la-strlcat.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnfs_la-strlcpy.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnfs_la-svc_create.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnfs_la-svc_socket.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnfs_la-wildmat.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnfs_la-xcommon.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnfs_la-xio.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/xlog.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +libnfs_la-exports.lo: exports.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnfs_la-exports.lo -MD -MP -MF $(DEPDIR)/libnfs_la-exports.Tpo -c -o libnfs_la-exports.lo `test -f 'exports.c' || echo '$(srcdir)/'`exports.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnfs_la-exports.Tpo $(DEPDIR)/libnfs_la-exports.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='exports.c' object='libnfs_la-exports.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnfs_la-exports.lo `test -f 'exports.c' || echo '$(srcdir)/'`exports.c + +libnfs_la-rmtab.lo: rmtab.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnfs_la-rmtab.lo -MD -MP -MF $(DEPDIR)/libnfs_la-rmtab.Tpo -c -o libnfs_la-rmtab.lo `test -f 'rmtab.c' || echo '$(srcdir)/'`rmtab.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnfs_la-rmtab.Tpo $(DEPDIR)/libnfs_la-rmtab.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rmtab.c' object='libnfs_la-rmtab.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnfs_la-rmtab.lo `test -f 'rmtab.c' || echo '$(srcdir)/'`rmtab.c + +libnfs_la-xio.lo: xio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnfs_la-xio.lo -MD -MP -MF $(DEPDIR)/libnfs_la-xio.Tpo -c -o libnfs_la-xio.lo `test -f 'xio.c' || echo '$(srcdir)/'`xio.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnfs_la-xio.Tpo $(DEPDIR)/libnfs_la-xio.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xio.c' object='libnfs_la-xio.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnfs_la-xio.lo `test -f 'xio.c' || echo '$(srcdir)/'`xio.c + +libnfs_la-rpcmisc.lo: rpcmisc.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnfs_la-rpcmisc.lo -MD -MP -MF $(DEPDIR)/libnfs_la-rpcmisc.Tpo -c -o libnfs_la-rpcmisc.lo `test -f 'rpcmisc.c' || echo '$(srcdir)/'`rpcmisc.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnfs_la-rpcmisc.Tpo $(DEPDIR)/libnfs_la-rpcmisc.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rpcmisc.c' object='libnfs_la-rpcmisc.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnfs_la-rpcmisc.lo `test -f 'rpcmisc.c' || echo '$(srcdir)/'`rpcmisc.c + +libnfs_la-rpcdispatch.lo: rpcdispatch.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnfs_la-rpcdispatch.lo -MD -MP -MF $(DEPDIR)/libnfs_la-rpcdispatch.Tpo -c -o libnfs_la-rpcdispatch.lo `test -f 'rpcdispatch.c' || echo '$(srcdir)/'`rpcdispatch.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnfs_la-rpcdispatch.Tpo $(DEPDIR)/libnfs_la-rpcdispatch.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rpcdispatch.c' object='libnfs_la-rpcdispatch.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnfs_la-rpcdispatch.lo `test -f 'rpcdispatch.c' || echo '$(srcdir)/'`rpcdispatch.c + +libnfs_la-xcommon.lo: xcommon.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnfs_la-xcommon.lo -MD -MP -MF $(DEPDIR)/libnfs_la-xcommon.Tpo -c -o libnfs_la-xcommon.lo `test -f 'xcommon.c' || echo '$(srcdir)/'`xcommon.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnfs_la-xcommon.Tpo $(DEPDIR)/libnfs_la-xcommon.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='xcommon.c' object='libnfs_la-xcommon.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnfs_la-xcommon.lo `test -f 'xcommon.c' || echo '$(srcdir)/'`xcommon.c + +libnfs_la-wildmat.lo: wildmat.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnfs_la-wildmat.lo -MD -MP -MF $(DEPDIR)/libnfs_la-wildmat.Tpo -c -o libnfs_la-wildmat.lo `test -f 'wildmat.c' || echo '$(srcdir)/'`wildmat.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnfs_la-wildmat.Tpo $(DEPDIR)/libnfs_la-wildmat.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='wildmat.c' object='libnfs_la-wildmat.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnfs_la-wildmat.lo `test -f 'wildmat.c' || echo '$(srcdir)/'`wildmat.c + +libnfs_la-mydaemon.lo: mydaemon.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnfs_la-mydaemon.lo -MD -MP -MF $(DEPDIR)/libnfs_la-mydaemon.Tpo -c -o libnfs_la-mydaemon.lo `test -f 'mydaemon.c' || echo '$(srcdir)/'`mydaemon.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnfs_la-mydaemon.Tpo $(DEPDIR)/libnfs_la-mydaemon.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='mydaemon.c' object='libnfs_la-mydaemon.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnfs_la-mydaemon.lo `test -f 'mydaemon.c' || echo '$(srcdir)/'`mydaemon.c + +libnfs_la-rpc_socket.lo: rpc_socket.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnfs_la-rpc_socket.lo -MD -MP -MF $(DEPDIR)/libnfs_la-rpc_socket.Tpo -c -o libnfs_la-rpc_socket.lo `test -f 'rpc_socket.c' || echo '$(srcdir)/'`rpc_socket.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnfs_la-rpc_socket.Tpo $(DEPDIR)/libnfs_la-rpc_socket.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='rpc_socket.c' object='libnfs_la-rpc_socket.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnfs_la-rpc_socket.lo `test -f 'rpc_socket.c' || echo '$(srcdir)/'`rpc_socket.c + +libnfs_la-getport.lo: getport.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnfs_la-getport.lo -MD -MP -MF $(DEPDIR)/libnfs_la-getport.Tpo -c -o libnfs_la-getport.lo `test -f 'getport.c' || echo '$(srcdir)/'`getport.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnfs_la-getport.Tpo $(DEPDIR)/libnfs_la-getport.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='getport.c' object='libnfs_la-getport.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnfs_la-getport.lo `test -f 'getport.c' || echo '$(srcdir)/'`getport.c + +libnfs_la-svc_socket.lo: svc_socket.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnfs_la-svc_socket.lo -MD -MP -MF $(DEPDIR)/libnfs_la-svc_socket.Tpo -c -o libnfs_la-svc_socket.lo `test -f 'svc_socket.c' || echo '$(srcdir)/'`svc_socket.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnfs_la-svc_socket.Tpo $(DEPDIR)/libnfs_la-svc_socket.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='svc_socket.c' object='libnfs_la-svc_socket.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnfs_la-svc_socket.lo `test -f 'svc_socket.c' || echo '$(srcdir)/'`svc_socket.c + +libnfs_la-cacheio.lo: cacheio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnfs_la-cacheio.lo -MD -MP -MF $(DEPDIR)/libnfs_la-cacheio.Tpo -c -o libnfs_la-cacheio.lo `test -f 'cacheio.c' || echo '$(srcdir)/'`cacheio.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnfs_la-cacheio.Tpo $(DEPDIR)/libnfs_la-cacheio.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='cacheio.c' object='libnfs_la-cacheio.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnfs_la-cacheio.lo `test -f 'cacheio.c' || echo '$(srcdir)/'`cacheio.c + +libnfs_la-closeall.lo: closeall.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnfs_la-closeall.lo -MD -MP -MF $(DEPDIR)/libnfs_la-closeall.Tpo -c -o libnfs_la-closeall.lo `test -f 'closeall.c' || echo '$(srcdir)/'`closeall.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnfs_la-closeall.Tpo $(DEPDIR)/libnfs_la-closeall.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='closeall.c' object='libnfs_la-closeall.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnfs_la-closeall.lo `test -f 'closeall.c' || echo '$(srcdir)/'`closeall.c + +libnfs_la-nfs_mntent.lo: nfs_mntent.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnfs_la-nfs_mntent.lo -MD -MP -MF $(DEPDIR)/libnfs_la-nfs_mntent.Tpo -c -o libnfs_la-nfs_mntent.lo `test -f 'nfs_mntent.c' || echo '$(srcdir)/'`nfs_mntent.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnfs_la-nfs_mntent.Tpo $(DEPDIR)/libnfs_la-nfs_mntent.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='nfs_mntent.c' object='libnfs_la-nfs_mntent.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnfs_la-nfs_mntent.lo `test -f 'nfs_mntent.c' || echo '$(srcdir)/'`nfs_mntent.c + +libnfs_la-svc_create.lo: svc_create.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnfs_la-svc_create.lo -MD -MP -MF $(DEPDIR)/libnfs_la-svc_create.Tpo -c -o libnfs_la-svc_create.lo `test -f 'svc_create.c' || echo '$(srcdir)/'`svc_create.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnfs_la-svc_create.Tpo $(DEPDIR)/libnfs_la-svc_create.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='svc_create.c' object='libnfs_la-svc_create.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnfs_la-svc_create.lo `test -f 'svc_create.c' || echo '$(srcdir)/'`svc_create.c + +libnfs_la-atomicio.lo: atomicio.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnfs_la-atomicio.lo -MD -MP -MF $(DEPDIR)/libnfs_la-atomicio.Tpo -c -o libnfs_la-atomicio.lo `test -f 'atomicio.c' || echo '$(srcdir)/'`atomicio.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnfs_la-atomicio.Tpo $(DEPDIR)/libnfs_la-atomicio.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='atomicio.c' object='libnfs_la-atomicio.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnfs_la-atomicio.lo `test -f 'atomicio.c' || echo '$(srcdir)/'`atomicio.c + +libnfs_la-strlcat.lo: strlcat.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnfs_la-strlcat.lo -MD -MP -MF $(DEPDIR)/libnfs_la-strlcat.Tpo -c -o libnfs_la-strlcat.lo `test -f 'strlcat.c' || echo '$(srcdir)/'`strlcat.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnfs_la-strlcat.Tpo $(DEPDIR)/libnfs_la-strlcat.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strlcat.c' object='libnfs_la-strlcat.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnfs_la-strlcat.lo `test -f 'strlcat.c' || echo '$(srcdir)/'`strlcat.c + +libnfs_la-strlcpy.lo: strlcpy.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libnfs_la-strlcpy.lo -MD -MP -MF $(DEPDIR)/libnfs_la-strlcpy.Tpo -c -o libnfs_la-strlcpy.lo `test -f 'strlcpy.c' || echo '$(srcdir)/'`strlcpy.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libnfs_la-strlcpy.Tpo $(DEPDIR)/libnfs_la-strlcpy.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='strlcpy.c' object='libnfs_la-strlcpy.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libnfs_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libnfs_la-strlcpy.lo `test -f 'strlcpy.c' || echo '$(srcdir)/'`strlcpy.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LIBRARIES) $(LTLIBRARIES) +installdirs: +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + clean-noinstLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/conffile.Plo + -rm -f ./$(DEPDIR)/libnfs_la-atomicio.Plo + -rm -f ./$(DEPDIR)/libnfs_la-cacheio.Plo + -rm -f ./$(DEPDIR)/libnfs_la-closeall.Plo + -rm -f ./$(DEPDIR)/libnfs_la-exports.Plo + -rm -f ./$(DEPDIR)/libnfs_la-getport.Plo + -rm -f ./$(DEPDIR)/libnfs_la-mydaemon.Plo + -rm -f ./$(DEPDIR)/libnfs_la-nfs_mntent.Plo + -rm -f ./$(DEPDIR)/libnfs_la-rmtab.Plo + -rm -f ./$(DEPDIR)/libnfs_la-rpc_socket.Plo + -rm -f ./$(DEPDIR)/libnfs_la-rpcdispatch.Plo + -rm -f ./$(DEPDIR)/libnfs_la-rpcmisc.Plo + -rm -f ./$(DEPDIR)/libnfs_la-strlcat.Plo + -rm -f ./$(DEPDIR)/libnfs_la-strlcpy.Plo + -rm -f ./$(DEPDIR)/libnfs_la-svc_create.Plo + -rm -f ./$(DEPDIR)/libnfs_la-svc_socket.Plo + -rm -f ./$(DEPDIR)/libnfs_la-wildmat.Plo + -rm -f ./$(DEPDIR)/libnfs_la-xcommon.Plo + -rm -f ./$(DEPDIR)/libnfs_la-xio.Plo + -rm -f ./$(DEPDIR)/xlog.Plo + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/conffile.Plo + -rm -f ./$(DEPDIR)/libnfs_la-atomicio.Plo + -rm -f ./$(DEPDIR)/libnfs_la-cacheio.Plo + -rm -f ./$(DEPDIR)/libnfs_la-closeall.Plo + -rm -f ./$(DEPDIR)/libnfs_la-exports.Plo + -rm -f ./$(DEPDIR)/libnfs_la-getport.Plo + -rm -f ./$(DEPDIR)/libnfs_la-mydaemon.Plo + -rm -f ./$(DEPDIR)/libnfs_la-nfs_mntent.Plo + -rm -f ./$(DEPDIR)/libnfs_la-rmtab.Plo + -rm -f ./$(DEPDIR)/libnfs_la-rpc_socket.Plo + -rm -f ./$(DEPDIR)/libnfs_la-rpcdispatch.Plo + -rm -f ./$(DEPDIR)/libnfs_la-rpcmisc.Plo + -rm -f ./$(DEPDIR)/libnfs_la-strlcat.Plo + -rm -f ./$(DEPDIR)/libnfs_la-strlcpy.Plo + -rm -f ./$(DEPDIR)/libnfs_la-svc_create.Plo + -rm -f ./$(DEPDIR)/libnfs_la-svc_socket.Plo + -rm -f ./$(DEPDIR)/libnfs_la-wildmat.Plo + -rm -f ./$(DEPDIR)/libnfs_la-xcommon.Plo + -rm -f ./$(DEPDIR)/libnfs_la-xio.Plo + -rm -f ./$(DEPDIR)/xlog.Plo + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-noinstLIBRARIES \ + clean-noinstLTLIBRARIES cscopelist-am ctags ctags-am distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/support/nfs/atomicio.c b/support/nfs/atomicio.c new file mode 100644 index 0000000..0e81838 --- /dev/null +++ b/support/nfs/atomicio.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2002 Marius Aamodt Eriksen <marius@monkey.org> + * Copyright (c) 1995,1999 Theo de Raadt. All rights reserved. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <unistd.h> +#include <errno.h> + +#include "nfslib.h" + +/* + * ensure all of data on socket comes through. f==read || f==write + */ +ssize_t atomicio(ssize_t(*f) (int, void *, size_t), int fd, void *_s, size_t n) +{ + char *s = _s; + ssize_t res, pos = 0; + + while ((ssize_t)n > pos) { + res = (f) (fd, s + pos, n - pos); + switch (res) { + case -1: + if (errno == EINTR || errno == EAGAIN) + continue; + /* FALLTHRU */ + case 0: + if (pos != 0) + return pos; + return res; + default: + pos += res; + } + } + return pos; +} diff --git a/support/nfs/cacheio.c b/support/nfs/cacheio.c new file mode 100644 index 0000000..bd4da0e --- /dev/null +++ b/support/nfs/cacheio.c @@ -0,0 +1,253 @@ +/* + * support/nfs/cacheio.c + * support IO on the cache channel files in 2.5 and beyond. + * These use 'qwords' which are like words, but with a little quoting. + * + */ + + +/* + * Support routines for text-based upcalls. + * Fields are separated by spaces. + * Fields are either mangled to quote space tab newline slosh with slosh + * or a hexified with a leading \x + * Record is terminated with newline. + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <nfslib.h> +#include <inttypes.h> +#include <stdio.h> +#include <stdio_ext.h> +#include <string.h> +#include <ctype.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <time.h> +#include <errno.h> + +void qword_add(char **bpp, int *lp, char *str) +{ + char *bp = *bpp; + int len = *lp; + char c; + + if (len < 0) return; + + while ((c=*str++) && len > 0) + switch(c) { + case ' ': + case '\t': + case '\n': + case '\\': + if (len >= 4) { + *bp++ = '\\'; + *bp++ = '0' + ((c & 0300)>>6); + *bp++ = '0' + ((c & 0070)>>3); + *bp++ = '0' + ((c & 0007)>>0); + } + len -= 4; + break; + default: + *bp++ = c; + len--; + } + if (c || len <1) len = -1; + else { + *bp++ = ' '; + len--; + } + *bpp = bp; + *lp = len; +} + +void qword_addhex(char **bpp, int *lp, char *buf, int blen) +{ + char *bp = *bpp; + int len = *lp; + + if (len < 0) return; + + if (len > 2) { + *bp++ = '\\'; + *bp++ = 'x'; + len -= 2; + while (blen && len >= 2) { + unsigned char c = *buf++; + *bp++ = '0' + ((c&0xf0)>>4) + (c>=0xa0)*('a'-'9'-1); + *bp++ = '0' + (c&0x0f) + ((c&0x0f)>=0x0a)*('a'-'9'-1); + len -= 2; + blen--; + } + } + if (blen || len<1) len = -1; + else { + *bp++ = ' '; + len--; + } + *bpp = bp; + *lp = len; +} + +void qword_addint(char **bpp, int *lp, int n) +{ + int len; + + len = snprintf(*bpp, *lp, "%d ", n); + if (len > *lp) + len = *lp; + *bpp += len; + *lp -= len; +} + +void qword_adduint(char **bpp, int *lp, unsigned int n) +{ + int len; + + len = snprintf(*bpp, *lp, "%u ", n); + if (len > *lp) + len = *lp; + *bpp += len; + *lp -= len; +} + +void qword_addeol(char **bpp, int *lp) +{ + if (*lp <= 0) + return; + **bpp = '\n'; + (*bpp)++; + (*lp)--; +} + +#define isodigit(c) (isdigit(c) && c <= '7') +int qword_get(char **bpp, char *dest, int bufsize) +{ + /* return bytes copied, or -1 on error */ + char *bp = *bpp; + int len = 0; + + while (*bp == ' ') bp++; + + if (bp[0] == '\\' && bp[1] == 'x') { + /* HEX STRING */ + bp += 2; + while (isxdigit(bp[0]) && isxdigit(bp[1]) && len < bufsize) { + int byte = isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10; + bp++; + byte <<= 4; + byte |= isdigit(*bp) ? *bp-'0' : toupper(*bp)-'A'+10; + *dest++ = byte; + bp++; + len++; + } + } else { + /* text with \nnn octal quoting */ + while (*bp != ' ' && *bp != '\n' && *bp && len < bufsize-1) { + if (*bp == '\\' && + isodigit(bp[1]) && (bp[1] <= '3') && + isodigit(bp[2]) && + isodigit(bp[3])) { + int byte = (*++bp -'0'); + bp++; + byte = (byte << 3) | (*bp++ - '0'); + byte = (byte << 3) | (*bp++ - '0'); + *dest++ = byte; + len++; + } else { + *dest++ = *bp++; + len++; + } + } + } + + if (*bp != ' ' && *bp != '\n' && *bp != '\0') + return -1; + while (*bp == ' ') bp++; + *bpp = bp; + *dest = '\0'; + return len; +} + +int qword_get_int(char **bpp, int *anint) +{ + char buf[50]; + char *ep; + int rv; + int len = qword_get(bpp, buf, 50); + if (len < 0) return -1; + if (len ==0) return -1; + rv = strtol(buf, &ep, 0); + if (*ep) return -1; + *anint = rv; + return 0; +} + +int qword_get_uint(char **bpp, unsigned int *anint) +{ + char buf[50]; + char *ep; + unsigned int rv; + int len = qword_get(bpp, buf, 50); + if (len < 0) return -1; + if (len ==0) return -1; + rv = strtoul(buf, &ep, 0); + if (*ep) return -1; + *anint = rv; + return 0; +} + +/* flush the kNFSd caches. + * Set the flush time to the mtime of the etab state file or + * if force, to now. + * the caches to flush are: + * auth.unix.ip nfsd.export nfsd.fh + */ + +void +cache_flush(void) +{ + int c; + char stime[32]; + char path[200]; + time_t now; + /* Note: the order of these caches is important. + * They need to be flushed in dependancy order. So + * a cache that references items in another cache, + * as nfsd.fh entries reference items in nfsd.export, + * must be flushed before the cache that it references. + */ + static char *cachelist[] = { + "auth.unix.ip", + "auth.unix.gid", + "nfsd.fh", + "nfsd.export", + NULL + }; + now = time(0); + + /* Since v4.16-rc2-3-g3b68e6ee3cbd the timestamp written is ignored. + * It is safest always to flush caches if there is any doubt. + * For earlier kernels, writing the next second from now is + * the best we can do. + */ + sprintf(stime, "%" PRId64 "\n", (int64_t)now+1); + for (c=0; cachelist[c]; c++) { + int fd; + sprintf(path, "/proc/net/rpc/%s/flush", cachelist[c]); + fd = open(path, O_RDWR); + if (fd >= 0) { + if (write(fd, stime, strlen(stime)) != (ssize_t)strlen(stime)) { + xlog_warn("Writing to '%s' failed: errno %d (%s)", + path, errno, strerror(errno)); + } + close(fd); + } + } +} diff --git a/support/nfs/closeall.c b/support/nfs/closeall.c new file mode 100644 index 0000000..e07253e --- /dev/null +++ b/support/nfs/closeall.c @@ -0,0 +1,39 @@ +/* + * support/nfs/closeall.c + * Close all file descriptors greater than some limit, + * Use readdir "/proc/self/fd" to avoid excess close(2) calls. + */ + +#include <unistd.h> +#include <stdlib.h> +#include <dirent.h> +#include <errno.h> + +#include "nfslib.h" + +void +closeall(int min) +{ + char *endp; + long n; + DIR *dir = opendir("/proc/self/fd"); + + if (dir != NULL) { + int dfd = dirfd(dir); + struct dirent *d; + + while ((d = readdir(dir)) != NULL) { + errno = 0; + n = strtol(d->d_name, &endp, 10); + if (!errno && *endp == '\0' && endp != d->d_name && + n >= min && n != dfd) + (void) close(n); + } + closedir(dir); + } else { + int fd = sysconf(_SC_OPEN_MAX); + while (--fd >= min) + if(fd >= 0) + (void) close(fd); + } +} diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c new file mode 100644 index 0000000..fd4a17a --- /dev/null +++ b/support/nfs/conffile.c @@ -0,0 +1,2345 @@ +/* $OpenBSD: conf.c,v 1.55 2003/06/03 14:28:16 ho Exp $ */ +/* $EOM: conf.c,v 1.48 2000/12/04 02:04:29 angelos Exp $ */ + +/* + * Copyright (c) 1998, 1999, 2000, 2001 Niklas Hallqvist. All rights reserved. + * Copyright (c) 2000, 2001, 2002 Håkan Olsson. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * This code was written under funding by Ericsson Radio Systems. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/param.h> +#include <sys/mman.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <netinet/in.h> +#include <arpa/inet.h> +#include <ctype.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <err.h> +#include <syslog.h> +#include <libgen.h> +#include <sys/file.h> +#include <time.h> +#include <dirent.h> + +#include "conffile.h" +#include "xlog.h" + +#define CONF_FILE_EXT ".conf" +#define CONF_FILE_EXT_LEN ((int) (sizeof(CONF_FILE_EXT) - 1)) + +#pragma GCC visibility push(hidden) + +static void conf_load_defaults(void); +static char * conf_readfile(const char *path); +static int conf_set(int , const char *, const char *, const char *, + const char *, int , int ); +static void conf_parse(int trans, char *buf, + char **section, char **subsection, const char *filename); + +struct conf_trans { + TAILQ_ENTRY (conf_trans) link; + int trans; + enum conf_op { CONF_SET, CONF_REMOVE, CONF_REMOVE_SECTION } op; + char *section; + char *arg; + char *tag; + char *value; + int override; + int is_default; +}; + +TAILQ_HEAD (conf_trans_head, conf_trans) conf_trans_queue; + +/* + * Radix-64 Encoding. + */ + +static const uint8_t asc2bin[] = +{ + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 62, 255, 255, 255, 63, + 52, 53, 54, 55, 56, 57, 58, 59, + 60, 61, 255, 255, 255, 255, 255, 255, + 255, 0, 1, 2, 3, 4, 5, 6, + 7, 8, 9, 10, 11, 12, 13, 14, + 15, 16, 17, 18, 19, 20, 21, 22, + 23, 24, 25, 255, 255, 255, 255, 255, + 255, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 36, 37, 38, 39, 40, + 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 255, 255, 255, 255, 255 +}; + +struct conf_binding { + LIST_ENTRY (conf_binding) link; + char *section; + char *arg; + char *tag; + char *value; + int is_default; +}; + +LIST_HEAD (conf_bindings, conf_binding) conf_bindings[256]; + +const char *modified_by = NULL; + +static __inline__ uint8_t +conf_hash(const char *s) +{ + uint8_t hash = 0; + + while (*s) { + hash = ((hash << 1) | (hash >> 7)) ^ tolower (*s); + s++; + } + return hash; +} + +/* + * free all the component parts of a conf_binding struct + */ +static void free_confbind(struct conf_binding *cb) +{ + if (!cb) + return; + if (cb->section) + free(cb->section); + if (cb->arg) + free(cb->arg); + if (cb->tag) + free(cb->tag); + if (cb->value) + free(cb->value); + free(cb); +} + +static void free_conftrans(struct conf_trans *ct) +{ + if (!ct) + return; + if (ct->section) + free(ct->section); + if (ct->arg) + free(ct->arg); + if (ct->tag) + free(ct->tag); + if (ct->value) + free(ct->value); + free(ct); +} + +/* + * Insert a tag-value combination from LINE (the equal sign is at POS) + */ +static int +conf_remove_now(const char *section, const char *tag) +{ + struct conf_binding *cb, *next; + + cb = LIST_FIRST(&conf_bindings[conf_hash (section)]); + for (; cb; cb = next) { + next = LIST_NEXT(cb, link); + if (strcasecmp(cb->section, section) == 0 + && strcasecmp(cb->tag, tag) == 0) { + LIST_REMOVE(cb, link); + xlog(LOG_INFO,"[%s]:%s->%s removed", section, tag, cb->value); + free_confbind(cb); + return 0; + } + } + return 1; +} + +static int +conf_remove_section_now(const char *section) +{ + struct conf_binding *cb, *next; + int unseen = 1; + + cb = LIST_FIRST(&conf_bindings[conf_hash (section)]); + for (; cb; cb = next) { + next = LIST_NEXT(cb, link); + if (strcasecmp(cb->section, section) == 0) { + unseen = 0; + LIST_REMOVE(cb, link); + xlog(LOG_INFO, "[%s]:%s->%s removed", section, cb->tag, cb->value); + free_confbind(cb); + } + } + return unseen; +} + +/* + * Insert a tag-value combination from LINE (the equal sign is at POS) + * into SECTION of our configuration database. + */ +static int +conf_set_now(const char *section, const char *arg, const char *tag, + const char *value, int override, int is_default) +{ + struct conf_binding *node = 0; + + if (override) + conf_remove_now(section, tag); + else if (conf_get_section(section, arg, tag)) { + if (!is_default) { + xlog(LOG_INFO, "conf_set: duplicate tag [%s]:%s, ignoring...", + section, tag); + } + return 1; + } + node = calloc(1, sizeof *node); + if (!node) { + xlog_warn("conf_set: calloc (1, %lu) failed", (unsigned long)sizeof *node); + return 1; + } + node->section = strdup(section); + if (arg) + node->arg = strdup(arg); + node->tag = strdup(tag); + node->value = strdup(value); + node->is_default = is_default; + LIST_INSERT_HEAD(&conf_bindings[conf_hash (section)], node, link); + return 0; +} + +/* Attempt to construct a relative path to the new file */ +static char * +relative_path(const char *oldfile, const char *newfile) +{ + char *tmpcopy = NULL; + char *dir = NULL; + char *relpath = NULL; + size_t pathlen; + + if (!newfile) + return strdup(oldfile); + + if (newfile[0] == '/') + return strdup(newfile); + + tmpcopy = strdup(oldfile); + if (!tmpcopy) + goto mem_err; + + dir = dirname(tmpcopy); + + pathlen = strlen(dir) + strlen(newfile) + 2; + relpath = calloc(1, pathlen); + if (!relpath) + goto mem_err; + + snprintf(relpath, pathlen, "%s/%s", dir, newfile); + + free(tmpcopy); + return relpath; +mem_err: + if (tmpcopy) + free(tmpcopy); + return NULL; +} + + +/* + * Parse the line LINE of SZ bytes. Skip Comments, recognize section + * headers and feed tag-value pairs into our configuration database. + */ +static void +conf_parse_line(int trans, char *line, const char *filename, int lineno, char **section, char **subsection) +{ + char *val, *ptr; + char *inc_section = NULL, *inc_subsection = NULL; + char *relpath, *subconf; + + /* Strip off any leading blanks */ + while (isspace(*line)) + line++; + + /* Ignore blank lines */ + if (*line == '\0') + return; + + /* Lines starting with '#' or ';' are comments. */ + if (*line == '#' || *line == ';') + return; + + /* '[section]' parsing... */ + if (*line == '[') { + line++; + + if (*section) { + free(*section); + *section = NULL; + } + if (*subsection) { + free(*subsection); + *subsection = NULL; + } + + /* Strip off any blanks after '[' */ + while (isblank(*line)) + line++; + + /* find the closing ] */ + ptr = strchr(line, ']'); + if (ptr == NULL) { + xlog_warn("config error at %s:%d: " + "non-matched ']', ignoring until next section", + filename, lineno); + return; + } + + /* just ignore everything after the closing ] */ + *(ptr--) = '\0'; + + /* Strip off any blanks before ']' */ + while (ptr >= line && isblank(*ptr)) + *(ptr--)='\0'; + + /* look for an arg to split from the section name */ + val = strchr(line, '"'); + if (val != NULL) { + ptr = val - 1; + *(val++) = '\0'; + + /* trim away any whitespace before the " */ + while (ptr > line && isblank(*ptr)) + *(ptr--)='\0'; + } + + /* copy the section name */ + *section = strdup(line); + if (!*section) { + xlog_warn("config error at %s:%d:" + "malloc failed", filename, lineno); + return; + } + + /* there is no arg, we are done */ + if (val == NULL) + return; + + /* check for the closing " */ + ptr = strchr(val, '"'); + if (ptr == NULL) { + xlog_warn("config error at %s:%d: " + "non-matched '\"', ignoring until next section", + filename, lineno); + return; + } + *ptr = '\0'; + *subsection = strdup(val); + if (!*subsection) + xlog_warn("config error at %s:%d: " + "malloc failed", filename, lineno); + return; + } + + /* Deal with assignments. */ + ptr = strchr(line, '='); + + /* not an assignment line */ + if (ptr == NULL) { + /* Other non-empty lines are weird. */ + if (line[strspn(line, " \t")]) + xlog_warn("config error at %s:%d: " + "line not empty and not an assignment", + filename, lineno); + return; + } + + /* If no section, we are ignoring the line. */ + if (!*section) { + xlog_warn("config error at %s:%d: " + "ignoring line not in a section", + filename, lineno); + return; + } + + val = ptr + 1; + *(ptr--) = '\0'; + + /* strip spaces before and after the = */ + while (ptr >= line && isblank(*ptr)) + *(ptr--)='\0'; + while (*val != '\0' && isblank(*val)) + val++; + + if (*val == '"') { + val++; + ptr = strchr(val, '"'); + if (ptr == NULL) { + xlog_warn("config error at %s:%d: " + "unmatched quotes",filename, lineno); + return; + } + *ptr = '\0'; + } else + if (*val == '\'') { + val++; + ptr = strchr(val, '\''); + if (ptr == NULL) { + xlog_warn("config error at %s:%d: " + "unmatched quotes", filename, lineno); + return; + } + *ptr = '\0'; + } else { + /* Trim any trailing spaces and comments */ + if ((ptr=strchr(val, '#'))!=NULL) + *ptr = '\0'; + if ((ptr=strchr(val, ';'))!=NULL) + *ptr = '\0'; + + ptr = val + strlen(val) - 1; + while (ptr > val && isspace(*ptr)) + *(ptr--) = '\0'; + } + + if (*line == '\0') { + xlog_warn("config error at %s:%d: " + "missing tag in assignment", filename, lineno); + return; + } + + if (strcasecmp(line, "include")==0) { + /* load and parse subordinate config files */ + _Bool optional = false; + + if (val && *val == '-') { + optional = true; + val++; + } + + relpath = relative_path(filename, val); + if (relpath == NULL) { + if (!optional) + xlog_warn("config error at %s:%d: error loading included config", + filename, lineno); + return; + } + + subconf = conf_readfile(relpath); + if (subconf == NULL) { + if (!optional) + xlog_warn("config error at %s:%d: error loading included config", + filename, lineno); + if (relpath) + free(relpath); + return; + } + + /* copy the section data so the included file can inherit it + * without accidentally changing it for us */ + if (*section != NULL) { + inc_section = strdup(*section); + if (*subsection != NULL) + inc_subsection = strdup(*subsection); + } + + conf_parse(trans, subconf, &inc_section, &inc_subsection, relpath); + + if (inc_section) + free(inc_section); + if (inc_subsection) + free(inc_subsection); + if (relpath) + free(relpath); + free(subconf); + } else { + /* XXX Perhaps should we not ignore errors? */ + conf_set(trans, *section, *subsection, line, val, 1, 0); + } +} + +/* Parse the mapped configuration file. */ +static void +conf_parse(int trans, char *buf, char **section, char **subsection, const char *filename) +{ + char *cp = buf; + char *bufend = NULL; + char *line; + int lineno = 0; + + line = cp; + bufend = buf + strlen(buf); + while (cp < bufend) { + if (*cp == '\n') { + /* Check for escaped newlines. */ + if (cp > buf && *(cp - 1) == '\\') + *(cp - 1) = *cp = ' '; + else { + *cp = '\0'; + lineno++; + conf_parse_line(trans, line, filename, lineno, section, subsection); + line = cp + 1; + } + } + cp++; + } + if (cp != line) + xlog_warn("conf_parse: last line non-terminated, ignored."); +} + +static void +conf_load_defaults(void) +{ + /* No defaults */ + return; +} + +static char * +conf_readfile(const char *path) +{ + struct stat sb; + if (!path) { + xlog(L_ERROR, "conf_readfile: no path given"); + return NULL; + } + + if ((stat (path, &sb) == 0) || (errno != ENOENT)) { + char *new_conf_addr = NULL; + off_t sz; + int fd = open (path, O_RDONLY, 0); + + if (fd == -1) { + xlog_warn("conf_readfile: open (\"%s\", O_RDONLY) failed", path); + return NULL; + } + + /* Grab a shared lock to ensure its not mid-rewrite */ + if (flock(fd, LOCK_SH)) { + xlog_warn("conf_readfile: attempt to grab read lock failed: %s", + strerror(errno)); + goto fail; + } + + /* only after we have the lock, check the file size ready to read it */ + sz = lseek(fd, 0, SEEK_END); + if (sz < 0) { + xlog_warn("conf_readfile: unable to determine file size: %s", + strerror(errno)); + goto fail; + } + lseek(fd, 0, SEEK_SET); + + new_conf_addr = malloc(sz+1); + if (!new_conf_addr) { + xlog_warn("conf_readfile: malloc (%lu) failed", (unsigned long)sz); + goto fail; + } + + /* XXX I assume short reads won't happen here. */ + if (read (fd, new_conf_addr, sz) != (int)sz) { + xlog_warn("conf_readfile: read (%d, %p, %lu) failed", + fd, new_conf_addr, (unsigned long)sz); + goto fail; + } + close(fd); + + /* XXX Should we not care about errors and rollback? */ + new_conf_addr[sz] = '\0'; + return new_conf_addr; + fail: + close(fd); + if (new_conf_addr) + free(new_conf_addr); + } + return NULL; +} + +/* remove and free up any existing config state */ +static void conf_free_bindings(void) +{ + unsigned int i; + for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) { + struct conf_binding *cb, *next; + + cb = LIST_FIRST(&conf_bindings[i]); + for (; cb; cb = next) { + next = LIST_NEXT(cb, link); + LIST_REMOVE(cb, link); + free_confbind(cb); + } + LIST_INIT(&conf_bindings[i]); + } +} + +static int +conf_load_files(int trans, const char *conf_file) +{ + char *conf_data; + char *section = NULL; + char *subsection = NULL; + + conf_data = conf_readfile(conf_file); + if (conf_data == NULL) + return 1; + + /* Load default configuration values. */ + conf_load_defaults(); + + /* Parse config contents into the transaction queue */ + conf_parse(trans, conf_data, §ion, &subsection, conf_file); + if (section) + free(section); + if (subsection) + free(subsection); + free(conf_data); + + return 0; +} +/* Open the config file and map it into our address space, then parse it. */ +static int +conf_load_file(const char *conf_file) +{ + int trans; + char * conf_data; + + trans = conf_begin(); + conf_data = conf_readfile(conf_file); + + if (conf_data == NULL) + return 1; + + /* Load default configuration values. */ + conf_load_defaults(); + + /* Parse config contents into the transaction queue */ + char *section = NULL; + char *subsection = NULL; + conf_parse(trans, conf_data, §ion, &subsection, conf_file); + if (section) free(section); + if (subsection) free(subsection); + free(conf_data); + + /* Free potential existing configuration. */ + conf_free_bindings(); + + /* Apply the new configuration values */ + conf_end(trans, 1); + return 0; +} + +static void +conf_init_dir(const char *conf_file) +{ + struct dirent **namelist = NULL; + char *dname, fname[PATH_MAX], *cname; + int n = 0, nfiles = 0, i, fname_len, dname_len; + int trans, rv, path_len; + + dname = malloc(strlen(conf_file) + 3); + if (dname == NULL) { + xlog(L_WARNING, "conf_init_dir: malloc: %s", strerror(errno)); + return; + } + sprintf(dname, "%s.d", conf_file); + + n = scandir(dname, &namelist, NULL, versionsort); + if (n < 0) { + if (errno != ENOENT) { + xlog(L_WARNING, "conf_init_dir: scandir %s: %s", + dname, strerror(errno)); + } + free(dname); + return; + } else if (n == 0) { + free(dname); + return; + } + + trans = conf_begin(); + dname_len = strlen(dname); + for (i = 0; i < n; i++ ) { + struct dirent *d = namelist[i]; + + switch (d->d_type) { + case DT_UNKNOWN: + case DT_REG: + case DT_LNK: + break; + default: + continue; + } + if (*d->d_name == '.') + continue; + + fname_len = strlen(d->d_name); + path_len = (fname_len + dname_len); + if (!fname_len || path_len > PATH_MAX) { + xlog(L_WARNING, "conf_init_dir: Too long file name: %s in %s", + d->d_name, dname); + continue; + } + + /* + * Check the naming of the file. Only process files + * that end with CONF_FILE_EXT + */ + if (fname_len <= CONF_FILE_EXT_LEN) { + xlog(D_GENERAL, "conf_init_dir: %s: name too short", + d->d_name); + continue; + } + cname = (d->d_name + (fname_len - CONF_FILE_EXT_LEN)); + if (strcmp(cname, CONF_FILE_EXT) != 0) { + xlog(D_GENERAL, "conf_init_dir: %s: invalid file extension", + d->d_name); + continue; + } + + rv = snprintf(fname, PATH_MAX, "%s/%s", dname, d->d_name); + if (rv < path_len) { + xlog(L_WARNING, "conf_init_dir: file name: %s/%s too short", + d->d_name, dname); + continue; + } + + if (conf_load_files(trans, fname)) + continue; + nfiles++; + } + + if (nfiles) { + /* Apply the configuration values */ + conf_end(trans, 1); + } + for (i = 0; i < n; i++) + free(namelist[i]); + free(namelist); + free(dname); + + return; +} + +int +conf_init_file(const char *conf_file) +{ + unsigned int i; + int ret; + + for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) + LIST_INIT (&conf_bindings[i]); + + TAILQ_INIT (&conf_trans_queue); + + if (conf_file == NULL) + conf_file=NFS_CONFFILE; + + /* + * First parse the give config file + * then parse the config.conf.d directory + * (if it exists) + * + */ + ret = conf_load_file(conf_file); + + /* + * When the same variable is set in both files + * the conf.d file will override the config file. + * This allows automated admin systems to + * have the final say. + */ + conf_init_dir(conf_file); + + return ret; +} + +/* + * Empty the config and free up any used memory + */ +void +conf_cleanup(void) +{ + conf_free_bindings(); + + struct conf_trans *node, *next; + for (node = TAILQ_FIRST(&conf_trans_queue); node; node = next) { + next = TAILQ_NEXT(node, link); + TAILQ_REMOVE (&conf_trans_queue, node, link); + free_conftrans(node); + } + TAILQ_INIT(&conf_trans_queue); +} + +/* + * Return the numeric value denoted by TAG in section SECTION or DEF + * if that tag does not exist. + */ +int +conf_get_num(const char *section, const char *tag, int def) +{ + char *value = conf_get_str(section, tag); + + if (value) + return atoi(value); + + return def; +} + +/* + * Return the Boolean value denoted by TAG in section SECTION, or DEF + * if that tags does not exist. + * FALSE is returned for case-insensitive comparisons with 0, f, false, n, no, off + * TRUE is returned for 1, t, true, y, yes, on + * A failure to match one of these results in DEF + */ +_Bool +conf_get_bool(const char *section, const char *tag, _Bool def) +{ + char *value = conf_get_str(section, tag); + + if (!value) + return def; + if (strcasecmp(value, "1") == 0 || + strcasecmp(value, "t") == 0 || + strcasecmp(value, "true") == 0 || + strcasecmp(value, "y") == 0 || + strcasecmp(value, "yes") == 0 || + strcasecmp(value, "on") == 0) + return true; + + if (strcasecmp(value, "0") == 0 || + strcasecmp(value, "f") == 0 || + strcasecmp(value, "false") == 0 || + strcasecmp(value, "n") == 0 || + strcasecmp(value, "no") == 0 || + strcasecmp(value, "off") == 0) + return false; + return def; +} + +/* Validate X according to the range denoted by TAG in section SECTION. */ +int +conf_match_num(const char *section, const char *tag, int x) +{ + char *value = conf_get_str (section, tag); + int val, min, max, n; + + if (!value) + return 0; + n = sscanf (value, "%d,%d:%d", &val, &min, &max); + switch (n) { + case 1: + xlog(LOG_INFO, "conf_match_num: %s:%s %d==%d?", section, tag, val, x); + return x == val; + case 3: + xlog(LOG_INFO, "conf_match_num: %s:%s %d<=%d<=%d?", section, + tag, min, x, max); + return min <= x && max >= x; + default: + xlog(LOG_INFO, "conf_match_num: section %s tag %s: invalid number spec %s", + section, tag, value); + } + return 0; +} + +/* Return the string value denoted by TAG in section SECTION. */ +char * +conf_get_str(const char *section, const char *tag) +{ + return conf_get_section(section, NULL, tag); +} + +/* Return the string value denoted by TAG in section SECTION, + * unless it is not set, in which case return def + */ +char * +conf_get_str_with_def(const char *section, const char *tag, char *def) +{ + char * result = conf_get_section(section, NULL, tag); + if (!result) + return def; + return result; +} + +/* + * Retrieve an entry without interpreting its contents + */ +char * +conf_get_entry(const char *section, const char *arg, const char *tag) +{ + struct conf_binding *cb; + + cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); + for (; cb; cb = LIST_NEXT (cb, link)) { + if (strcasecmp(section, cb->section) != 0) + continue; + if (arg && (cb->arg == NULL || strcasecmp(arg, cb->arg) != 0)) + continue; + if (!arg && cb->arg) + continue; + if (strcasecmp(tag, cb->tag) != 0) + continue; + return cb->value; + } + return 0; +} + +/* + * Find a section that may or may not have an argument + */ +char * +conf_get_section(const char *section, const char *arg, const char *tag) +{ + struct conf_binding *cb; +retry: + cb = LIST_FIRST (&conf_bindings[conf_hash (section)]); + for (; cb; cb = LIST_NEXT (cb, link)) { + if (strcasecmp(section, cb->section) != 0) + continue; + if (arg && (cb->arg == NULL || strcasecmp(arg, cb->arg) != 0)) + continue; + if (!arg && cb->arg) + continue; + if (strcasecmp(tag, cb->tag) != 0) + continue; + if (cb->value[0] == '$') { + /* expand $name from [environment] section, + * or from environment + */ + char *env = getenv(cb->value+1); + if (env && *env) + return env; + section = "environment"; + tag = cb->value + 1; + goto retry; + } + return cb->value; + } + return 0; +} + +/* + * Build a list of string values out of the comma separated value denoted by + * TAG in SECTION. + */ +struct conf_list * +conf_get_list(const char *section, const char *tag) +{ + char *liststr = 0, *p, *field, *t; + struct conf_list *list = 0; + struct conf_list_node *node; + + list = malloc (sizeof *list); + if (!list) + goto cleanup; + TAILQ_INIT (&list->fields); + list->cnt = 0; + liststr = conf_get_str(section, tag); + if (!liststr) + goto cleanup; + liststr = strdup (liststr); + if (!liststr) + goto cleanup; + p = liststr; + while ((field = strsep (&p, ",")) != NULL) { + /* Skip leading whitespace */ + while (isspace (*field)) + field++; + /* Skip trailing whitespace */ + if (p) { + for (t = p - 1; t > field && isspace (*t); t--) + *t = '\0'; + } + if (*field == '\0') { + xlog(LOG_INFO, "conf_get_list: empty field, ignoring..."); + continue; + } + list->cnt++; + node = calloc (1, sizeof *node); + if (!node) + goto cleanup; + node->field = strdup (field); + if (!node->field) { + free(node); + goto cleanup; + } + TAILQ_INSERT_TAIL (&list->fields, node, link); + } + free (liststr); + return list; + +cleanup: + if (list) + conf_free_list(list); + if (liststr) + free(liststr); + return 0; +} + +struct conf_list * +conf_get_tag_list(const char *section, const char *arg) +{ + struct conf_list *list = 0; + struct conf_list_node *node; + struct conf_binding *cb; + + list = malloc(sizeof *list); + if (!list) + goto cleanup; + TAILQ_INIT(&list->fields); + list->cnt = 0; + cb = LIST_FIRST(&conf_bindings[conf_hash (section)]); + for (; cb; cb = LIST_NEXT(cb, link)) { + if (strcasecmp (section, cb->section) == 0) { + if (arg != NULL && strcasecmp(arg, cb->arg) != 0) + continue; + list->cnt++; + node = calloc(1, sizeof *node); + if (!node) + goto cleanup; + node->field = strdup(cb->tag); + if (!node->field) { + free(node); + goto cleanup; + } + TAILQ_INSERT_TAIL(&list->fields, node, link); + } + } + return list; + +cleanup: + if (list) + conf_free_list(list); + return 0; +} + +/* Decode a PEM encoded buffer. */ +int +conf_decode_base64 (uint8_t *out, uint32_t *len, const unsigned char *buf) +{ + uint32_t c = 0; + uint8_t c1, c2, c3, c4; + + while (*buf) { + if (*buf > 127 || (c1 = asc2bin[*buf]) == 255) + return 0; + + buf++; + if (*buf > 127 || (c2 = asc2bin[*buf]) == 255) + return 0; + + buf++; + if (*buf == '=') { + c3 = c4 = 0; + c++; + + /* Check last four bit */ + if (c2 & 0xF) + return 0; + + if (strcmp((char *)buf, "==") == 0) + buf++; + else + return 0; + } else if (*buf > 127 || (c3 = asc2bin[*buf]) == 255) + return 0; + else { + if (*++buf == '=') { + c4 = 0; + c += 2; + + /* Check last two bit */ + if (c3 & 3) + return 0; + + if (strcmp((char *)buf, "=")) + return 0; + } else if (*buf > 127 || (c4 = asc2bin[*buf]) == 255) + return 0; + else + c += 3; + } + + buf++; + *out++ = (c1 << 2) | (c2 >> 4); + *out++ = (c2 << 4) | (c3 >> 2); + *out++ = (c3 << 6) | c4; + } + + *len = c; + return 1; +} + +void +conf_free_list(struct conf_list *list) +{ + struct conf_list_node *node = TAILQ_FIRST(&list->fields); + + while (node) { + TAILQ_REMOVE(&list->fields, node, link); + if (node->field) + free(node->field); + free (node); + node = TAILQ_FIRST(&list->fields); + } + free (list); +} + +int +conf_begin(void) +{ + static int seq = 0; + + return ++seq; +} + +static struct conf_trans * +conf_trans_node(int transaction, enum conf_op op) +{ + struct conf_trans *node; + + node = calloc (1, sizeof *node); + if (!node) { + xlog_warn("conf_trans_node: calloc (1, %lu) failed", + (unsigned long)sizeof *node); + return 0; + } + node->trans = transaction; + node->op = op; + TAILQ_INSERT_TAIL (&conf_trans_queue, node, link); + return node; +} + +/* Queue a set operation. */ +static int +conf_set(int transaction, const char *section, const char *arg, + const char *tag, const char *value, int override, int is_default) +{ + struct conf_trans *node; + + if (!value || !*value) + return 0; + node = conf_trans_node(transaction, CONF_SET); + if (!node) + return 1; + node->section = strdup(section); + if (!node->section) { + xlog_warn("conf_set: strdup(\"%s\") failed", section); + goto fail; + } + /* Make Section names case-insensitive */ + upper2lower(node->section); + + if (arg) { + node->arg = strdup(arg); + if (!node->arg) { + xlog_warn("conf_set: strdup(\"%s\") failed", arg); + goto fail; + } + } else + node->arg = NULL; + + node->tag = strdup(tag); + if (!node->tag) { + xlog_warn("conf_set: strdup(\"%s\") failed", tag); + goto fail; + } + node->value = strdup(value); + if (!node->value) { + xlog_warn("conf_set: strdup(\"%s\") failed", value); + goto fail; + } + node->override = override; + node->is_default = is_default; + return 0; + +fail: + free_conftrans(node); + return 1; +} + +/* Queue a remove operation. */ +int +conf_remove(int transaction, const char *section, const char *tag) +{ + struct conf_trans *node; + + node = conf_trans_node(transaction, CONF_REMOVE); + if (!node) + goto fail; + node->section = strdup(section); + if (!node->section) { + xlog_warn("conf_remove: strdup(\"%s\") failed", section); + goto fail; + } + node->tag = strdup(tag); + if (!node->tag) { + xlog_warn("conf_remove: strdup(\"%s\") failed", tag); + goto fail; + } + return 0; + +fail: + free_conftrans(node); + return 1; +} + +/* Queue a remove section operation. */ +int +conf_remove_section(int transaction, const char *section) +{ + struct conf_trans *node; + + node = conf_trans_node(transaction, CONF_REMOVE_SECTION); + if (!node) + goto fail; + node->section = strdup(section); + if (!node->section) { + xlog_warn("conf_remove_section: strdup(\"%s\") failed", section); + goto fail; + } + return 0; + +fail: + free_conftrans(node); + return 1; +} + +/* Execute all queued operations for this transaction. Cleanup. */ +int +conf_end(int transaction, int commit) +{ + struct conf_trans *node, *next; + + for (node = TAILQ_FIRST(&conf_trans_queue); node; node = next) { + next = TAILQ_NEXT(node, link); + if (node->trans == transaction) { + if (commit) { + switch (node->op) { + case CONF_SET: + conf_set_now(node->section, node->arg, + node->tag, node->value, node->override, + node->is_default); + break; + case CONF_REMOVE: + conf_remove_now(node->section, node->tag); + break; + case CONF_REMOVE_SECTION: + conf_remove_section_now(node->section); + break; + default: + xlog(LOG_INFO, "conf_end: unknown operation: %d", node->op); + } + } + TAILQ_REMOVE (&conf_trans_queue, node, link); + free_conftrans(node); + } + } + return 0; +} + +/* + * Dump running configuration upon SIGUSR1. + * Configuration is "stored in reverse order", so reverse it again. + */ +struct dumper { + char *section; + char *arg; + char *tag; + char *value; + struct dumper *next; +}; + +/* + * Test if two nodes belong to the same (sub)sections + */ +static int +dumper_section_compare(const struct dumper *nodea, const struct dumper *nodeb) +{ + int ret; + + /* missing node, shouldnt happen */ + if (!nodea || !nodeb) + return -1; + + /* no section names at all, they are equal */ + if (!nodea->section && !nodeb->section) + return 0; + + /* if only one has a section name, the blank one goes first */ + if (!nodea->section && nodeb->section) + return -1; + + if (nodea->section && !nodeb->section) + return 1; + + /* both have section names, but do they match */ + ret = strcmp(nodea->section, nodeb->section); + + /* section names differ, that was easy */ + if (ret != 0) + return ret; + + /* sections matched, but how about sub-sections, + * again, if only one has a value the blank goes first + */ + if (!nodea->arg && nodeb->arg) + return -1; + + if (nodea->arg && !nodeb->arg) + return 1; + + /* both have sub-section args and they differ */ + if (nodea->arg && nodeb->arg + && (ret=strcmp(nodea->arg, nodeb->arg))!=0) + return ret; + + return 0; +} + +/* If a string starts or ends with a space it should be quoted */ +static bool +should_escape(const char *text) +{ + int len; + + /* no string, no escaping needed */ + if (!text) + return false; + + /* first character is a space */ + if (isspace(text[0])) + return true; + + /* last character is a space */ + len = strlen(text); + if (isspace(text[len-1])) + return true; + + return false; +} + +static void +conf_report_dump_text(struct dumper *head, FILE *ff) +{ + const struct dumper *node = head; + const struct dumper *last = NULL; + + for (node=head; node!=NULL; node=node->next) { + /* starting a new section, print the section header */ + if (dumper_section_compare(last, node)!=0) { + if (node != head) + fprintf(ff, "\n"); + if (node->arg) + fprintf(ff, "[%s \"%s\"]\n", node->section, node->arg); + else + fprintf(ff, "[%s]\n", node->section); + } + + /* now print the tag and its value */ + fprintf(ff, " %s", node->tag); + if (node->value) { + if (should_escape(node->value)) + fprintf(ff, " = \"%s\"", node->value); + else + fprintf(ff, " = %s", node->value); + } + fprintf(ff, "\n"); + + last = node; + } +} + +/* sort by tag compare function */ +static int +dumper_compare(const void *a, const void *b) +{ + const struct dumper *nodea = *(struct dumper **)a; + const struct dumper *nodeb = *(struct dumper **)b; + int ret; + + /* missing node, shouldnt happen */ + if (!nodea || !nodeb) + return -1; + + /* are the two nodes in different (sub)sections */ + ret = dumper_section_compare(nodea, nodeb); + if (ret != 0) + return ret; + + /* sub-sections match (both blank, or both same) + * so we compare the tag names + */ + + /* blank tags shouldnt happen, but paranoia */ + if (!nodea->tag && !nodeb->tag) + return 0; + + /* still shouldnt happen, but use the blank-goes-first logic */ + if (!nodea->tag && nodeb->tag) + return -1; + if ( nodea->tag && !nodeb->tag) + return 1; + + /* last test, compare the tags directly */ + ret = strcmp(nodea->tag, nodeb->tag); + return ret; +} + +/* sort all of the report nodes */ +static struct dumper * +conf_report_sort(struct dumper *start) +{ + struct dumper **list; + struct dumper *node; + unsigned int count = 0; + unsigned int i=0; + + /* how long is this list */ + for (node=start; node!=NULL; node=node->next) + count++; + + /* no need to sort a list with less than 2 items */ + if (count < 2) + return start; + + /* build an array of all the nodes */ + list = calloc(count, sizeof(struct dumper *)); + if (!list) + goto mem_err; + + for (node=start,i=0; node!=NULL; node=node->next) { + list[i++] = node; + } + + /* sort the array alphabetically by section and tag */ + qsort(list, count, sizeof(struct dumper *), dumper_compare); + + /* rebuild the linked list in sorted order */ + for (i=0; i<count-1; i++) { + list[i]->next = list[i+1]; + } + list[count-1]->next = NULL; + + /* remember the new head of list and discard the sorting array */ + node = list[0]; + free(list); + + /* return the new head of list */ + return node; + +mem_err: + free(list); + return NULL; +} + +/* Output a copy of the current configuration to file */ +void +conf_report(FILE *outfile) +{ + struct conf_binding *cb = NULL; + unsigned int i; + struct dumper *dumper = NULL, *dnode = NULL; + + xlog(LOG_INFO, "conf_report: dumping running configuration"); + + /* build a linked list of all the config nodes */ + for (i = 0; i < sizeof conf_bindings / sizeof conf_bindings[0]; i++) { + for (cb = LIST_FIRST(&conf_bindings[i]); cb; cb = LIST_NEXT(cb, link)) { + struct dumper *newnode = calloc(1, sizeof (struct dumper)); + if (!newnode) + goto mem_fail; + + newnode->next = dumper; + dumper = newnode; + + newnode->section = cb->section; + newnode->arg = cb->arg; + newnode->tag = cb->tag; + newnode->value = cb->value; + } + } + + /* sort the list then print it */ + dumper = conf_report_sort(dumper); + conf_report_dump_text(dumper, outfile); + goto cleanup; + +mem_fail: + xlog_warn("conf_report: malloc/calloc failed"); +cleanup: + /* traverse the linked list freeing all the nodes */ + while ((dnode = dumper) != 0) { + dumper = dumper->next; + free(dnode); + } + return; +} + +/* struct and queue for buffing output lines */ +TAILQ_HEAD(tailhead, outbuffer); + +struct outbuffer { + TAILQ_ENTRY(outbuffer) link; + char *text; +}; + +static struct outbuffer * +make_outbuffer(char *line) +{ + struct outbuffer *new; + + if (line == NULL) + return NULL; + + new = calloc(1, sizeof(struct outbuffer)); + if (new == NULL) { + xlog(L_ERROR, "malloc error creating outbuffer"); + return NULL; + } + new->text = line; + return new; +} + +/* compose a properly escaped tag=value line */ +static char * +make_tagline(const char *tag, const char *value) +{ + char *line; + int ret; + + if (!value) + return NULL; + + if (should_escape(value)) + ret = asprintf(&line, "%s = \"%s\"\n", tag, value); + else + ret = asprintf(&line, "%s = %s\n", tag, value); + + if (ret == -1) { + xlog(L_ERROR, "malloc error composing a tag line"); + return NULL; + } + return line; +} + +/* compose a section header line */ +static char * +make_section(const char *section, const char *arg) +{ + char *line; + int ret; + + if (arg) + ret = asprintf(&line, "[%s \"%s\"]\n", section, arg); + else + ret = asprintf(&line, "[%s]\n", section); + + if (ret == -1) { + xlog(L_ERROR, "malloc error composing section header"); + return NULL; + } + return line; +} + +/* compose a comment line (with or without tag) */ +static char * +make_comment(const char *tag, const char *comment) +{ + char *line; + int ret; + + if (tag == NULL || *tag == '\0') { + ret = asprintf(&line, "# %s\n", comment); + } else { + ret = asprintf(&line, "# %s: %s\n", tag, comment); + } + + if (ret == -1) { + xlog(L_ERROR, "malloc error composing header"); + return NULL; + } + + return line; +} + +/* compose a 'file modified' comment */ +static char * +make_timestamp(const char *tag, time_t when) +{ + struct tm *tstamp; + char datestr[80]; + char *result = NULL, *tmpstr = NULL; + int ret; + + tstamp = localtime(&when); + if (strftime(datestr, sizeof(datestr), "%b %d %Y %H:%M:%S", tstamp) == 0) { + xlog(L_ERROR, "error composing date"); + datestr[0] = '\0'; + } + + if (modified_by) { + ret = asprintf(&tmpstr, "%s on %s", modified_by, datestr); + if (ret == -1) { + xlog(L_ERROR, "malloc error composing a time stamp"); + return NULL; + } + result = make_comment(tag, tmpstr); + free(tmpstr); + } else { + result = make_comment(tag, datestr); + } + return result; +} + +/* does the supplied line contain the named section header */ +static bool +is_section(const char *line, const char *section, const char *arg) +{ + char *end; + char *name; + char *sub; + bool found = false; + + /* Not a valid section name */ + if (strcmp(section, "#") == 0) + return false; + + /* skip leading white space */ + while (*line == '[' || isspace(*line)) + line++; + + name = strdup(line); + if (name == NULL) { + xlog_warn("conf_write: malloc failed "); + return false; + } + + /* find the end */ + end = strchr(name, ']'); + + /* malformed line */ + if (end == NULL) { + xlog_warn("conf_write: warning: malformed section name"); + goto cleanup; + } + + while (*end && ( *end == ']' || isblank(*end))) + *(end--) = '\0'; + + /* is there a subsection name (aka arg) */ + sub = strchr(name, '"'); + if (sub) { + end = sub - 1; + *(sub++) = '\0'; + + /* trim whitespace between section name and arg */ + while (end > name && isblank(*end)) + *(end--) = '\0'; + + /* trim off closing quote */ + end = strchr(sub, '"'); + if (end == NULL) { + xlog_warn("conf_write: warning: malformed sub-section name"); + goto cleanup; + } + *end = '\0'; + } + + /* ready to compare */ + if (strcasecmp(section, name)!=0) + goto cleanup; + + if (arg != NULL) { + if (sub == NULL || strcasecmp(arg, sub)!=0) + goto cleanup; + } else { + if (sub != NULL) + goto cleanup; + } + + found = true; + +cleanup: + free(name); + return found; +} + +/* check that line contains the specified tag assignment */ +static bool +is_tag(const char *line, const char *tagname) +{ + char *end; + char *name; + bool found = false; + + /* quick check, is this even an assignment line */ + end = strchr(line, '='); + if (end == NULL) + return false; + + /* skip leading white space before tag name */ + while (isblank(*line)) + line++; + + name = strdup(line); + if (name == NULL) { + xlog_warn("conf_write: malloc failed"); + return false; + } + + /* trim any newline characters */ + end = strchr(name, '\n'); + if (end) + *end = '\0'; + end = strchr(name, '\r'); + if (end) + *end = '\0'; + + /* find the assignment equals sign */ + end = strchr(name, '='); + + /* malformed line, i swear the equals was there earlier */ + if (end == NULL) { + xlog_warn("conf_write: warning: malformed tag name"); + goto cleanup; + } + + /* trim trailing whitespace after tag name */ + do { + *(end--) = '\0'; + }while (end > name && *end && isblank(*end)); + + /* quoted string, take contents of quotes only */ + if (*name == '"') { + char * new = strdup(name+1); + end = strchr(new, '"'); + if (end != NULL) { + *end = 0; + free(name); + name = new; + } else { + free(new); + } + } + + /* now compare */ + if (strcasecmp(tagname, name) == 0) + found = true; + +cleanup: + free(name); + return found; +} + +/* is this an empty line ? */ +static bool +is_empty(const char *line) +{ + const char *p = line; + + if (line == NULL) + return true; + if (*line == '\0') + return true; + + while (*p != '\0' && isspace(*p)) + p++; + + if (*p == '\0') + return true; + + return false; +} + +/* is this line just a comment ? */ +static bool +is_comment(const char *line) +{ + if (line == NULL) + return false; + + while (isblank(*line)) + line++; + + if (*line == '#') + return true; + + return false; +} + +/* check that line contains the specified comment header */ +static bool +is_taggedcomment(const char *line, const char *field) +{ + char *end; + char *name; + bool found = false; + + if (line == NULL) + return false; + + while (isblank(*line)) + line++; + + if (*line != '#') + return false; + + line++; + + /* quick check, is this even a likely formatted line */ + end = strchr(line, ':'); + if (end == NULL) + return false; + + /* skip leading white space before field name */ + while (isblank(*line)) + line++; + + name = strdup(line); + if (name == NULL) { + xlog_warn("conf_write: malloc failed"); + return false; + } + + /* strip trailing spaces from the name */ + end = strchr(name, ':'); + if (end) *(end--) = 0; + while (end && end > name && isblank(*end)) + *(end--)=0; + + if (strcasecmp(name, field)==0) + found = true; + + free(name); + return found; +} + + +/* delete a buffer queue whilst optionally outputting to file */ +static int +flush_outqueue(struct tailhead *queue, FILE *fout) +{ + int ret = 0; + while (queue->tqh_first != NULL) { + struct outbuffer *ob = queue->tqh_first; + TAILQ_REMOVE(queue, ob, link); + if (ob->text) { + if (fout) { + ret = fprintf(fout, "%s", ob->text); + if (ret == -1) { + xlog(L_ERROR, "Error writing to config file: %s", + strerror(errno)); + fout = NULL; + } + } + free(ob->text); + } + free(ob); + } + if (ret == -1) + return 1; + return 0; +} + +/* append one queue to another */ +static void +append_queue(struct tailhead *inq, struct tailhead *outq) +{ + while (inq->tqh_first != NULL) { + struct outbuffer *ob = inq->tqh_first; + TAILQ_REMOVE(inq, ob, link); + TAILQ_INSERT_TAIL(outq, ob, link); + } +} + +/* read one line of text from a file, growing the buffer as necessary */ +static int +read_line(char **buff, int *buffsize, FILE *in) +{ + char *readp; + int used = 0; + bool again = false; + + /* make sure we have a buffer to read into */ + if (*buff == NULL) { + *buffsize = 4096; + *buff = calloc(1, *buffsize); + if (*buff == NULL) { + xlog(L_ERROR, "malloc error for read buffer"); + return -1; + } + } + + readp = *buff; + + do { + int len; + + /* read in a chunk */ + if (fgets(readp, *buffsize-used, in)==NULL) + return -1; + + len = strlen(*buff); + if (len == 0) + return -1; + + /* was this the end of a line, or partial read */ + readp = *buff + len - 1; + + if (*readp != '\n' && *readp !='\r') { + /* no nl/cr must be partial read, go again */ + readp++; + again = true; + } else { + /* that was a normal end of line */ + again = false; + } + + /* do we need more space */ + if (again && *buffsize - len < 1024) { + int offset = readp - *buff; + char *newbuff; + *buffsize += 4096; + newbuff = realloc(*buff, *buffsize); + if (newbuff == NULL) { + xlog(L_ERROR, "malloc error reading line"); + return -1; + } + *buff = newbuff; + readp = newbuff + offset; + } + } while(again); + return 0; +} + +/* append a line to the given location in the queue */ +static int +append_line(struct tailhead *queue, struct outbuffer *entry, char *line) +{ + int ret = 0; + char *end; + bool splitmode = false; + char *start = line; + + if (line == NULL) + return -1; + + /* if there are \n's in the middle of the string + * then we need to split it into folded lines */ + do { + char *thisline; + struct outbuffer *qbuff; + + end = strchr(start, '\n'); + if (end && *(end+1) != '\0') { + *end = '\0'; + + ret = asprintf(&thisline, "%s\\\n", start); + if (ret == -1) { + xlog(L_ERROR, "malloc error composing output"); + return -1; + } + splitmode = true; + start = end+1; + } else { + end = NULL; + if (splitmode) { + thisline = strdup(start); + if (thisline == NULL) + return -1; + } else { + thisline = start; + } + } + + qbuff = make_outbuffer(thisline); + if (qbuff == NULL) + return -1; + + if (entry) { + TAILQ_INSERT_AFTER(queue, entry, qbuff, link); + entry = TAILQ_NEXT(entry, link); + } else { + TAILQ_INSERT_TAIL(queue, qbuff, link); + } + }while (end != NULL); + + /* we malloced copies of this, so free the original */ + if (splitmode) + free(line); + + return 0; +} + +/* is this a "folded" line, i.e. ends in backslash */ +static bool +is_folded(const char *line) +{ + const char *end; + if (line == NULL) + return false; + + end = line + strlen(line); + while (end > line) { + end--; + if (*end != '\n' && *end != '\r') + break; + } + + if (*end == '\\') + return true; + + return false; +} + +static int +lock_file(FILE *f) +{ + int ret; + ret = flock(fileno(f), LOCK_EX); + if (ret) + xlog(L_ERROR, "Error could not lock the file"); + return ret; +} + +/*** + * Write a value to an nfs.conf style filename + * + * create the file if it doesnt already exist + * if value==NULL removes the setting (if present) + */ +int +conf_write(const char *filename, const char *section, const char *arg, + const char *tag, const char *value) +{ + FILE *infile = NULL; + int ret = 1; + struct tailhead outqueue; + struct tailhead inqueue; + char * buff = NULL; + int buffsize = 0; + time_t now = time(NULL); + + TAILQ_INIT(&inqueue); + TAILQ_INIT(&outqueue); + + if (!filename) { + xlog_warn("conf_write: no filename supplied"); + return ret; + } + + if (!section || !tag) { + xlog_warn("conf_write: section or tag name missing"); + return ret; + } + + infile = fopen(filename, "r+"); + if (!infile) { + if (!value) { + xlog_warn("conf_write: config file \"%s\" not found, nothing to do", filename); + ret = 0; + goto cleanup; + } + + xlog_warn("conf_write: config file \"%s\" not found, creating.", filename); + infile = fopen(filename, "wx"); + if (!infile) { + xlog(L_ERROR, "conf_write: Error creating config file \"%s\".", filename); + goto cleanup; + } + + if (lock_file(infile)) + goto cleanup; + + if (strcmp(section, "#") == 0) { + if (append_line(&inqueue, NULL, make_comment(tag, value))) + goto cleanup; + } else { + if (append_line(&inqueue, NULL, make_section(section, arg))) + goto cleanup; + + if (append_line(&inqueue, NULL, make_tagline(tag, value))) + goto cleanup; + } + + append_queue(&inqueue, &outqueue); + } else + if (strcmp(section, "#") == 0) { + /* Adding a comment line */ + struct outbuffer *where = NULL; + struct outbuffer *next = NULL; + bool found = false; + int err = 0; + + if (lock_file(infile)) + goto cleanup; + + buffsize = 4096; + buff = calloc(1, buffsize); + if (buff == NULL) { + xlog(L_ERROR, "malloc error for read buffer"); + goto cleanup; + } + buff[0] = '\0'; + + /* read in the file */ + do { + if (*buff != '\0' + && !is_taggedcomment(buff, "Modified")) { + if (append_line(&inqueue, NULL, strdup(buff))) + goto cleanup; + } + + err = read_line(&buff, &buffsize, infile); + } while (err == 0); + + /* if a tagged comment, look for an existing instance */ + if (tag && *tag != '\0') { + where = TAILQ_FIRST(&inqueue); + while (where != NULL) { + next = TAILQ_NEXT(where, link); + struct outbuffer *prev = TAILQ_PREV(where, tailhead, link); + if (is_taggedcomment(where->text, tag)) { + TAILQ_REMOVE(&inqueue, where, link); + free(where->text); + free(where); + found = true; + if (append_line(&inqueue, prev, make_comment(tag, value))) + goto cleanup; + } + where = next; + } + } + /* it wasn't tagged or we didn't find it */ + if (!found) { + /* does the file end in a blank line or a comment */ + if (!TAILQ_EMPTY(&inqueue)) { + struct outbuffer *tail = TAILQ_LAST(&inqueue, tailhead); + if (tail && !is_empty(tail->text) && !is_comment(tail->text)) { + /* no, so add one for clarity */ + if (append_line(&inqueue, NULL, strdup("\n"))) + goto cleanup; + } + } + /* add the new comment line */ + if (append_line(&inqueue, NULL, make_comment(tag, value))) + goto cleanup; + } + /* move everything over to the outqueue for writing */ + append_queue(&inqueue, &outqueue); + } else { + bool found = false; + int err = 0; + + if (lock_file(infile)) + goto cleanup; + + buffsize = 4096; + buff = calloc(1, buffsize); + if (buff == NULL) { + xlog(L_ERROR, "malloc error for read buffer"); + goto cleanup; + } + + buff[0] = '\0'; + do { + struct outbuffer *where = NULL; + + /* read in one section worth of lines */ + do { + if (*buff != '\0' + && !is_taggedcomment(buff, "Modified")) { + if (append_line(&inqueue, NULL, strdup(buff))) + goto cleanup; + } + + err = read_line(&buff, &buffsize, infile); + } while (err == 0 && buff[0] != '['); + + /* find the section header */ + where = TAILQ_FIRST(&inqueue); + while (where != NULL) { + if (where->text != NULL && where->text[0] == '[') + break; + where = TAILQ_NEXT(where, link); + } + + /* this is the section we care about */ + if (where != NULL && is_section(where->text, section, arg)) { + struct outbuffer *section_start = where; + + /* is there an existing assignment */ + while ((where = TAILQ_NEXT(where, link)) != NULL) { + if (is_tag(where->text, tag)) { + found = true; + break; + } + } + + /* no active assignment, but is there a commented one */ + if (!found) { + where = section_start; + while ((where = TAILQ_NEXT(where, link)) != NULL) { + if (is_comment(where->text)) { + char *cline = where->text; + while (isspace(*cline)) + cline++; + + if (*cline != '#') + continue; + cline++; + + if (is_tag(cline, tag)) { + found = true; + break; + } + } + } + } + + /* replace the located tag with an updated one */ + if (found) { + struct outbuffer *prev = TAILQ_PREV(where, tailhead, link); + bool again = false; + + /* remove current tag */ + do { + struct outbuffer *next = TAILQ_NEXT(where, link); + TAILQ_REMOVE(&inqueue, where, link); + if (is_folded(where->text)) + again = true; + else + again = false; + free(where->text); + free(where); + where = next; + } while(again && where != NULL); + + /* insert new tag */ + if (value) { + if (append_line(&inqueue, prev, make_tagline(tag, value))) + goto cleanup; + } + } else + /* no existing assignment found and we need to add one */ + if (value) { + /* rewind past blank lines and comments */ + struct outbuffer *tail = TAILQ_LAST(&inqueue, tailhead); + + /* comments immediately before a section usually relate + * to the section below them */ + while (tail != NULL && is_comment(tail->text)) + tail = TAILQ_PREV(tail, tailhead, link); + + /* there is usually blank line(s) between sections */ + while (tail != NULL && is_empty(tail->text)) + tail = TAILQ_PREV(tail, tailhead, link); + + /* now add the tag here */ + if (append_line(&inqueue, tail, make_tagline(tag, value))) + goto cleanup; + + found = true; + } + } + + /* EOF and correct section not found, so add one */ + if (err && !found && value) { + /* did the last section end in a blank line */ + struct outbuffer *tail = TAILQ_LAST(&inqueue, tailhead); + if (tail && !is_empty(tail->text)) { + /* no, so add one for clarity */ + if (append_line(&inqueue, NULL, strdup("\n"))) + goto cleanup; + } + + /* add the new section header */ + if (append_line(&inqueue, NULL, make_section(section, arg))) + goto cleanup; + + /* now add the tag */ + if (append_line(&inqueue, NULL, make_tagline(tag, value))) + goto cleanup; + } + + /* we are done with this section, move it to the out queue */ + append_queue(&inqueue, &outqueue); + } while(err == 0); + } + + if (modified_by) { + /* check for and update the Modified header */ + /* does the file end in a blank line or a comment */ + if (!TAILQ_EMPTY(&outqueue)) { + struct outbuffer *tail = TAILQ_LAST(&outqueue, tailhead); + if (tail && !is_empty(tail->text) && !is_comment(tail->text)) { + /* no, so add one for clarity */ + if (append_line(&outqueue, NULL, strdup("\n"))) + goto cleanup; + } + } + + /* now append the modified date comment */ + if (append_line(&outqueue, NULL, make_timestamp("Modified", now))) + goto cleanup; + } + + /* now rewind and overwrite the file with the updated data */ + rewind(infile); + + if (ftruncate(fileno(infile), 0)) { + xlog(L_ERROR, "Error truncating config file"); + goto cleanup; + } + + if (flush_outqueue(&outqueue, infile)) + goto cleanup; + + if (infile) { + fclose(infile); + infile = NULL; + } + + ret = 0; + +cleanup: + flush_outqueue(&inqueue, NULL); + flush_outqueue(&outqueue, NULL); + + if (buff) + free(buff); + if (infile) + fclose(infile); + return ret; +} diff --git a/support/nfs/exports.c b/support/nfs/exports.c new file mode 100644 index 0000000..15dc574 --- /dev/null +++ b/support/nfs/exports.c @@ -0,0 +1,999 @@ +/* + * support/nfs/export.c + * + * Parse the exports file. Derived from the unfsd implementation. + * + * Authors: Donald J. Becker, <becker@super.org> + * Rick Sladkey, <jrs@world.std.com> + * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> + * Olaf Kirch, <okir@monad.swb.de> + * Alexander O. Yuriev, <alex@bach.cis.temple.edu> + * + * This software maybe be used for any purpose provided + * the above copyright notice is retained. It is supplied + * as is, with no warranty expressed or implied. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/param.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <ctype.h> +#include <unistd.h> +#include <errno.h> +#include "nfslib.h" +#include "exportfs.h" +#include "xmalloc.h" +#include "xlog.h" +#include "xio.h" +#include "pseudoflavors.h" +#include "reexport.h" + +#define EXPORT_DEFAULT_FLAGS \ + (NFSEXP_READONLY|NFSEXP_ROOTSQUASH|NFSEXP_GATHERED_WRITES|NFSEXP_NOSUBTREECHECK) + +struct flav_info flav_map[] = { + { "krb5", RPC_AUTH_GSS_KRB5, 1}, + { "krb5i", RPC_AUTH_GSS_KRB5I, 1}, + { "krb5p", RPC_AUTH_GSS_KRB5P, 1}, + { "unix", AUTH_UNIX, 0}, + { "sys", AUTH_SYS, 0}, + { "null", AUTH_NULL, 0}, + { "none", AUTH_NONE, 0}, +}; + +const int flav_map_size = sizeof(flav_map)/sizeof(flav_map[0]); + +int default_ttl = 30 * 60; + +static char *efname = NULL; +static XFILE *efp = NULL; +static int first; +static int has_default_opts, has_default_subtree_opts; +static int *squids = NULL, nsquids = 0, + *sqgids = NULL, nsqgids = 0; + +static int getexport(char *exp, int len); +static int getpath(char *path, int len); +static int parseopts(char *cp, struct exportent *ep, int warn, int *had_subtree_opt_ptr); +static int parsesquash(char *list, int **idp, int *lenp, char **ep); +static int parsenum(char **cpp); +static void freesquash(void); +static void syntaxerr(char *msg); +static struct flav_info *find_flavor(char *name); + +void +setexportent(char *fname, char *type) +{ + if (efp) + endexportent(); + if (!fname) + fname = _PATH_EXPORTS; + if (!(efp = xfopen(fname, type))) + xlog(L_ERROR, "can't open %s for %sing", + fname, strcmp(type, "r")? "writ" : "read"); + efname = strdup(fname); + first = 1; +} + +static void init_exportent (struct exportent *ee, int fromkernel) +{ + ee->e_flags = EXPORT_DEFAULT_FLAGS; + /* some kernels assume the default is sync rather than + * async. More recent kernels always report one or other, + * but this test makes sure we assume same as kernel + * Ditto for wgather + */ + if (fromkernel) { + ee->e_flags &= ~NFSEXP_ASYNC; + ee->e_flags &= ~NFSEXP_GATHERED_WRITES; + } + ee->e_anonuid = 65534; + ee->e_anongid = 65534; + ee->e_squids = NULL; + ee->e_sqgids = NULL; + ee->e_mountpoint = NULL; + ee->e_fslocmethod = FSLOC_NONE; + ee->e_fslocdata = NULL; + ee->e_secinfo[0].flav = NULL; + ee->e_xprtsec[0].info = NULL; + ee->e_nsquids = 0; + ee->e_nsqgids = 0; + ee->e_uuid = NULL; + ee->e_ttl = default_ttl; + ee->e_reexport = REEXP_NONE; +} + +struct exportent * +getexportent(int fromkernel, int fromexports) +{ + static struct exportent ee, def_ee; + char exp[512], *hostname; + char rpath[MAXPATHLEN+1]; + char *opt, *sp; + int ok; + + if (!efp) + return NULL; + + freesquash(); + + if (first || (ok = getexport(exp, sizeof(exp))) == 0) { + has_default_opts = 0; + has_default_subtree_opts = 0; + + init_exportent(&def_ee, fromkernel); + + ok = getpath(def_ee.e_path, sizeof(def_ee.e_path)); + if (ok <= 0) + return NULL; + + ok = getexport(exp, sizeof(exp)); + } + if (ok < 0) { + xlog(L_ERROR, "expected client(options...)"); + return NULL; + } + first = 0; + + /* + * Check for default options. The kernel will never have default + * options in /proc/fs/nfs/exports, however due to the initial '-' in + * the -test-client- string from the test export we have to check that + * we're not reading from the kernel. + */ + if (exp[0] == '-' && !fromkernel) { + if (parseopts(exp + 1, &def_ee, 0, &has_default_subtree_opts) < 0) + return NULL; + + has_default_opts = 1; + + ok = getexport(exp, sizeof(exp)); + if (ok < 0) { + xlog(L_ERROR, "expected client(options...)"); + return NULL; + } + } + + xfree(ee.e_hostname); + xfree(ee.e_realpath); + ee = def_ee; + + /* Check for default client */ + if (ok == 0) + exp[0] = '\0'; + + hostname = exp; + if ((opt = strchr(exp, '(')) != NULL) { + if (opt == exp) { + xlog(L_WARNING, "No host name given with %s %s, suggest *%s to avoid warning", ee.e_path, exp, exp); + hostname = "*"; + } + *opt++ = '\0'; + if (!(sp = strchr(opt, ')')) || sp[1] != '\0') { + syntaxerr("bad option list"); + return NULL; + } + *sp = '\0'; + } else { + if (!has_default_opts) + xlog(L_WARNING, "No options for %s %s: suggest %s(sync) to avoid warning", ee.e_path, exp, exp); + } + ee.e_hostname = xstrdup(hostname); + + if (parseopts(opt, &ee, fromexports && !has_default_subtree_opts, 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; + } + + 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'; + } + + return ⅇ +} + +static const struct secinfo_flag_displaymap { + unsigned int flag; + const char *set; + const char *unset; +} secinfo_flag_displaymap[] = { + { NFSEXP_READONLY, "ro", "rw" }, + { NFSEXP_INSECURE_PORT, "insecure", "secure" }, + { NFSEXP_ROOTSQUASH, "root_squash", "no_root_squash" }, + { NFSEXP_ALLSQUASH, "all_squash", "no_all_squash" }, + { 0, NULL, NULL } +}; + +static void secinfo_flags_show(FILE *fp, unsigned int flags, unsigned int mask) +{ + const struct secinfo_flag_displaymap *p; + + for (p = &secinfo_flag_displaymap[0]; p->flag != 0; p++) { + if (!(mask & p->flag)) + continue; + fprintf(fp, ",%s", (flags & p->flag) ? p->set : p->unset); + } +} + +void secinfo_show(FILE *fp, struct exportent *ep) +{ + const struct export_features *ef; + struct sec_entry *p1, *p2; + + ef = get_export_features(); + + if (ep->e_secinfo[0].flav == NULL) + secinfo_addflavor(find_flavor("sys"), ep); + for (p1=ep->e_secinfo; p1->flav; p1=p2) { + fprintf(fp, ",sec=%s", p1->flav->flavour); + for (p2=p1+1; (p2->flav != NULL) && (p1->flags == p2->flags); + p2++) { + fprintf(fp, ":%s", p2->flav->flavour); + } + secinfo_flags_show(fp, p1->flags, ef->secinfo_flags); + } +} + +void xprtsecinfo_show(FILE *fp, struct exportent *ep) +{ + struct xprtsec_entry *p1, *p2; + + for (p1 = ep->e_xprtsec; p1->info; p1 = p2) { + fprintf(fp, ",xprtsec=%s", p1->info->name); + for (p2 = p1 + 1; p2->info && (p1->flags == p2->flags); p2++) + fprintf(fp, ":%s", p2->info->name); + } +} + +static void +fprintpath(FILE *fp, const char *path) +{ + int i; + for (i=0; path[i]; i++) + if (iscntrl(path[i]) || path[i] == '"' || path[i] == '\\' || path[i] == '#' || isspace(path[i])) + fprintf(fp, "\\%03o", path[i]); + else + fprintf(fp, "%c", path[i]); +} + +void +putexportent(struct exportent *ep) +{ + FILE *fp; + int *id, i; + + if (!efp) + return; + + fp = efp->x_fp; + fprintpath(fp, ep->e_path); + fprintf(fp, "\t%s(", ep->e_hostname); + fprintf(fp, "%s,", (ep->e_flags & NFSEXP_READONLY)? "ro" : "rw"); + fprintf(fp, "%ssync,", (ep->e_flags & NFSEXP_ASYNC)? "a" : ""); + fprintf(fp, "%swdelay,", (ep->e_flags & NFSEXP_GATHERED_WRITES)? + "" : "no_"); + fprintf(fp, "%shide,", (ep->e_flags & NFSEXP_NOHIDE)? + "no" : ""); + fprintf(fp, "%scrossmnt,", (ep->e_flags & NFSEXP_CROSSMOUNT)? + "" : "no"); + fprintf(fp, "%ssecure,", (ep->e_flags & NFSEXP_INSECURE_PORT)? + "in" : ""); + fprintf(fp, "%sroot_squash,", (ep->e_flags & NFSEXP_ROOTSQUASH)? + "" : "no_"); + fprintf(fp, "%sall_squash,", (ep->e_flags & NFSEXP_ALLSQUASH)? + "" : "no_"); + fprintf(fp, "%ssubtree_check,", (ep->e_flags & NFSEXP_NOSUBTREECHECK)? + "no_" : ""); + fprintf(fp, "%ssecure_locks,", (ep->e_flags & NFSEXP_NOAUTHNLM)? + "in" : ""); + fprintf(fp, "%sacl,", (ep->e_flags & NFSEXP_NOACL)? + "no_" : ""); + if (ep->e_flags & NFSEXP_NOREADDIRPLUS) + fprintf(fp, "nordirplus,"); + if (ep->e_flags & NFSEXP_SECURITY_LABEL) + fprintf(fp, "security_label,"); + fprintf(fp, "%spnfs,", (ep->e_flags & NFSEXP_PNFS)? "" : "no_"); + if (ep->e_flags & NFSEXP_FSID) { + fprintf(fp, "fsid=%d,", ep->e_fsid); + } + if (ep->e_uuid) + fprintf(fp, "fsid=%s,", ep->e_uuid); + + if (ep->e_reexport) { + fprintf(fp, "reexport="); + switch (ep->e_reexport) { + case REEXP_AUTO_FSIDNUM: + fprintf(fp, "auto-fsidnum"); + break; + case REEXP_PREDEFINED_FSIDNUM: + fprintf(fp, "predefined-fsidnum"); + break; + default: + xlog(L_ERROR, "unknown reexport method %i", ep->e_reexport); + fprintf(fp, "none"); + } + fprintf(fp, ","); + } + + if (ep->e_mountpoint) + fprintf(fp, "mountpoint%s%s,", + ep->e_mountpoint[0]?"=":"", ep->e_mountpoint); + switch (ep->e_fslocmethod) { + case FSLOC_NONE: + break; + case FSLOC_REFER: + fprintf(fp, "refer="); + fprintpath(fp, ep->e_fslocdata); + fprintf(fp, ","); + break; + case FSLOC_REPLICA: + fprintf(fp, "replicas="); + fprintpath(fp, ep->e_fslocdata); + fprintf(fp, ","); + break; +#ifdef DEBUG + case FSLOC_STUB: + fprintf(fp, "fsloc=stub,"); + break; +#endif + default: + xlog(L_ERROR, "unknown fsloc method for %s:%s", + ep->e_hostname, ep->e_path); + } + if ((id = ep->e_squids) != NULL) { + fprintf(fp, "squash_uids="); + for (i = 0; i < ep->e_nsquids; i += 2) + if (id[i] != id[i+1]) + fprintf(fp, "%d-%d,", id[i], id[i+1]); + else + fprintf(fp, "%d,", id[i]); + } + if ((id = ep->e_sqgids) != NULL) { + fprintf(fp, "squash_gids="); + for (i = 0; i < ep->e_nsquids; i += 2) + if (id[i] != id[i+1]) + fprintf(fp, "%d-%d,", id[i], id[i+1]); + else + fprintf(fp, "%d,", id[i]); + } + fprintf(fp, "anonuid=%d,anongid=%d", ep->e_anonuid, ep->e_anongid); + secinfo_show(fp, ep); + xprtsecinfo_show(fp, ep); + fprintf(fp, ")\n"); +} + +void +endexportent(void) +{ + if (efp) + xfclose(efp); + efp = NULL; + if (efname) + free(efname); + efname = NULL; + freesquash(); +} + +void +dupexportent(struct exportent *dst, struct exportent *src) +{ + int n; + + *dst = *src; + if ((n = src->e_nsquids) != 0) { + dst->e_squids = (int *) xmalloc(n * sizeof(int)); + memcpy(dst->e_squids, src->e_squids, n * sizeof(int)); + } + if ((n = src->e_nsqgids) != 0) { + dst->e_sqgids = (int *) xmalloc(n * sizeof(int)); + memcpy(dst->e_sqgids, src->e_sqgids, n * sizeof(int)); + } + if (src->e_mountpoint) + dst->e_mountpoint = strdup(src->e_mountpoint); + if (src->e_fslocdata) + dst->e_fslocdata = strdup(src->e_fslocdata); + if (src->e_uuid) + dst->e_uuid = strdup(src->e_uuid); + dst->e_hostname = NULL; + dst->e_realpath = NULL; +} + +struct exportent * +mkexportent(char *hname, char *path, char *options) +{ + static struct exportent ee; + + init_exportent(&ee, 0); + + xfree(ee.e_hostname); + ee.e_hostname = xstrdup(hname); + xfree(ee.e_realpath); + 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'; + if (parseopts(options, &ee, 0, NULL) < 0) + return NULL; + return ⅇ +} + +int +updateexportent(struct exportent *eep, char *options) +{ + if (parseopts(options, eep, 0, NULL) < 0) + return 0; + return 1; +} + + +static int valid_uuid(char *uuid) +{ + /* must have 32 hex digits */ + int cnt; + for (cnt = 0 ; *uuid; uuid++) + if (isxdigit(*uuid)) + cnt++; + return cnt == 32; +} + +/* + * Append the given flavor to the exportent's e_secinfo array, or + * do nothing if it's already there. Returns the index of flavor + * in the resulting array in any case. + */ +int secinfo_addflavor(struct flav_info *flav, struct exportent *ep) +{ + struct sec_entry *p; + + for (p=ep->e_secinfo; p->flav; p++) { + if (p->flav == flav || p->flav->fnum == flav->fnum) + return p - ep->e_secinfo; + } + if (p - ep->e_secinfo >= SECFLAVOR_COUNT) { + xlog(L_ERROR, "more than %d security flavors on an export\n", + SECFLAVOR_COUNT); + return -1; + } + p->flav = flav; + p->flags = ep->e_flags; + (p+1)->flav = NULL; + return p - ep->e_secinfo; +} + +static struct flav_info *find_flavor(char *name) +{ + struct flav_info *flav; + for (flav = flav_map; flav < flav_map + flav_map_size; flav++) + if (strcmp(flav->flavour, name) == 0) + return flav; + return NULL; +} + +/* @str is a colon seperated list of security flavors. Their order + * is recorded in @ep, and a bitmap corresponding to the list is returned. + * A zero return indicates an error. + */ +static unsigned int parse_flavors(char *str, struct exportent *ep) +{ + unsigned int out=0; + char *flavor; + int bit; + + while ( (flavor=strsep(&str, ":")) ) { + struct flav_info *flav = find_flavor(flavor); + if (flav == NULL) { + xlog(L_ERROR, "unknown flavor %s\n", flavor); + return 0; + } + bit = secinfo_addflavor(flav, ep); + if (bit < 0) + return 0; + out |= 1<<bit; + } + return out; +} + +static const struct xprtsec_info xprtsec_name2info[] = { + { "none", NFSEXP_XPRTSEC_NONE }, + { "tls", NFSEXP_XPRTSEC_TLS }, + { "mtls", NFSEXP_XPRTSEC_MTLS }, + { NULL, 0 } +}; + +static const struct xprtsec_info *find_xprtsec_info(const char *name) +{ + const struct xprtsec_info *info; + + for (info = xprtsec_name2info; info->name; info++) + if (strcmp(info->name, name) == 0) + return info; + return NULL; +} + +/* + * Append the given xprtsec mode to the exportent's e_xprtsec array, + * or do nothing if it's already there. Returns the index of flavor in + * the resulting array in any case. + */ +static int xprtsec_addmode(const struct xprtsec_info *info, struct exportent *ep) +{ + struct xprtsec_entry *p; + + for (p = ep->e_xprtsec; p->info; p++) + if (p->info == info || p->info->number == info->number) + return p - ep->e_xprtsec; + + if (p - ep->e_xprtsec >= XPRTSECMODE_COUNT) { + xlog(L_ERROR, "more than %d xprtsec modes on an export\n", + XPRTSECMODE_COUNT); + return -1; + } + p->info = info; + p->flags = ep->e_flags; + (p + 1)->info = NULL; + return p - ep->e_xprtsec; +} + +/* + * @str is a colon seperated list of transport layer security modes. + * Their order is recorded in @ep, and a bitmap corresponding to the + * list is returned. + * + * A zero return indicates an error. + */ +static unsigned int parse_xprtsec(char *str, struct exportent *ep) +{ + unsigned int out = 0; + char *name; + + while ((name = strsep(&str, ":"))) { + const struct xprtsec_info *info = find_xprtsec_info(name); + int bit; + + if (!info) { + xlog(L_ERROR, "unknown xprtsec mode %s\n", name); + return 0; + } + bit = xprtsec_addmode(info, ep); + if (bit < 0) + return 0; + out |= 1 << bit; + } + return out; +} + +/* Sets the bits in @mask for the appropriate security flavor flags. */ +static void setflags(int mask, unsigned int active, struct exportent *ep) +{ + int bit=0; + + ep->e_flags |= mask; + + while (active) { + if (active & 1) + ep->e_secinfo[bit].flags |= mask; + bit++; + active >>= 1; + } +} + +/* Clears the bits in @mask for the appropriate security flavor flags. */ +static void clearflags(int mask, unsigned int active, struct exportent *ep) +{ + int bit=0; + + ep->e_flags &= ~mask; + + while (active) { + if (active & 1) + ep->e_secinfo[bit].flags &= ~mask; + bit++; + active >>= 1; + } +} + +/* + * For those flags which are not allowed to vary by pseudoflavor, + * ensure that the export flags agree with the flags on each + * pseudoflavor: + */ +void fix_pseudoflavor_flags(struct exportent *ep) +{ + struct export_features *ef; + struct sec_entry *p; + + ef = get_export_features(); + for (p = ep->e_secinfo; p->flav; p++) + p->flags |= ep->e_flags & ~ef->secinfo_flags; +} + +/* + * Parse option string pointed to by cp and set mount options accordingly. + */ +static int +parseopts(char *cp, struct exportent *ep, int warn, int *had_subtree_opt_ptr) +{ + int had_subtree_opt = 0; + char *flname = efname?efname:"command line"; + int flline = efp?efp->x_line:0; + unsigned int active = 0; + int saw_reexport = 0; + + squids = ep->e_squids; nsquids = ep->e_nsquids; + sqgids = ep->e_sqgids; nsqgids = ep->e_nsqgids; + if (!cp) + goto out; + + while (isblank(*cp)) + cp++; + + while (*cp) { + char *opt = strdup(cp); + char *optstart = cp; + while (*cp && *cp != ',') + cp++; + if (*cp) { + opt[cp-optstart] = '\0'; + cp++; + } + + /* process keyword */ + if (strcmp(opt, "ro") == 0) + setflags(NFSEXP_READONLY, active, ep); + else if (strcmp(opt, "rw") == 0) + clearflags(NFSEXP_READONLY, active, ep); + else if (!strcmp(opt, "secure")) + clearflags(NFSEXP_INSECURE_PORT, active, ep); + else if (!strcmp(opt, "insecure")) + setflags(NFSEXP_INSECURE_PORT, active, ep); + else if (!strcmp(opt, "sync")) + clearflags(NFSEXP_ASYNC, active, ep); + else if (!strcmp(opt, "async")) + setflags(NFSEXP_ASYNC, active, ep); + else if (!strcmp(opt, "nordirplus")) + setflags(NFSEXP_NOREADDIRPLUS, active, ep); + else if (!strcmp(opt, "security_label")) + setflags(NFSEXP_SECURITY_LABEL, active, ep); + else if (!strcmp(opt, "nohide")) + setflags(NFSEXP_NOHIDE, active, ep); + else if (!strcmp(opt, "hide")) + clearflags(NFSEXP_NOHIDE, active, ep); + else if (!strcmp(opt, "crossmnt")) + setflags(NFSEXP_CROSSMOUNT, active, ep); + else if (!strcmp(opt, "nocrossmnt")) + clearflags(NFSEXP_CROSSMOUNT, active, ep); + else if (!strcmp(opt, "wdelay")) + setflags(NFSEXP_GATHERED_WRITES, active, ep); + else if (!strcmp(opt, "no_wdelay")) + clearflags(NFSEXP_GATHERED_WRITES, active, ep); + else if (strcmp(opt, "root_squash") == 0) + setflags(NFSEXP_ROOTSQUASH, active, ep); + else if (!strcmp(opt, "no_root_squash")) + clearflags(NFSEXP_ROOTSQUASH, active, ep); + else if (strcmp(opt, "all_squash") == 0) + setflags(NFSEXP_ALLSQUASH, active, ep); + else if (strcmp(opt, "no_all_squash") == 0) + clearflags(NFSEXP_ALLSQUASH, active, ep); + else if (strcmp(opt, "subtree_check") == 0) { + had_subtree_opt = 1; + clearflags(NFSEXP_NOSUBTREECHECK, active, ep); + } else if (strcmp(opt, "no_subtree_check") == 0) { + had_subtree_opt = 1; + setflags(NFSEXP_NOSUBTREECHECK, active, ep); + } else if (strcmp(opt, "auth_nlm") == 0) + clearflags(NFSEXP_NOAUTHNLM, active, ep); + else if (strcmp(opt, "no_auth_nlm") == 0) + setflags(NFSEXP_NOAUTHNLM, active, ep); + else if (strcmp(opt, "secure_locks") == 0) + clearflags(NFSEXP_NOAUTHNLM, active, ep); + else if (strcmp(opt, "insecure_locks") == 0) + setflags(NFSEXP_NOAUTHNLM, active, ep); + else if (strcmp(opt, "acl") == 0) + clearflags(NFSEXP_NOACL, active, ep); + else if (strcmp(opt, "no_acl") == 0) + setflags(NFSEXP_NOACL, active, ep); + else if (!strcmp(opt, "pnfs")) + setflags(NFSEXP_PNFS, active, ep); + else if (!strcmp(opt, "no_pnfs")) + clearflags(NFSEXP_PNFS, active, ep); + else if (strncmp(opt, "anonuid=", 8) == 0) { + char *oe; + ep->e_anonuid = strtol(opt+8, &oe, 10); + if (opt[8]=='\0' || *oe != '\0') { + xlog(L_ERROR, "%s: %d: bad anonuid \"%s\"\n", + flname, flline, opt); +bad_option: + free(opt); + return -1; + } + } else if (strncmp(opt, "anongid=", 8) == 0) { + char *oe; + ep->e_anongid = strtol(opt+8, &oe, 10); + if (opt[8]=='\0' || *oe != '\0') { + xlog(L_ERROR, "%s: %d: bad anongid \"%s\"\n", + flname, flline, opt); + goto bad_option; + } + } else if (strncmp(opt, "squash_uids=", 12) == 0) { + if (parsesquash(opt+12, &squids, &nsquids, &cp) < 0) { + goto bad_option; + } + } else if (strncmp(opt, "squash_gids=", 12) == 0) { + if (parsesquash(opt+12, &sqgids, &nsqgids, &cp) < 0) { + goto bad_option; + } + } else if (strncmp(opt, "fsid=", 5) == 0) { + char *oe; + + if (saw_reexport) { + xlog(L_ERROR, "%s:%d: 'fsid=' has to be before 'reexport=' %s\n", + flname, flline, opt); + goto bad_option; + } + + if (strcmp(opt+5, "root") == 0) { + ep->e_fsid = 0; + setflags(NFSEXP_FSID, active, ep); + } else { + ep->e_fsid = strtoul(opt+5, &oe, 0); + if (opt[5]!='\0' && *oe == '\0') + setflags(NFSEXP_FSID, active, ep); + else if (valid_uuid(opt+5)) + ep->e_uuid = strdup(opt+5); + else { + xlog(L_ERROR, "%s: %d: bad fsid \"%s\"\n", + flname, flline, opt); + goto bad_option; + } + } + } else if (strcmp(opt, "mountpoint")==0 || + strcmp(opt, "mp") == 0 || + strncmp(opt, "mountpoint=", 11)==0 || + strncmp(opt, "mp=", 3) == 0) { + char * mp = strchr(opt, '='); + if (mp) + ep->e_mountpoint = strdup(mp+1); + else + ep->e_mountpoint = strdup(""); +#ifdef DEBUG + } else if (strncmp(opt, "fsloc=", 6) == 0) { + if (strcmp(opt+6, "stub") == 0) + ep->e_fslocmethod = FSLOC_STUB; + else { + xlog(L_ERROR, "%s:%d: bad option %s\n", + flname, flline, opt); + goto bad_option; + } +#endif + } else if (strncmp(opt, "refer=", 6) == 0) { + ep->e_fslocmethod = FSLOC_REFER; + ep->e_fslocdata = strdup(opt+6); + } else if (strncmp(opt, "replicas=", 9) == 0) { + ep->e_fslocmethod = FSLOC_REPLICA; + ep->e_fslocdata = strdup(opt+9); + } else if (strncmp(opt, "sec=", 4) == 0) { + active = parse_flavors(opt+4, ep); + if (!active) + goto bad_option; + } else if (strncmp(opt, "xprtsec=", 8) == 0) { + if (!parse_xprtsec(opt + 8, ep)) + goto bad_option; + } else if (strncmp(opt, "reexport=", 9) == 0) { + char *strategy = strchr(opt, '='); + + if (!strategy) { + xlog(L_ERROR, "%s:%d: bad option %s\n", + flname, flline, opt); + goto bad_option; + } + strategy++; + + if (saw_reexport) { + xlog(L_ERROR, "%s:%d: only one 'reexport=' is allowed%s\n", + flname, flline, opt); + goto bad_option; + } + + if (strcmp(strategy, "auto-fsidnum") == 0) { + ep->e_reexport = REEXP_AUTO_FSIDNUM; + } else if (strcmp(strategy, "predefined-fsidnum") == 0) { + ep->e_reexport = REEXP_PREDEFINED_FSIDNUM; + } else if (strcmp(strategy, "none") == 0) { + ep->e_reexport = REEXP_NONE; + } else { + xlog(L_ERROR, "%s:%d: bad option %s\n", + flname, flline, strategy); + goto bad_option; + } + + if (reexpdb_apply_reexport_settings(ep, flname, flline) != 0) + goto bad_option; + + if (ep->e_fsid) + setflags(NFSEXP_FSID, active, ep); + + saw_reexport = 1; + } else { + xlog(L_ERROR, "%s:%d: unknown keyword \"%s\"\n", + flname, flline, opt); + setflags(NFSEXP_ALLSQUASH | NFSEXP_READONLY, active, ep); + goto bad_option; + } + free(opt); + while (isblank(*cp)) + cp++; + } + + fix_pseudoflavor_flags(ep); + ep->e_squids = squids; + ep->e_sqgids = sqgids; + ep->e_nsquids = nsquids; + ep->e_nsqgids = nsqgids; + +out: + if (warn && !had_subtree_opt) + xlog(L_WARNING, "%s [%d]: Neither 'subtree_check' or 'no_subtree_check' specified for export \"%s:%s\".\n" + " Assuming default behaviour ('no_subtree_check').\n" + " NOTE: this default has changed since nfs-utils version 1.0.x\n", + + flname, flline, + ep->e_hostname, ep->e_path); + if (had_subtree_opt_ptr) + *had_subtree_opt_ptr = had_subtree_opt; + + return 1; +} + +static int +parsesquash(char *list, int **idp, int *lenp, char **ep) +{ + char *cp = list; + int id0, id1; + int len = *lenp; + int *id = *idp; + + if (**ep) + *--(*ep) = ','; + + do { + id0 = parsenum(&cp); + if (*cp == '-') { + cp++; + id1 = parsenum(&cp); + } else { + id1 = id0; + } + if (id0 == -1 || id1 == -1) { + syntaxerr("uid/gid -1 not permitted"); + xfree(id); + return -1; + } + if ((len % 8) == 0) + id = (int *) xrealloc(id, (len + 8) * sizeof(*id)); + id[len++] = id0; + id[len++] = id1; + if (!*cp || *cp == ')' || (*cp == ',' && !isdigit(cp[1]))) + break; + if (*cp != ',') { + syntaxerr("bad uid/gid list"); + xfree(id); + return -1; + } + cp++; + } while(1); + + if (**ep == ',') (*ep)++; + + *lenp = len; + *idp = id; + return 1; +} + +static void +freesquash(void) +{ + if (squids) { + xfree (squids); + squids = NULL; + nsquids = 0; + } + if (sqgids) { + xfree (sqgids); + sqgids = NULL; + nsqgids = 0; + } +} + +static int +parsenum(char **cpp) +{ + char *cp = *cpp, c; + int num = 0; + + if (**cpp == '-') + (*cpp)++; + while (isdigit(**cpp)) + (*cpp)++; + c = **cpp; **cpp = '\0'; num = atoi(cp); **cpp = c; + return num; +} + +static int +getpath(char *path, int len) +{ + xskip(efp, " \t\n"); + return xgettok(efp, 0, path, len); +} + +static int +getexport(char *exp, int len) +{ + int ok; + + xskip(efp, " \t"); + if ((ok = xgettok(efp, 0, exp, len)) < 0) + xlog(L_ERROR, "%s:%d: syntax error", + efname?"command line":efname, efp->x_line); + return ok; +} + +static void +syntaxerr(char *msg) +{ + xlog(L_ERROR, "%s:%d: syntax error: %s", + efname, efp?efp->x_line:0, msg); +} +struct export_features *get_export_features(void) +{ + static char *path = "/proc/fs/nfsd/export_features"; + static struct export_features ef; + static int cached = 0; + char buf[50]; + int c; + int fd; + + if (cached) + return &ef; + + ef.flags = NFSEXP_OLDFLAGS; + ef.secinfo_flags = NFSEXP_OLD_SECINFO_FLAGS; + + fd = open(path, O_RDONLY); + if (fd == -1) + goto good; + c = read(fd, buf, 50); + close(fd); + if (c == -1) + goto err; + buf[c] = 0; + c = sscanf(buf, "%x %x", &ef.flags, &ef.secinfo_flags); + if (c != 2) + goto err; +good: + cached = 1; + return &ef; +err: + xlog(L_WARNING, "unexpected error reading %s", path); + return &ef; +} diff --git a/support/nfs/getport.c b/support/nfs/getport.c new file mode 100644 index 0000000..813f7bf --- /dev/null +++ b/support/nfs/getport.c @@ -0,0 +1,1127 @@ +/* + * Provide a variety of APIs that query an rpcbind daemon to + * discover RPC service ports and allowed protocol version + * numbers. + * + * Copyright (C) 2008 Oracle Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/types.h> +#include <sys/time.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <arpa/inet.h> + +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> + +#ifdef HAVE_LIBTIRPC +#include <netconfig.h> +#include <rpc/rpcb_prot.h> +#endif + +#include "sockaddr.h" +#include "nfsrpc.h" +#include "nfslib.h" + +/* + * Try a local socket first to access the local rpcbind daemon + * + * Rpcbind's local socket service does not seem to be working. + * Disable this logic for now. + */ +#ifdef HAVE_LIBTIRPC +#undef NFS_GP_LOCAL +#else /* !HAVE_LIBTIRPC */ +#undef NFS_GP_LOCAL +#endif /* !HAVE_LIBTIRPC */ + +#ifdef HAVE_LIBTIRPC +static const rpcvers_t default_rpcb_version = RPCBVERS_4; +#else /* !HAVE_LIBTIRPC */ +static const rpcvers_t default_rpcb_version = PMAPVERS; +#endif /* !HAVE_LIBTIRPC */ + +/* + * Historical: Map TCP connect timeouts to timeout + * error code used by UDP. + */ +static void +nfs_gp_map_tcp_errorcodes(const unsigned short protocol) +{ + if (protocol != IPPROTO_TCP) + return; + + switch (rpc_createerr.cf_error.re_errno) { + case ETIMEDOUT: + rpc_createerr.cf_stat = RPC_TIMEDOUT; + break; + case ECONNREFUSED: + rpc_createerr.cf_stat = RPC_CANTRECV; + break; + } +} + +/* + * There's no easy way to tell how the local system's networking + * and rpcbind is configured (ie. whether we want to use IPv6 or + * IPv4 loopback to contact RPC services on the local host). We + * punt and simply try to look up "localhost". + * + * Returns TRUE on success. + */ +static int nfs_gp_loopback_address(struct sockaddr *sap, socklen_t *salen) +{ + struct addrinfo *gai_results; + int ret = 0; + + if (getaddrinfo("localhost", NULL, NULL, &gai_results)) + return 0; + + if (*salen >= gai_results->ai_addrlen) { + memcpy(sap, gai_results->ai_addr, + gai_results->ai_addrlen); + *salen = gai_results->ai_addrlen; + ret = 1; + } + + nfs_freeaddrinfo(gai_results); + return ret; +} + +/* + * Look up a network service in /etc/services and return the + * network-order port number of that service. + */ +static in_port_t nfs_gp_getservbyname(const char *service, + const unsigned short protocol) +{ + const struct addrinfo gai_hint = { + .ai_family = AF_INET, + .ai_protocol = protocol, + .ai_flags = AI_PASSIVE, + }; + struct addrinfo *gai_results; + const struct sockaddr_in *sin; + in_port_t port; + + if (getaddrinfo(NULL, service, &gai_hint, &gai_results) != 0) + return 0; + + sin = (const struct sockaddr_in *)gai_results->ai_addr; + port = sin->sin_port; + + nfs_freeaddrinfo(gai_results); + return port; +} + +/* + * Discover the port number that should be used to contact an + * rpcbind service. This will detect if the port has a local + * value that may have been set in /etc/services. + * + * Returns network byte-order port number of rpcbind service + * on this system. + */ +static in_port_t nfs_gp_get_rpcb_port(const unsigned short protocol) +{ + static const char *rpcb_netnametbl[] = { + "rpcbind", + "portmapper", + "sunrpc", + NULL, + }; + unsigned int i; + + for (i = 0; rpcb_netnametbl[i] != NULL; i++) { + in_port_t port; + + port = nfs_gp_getservbyname(rpcb_netnametbl[i], protocol); + if (port != 0) + return port; + } + + return (in_port_t)htons((uint16_t)PMAPPORT); +} + +/* + * Set up an RPC client for communicating with an rpcbind daemon at + * @sap over @transport with protocol version @version. + * + * Returns a pointer to a prepared RPC client if successful, and + * @timeout is initialized; caller must destroy a non-NULL returned RPC + * client. Otherwise returns NULL, and rpc_createerr.cf_stat is set to + * reflect the error. + */ +static CLIENT *nfs_gp_get_rpcbclient(struct sockaddr *sap, + const socklen_t salen, + const unsigned short transport, + const rpcvers_t version, + struct timeval *timeout) +{ + static const char *rpcb_pgmtbl[] = { + "rpcbind", + "portmap", + "portmapper", + "sunrpc", + NULL, + }; + rpcprog_t rpcb_prog = nfs_getrpcbyname(RPCBPROG, rpcb_pgmtbl); + CLIENT *clnt; + + nfs_set_port(sap, ntohs(nfs_gp_get_rpcb_port(transport))); + clnt = nfs_get_rpcclient(sap, salen, transport, rpcb_prog, + version, timeout); + nfs_gp_map_tcp_errorcodes(transport); + return clnt; +} + +/** + * nfs_get_proto - Convert a netid to an address family and protocol number + * @netid: C string containing a netid + * @family: OUT: address family + * @protocol: OUT: protocol number + * + * Returns 1 and fills in @protocol if the netid was recognized; + * otherwise zero is returned. + */ +#ifdef HAVE_LIBTIRPC +int +nfs_get_proto(const char *netid, sa_family_t *family, unsigned long *protocol) +{ + struct netconfig *nconf; + struct protoent *proto; + + /* + * IANA does not define a protocol number for rdma netids, + * since "rdma" is not an IP protocol. + */ + if (strcmp(netid, "rdma") == 0) { + *family = AF_INET; + *protocol = NFSPROTO_RDMA; + return 1; + } + if (strcmp(netid, "rdma6") == 0) { + *family = AF_INET6; + *protocol = NFSPROTO_RDMA; + return 1; + } + + nconf = getnetconfigent(netid); + if (nconf == NULL) + return 0; + + proto = getprotobyname(nconf->nc_proto); + if (proto == NULL) { + freenetconfigent(nconf); + return 0; + } + + *family = AF_UNSPEC; + if (strcmp(nconf->nc_protofmly, NC_INET) == 0) + *family = AF_INET; + if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) + *family = AF_INET6; + freenetconfigent(nconf); + + *protocol = (unsigned long)proto->p_proto; + return 1; +} +#else /* !HAVE_LIBTIRPC */ +int +nfs_get_proto(const char *netid, sa_family_t *family, unsigned long *protocol) +{ + struct protoent *proto; + + /* + * IANA does not define a protocol number for rdma netids, + * since "rdma" is not an IP protocol. + */ + if (strcmp(netid, "rdma") == 0) { + *family = AF_INET; + *protocol = NFSPROTO_RDMA; + return 1; + } + + proto = getprotobyname(netid); + if (proto == NULL) + return 0; + + *family = AF_INET; + *protocol = (unsigned long)proto->p_proto; + return 1; +} +#endif /* !HAVE_LIBTIRPC */ + +/** + * nfs_get_netid - Convert a protocol family and protocol name to a netid + * @family: protocol family + * @protocol: protocol number + * + * One of the arguments passed when querying remote rpcbind services + * via rpcbind v3 or v4 is a netid string. This replaces the pm_prot + * field used in legacy PMAP_GETPORT calls. + * + * RFC 1833 says netids are not standard but rather defined on the local + * host. There are, however, standard definitions for nc_protofmly and + * nc_proto that can be used to derive a netid string on the local host, + * based on the contents of /etc/netconfig. + * + * Walk through the local netconfig database and grab the netid of the + * first entry that matches @family and @protocol and whose netid string + * fits in the provided buffer. + * + * Returns a '\0'-terminated string if successful. Caller must + * free the returned string. Otherwise NULL is returned, and + * rpc_createerr.cf_stat is set to reflect the error. + */ +#ifdef HAVE_LIBTIRPC +char *nfs_get_netid(const sa_family_t family, const unsigned long protocol) +{ + char *nc_protofmly, *nc_proto, *nc_netid; + struct netconfig *nconf; + struct protoent *proto; + void *handle; + + switch (family) { + case AF_LOCAL: + case AF_INET: + nc_protofmly = NC_INET; + break; + case AF_INET6: + nc_protofmly = NC_INET6; + break; + default: + goto out; + } + + proto = getprotobynumber(protocol); + if (proto == NULL) + goto out; + nc_proto = proto->p_name; + + handle = setnetconfig(); + while ((nconf = getnetconfig(handle)) != NULL) { + + if (nconf->nc_protofmly != NULL && + strcmp(nconf->nc_protofmly, nc_protofmly) != 0) + continue; + if (nconf->nc_proto != NULL && + strcmp(nconf->nc_proto, nc_proto) != 0) + continue; + + nc_netid = strdup(nconf->nc_netid); + endnetconfig(handle); + + if (nc_netid == NULL) + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + return nc_netid; + } + endnetconfig(handle); + +out: + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return NULL; +} +#else /* !HAVE_LIBTIRPC */ +char *nfs_get_netid(const sa_family_t family, const unsigned long protocol) +{ + struct protoent *proto; + char *netid; + + if (family != AF_INET) + goto out; + proto = getprotobynumber((int)protocol); + if (proto == NULL) + goto out; + + netid = strdup(proto->p_name); + if (netid == NULL) + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + return netid; + +out: + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return NULL; +} +#endif /* !HAVE_LIBTIRPC */ + +/* + * Extract a port number from a universal address, and terminate the + * string in @addrstr just after the address part. + * + * Returns -1 if unsuccesful; otherwise a decoded port number (possibly 0) + * is returned. + */ +static int nfs_gp_universal_porthelper(char *addrstr) +{ + char *p, *endptr; + unsigned long portlo, porthi; + int port = -1; + + p = strrchr(addrstr, '.'); + if (p == NULL) + goto out; + portlo = strtoul(p + 1, &endptr, 10); + if (*endptr != '\0' || portlo > 255) + goto out; + *p = '\0'; + + p = strrchr(addrstr, '.'); + if (p == NULL) + goto out; + porthi = strtoul(p + 1, &endptr, 10); + if (*endptr != '\0' || porthi > 255) + goto out; + *p = '\0'; + port = (porthi << 8) | portlo; + +out: + return port; +} + +/** + * nfs_universal2port - extract port number from a "universal address" + * @uaddr: '\0'-terminated C string containing a universal address + * + * Universal addresses (defined in RFC 1833) are used when calling an + * rpcbind daemon via protocol versions 3 or 4.. + * + * Returns -1 if unsuccesful; otherwise a decoded port number (possibly 0) + * is returned. + */ +int nfs_universal2port(const char *uaddr) +{ + char *addrstr; + int port = -1; + + addrstr = strdup(uaddr); + if (addrstr != NULL) { + port = nfs_gp_universal_porthelper(addrstr); + free(addrstr); + } + return port; +} + +/** + * nfs_sockaddr2universal - convert a sockaddr to a "universal address" + * @sap: pointer to a socket address + * + * Universal addresses (defined in RFC 1833) are used when calling an + * rpcbind daemon via protocol versions 3 or 4.. + * + * Returns a '\0'-terminated string if successful; caller must free + * the returned string. Otherwise NULL is returned and + * rpc_createerr.cf_stat is set to reflect the error. + * + * inet_ntop(3) is used here, since getnameinfo(3) is not available + * in some earlier glibc releases, and we don't require support for + * scope IDs for universal addresses. + */ +char *nfs_sockaddr2universal(const struct sockaddr *sap) +{ + const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap; + const struct sockaddr_un *sun = (const struct sockaddr_un *)sap; + const struct sockaddr_in *sin = (const struct sockaddr_in *)sap; + char buf[INET6_ADDRSTRLEN + 8 /* for port information */]; + uint16_t port; + size_t count; + char *result; + int len; + + switch (sap->sa_family) { + case AF_LOCAL: + return strndup(sun->sun_path, sizeof(sun->sun_path)); + case AF_INET: + if (inet_ntop(AF_INET, (const void *)&sin->sin_addr.s_addr, + buf, (socklen_t)sizeof(buf)) == NULL) + goto out_err; + port = ntohs(sin->sin_port); + break; + case AF_INET6: + if (inet_ntop(AF_INET6, (const void *)&sin6->sin6_addr, + buf, (socklen_t)sizeof(buf)) == NULL) + goto out_err; + port = ntohs(sin6->sin6_port); + break; + default: + goto out_err; + } + + count = sizeof(buf) - strlen(buf); + len = snprintf(buf + strlen(buf), count, ".%u.%u", + (unsigned)(port >> 8), (unsigned)(port & 0xff)); + /* before glibc 2.0.6, snprintf(3) could return -1 */ + if (len < 0 || (size_t)len > count) + goto out_err; + + result = strdup(buf); + if (result != NULL) + return result; + +out_err: + rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; + return NULL; +} + +/* + * Send a NULL request to the indicated RPC service. + * + * Returns 1 if the service responded; otherwise 0; + */ +static int nfs_gp_ping(CLIENT *client, struct timeval timeout) +{ + enum clnt_stat status; + + status = CLNT_CALL(client, NULLPROC, + (xdrproc_t)xdr_void, NULL, + (xdrproc_t)xdr_void, NULL, + timeout); + + if (status != RPC_SUCCESS) { + rpc_createerr.cf_stat = status; + CLNT_GETERR(client, &rpc_createerr.cf_error); + } + return (int)(status == RPC_SUCCESS); +} + +#ifdef HAVE_LIBTIRPC + +/* + * Initialize the rpcb argument for a GETADDR request. + * + * Returns 1 if successful, and caller must free strings pointed + * to by r_netid and r_addr; otherwise 0. + */ +static int nfs_gp_init_rpcb_parms(const struct sockaddr *sap, + const rpcprog_t program, + const rpcvers_t version, + const unsigned short protocol, + struct rpcb *parms) +{ + char *netid, *addr; + + netid = nfs_get_netid(sap->sa_family, protocol); + if (netid == NULL) + return 0; + + addr = nfs_sockaddr2universal(sap); + if (addr == NULL) { + free(netid); + return 0; + } + + memset(parms, 0, sizeof(*parms)); + parms->r_prog = program; + parms->r_vers = version; + parms->r_netid = netid; + parms->r_addr = addr; + parms->r_owner = ""; + + return 1; +} + +static void nfs_gp_free_rpcb_parms(struct rpcb *parms) +{ + free(parms->r_netid); + free(parms->r_addr); +} + +/* + * Try rpcbind GETADDR via version 4. If that fails, try same + * request via version 3. + * + * Returns non-zero port number on success; otherwise returns + * zero. rpccreateerr is set to reflect the nature of the error. + */ +static unsigned short nfs_gp_rpcb_getaddr(CLIENT *client, + struct rpcb *parms, + struct timeval timeout) +{ + rpcvers_t rpcb_version; + struct rpc_err rpcerr; + int port = 0; + + for (rpcb_version = RPCBVERS_4; + rpcb_version >= RPCBVERS_3; + rpcb_version--) { + enum clnt_stat status; + char *uaddr = NULL; + + CLNT_CONTROL(client, CLSET_VERS, (void *)&rpcb_version); + status = CLNT_CALL(client, (rpcproc_t)RPCBPROC_GETADDR, + (xdrproc_t)xdr_rpcb, (void *)parms, + (xdrproc_t)xdr_wrapstring, (void *)&uaddr, + timeout); + + switch (status) { + case RPC_SUCCESS: + if ((uaddr == NULL) || (uaddr[0] == '\0')) { + rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; + return 0; + } + + port = nfs_universal2port(uaddr); + xdr_free((xdrproc_t)xdr_wrapstring, (char *)&uaddr); + if (port == -1) { + rpc_createerr.cf_stat = RPC_N2AXLATEFAILURE; + return 0; + } + return (unsigned short)port; + case RPC_PROGVERSMISMATCH: + clnt_geterr(client, &rpcerr); + if (rpcerr.re_vers.low > RPCBVERS4) + return 0; + continue; + case RPC_PROCUNAVAIL: + case RPC_PROGUNAVAIL: + continue; + default: + /* Most likely RPC_TIMEDOUT or RPC_CANTRECV */ + rpc_createerr.cf_stat = status; + clnt_geterr(client, &rpc_createerr.cf_error); + return 0; + } + + } + + if (port == 0) { + rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; + clnt_geterr(client, &rpc_createerr.cf_error); + } + return port; +} + +#endif /* HAVE_LIBTIRPC */ + +/* + * Try GETPORT request via rpcbind version 2. + * + * Returns non-zero port number on success; otherwise returns + * zero. rpccreateerr is set to reflect the nature of the error. + */ +static unsigned long nfs_gp_pmap_getport(CLIENT *client, + struct pmap *parms, + struct timeval timeout) +{ + enum clnt_stat status; + unsigned long port; + + status = CLNT_CALL(client, (rpcproc_t)PMAPPROC_GETPORT, + (xdrproc_t)xdr_pmap, (void *)parms, + (xdrproc_t)xdr_u_long, (void *)&port, + timeout); + + if (status != RPC_SUCCESS) { + rpc_createerr.cf_stat = status; + CLNT_GETERR(client, &rpc_createerr.cf_error); + port = 0; + } else if (port == 0) + rpc_createerr.cf_stat = RPC_PROGNOTREGISTERED; + + return port; +} + +#ifdef HAVE_LIBTIRPC + +static unsigned short nfs_gp_getport_rpcb(CLIENT *client, + const struct sockaddr *sap, + const rpcprog_t program, + const rpcvers_t version, + const unsigned short protocol, + struct timeval timeout) +{ + unsigned short port = 0; + struct rpcb parms; + + if (nfs_gp_init_rpcb_parms(sap, program, version, + protocol, &parms) != 0) { + port = nfs_gp_rpcb_getaddr(client, &parms, timeout); + nfs_gp_free_rpcb_parms(&parms); + } + + return port; +} + +#endif /* HAVE_LIBTIRPC */ + +static unsigned long nfs_gp_getport_pmap(CLIENT *client, + const rpcprog_t program, + const rpcvers_t version, + const unsigned short protocol, + struct timeval timeout) +{ + struct pmap parms = { + .pm_prog = program, + .pm_vers = version, + .pm_prot = protocol, + }; + rpcvers_t pmap_version = PMAPVERS; + + CLNT_CONTROL(client, CLSET_VERS, (void *)&pmap_version); + return nfs_gp_pmap_getport(client, &parms, timeout); +} + +/* + * Try an AF_INET6 request via rpcbind v4/v3; try an AF_INET + * request via rpcbind v2. + * + * Returns non-zero port number on success; otherwise returns + * zero. rpccreateerr is set to reflect the nature of the error. + */ +static unsigned short nfs_gp_getport(CLIENT *client, + const struct sockaddr *sap, + const rpcprog_t program, + const rpcvers_t version, + const unsigned short protocol, + struct timeval timeout) +{ + switch (sap->sa_family) { +#ifdef HAVE_LIBTIRPC + case AF_INET6: + return nfs_gp_getport_rpcb(client, sap, program, + version, protocol, timeout); +#endif /* HAVE_LIBTIRPC */ + case AF_INET: + return nfs_gp_getport_pmap(client, program, version, + protocol, timeout); + } + + rpc_createerr.cf_stat = RPC_UNKNOWNADDR; + return 0; +} + +/** + * nfs_rpc_ping - Determine if RPC service is responding to requests + * @sap: pointer to address of server to query (port is already filled in) + * @salen: length of server address + * @program: requested RPC program number + * @version: requested RPC version number + * @protocol: requested IPPROTO_ value of transport protocol + * @timeout: pointer to request timeout (NULL means use default timeout) + * + * Returns 1 if the remote service responded without an error; otherwise + * zero. + */ +int nfs_rpc_ping(const struct sockaddr *sap, const socklen_t salen, + const rpcprog_t program, const rpcvers_t version, + const unsigned short protocol, const struct timeval *timeout) +{ + union nfs_sockaddr address; + struct sockaddr *saddr = &address.sa; + CLIENT *client; + struct timeval tout = { -1, 0 }; + int result = 0; + + if (timeout != NULL) + tout = *timeout; + + nfs_clear_rpc_createerr(); + + memcpy(saddr, sap, (size_t)salen); + client = nfs_get_rpcclient(saddr, salen, protocol, + program, version, &tout); + if (client != NULL) { + result = nfs_gp_ping(client, tout); + nfs_gp_map_tcp_errorcodes(protocol); + CLNT_DESTROY(client); + } + + return result; +} + +/** + * nfs_getport - query server's rpcbind to get port number for an RPC service + * @sap: pointer to address of server to query + * @salen: length of server's address + * @program: requested RPC program number + * @version: requested RPC version number + * @protocol: IPPROTO_ value of requested transport protocol + * + * Uses any acceptable rpcbind version to discover the port number for the + * RPC service described by the given [program, version, transport] tuple. + * Uses a quick timeout and an ephemeral source port. Supports AF_INET and + * AF_INET6 server addresses. + * + * Returns a positive integer representing the port number of the RPC + * service advertised by the server (in host byte order), or zero if the + * service is not advertised or there was some problem querying the server's + * rpcbind daemon. rpccreateerr is set to reflect the underlying cause of + * the error. + * + * There are a variety of ways to choose which transport and rpcbind versions + * to use. We chose to conserve local resources and try to avoid incurring + * timeouts. + * + * Transport + * To provide rudimentary support for traversing firewalls, query the remote + * using the same transport as the requested service. This provides some + * guarantee that the requested transport is available between this client + * and the server, and if the caller specifically requests TCP, for example, + * this may be becuase a firewall is in place that blocks UDP traffic. We + * could try both, but that could involve a lengthy timeout in several cases, + * and would often consume an extra ephemeral port. + * + * Rpcbind version + * To avoid using up too many ephemeral ports, AF_INET queries use tried-and- + * true rpcbindv2, and don't try the newer versions; and AF_INET6 queries use + * rpcbindv4, then rpcbindv3 on the same socket. The newer rpcbind protocol + * versions can adequately detect if a remote RPC service does not support + * AF_INET6 at all. The rpcbind socket is re-used in an attempt to keep the + * overall number of consumed ephemeral ports low. + */ +unsigned short nfs_getport(const struct sockaddr *sap, + const socklen_t salen, + const rpcprog_t program, + const rpcvers_t version, + const unsigned short protocol) +{ + union nfs_sockaddr address; + struct sockaddr *saddr = &address.sa; + struct timeval timeout = { -1, 0 }; + unsigned short port = 0; + CLIENT *client; + + nfs_clear_rpc_createerr(); + + memcpy(saddr, sap, (size_t)salen); + client = nfs_gp_get_rpcbclient(saddr, salen, protocol, + default_rpcb_version, &timeout); + if (client != NULL) { + port = nfs_gp_getport(client, saddr, program, + version, protocol, timeout); + CLNT_DESTROY(client); + } + + return port; +} + +/** + * nfs_getport_ping - query server's rpcbind and do RPC ping to verify result + * @sap: IN: pointer to address of server to query; + * OUT: pointer to updated address + * @salen: length of server's address + * @program: requested RPC program number + * @version: requested RPC version number + * @protocol: IPPROTO_ value of requested transport protocol + * + * Uses any acceptable rpcbind version to discover the port number for the + * RPC service described by the given [program, version, transport] tuple. + * Uses a quick timeout and an ephemeral source port. Supports AF_INET and + * AF_INET6 server addresses. + * + * Returns a 1 and sets the port number in the passed-in server address + * if both the query and the ping were successful; otherwise zero. + * rpccreateerr is set to reflect the underlying cause of the error. + */ +int nfs_getport_ping(struct sockaddr *sap, const socklen_t salen, + const rpcprog_t program, const rpcvers_t version, + const unsigned short protocol) +{ + struct timeval timeout = { -1, 0 }; + unsigned short port = 0; + CLIENT *client; + int result = 0; + + nfs_clear_rpc_createerr(); + + client = nfs_gp_get_rpcbclient(sap, salen, protocol, + default_rpcb_version, &timeout); + if (client != NULL) { + port = nfs_gp_getport(client, sap, program, + version, protocol, timeout); + CLNT_DESTROY(client); + client = NULL; + } + + if (port != 0) { + union nfs_sockaddr address; + struct sockaddr *saddr = &address.sa; + + memcpy(saddr, sap, (size_t)salen); + nfs_set_port(saddr, port); + + nfs_clear_rpc_createerr(); + + client = nfs_get_rpcclient(saddr, salen, protocol, + program, version, &timeout); + if (client != NULL) { + result = nfs_gp_ping(client, timeout); + nfs_gp_map_tcp_errorcodes(protocol); + CLNT_DESTROY(client); + } + } + + if (result) + nfs_set_port(sap, port); + + return result; +} + +/** + * nfs_getlocalport - query local rpcbind to get port number for an RPC service + * @program: requested RPC program number + * @version: requested RPC version number + * @protocol: IPPROTO_ value of requested transport protocol + * + * Uses any acceptable rpcbind version to discover the port number for the + * RPC service described by the given [program, version, transport] tuple. + * Uses a quick timeout and an ephemeral source port. Supports AF_INET and + * AF_INET6 local addresses. + * + * Returns a positive integer representing the port number of the RPC + * service advertised by the server (in host byte order), or zero if the + * service is not advertised or there was some problem querying the server's + * rpcbind daemon. rpccreateerr is set to reflect the underlying cause of + * the error. + * + * Try an AF_LOCAL connection first. The rpcbind daemon implementation should + * listen on AF_LOCAL. + * + * If that doesn't work (for example, if portmapper is running, or rpcbind + * isn't listening on /run/rpcbind.sock), send a query via UDP to localhost + * (UDP doesn't leave a socket in TIME_WAIT, and the timeout is a relatively + * short 3 seconds). + */ +unsigned short nfs_getlocalport(const rpcprot_t program, + const rpcvers_t version, + const unsigned short protocol) +{ + union nfs_sockaddr address; + struct sockaddr *lb_addr = &address.sa; + socklen_t lb_len = sizeof(*lb_addr); + unsigned short port = 0; + +#ifdef NFS_GP_LOCAL + const struct sockaddr_un sun = { + .sun_family = AF_LOCAL, + .sun_path = _PATH_RPCBINDSOCK, + }; + const struct sockaddr *sap = (struct sockaddr *)&sun; + const socklen_t salen = SUN_LEN(&sun); + CLIENT *client; + struct timeval timeout = { -1, 0 }; + + nfs_clear_rpc_createerr(); + + client = nfs_gp_get_rpcbclient(sap, salen, 0, RPCBVERS_4, &timeout); + if (client != NULL) { + struct rpcb parms; + + if (nfs_gp_init_rpcb_parms(sap, program, version, + protocol, &parms) != 0) { + port = nfs_gp_rpcb_getaddr(client, &parms, timeout); + nfs_gp_free_rpcb_parms(&parms); + } + CLNT_DESTROY(client); + } +#endif /* NFS_GP_LOCAL */ + + if (port == 0) { + nfs_clear_rpc_createerr(); + + if (nfs_gp_loopback_address(lb_addr, &lb_len)) { + port = nfs_getport(lb_addr, lb_len, + program, version, protocol); + } else + rpc_createerr.cf_stat = RPC_UNKNOWNADDR; + } + + return port; +} + +/** + * nfs_rpcb_getaddr - query rpcbind via rpcbind versions 4 and 3 + * @sap: pointer to address of server to query + * @salen: length of server address + * @transport: transport protocol to use for the query + * @addr: pointer to r_addr address + * @program: requested RPC program number + * @version: requested RPC version number + * @protocol: requested IPPROTO_ value of transport protocol + * @timeout: pointer to request timeout (NULL means use default timeout) + * + * Returns a positive integer representing the port number of the RPC + * service advertised by the server (in host byte order), or zero if the + * service is not advertised or there was some problem querying the + * server's rpcbind daemon. rpccreateerr is set to reflect the + * underlying cause of the error. + * + * This function provides similar functionality to nfs_pmap_getport(), + * but performs the rpcbind lookup via rpcbind version 4. If the server + * doesn't support rpcbind version 4, it will retry with version 3. + * The GETADDR procedure is exactly the same in these two versions of + * the rpcbind protocol, so the socket, RPC client, and arguments are + * re-used when retrying, saving ephemeral port space. + * + * These RPC procedures take a universal address as an argument, so the + * query will fail if the remote rpcbind daemon doesn't find an entry + * with a matching address. A matching address includes an ANYADDR + * address of the same address family. In this way an RPC server can + * advertise via rpcbind that it does not support AF_INET6. + */ +#ifdef HAVE_LIBTIRPC + +unsigned short nfs_rpcb_getaddr(const struct sockaddr *sap, + const socklen_t salen, + const unsigned short transport, + const struct sockaddr *addr, + const rpcprog_t program, + const rpcvers_t version, + const unsigned short protocol, + const struct timeval *timeout) +{ + union nfs_sockaddr address; + struct sockaddr *saddr = &address.sa; + CLIENT *client; + struct rpcb parms; + struct timeval tout = { -1, 0 }; + unsigned short port = 0; + + if (timeout != NULL) + tout = *timeout; + + nfs_clear_rpc_createerr(); + + memcpy(saddr, sap, (size_t)salen); + client = nfs_gp_get_rpcbclient(saddr, salen, transport, + RPCBVERS_4, &tout); + if (client != NULL) { + if (nfs_gp_init_rpcb_parms(addr, program, version, + protocol, &parms) != 0) { + port = nfs_gp_rpcb_getaddr(client, &parms, tout); + nfs_gp_free_rpcb_parms(&parms); + } + CLNT_DESTROY(client); + } + + return port; +} + +#else /* !HAVE_LIBTIRPC */ + +unsigned short nfs_rpcb_getaddr(__attribute__((unused)) const struct sockaddr *sap, + __attribute__((unused)) const socklen_t salen, + __attribute__((unused)) const unsigned short transport, + __attribute__((unused)) const struct sockaddr *addr, + __attribute__((unused)) const rpcprog_t program, + __attribute__((unused)) const rpcvers_t version, + __attribute__((unused)) const unsigned short protocol, + __attribute__((unused)) const struct timeval *timeout) +{ + nfs_clear_rpc_createerr(); + + rpc_createerr.cf_stat = RPC_UNKNOWNADDR; + return 0; +} + +#endif /* !HAVE_LIBTIRPC */ + +/** + * nfs_pmap_getport - query rpcbind via the portmap protocol (rpcbindv2) + * @sin: pointer to AF_INET address of server to query + * @transport: transport protocol to use for the query + * @program: requested RPC program number + * @version: requested RPC version number + * @protocol: requested IPPROTO_ value of transport protocol + * @timeout: pointer to request timeout (NULL means use default timeout) + * + * Returns a positive integer representing the port number of the RPC service + * advertised by the server (in host byte order), or zero if the service is + * not advertised or there was some problem querying the server's rpcbind + * daemon. rpccreateerr is set to reflect the underlying cause of the error. + * + * nfs_pmap_getport() is very similar to pmap_getport(), except that: + * + * 1. This version always tries to use an ephemeral port, since reserved + * ports are not needed for GETPORT queries. This conserves the very + * limited reserved port space, helping reduce failed socket binds + * during mount storms. + * + * 2. This version times out quickly by default. It time-limits the + * connect process as well as the actual RPC call, and even allows the + * caller to specify the timeout. + * + * 3. This version shares code with the rpcbindv3 and rpcbindv4 query + * functions. It can use a TI-RPC generated CLIENT. + */ +unsigned long nfs_pmap_getport(const struct sockaddr_in *sin, + const unsigned short transport, + const unsigned long program, + const unsigned long version, + const unsigned long protocol, + const struct timeval *timeout) +{ + struct sockaddr_in address; + struct sockaddr *saddr = (struct sockaddr *)&address; + CLIENT *client; + struct pmap parms = { + .pm_prog = program, + .pm_vers = version, + .pm_prot = protocol, + }; + struct timeval tout = { -1, 0 }; + unsigned long port = 0; + + if (timeout != NULL) + tout = *timeout; + + nfs_clear_rpc_createerr(); + + memcpy(saddr, sin, sizeof(address)); + client = nfs_gp_get_rpcbclient(saddr, (socklen_t)sizeof(*sin), + transport, PMAPVERS, &tout); + if (client != NULL) { + port = nfs_gp_pmap_getport(client, &parms, tout); + CLNT_DESTROY(client); + } + + return port; +} + +static const char *nfs_ns_pgmtbl[] = { + "status", + NULL, +}; + +/* + * nfs_probe_statd - use nfs_pmap_getport to see if statd is running locally + * + * Returns non-zero if statd is running locally. + */ +int nfs_probe_statd(void) +{ + struct sockaddr_in addr = { + .sin_family = AF_INET, + .sin_addr.s_addr = htonl(INADDR_LOOPBACK), + }; + rpcprog_t program = nfs_getrpcbyname(NSMPROG, nfs_ns_pgmtbl); + + return nfs_getport_ping((struct sockaddr *)(char *)&addr, sizeof(addr), + program, (rpcvers_t)1, IPPROTO_UDP); +} diff --git a/support/nfs/mydaemon.c b/support/nfs/mydaemon.c new file mode 100644 index 0000000..d1cf08d --- /dev/null +++ b/support/nfs/mydaemon.c @@ -0,0 +1,153 @@ +/* + mydaemon.c + + Copyright (c) 2000 The Regents of the University of Michigan. + All rights reserved. + + Copyright (c) 2000 Dug Song <dugsong@UMICH.EDU>. + Copyright (c) 2002 Andy Adamson <andros@UMICH.EDU>. + Copyright (c) 2002 Marius Aamodt Eriksen <marius@UMICH.EDU>. + Copyright (c) 2002 J. Bruce Fields <bfields@UMICH.EDU>. + Copyright (c) 2013 Jeff Layton <jlayton@redhat.com> + + All rights reserved, all wrongs reversed. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions + are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +*/ + +#include <sys/param.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <unistd.h> +#include <stdio.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <syslog.h> +#include <xlog.h> + +#include "nfslib.h" + +static int pipefds[2] = { -1, -1}; + +/** + * daemon_init - initial daemon setup + * @fg: whether to run in the foreground + * + * This function is like daemon(), but with our own special sauce to delay + * the exit of the parent until the child is set up properly. A pipe is created + * between parent and child. The parent process will wait to exit until the + * child dies or writes an int on the pipe signaling its status. + */ +void +daemon_init(bool fg) +{ + int pid, status, tempfd; + + if (fg) + return; + + if (pipe(pipefds) < 0) { + xlog_err("mydaemon: pipe() failed: errno %d (%s)\n", + errno, strerror(errno)); + exit(EXIT_FAILURE); + } + + pid = fork(); + if (pid < 0) { + xlog_err("mydaemon: fork() failed: errno %d (%s)\n", + errno, strerror(errno)); + exit(EXIT_FAILURE); + } + + if (pid > 0) { + /* Parent */ + close(pipefds[1]); + if (read(pipefds[0], &status, sizeof(status)) != sizeof(status)) + exit(EXIT_FAILURE); + exit(status); + } + + /* Child */ + close(pipefds[0]); + setsid (); + + if (chdir ("/")) { + xlog_err("mydaemon: chdir() failed: errno %d (%s)\n", + errno, strerror(errno)); + exit(EXIT_FAILURE); + } + + while (pipefds[1] <= 2) { + pipefds[1] = dup(pipefds[1]); + if (pipefds[1] < 0) { + xlog_err("mydaemon: dup() failed: errno %d (%s)\n", + errno, strerror(errno)); + exit(EXIT_FAILURE); + } + } + + tempfd = open("/dev/null", O_RDWR); + if (tempfd < 0) { + xlog_err("mydaemon: can't open /dev/null: errno %d " + "(%s)\n", errno, strerror(errno)); + exit(EXIT_FAILURE); + } + + dup2(tempfd, 0); + dup2(tempfd, 1); + dup2(tempfd, 2); + close(tempfd); + closelog(); + dup2(pipefds[1], 3); + pipefds[1] = 3; + closeall(4); +} + +/** + * daemon_ready - tell interested parties that the daemon is ready + * + * This function tells e.g. the parent process that the daemon is up + * and running. + */ +void +daemon_ready(void) +{ + int status = 0; + + if (pipefds[1] > 0) { + if (write(pipefds[1], &status, sizeof(status)) != sizeof(status)) { + xlog_err("WARN: writing to parent pipe failed: errno " + "%d (%s)\n", errno, strerror(errno)); + } + close(pipefds[1]); + pipefds[1] = -1; + } +} + diff --git a/support/nfs/nfs_mntent.c b/support/nfs/nfs_mntent.c new file mode 100644 index 0000000..25e5944 --- /dev/null +++ b/support/nfs/nfs_mntent.c @@ -0,0 +1,240 @@ +/* Private version of the libc *mntent() routines. */ +/* Note slightly different prototypes. */ + +/* 1999-02-22 Arkadiusz Miskiewicz <misiek@pld.ORG.PL> + * - added Native Language Support + * + * 2006-06-08 Amit Gud <agud@redhat.com> + * - Moved to nfs-utils/support/nfs from util-linux/mount + */ + +#include <stdio.h> +#include <string.h> /* for strchr */ +#include <ctype.h> /* for isdigit */ +#include <sys/stat.h> /* for umask */ +#include <unistd.h> /* for ftruncate */ +#include <errno.h> /* for errno */ + +#include "nfs_mntent.h" +#include "nls.h" +#include "xcommon.h" + +/* Unfortunately the classical Unix /etc/mtab and /etc/fstab + do not handle directory names containing spaces. + Here we mangle them, replacing a space by \040. + What do other Unices do? */ + +static unsigned char need_escaping[] = { ' ', '\t', '\n', '\\' }; + +static char * +mangle(const char *arg) { + const unsigned char *s = (const unsigned char *)arg; + char *ss, *sp; + unsigned int n; + + n = strlen(arg); + ss = sp = xmalloc(4*n+1); + while(1) { + for (n = 0; n < sizeof(need_escaping); n++) { + if (*s == need_escaping[n]) { + *sp++ = '\\'; + *sp++ = '0' + ((*s & 0300) >> 6); + *sp++ = '0' + ((*s & 070) >> 3); + *sp++ = '0' + (*s & 07); + goto next; + } + } + *sp++ = *s; + if (*s == 0) + break; + next: + s++; + } + return ss; +} + +static int +is_space_or_tab (char c) { + return (c == ' ' || c == '\t'); +} + +static char * +skip_spaces(char *s) { + while (is_space_or_tab(*s)) + s++; + return s; +} + +static char * +skip_nonspaces(char *s) { + while (*s && !is_space_or_tab(*s)) + s++; + return s; +} + +#define isoctal(a) (((a) & ~7) == '0') + +/* returns malloced pointer - no more strdup required */ +static char * +unmangle(char *s) { + char *ret, *ss, *sp; + + ss = skip_nonspaces(s); + ret = sp = xmalloc(ss-s+1); + while(s != ss) { + if (*s == '\\' && isoctal(s[1]) && isoctal(s[2]) && isoctal(s[3])) { + *sp++ = 64*(s[1] & 7) + 8*(s[2] & 7) + (s[3] & 7); + s += 4; + } else + *sp++ = *s++; + } + *sp = 0; + return ret; +} + +/* + * fstat'ing the file and allocating a buffer holding all of it + * may be a bad idea: if the file is /proc/mounts, the stat + * returns 0. + * (On the other hand, mangling and unmangling is meaningless + * for /proc/mounts.) + */ + +mntFILE * +nfs_setmntent (const char *file, char *mode) { + mntFILE *mfp = xmalloc(sizeof(*mfp)); + mode_t old_umask = umask(077); + + mfp->mntent_fp = fopen(file, mode); + umask(old_umask); + mfp->mntent_file = xstrdup(file); + mfp->mntent_errs = (mfp->mntent_fp == NULL); + mfp->mntent_softerrs = 0; + mfp->mntent_lineno = 0; + return mfp; +} + +void +nfs_endmntent (mntFILE *mfp) { + if (mfp) { + if (mfp->mntent_fp) + fclose(mfp->mntent_fp); + if (mfp->mntent_file) + free(mfp->mntent_file); + free(mfp); + } +} + +int +nfs_addmntent (mntFILE *mfp, struct mntent *mnt) { + char *m1, *m2, *m3, *m4; + int res; + off_t length; + + if (fseek (mfp->mntent_fp, 0, SEEK_END)) + return 1; /* failure */ + length = ftell(mfp->mntent_fp); + + m1 = mangle(mnt->mnt_fsname); + m2 = mangle(mnt->mnt_dir); + m3 = mangle(mnt->mnt_type); + m4 = mangle(mnt->mnt_opts); + + res = fprintf (mfp->mntent_fp, "%s %s %s %s %d %d\n", + m1, m2, m3, m4, mnt->mnt_freq, mnt->mnt_passno); + + free(m1); + free(m2); + free(m3); + free(m4); + if (res >= 0) { + res = fflush(mfp->mntent_fp); + if (res < 0) { + nfs_error("Cant't flush out mtab: %s", strerror(errno)); + /* Avoid leaving a corrupt mtab file */ + if (ftruncate(fileno(mfp->mntent_fp), length)) + {/* Ignore this failure; Why confuse things */} + } + } + return (res < 0) ? 1 : 0; +} + +/* Read the next entry from the file fp. Stop reading at an incorrect entry. */ +struct mntent * +nfs_getmntent (mntFILE *mfp) { + static char buf[4096]; + static struct mntent me; + char *s; + + again: + if (mfp->mntent_errs || mfp->mntent_softerrs >= ERR_MAX) + return NULL; + + /* read the next non-blank non-comment line */ + do { + if (fgets (buf, sizeof(buf), mfp->mntent_fp) == NULL) + return NULL; + + mfp->mntent_lineno++; + s = strchr (buf, '\n'); + if (s == NULL) { + /* Missing final newline? Otherwise extremely */ + /* long line - assume file was corrupted */ + if (feof(mfp->mntent_fp)) { + fprintf(stderr, _("[mntent]: warning: no final " + "newline at the end of %s\n"), + mfp->mntent_file); + s = strchr (buf, 0); + } else { + mfp->mntent_errs = 1; + goto err; + } + } + *s = 0; + if (--s >= buf && *s == '\r') + *s = 0; + s = skip_spaces(buf); + } while (*s == '\0' || *s == '#'); + + me.mnt_fsname = unmangle(s); + s = skip_nonspaces(s); + s = skip_spaces(s); + me.mnt_dir = unmangle(s); + s = skip_nonspaces(s); + s = skip_spaces(s); + me.mnt_type = unmangle(s); + s = skip_nonspaces(s); + s = skip_spaces(s); + me.mnt_opts = unmangle(s); + s = skip_nonspaces(s); + s = skip_spaces(s); + + if (isdigit(*s)) { + me.mnt_freq = atoi(s); + while(isdigit(*s)) s++; + } else + me.mnt_freq = 0; + if(*s && !is_space_or_tab(*s)) + goto err; + + s = skip_spaces(s); + if(isdigit(*s)) { + me.mnt_passno = atoi(s); + while(isdigit(*s)) s++; + } else + me.mnt_passno = 0; + if(*s && !is_space_or_tab(*s)) + goto err; + + /* allow more stuff, e.g. comments, on this line */ + + return &me; + + err: + mfp->mntent_softerrs++; + fprintf(stderr, _("[mntent]: line %d in %s is bad%s\n"), + mfp->mntent_lineno, mfp->mntent_file, + (mfp->mntent_errs || mfp->mntent_softerrs >= ERR_MAX) ? + _("; rest of file ignored") : ""); + goto again; +} diff --git a/support/nfs/rmtab.c b/support/nfs/rmtab.c new file mode 100644 index 0000000..154b26f --- /dev/null +++ b/support/nfs/rmtab.c @@ -0,0 +1,173 @@ +/* + * support/nfs/rmtab.c + * + * Handling for rmtab. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <unistd.h> +#include <errno.h> +#include <signal.h> +#include "nfslib.h" + +/* + * Colons in incoming IPv6 presentation addresses have to + * replaced with another character, since rmtab already + * uses colons to delineate fields. + * + * Use a printable character, but one that would never be + * found in a presentation address or domain name + */ +#define IPV6_COLON ';' + +#define LINELEN (2048) + +static FILE *rmfp = NULL; + +struct state_paths rmtab; + +int +setrmtabent(char *type) +{ + if (rmfp) + fclose(rmfp); + rmfp = fsetrmtabent(rmtab.statefn, type); + return (rmfp != NULL); +} + +FILE * +fsetrmtabent(char *fname, char *type) +{ + int readonly = !strcmp(type, "r"); + FILE *fp; + + if (!fname) + return NULL; + if ((fp = fopen(fname, type)) == NULL) { + xlog(L_ERROR, "can't open %s for %sing", fname, + readonly ? "read" : "writ"); + return NULL; + } + return fp; +} + +struct rmtabent * +getrmtabent(int log, long *pos) +{ + return fgetrmtabent(rmfp, log, pos); +} + +struct rmtabent * +fgetrmtabent(FILE *fp, int log, long *pos) +{ + static struct rmtabent re; + char *count, *host, *path, *c; + static char buf[LINELEN]; + + errno = 0; + if (!fp) + return NULL; + do { + if (pos) + *pos = ftell (fp); + if (fgets(buf, sizeof(buf)-1, fp) == NULL) + return NULL; + host = buf; + if ((path = strchr(host, '\n')) != NULL) + *path = '\0'; + if (!(path = strchr(host, ':'))) { + if (log) + xlog(L_ERROR, "malformed entry in rmtab file"); + errno = EINVAL; + return NULL; + } + *path++ = '\0'; + count = strchr(path, ':'); + if (count) { + *count++ = '\0'; + re.r_count = strtol (count, NULL, 0); + } + else + re.r_count = 1; + } while (0); + + strncpy(re.r_client, host, sizeof (re.r_client) - 1); + re.r_client[sizeof (re.r_client) - 1] = '\0'; + for (c = re.r_client; *c != '\0'; c++) + if (*c == IPV6_COLON) + *c = ':'; + + strncpy(re.r_path, path, sizeof (re.r_path) - 1); + re.r_path[sizeof (re.r_path) - 1] = '\0'; + + return &re; +} + +void +putrmtabent(struct rmtabent *rep, long *pos) +{ + fputrmtabent(rmfp, rep, pos); +} + +void +fputrmtabent(FILE *fp, struct rmtabent *rep, long *pos) +{ + static char buf[LINELEN]; + char *c; + + if (!fp || (pos && fseek (fp, *pos, SEEK_SET) != 0)) + return; + + /* + * To avoid confusing the token parser in fgetrmtabent(), + * convert colons in incoming IPv6 presentation addresses + * to semicolons. + */ + if (strlen(rep->r_client) > sizeof(buf)) { + xlog(L_ERROR, "client name too large"); + return; + } + strncpy(buf, rep->r_client, sizeof(buf)); + for (c = buf; *c != '\0'; c++) + if (*c == ':') + *c = IPV6_COLON; + + (void)fprintf(fp, "%s:%s:0x%.8x\n", buf, rep->r_path, rep->r_count); +} + +void +endrmtabent(void) +{ + fendrmtabent(rmfp); + rmfp = NULL; +} + +void +fendrmtabent(FILE *fp) +{ + if (fp) + fclose(fp); +} + +void +rewindrmtabent(void) +{ + if (rmfp) + rewind(rmfp); +} + +void +frewindrmtabent(FILE *fp) +{ + if (fp) + rewind (fp); +} diff --git a/support/nfs/rpc_socket.c b/support/nfs/rpc_socket.c new file mode 100644 index 0000000..5fabf5a --- /dev/null +++ b/support/nfs/rpc_socket.c @@ -0,0 +1,560 @@ +/* + * Generic RPC client socket-level APIs for nfs-utils + * + * Copyright (C) 2008 Oracle Corporation. All rights reserved. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA + * + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/types.h> +#include <sys/time.h> + +#include <stdbool.h> +#include <unistd.h> +#include <fcntl.h> +#include <errno.h> + +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#include <arpa/inet.h> + +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> + +#include "sockaddr.h" +#include "nfsrpc.h" + +#ifdef HAVE_LIBTIRPC +#include <netconfig.h> +#include <rpc/rpcb_prot.h> +#endif /* HAVE_LIBTIRPC */ + +/* + * If "-1" is specified in the tv_sec field, use these defaults instead. + */ +#define NFSRPC_TIMEOUT_UDP (3) +#define NFSRPC_TIMEOUT_TCP (10) + + +/* + * Set up an RPC client for communicating via a AF_LOCAL socket. + * + * @timeout is initialized upon return + * + * Returns a pointer to a prepared RPC client if successful; caller + * must destroy a non-NULL returned RPC client. Otherwise NULL, and + * rpc_createerr.cf_stat is set to reflect the error. + */ +static CLIENT *nfs_get_localclient(const struct sockaddr *sap, + const socklen_t salen, + const rpcprog_t program, + const rpcvers_t version, + struct timeval *timeout) +{ +#ifdef HAVE_LIBTIRPC + struct sockaddr_storage address; + const struct netbuf nbuf = { + .maxlen = sizeof(struct sockaddr_un), + .len = (size_t)salen, + .buf = &address, + }; +#else + (void) salen; +#endif /* HAVE_LIBTIRPC */ + CLIENT *client; + int sock; + + sock = socket(AF_LOCAL, SOCK_STREAM, 0); + if (sock == -1) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + return NULL; + } + + if (timeout->tv_sec == -1) + timeout->tv_sec = NFSRPC_TIMEOUT_TCP; + +#ifdef HAVE_LIBTIRPC + memcpy(nbuf.buf, sap, (size_t)salen); + client = clnt_vc_create(sock, &nbuf, program, version, 0, 0); +#else /* !HAVE_LIBTIRPC */ + client = clntunix_create((struct sockaddr_un *)sap, + program, version, &sock, 0, 0); +#endif /* !HAVE_LIBTIRPC */ + if (client != NULL) + CLNT_CONTROL(client, CLSET_FD_CLOSE, NULL); + else + (void)close(sock); + + return client; +} + +#ifdef HAVE_LIBTIRPC + +/* + * Bind a socket using an unused privileged source port. + * + * Returns zero on success, or returns -1 on error. errno is + * set to reflect the nature of the error. + */ +static int nfs_bindresvport(const int sock, const sa_family_t family) +{ + struct sockaddr_in sin = { + .sin_family = AF_INET, + .sin_addr.s_addr = htonl(INADDR_ANY), + }; + struct sockaddr_in6 sin6 = { + .sin6_family = AF_INET6, + .sin6_addr = IN6ADDR_ANY_INIT, + }; + + switch (family) { + case AF_INET: + return bindresvport_sa(sock, (struct sockaddr *)(char *)&sin); + case AF_INET6: + return bindresvport_sa(sock, (struct sockaddr *)(char *)&sin6); + } + + errno = EAFNOSUPPORT; + return -1; +} + +#else /* !HAVE_LIBTIRPC */ + +/* + * Bind a socket using an unused privileged source port. + * + * Returns zero on success, or returns -1 on error. errno is + * set to reflect the nature of the error. + */ +static int nfs_bindresvport(const int sock, const sa_family_t family) +{ + if (family != AF_INET) { + errno = EAFNOSUPPORT; + return -1; + } + + return bindresvport(sock, NULL); +} + +#endif /* !HAVE_LIBTIRPC */ + +/* + * Perform a non-blocking connect on the socket fd. + * + * @timeout is modified to contain the time remaining (i.e. time provided + * minus time elasped). + * + * Returns zero on success, or returns -1 on error. errno is + * set to reflect the nature of the error. + */ +static int nfs_connect_nb(const int fd, const struct sockaddr *sap, + const socklen_t salen, struct timeval *timeout) +{ + int flags, ret; + fd_set rset; + + flags = fcntl(fd, F_GETFL, 0); + if (flags < 0) + return -1; + + ret = fcntl(fd, F_SETFL, flags | O_NONBLOCK); + if (ret < 0) + return -1; + + /* + * From here on subsequent sys calls could change errno so + * we set ret = -errno to capture it in case we decide to + * use it later. + */ + ret = connect(fd, sap, salen); + if (ret < 0 && errno != EINPROGRESS && errno != EINTR) { + ret = -1; + goto done; + } + + if (ret == 0) + goto done; + + /* now wait */ + FD_ZERO(&rset); + FD_SET(fd, &rset); + + while ((ret = select(fd + 1, NULL, &rset, NULL, timeout)) < 0) { + if (errno != EINTR) { + ret = -1; + goto done; + } else { + continue; + } + } + if (ret == 0) { + errno = ETIMEDOUT; + ret = -1; + goto done; + } + + if (FD_ISSET(fd, &rset)) { + int status; + socklen_t len = (socklen_t)sizeof(ret); + + status = getsockopt(fd, SOL_SOCKET, SO_ERROR, &ret, &len); + if (status < 0) { + ret = -1; + goto done; + } + + /* Oops - something wrong with connect */ + if (ret != 0) { + errno = ret; + ret = -1; + } + } + +done: + (void)fcntl(fd, F_SETFL, flags); + return ret; +} + +/* + * Set up an RPC client for communicating via a datagram socket. + * A connected UDP socket is used to detect a missing remote + * listener as quickly as possible. + * + * @timeout is initialized upon return + * + * Returns a pointer to a prepared RPC client if successful; caller + * must destroy a non-NULL returned RPC client. Otherwise NULL, and + * rpc_createerr.cf_stat is set to reflect the error. + */ +static CLIENT *nfs_get_udpclient(const struct sockaddr *sap, + const socklen_t salen, + const rpcprog_t program, + const rpcvers_t version, + struct timeval *timeout, + const int resvport) +{ + CLIENT *client; + int ret = 0; + int sock = 0; +#ifdef HAVE_LIBTIRPC + struct sockaddr_storage address; + const struct netbuf nbuf = { + .maxlen = salen, + .len = salen, + .buf = &address, + }; + +#else /* !HAVE_LIBTIRPC */ + + if (sap->sa_family != AF_INET) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return NULL; + } +#endif /* !HAVE_LIBTIRPC */ + + sock = socket((int)sap->sa_family, SOCK_DGRAM, IPPROTO_UDP); + if (sock == -1) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + return NULL; + } + + if (resvport) { + ret = nfs_bindresvport(sock, sap->sa_family); + + if (ret < 0) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + (void)close(sock); + return NULL; + } + } + + if (timeout->tv_sec == -1) + timeout->tv_sec = NFSRPC_TIMEOUT_UDP; + + ret = nfs_connect_nb(sock, sap, salen, timeout); + if (ret != 0) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + (void)close(sock); + return NULL; + } + +#ifdef HAVE_LIBTIRPC + memcpy(nbuf.buf, sap, (size_t)salen); + client = clnt_dg_create(sock, &nbuf, program, version, 0, 0); +#else /* !HAVE_LIBTIRPC */ + client = clntudp_create((struct sockaddr_in *)sap, program, + version, *timeout, &sock); +#endif /* !HAVE_LIBTIRPC */ + if (client != NULL) { + struct timeval retry_timeout = { 1, 0 }; + CLNT_CONTROL(client, CLSET_RETRY_TIMEOUT, + (char *)&retry_timeout); + CLNT_CONTROL(client, CLSET_FD_CLOSE, NULL); + } else + (void)close(sock); + + return client; +} + +/* + * Set up and connect an RPC client for communicating via a stream socket. + * + * @timeout is initialized upon return + * + * Returns a pointer to a prepared and connected RPC client if + * successful; caller must destroy a non-NULL returned RPC client. + * Otherwise NULL, and rpc_createerr.cf_stat is set to reflect the + * error. + */ +static CLIENT *nfs_get_tcpclient(const struct sockaddr *sap, + const socklen_t salen, + const rpcprog_t program, + const rpcvers_t version, + struct timeval *timeout, + const int resvport) +{ + CLIENT *client; + int ret = 0; + int sock = 0; +#ifdef HAVE_LIBTIRPC + struct sockaddr_storage address; + const struct netbuf nbuf = { + .maxlen = salen, + .len = salen, + .buf = &address, + }; + +#else /* !HAVE_LIBTIRPC */ + + if (sap->sa_family != AF_INET) { + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return NULL; + } +#endif /* !HAVE_LIBTIRPC */ + + sock = socket((int)sap->sa_family, SOCK_STREAM, IPPROTO_TCP); + if (sock == -1) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + return NULL; + } + + if (resvport) { + ret = nfs_bindresvport(sock, sap->sa_family); + + if (ret < 0) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + (void)close(sock); + return NULL; + } + } + + if (timeout->tv_sec == -1) + timeout->tv_sec = NFSRPC_TIMEOUT_TCP; + + ret = nfs_connect_nb(sock, sap, salen, timeout); + if (ret != 0) { + rpc_createerr.cf_stat = RPC_SYSTEMERROR; + rpc_createerr.cf_error.re_errno = errno; + (void)close(sock); + return NULL; + } + +#ifdef HAVE_LIBTIRPC + memcpy(nbuf.buf, sap, (size_t)salen); + client = clnt_vc_create(sock, &nbuf, program, version, 0, 0); +#else /* !HAVE_LIBTIRPC */ + client = clnttcp_create((struct sockaddr_in *)sap, + program, version, &sock, 0, 0); +#endif /* !HAVE_LIBTIRPC */ + if (client != NULL) + CLNT_CONTROL(client, CLSET_FD_CLOSE, NULL); + else + (void)close(sock); + + return client; +} + +/** + * nfs_get_rpcclient - acquire an RPC client + * @sap: pointer to socket address of RPC server + * @salen: length of socket address + * @transport: IPPROTO_ value of transport protocol to use + * @program: RPC program number + * @version: RPC version number + * @timeout: pointer to request timeout (must not be NULL) + * + * Set up an RPC client for communicating with an RPC program @program + * and @version on the server @sap over @transport. An unprivileged + * source port is used. + * + * Returns a pointer to a prepared RPC client if successful, and + * @timeout is initialized; caller must destroy a non-NULL returned RPC + * client. Otherwise returns NULL, and rpc_createerr.cf_stat is set to + * reflect the error. + */ +CLIENT *nfs_get_rpcclient(const struct sockaddr *sap, + const socklen_t salen, + const unsigned short transport, + const rpcprog_t program, + const rpcvers_t version, + struct timeval *timeout) +{ + nfs_clear_rpc_createerr(); + + switch (sap->sa_family) { + case AF_LOCAL: + return nfs_get_localclient(sap, salen, program, + version, timeout); + case AF_INET: + case AF_INET6: + if (nfs_get_port(sap) == 0) { + rpc_createerr.cf_stat = RPC_UNKNOWNADDR; + return NULL; + } + break; + default: + rpc_createerr.cf_stat = RPC_UNKNOWNADDR; + return NULL; + } + + switch (transport) { + case IPPROTO_TCP: + return nfs_get_tcpclient(sap, salen, program, version, + timeout, 0); + case 0: + case IPPROTO_UDP: + return nfs_get_udpclient(sap, salen, program, version, + timeout, 0); + } + + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return NULL; +} + +/** + * nfs_get_priv_rpcclient - acquire an RPC client + * @sap: pointer to socket address of RPC server + * @salen: length of socket address + * @transport: IPPROTO_ value of transport protocol to use + * @program: RPC program number + * @version: RPC version number + * @timeout: pointer to request timeout (must not be NULL) + * + * Set up an RPC client for communicating with an RPC program @program + * and @version on the server @sap over @transport. A privileged + * source port is used. + * + * Returns a pointer to a prepared RPC client if successful, and + * @timeout is initialized; caller must destroy a non-NULL returned RPC + * client. Otherwise returns NULL, and rpc_createerr.cf_stat is set to + * reflect the error. + */ +CLIENT *nfs_get_priv_rpcclient(const struct sockaddr *sap, + const socklen_t salen, + const unsigned short transport, + const rpcprog_t program, + const rpcvers_t version, + struct timeval *timeout) +{ + nfs_clear_rpc_createerr(); + + switch (sap->sa_family) { + case AF_LOCAL: + return nfs_get_localclient(sap, salen, program, + version, timeout); + case AF_INET: + case AF_INET6: + if (nfs_get_port(sap) == 0) { + rpc_createerr.cf_stat = RPC_UNKNOWNADDR; + return NULL; + } + break; + default: + rpc_createerr.cf_stat = RPC_UNKNOWNADDR; + return NULL; + } + + switch (transport) { + case IPPROTO_TCP: + return nfs_get_tcpclient(sap, salen, program, version, + timeout, 1); + case 0: + case IPPROTO_UDP: + return nfs_get_udpclient(sap, salen, program, version, + timeout, 1); + } + + rpc_createerr.cf_stat = RPC_UNKNOWNPROTO; + return NULL; +} + +/** + * nfs_getrpcbyname - convert an RPC program name to a rpcprog_t + * @program: default program number to use if names not found in db + * @table: pointer to table of 'char *' names to try to find + * + * Returns program number of first name to be successfully looked + * up, or the default program number if all lookups fail. + */ +rpcprog_t nfs_getrpcbyname(const rpcprog_t program, const char *table[]) +{ +#ifdef HAVE_GETRPCBYNAME + struct rpcent *entry; + unsigned int i; + + if (table != NULL) + for (i = 0; table[i] != NULL; i++) { + entry = getrpcbyname(table[i]); + if (entry) + return (rpcprog_t)entry->r_number; + } +#endif /* HAVE_GETRPCBYNAME */ + + return program; +} + +/* + * AUTH_SYS doesn't allow more than 16 gids in the supplemental group list. + * If there are more than that, trying to determine which ones to include + * in the list is problematic. This function creates an auth handle that + * only has the primary gid in the supplemental gids list. It's intended to + * be used for protocols where credentials really don't matter much (the MNT + * protocol, for instance). + */ +AUTH * +nfs_authsys_create(void) +{ + char machname[MAXHOSTNAMELEN + 1]; + uid_t uid = geteuid(); + gid_t gid = getegid(); + + if (gethostname(machname, sizeof(machname)) == -1) + return NULL; + + return authunix_create(machname, uid, gid, 1, &gid); +} diff --git a/support/nfs/rpcdispatch.c b/support/nfs/rpcdispatch.c new file mode 100644 index 0000000..7329f41 --- /dev/null +++ b/support/nfs/rpcdispatch.c @@ -0,0 +1,69 @@ +/* + * support/nfs/rcpdispatch.c + * + * Generic RPC dispatcher. + * + * Copyright (C) 1995, 1996, Olaf Kirch <okir@monad.swb.de> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <rpc/rpc.h> +#include <rpc/pmap_clnt.h> +#include <signal.h> +#include <arpa/inet.h> +#include <netdb.h> +#include <string.h> +#include "rpcmisc.h" +#include "xlog.h" + +void +rpc_dispatch(struct svc_req *rqstp, SVCXPRT *transp, + struct rpc_dtable *dtable, int nvers, + void *argp, void *resp) +{ + struct rpc_dentry *dent; + int rq_vers = (int)rqstp->rq_vers; + + if (rq_vers < 1 || rq_vers > nvers) { + svcerr_progvers(transp, 1, nvers); + return; + } + dtable += (rq_vers - 1); + if (rqstp->rq_proc > dtable->nproc) { + svcerr_noproc(transp); + return; + } + + if (dtable->nproc <= rqstp->rq_proc) { + svcerr_noproc(transp); + return; + } + + dent = dtable->entries + rqstp->rq_proc; + + if (dent->func == NULL) { + svcerr_noproc(transp); + return; + } + + memset(argp, 0, dent->xdr_arg_size); + memset(resp, 0, dent->xdr_res_size); + + if (!svc_getargs(transp, dent->xdr_arg_fn, argp)) { + svcerr_decode(transp); + return; + } + + if ((dent->func)(rqstp, argp, resp) && resp != 0) { + if (!svc_sendreply(transp, dent->xdr_res_fn, (caddr_t)resp)) + svcerr_systemerr(transp); + } + if (!svc_freeargs(transp, dent->xdr_arg_fn, argp)) { + xlog(L_ERROR, "failed to free RPC arguments"); + exit (2); + } +} diff --git a/support/nfs/rpcmisc.c b/support/nfs/rpcmisc.c new file mode 100644 index 0000000..d84c04f --- /dev/null +++ b/support/nfs/rpcmisc.c @@ -0,0 +1,213 @@ +/* + * Miscellaneous functions for RPC service startup and shutdown. + * + * This code is partially snarfed from rpcgen -s tcp -s udp, + * partly written by Mark Shand, Donald Becker, and Rick + * Sladkey. It was tweaked slightly by Olaf Kirch to be + * usable by both unfsd and mountd. + * + * This software may be used for any purpose provided + * the above copyright notice is retained. It is supplied + * as is, with no warranty expressed or implied. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <sys/socket.h> +#include <rpc/rpc.h> +#include <rpc/pmap_clnt.h> +#include <netinet/in.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <signal.h> +#include <fcntl.h> +#include <memory.h> +#include <errno.h> +#include <unistd.h> +#include <time.h> +#include "nfslib.h" +#include "rpcmisc.h" + +#if SIZEOF_SOCKLEN_T - 0 == 0 +#define socklen_t int +#endif + +#define _RPCSVC_CLOSEDOWN 120 +int _rpcpmstart = 0; +unsigned int _rpcprotobits = (NFSCTL_UDPBIT|NFSCTL_TCPBIT); +int _rpcsvcdirty = 0; + +static void +closedown(int sig) +{ + (void) signal(sig, closedown); + + if (_rpcsvcdirty == 0) { + static int size; + int i, openfd; + + if (NFSCTL_TCPISSET(_rpcprotobits) == 0) + exit(0); + + if (size == 0) + size = getdtablesize(); + + for (i = 0, openfd = 0; i < size && openfd < 2; i++) + if (FD_ISSET(i, &svc_fdset)) + openfd++; + if (openfd <= 1) + exit(0); + } + + (void) alarm(_RPCSVC_CLOSEDOWN); +} + +/* + * Create listener socket for a given port + * + * Return an open network socket on success; otherwise return -1 + * if some error occurs. + */ +static int +makesock(int port, int proto) +{ + struct sockaddr_in sin; + int sock, sock_type, val; + + sock_type = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM; + sock = socket(AF_INET, sock_type, proto); + if (sock < 0) { + xlog(L_FATAL, "Could not make a socket: %s", + strerror(errno)); + return -1; + } + memset((char *) &sin, 0, sizeof(sin)); + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = htonl(INADDR_ANY); + sin.sin_port = htons(port); + + val = 1; + if (proto == IPPROTO_TCP) + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + &val, sizeof(val)) < 0) + xlog(L_ERROR, "setsockopt failed: %s", + strerror(errno)); + + if (bind(sock, (struct sockaddr *) &sin, sizeof(sin)) == -1) { + xlog(L_FATAL, "Could not bind name to socket: %s", + strerror(errno)); + close(sock); + return -1; + } + + return svcsock_nonblock(sock); +} + +void +rpc_init(char *name, int prog, int vers, + void (*dispatch)(struct svc_req *, register SVCXPRT *), + int defport) +{ + struct sockaddr_in saddr; + SVCXPRT *transp; + int sock; + socklen_t asize; + + asize = sizeof(saddr); + sock = 0; + if (getsockname(0, (struct sockaddr *) &saddr, &asize) == 0 + && saddr.sin_family == AF_INET) { + socklen_t ssize = sizeof(int); + int fdtype = 0; + if (getsockopt(0, SOL_SOCKET, SO_TYPE, + (char *)&fdtype, &ssize) == -1) + xlog(L_FATAL, "getsockopt failed: %s", strerror(errno)); + /* inetd passes a UDP socket or a listening TCP socket. + * listen will fail on a connected TCP socket(passed by rsh). + */ + if (!(fdtype == SOCK_STREAM && listen(0,5) == -1)) { + switch(fdtype) { + case SOCK_DGRAM: + NFSCTL_UDPSET(_rpcprotobits); + break; + case SOCK_STREAM: + NFSCTL_TCPSET(_rpcprotobits); + break; + default: + xlog(L_FATAL, "getsockopt returns bad socket type: %d", fdtype); + } + _rpcpmstart = 1; + } + } + if (!_rpcpmstart) { + pmap_unset(prog, vers); + sock = RPC_ANYSOCK; + } + + if (NFSCTL_UDPISSET(_rpcprotobits)) { + static SVCXPRT *last_transp = NULL; + + if (_rpcpmstart == 0) { + if (last_transp + && (!defport || defport == last_transp->xp_port)) { + transp = last_transp; + goto udp_transport; + } + if (defport == 0) + sock = RPC_ANYSOCK; + else + sock = makesock(defport, IPPROTO_UDP); + } + if (sock == RPC_ANYSOCK) + sock = svcudp_socket (prog); + transp = svcudp_create(sock); + if (transp == NULL) { + xlog(L_FATAL, "cannot create udp service."); + } + udp_transport: + if (!svc_register(transp, prog, vers, dispatch, IPPROTO_UDP)) { + xlog(L_FATAL, "unable to register (%s, %d, udp).", + name, vers); + } + last_transp = transp; + } + + if (NFSCTL_TCPISSET(_rpcprotobits)) { + static SVCXPRT *last_transp = NULL; + + if (_rpcpmstart == 0) { + if (last_transp + && (!defport || defport == last_transp->xp_port)) { + transp = last_transp; + goto tcp_transport; + } + if (defport == 0) + sock = RPC_ANYSOCK; + else + sock = makesock(defport, IPPROTO_TCP); + } + if (sock == RPC_ANYSOCK) + sock = svctcp_socket (prog, 1); + transp = svctcp_create(sock, 0, 0); + if (transp == NULL) { + xlog(L_FATAL, "cannot create tcp service."); + } + tcp_transport: + if (!svc_register(transp, prog, vers, dispatch, IPPROTO_TCP)) { + xlog(L_FATAL, "unable to register (%s, %d, tcp).", + name, vers); + } + last_transp = transp; + } + + if (_rpcpmstart) { + signal(SIGALRM, closedown); + alarm(_RPCSVC_CLOSEDOWN); + } +} diff --git a/support/nfs/strlcat.c b/support/nfs/strlcat.c new file mode 100644 index 0000000..0edee14 --- /dev/null +++ b/support/nfs/strlcat.c @@ -0,0 +1,78 @@ +/* $OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: strlcat.c,v 1.8 2001/05/13 15:40:15 deraadt Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <string.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "nfslib.h" + +/* + * Appends src to string dst of size siz (unlike strncat, siz is the + * full size of dst, not space left). At most siz-1 characters + * will be copied. Always NUL terminates (unless siz <= strlen(dst)). + * Returns strlen(src) + MIN(siz, strlen(initial dst)). + * If retval >= siz, truncation occurred. + */ +size_t +strlcat(char *dst, + const char *src, + size_t siz) +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + size_t dlen; + + /* Find the end of dst and adjust bytes left but don't go past end */ + while (n-- != 0 && *d != '\0') + d++; + dlen = d - dst; + n = siz - dlen; + + if (n == 0) + return(dlen + strlen(s)); + while (*s != '\0') { + if (n != 1) { + *d++ = *s; + n--; + } + s++; + } + *d = '\0'; + + return(dlen + (s - src)); /* count does not include NUL */ +} diff --git a/support/nfs/strlcpy.c b/support/nfs/strlcpy.c new file mode 100644 index 0000000..23e3ae9 --- /dev/null +++ b/support/nfs/strlcpy.c @@ -0,0 +1,74 @@ +/* $OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $ */ + +/* + * Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#if defined(LIBC_SCCS) && !defined(lint) +static char *rcsid = "$OpenBSD: strlcpy.c,v 1.5 2001/05/13 15:40:16 deraadt Exp $"; +#endif /* LIBC_SCCS and not lint */ + +#include <sys/types.h> +#include <string.h> + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif /* HAVE_CONFIG_H */ + +#include "nfslib.h" + +/* + * Copy src to string dst of size siz. At most siz-1 characters + * will be copied. Always NUL terminates (unless siz == 0). + * Returns strlen(src); if retval >= siz, truncation occurred. + */ +size_t +strlcpy(char *dst, + const char *src, + size_t siz) +{ + register char *d = dst; + register const char *s = src; + register size_t n = siz; + + /* Copy as many bytes as will fit */ + if (n != 0 && --n != 0) { + do { + if ((*d++ = *s++) == 0) + break; + } while (--n != 0); + } + + /* Not enough room in dst, add NUL and traverse rest of src */ + if (n == 0) { + if (siz != 0) + *d = '\0'; /* NUL-terminate dst */ + while (*s++) + ; + } + + return(s - src - 1); /* count does not include NUL */ +} diff --git a/support/nfs/svc_create.c b/support/nfs/svc_create.c new file mode 100644 index 0000000..976c2d2 --- /dev/null +++ b/support/nfs/svc_create.c @@ -0,0 +1,525 @@ +/* + * Copyright 2009 Oracle. All rights reserved. + * + * This file is part of nfs-utils. + * + * nfs-utils is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * nfs-utils is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with nfs-utils. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <memory.h> +#include <signal.h> +#include <unistd.h> +#include <errno.h> +#include <netdb.h> +#include "nfslib.h" + +#include <netinet/in.h> + +#include <sys/socket.h> +#include <sys/resource.h> + +#include <rpc/rpc.h> +#include <rpc/svc.h> + +#ifdef HAVE_TCP_WRAPPER +#include "tcpwrapper.h" +#endif + +#include "sockaddr.h" +#include "rpcmisc.h" +#include "xlog.h" + +#ifdef HAVE_LIBTIRPC + +#include <rpc/rpc_com.h> + +#define SVC_CREATE_XPRT_CACHE_SIZE (8) +static SVCXPRT *svc_create_xprt_cache[SVC_CREATE_XPRT_CACHE_SIZE] = { NULL, }; + +/* + * Cache an SVC xprt, in case there are more programs or versions to + * register against it. + */ +static void +svc_create_cache_xprt(SVCXPRT *xprt) +{ + unsigned int i; + + /* Check if we've already got this one... */ + for (i = 0; i < SVC_CREATE_XPRT_CACHE_SIZE; i++) + if (svc_create_xprt_cache[i] == xprt) + return; + + /* No, we don't. Cache it. */ + for (i = 0; i < SVC_CREATE_XPRT_CACHE_SIZE; i++) + if (svc_create_xprt_cache[i] == NULL) { + svc_create_xprt_cache[i] = xprt; + return; + } + + xlog(L_ERROR, "%s: Failed to cache an xprt", __func__); +} + +/* + * Find a previously cached SVC xprt structure with the given bind address + * and transport semantics. + * + * Returns pointer to a cached SVC xprt. + * + * If no matching SVC XPRT can be found, NULL is returned. + */ +static SVCXPRT * +svc_create_find_xprt(const struct sockaddr *bindaddr, const struct netconfig *nconf) +{ + unsigned int i; + + for (i = 0; i < SVC_CREATE_XPRT_CACHE_SIZE; i++) { + SVCXPRT *xprt = svc_create_xprt_cache[i]; + struct sockaddr *sap; + + if (xprt == NULL) + continue; + if (strcmp(nconf->nc_netid, xprt->xp_netid) != 0) + continue; + sap = (struct sockaddr *)xprt->xp_ltaddr.buf; + if (!nfs_compare_sockaddr(bindaddr, sap)) + continue; + return xprt; + } + return NULL; +} + +/* + * Set up an appropriate bind address, given @port and @nconf. + * + * Returns getaddrinfo(3) results if successful. Caller must + * invoke freeaddrinfo(3) on these results. + * + * Otherwise NULL is returned if an error occurs. + */ +__attribute__((__malloc__)) +static struct addrinfo * +svc_create_bindaddr(struct netconfig *nconf, const uint16_t port) +{ + struct addrinfo *ai = NULL; + struct addrinfo hint = { + .ai_flags = AI_PASSIVE | AI_NUMERICSERV, + }; + char buf[8]; + int error; + + if (strcmp(nconf->nc_protofmly, NC_INET) == 0) + hint.ai_family = AF_INET; +#ifdef IPV6_SUPPORTED + else if (strcmp(nconf->nc_protofmly, NC_INET6) == 0) + hint.ai_family = AF_INET6; +#endif /* IPV6_SUPPORTED */ + else { + xlog(L_ERROR, "Unrecognized bind address family: %s", + nconf->nc_protofmly); + return NULL; + } + + if (strcmp(nconf->nc_proto, NC_UDP) == 0) + hint.ai_protocol = (int)IPPROTO_UDP; + else if (strcmp(nconf->nc_proto, NC_TCP) == 0) + hint.ai_protocol = (int)IPPROTO_TCP; + else { + xlog(L_ERROR, "Unrecognized bind address protocol: %s", + nconf->nc_proto); + return NULL; + } + + (void)snprintf(buf, sizeof(buf), "%u", port); + error = getaddrinfo(NULL, buf, &hint, &ai); + if (error != 0) { + xlog(L_ERROR, "Failed to construct bind address: %s", + gai_strerror(error)); + return NULL; + } + + return ai; +} + +/* + * Create a listener socket on a specific bindaddr, and set + * special socket options to allow it to share the same port + * as other listeners. + * + * Returns an open, bound, and possibly listening network + * socket on success. + * + * Otherwise returns -1 if some error occurs. + */ +static int +svc_create_sock(const struct sockaddr *sap, socklen_t salen, + struct netconfig *nconf) +{ + int fd, type, protocol; + int one = 1; + + switch(nconf->nc_semantics) { + case NC_TPI_CLTS: + type = SOCK_DGRAM; + break; + case NC_TPI_COTS_ORD: + type = SOCK_STREAM; + break; + default: + xlog(D_GENERAL, "%s: Unrecognized bind address semantics: %lu", + __func__, nconf->nc_semantics); + return -1; + } + + if (strcmp(nconf->nc_proto, NC_UDP) == 0) + protocol = (int)IPPROTO_UDP; + else if (strcmp(nconf->nc_proto, NC_TCP) == 0) + protocol = (int)IPPROTO_TCP; + else { + xlog(D_GENERAL, "%s: Unrecognized bind address protocol: %s", + __func__, nconf->nc_proto); + return -1; + } + + fd = socket((int)sap->sa_family, type, protocol); + if (fd == -1) { + xlog(L_ERROR, "Could not make a socket: (%d) %m", + errno); + return -1; + } + +#ifdef IPV6_SUPPORTED + if (sap->sa_family == AF_INET6) { + if (setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, + &one, sizeof(one)) == -1) { + xlog(L_ERROR, "Failed to set IPV6_V6ONLY: (%d) %m", + errno); + (void)close(fd); + return -1; + } + } +#endif /* IPV6_SUPPORTED */ + + if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, + &one, sizeof(one)) == -1) { + xlog(L_ERROR, "Failed to set SO_REUSEADDR: (%d) %m", + errno); + (void)close(fd); + return -1; + } + + if (bind(fd, sap, salen) == -1) { + xlog(L_ERROR, "Could not bind socket: (%d) %m", + errno); + (void)close(fd); + return -1; + } + + if (nconf->nc_semantics == NC_TPI_COTS_ORD) + if (listen(fd, SOMAXCONN) == -1) { + xlog(L_ERROR, "Could not listen on socket: (%d) %m", + errno); + (void)close(fd); + return -1; + } + + return fd; +} + +/* + * The simple case is allowing the TI-RPC library to create a + * transport itself, given just the bind address and transport + * semantics. + * + * Our local xprt cache is ignored in this path, since the + * caller is not interested in sharing listeners or ports, and + * the library automatically avoids ports already in use. + * + * Returns the count of started listeners (one or zero). + */ +static unsigned int +svc_create_nconf_rand_port(const char *name, const rpcprog_t program, + const rpcvers_t version, + void (*dispatch)(struct svc_req *, SVCXPRT *), + struct netconfig *nconf) +{ + struct t_bind bindaddr; + struct addrinfo *ai; + SVCXPRT *xprt; + + ai = svc_create_bindaddr(nconf, 0); + if (ai == NULL) + return 0; + + bindaddr.addr.buf = ai->ai_addr; + bindaddr.qlen = SOMAXCONN; + + xprt = svc_tli_create(RPC_ANYFD, nconf, &bindaddr, 0, 0); + nfs_freeaddrinfo(ai); + if (xprt == NULL) { + xlog(L_ERROR, "Failed to create listener xprt " + "(%s, %u, %s)", name, version, nconf->nc_netid); + return 0; + } + if (svcsock_nonblock(xprt->xp_fd) < 0) { + /* close() already done by svcsock_nonblock() */ + xprt->xp_fd = RPC_ANYFD; + SVC_DESTROY(xprt); + return 0; + } + + rpc_createerr.cf_stat = rpc_createerr.cf_error.re_errno = 0; + if (!svc_reg(xprt, program, version, dispatch, nconf)) { + /* svc_reg(3) destroys @xprt in this case */ + xlog(L_ERROR, "Failed to register (%s, %u, %s): %s", + name, version, nconf->nc_netid, + clnt_spcreateerror("svc_reg() err")); + return 0; + } + + return 1; +} + +/* + * If a port is specified on the command line, that port value will be + * the same for all listeners created here. Create each listener + * socket in advance and set SO_REUSEADDR, rather than allowing the + * RPC library to create the listeners for us on a randomly chosen + * port via svc_tli_create(RPC_ANYFD). + * + * Some callers want to listen for more than one RPC version using the + * same port number. For example, mountd could want to listen for MNT + * version 1, 2, and 3 requests. This means mountd must use the same + * set of listener sockets for multiple RPC versions, since, on one + * system, you can't have two listener sockets with the exact same + * bind address (and port) and transport protocol. + * + * To accomplish this, this function caches xprts as they are created. + * This cache is checked to see if a previously created xprt can be + * used, before creating a new xprt for this [program, version]. If + * there is a cached xprt with the same bindaddr and transport + * semantics, we simply register the new version with that xprt, + * rather than creating a fresh xprt for it. + * + * The xprt cache implemented here is local to a process. Two + * separate RPC daemons can not share a set of listeners. + * + * Returns the count of started listeners (one or zero). + */ +static unsigned int +svc_create_nconf_fixed_port(const char *name, const rpcprog_t program, + const rpcvers_t version, + void (*dispatch)(struct svc_req *, SVCXPRT *), + const uint16_t port, struct netconfig *nconf) +{ + struct addrinfo *ai; + SVCXPRT *xprt; + + ai = svc_create_bindaddr(nconf, port); + if (ai == NULL) + return 0; + + xprt = svc_create_find_xprt(ai->ai_addr, nconf); + if (xprt == NULL) { + int fd; + + fd = svc_create_sock(ai->ai_addr, ai->ai_addrlen, nconf); + fd = svcsock_nonblock(fd); + if (fd == -1) + goto out_free; + + xprt = svc_tli_create(fd, nconf, NULL, 0, 0); + if (xprt == NULL) { + xlog(D_GENERAL, "Failed to create listener xprt " + "(%s, %u, %s)", name, version, nconf->nc_netid); + (void)close(fd); + goto out_free; + } + } + + if (!svc_reg(xprt, program, version, dispatch, nconf)) { + /* svc_reg(3) destroys @xprt in this case */ + xlog(D_GENERAL, "Failed to register (%s, %u, %s)", + name, version, nconf->nc_netid); + goto out_free; + } + + svc_create_cache_xprt(xprt); + + nfs_freeaddrinfo(ai); + return 1; + +out_free: + nfs_freeaddrinfo(ai); + return 0; +} + +static unsigned int +svc_create_nconf(const char *name, const rpcprog_t program, + const rpcvers_t version, + void (*dispatch)(struct svc_req *, SVCXPRT *), + const uint16_t port, struct netconfig *nconf) +{ + if (port != 0) + return svc_create_nconf_fixed_port(name, program, + version, dispatch, port, nconf); + + return svc_create_nconf_rand_port(name, program, + version, dispatch, nconf); +} + +/** + * nfs_svc_create - start up RPC svc listeners + * @name: C string containing name of new service + * @program: RPC program number to register + * @version: RPC version number to register + * @dispatch: address of function that handles incoming RPC requests + * @port: if not zero, transport listens on this port + * + * Sets up network transports for receiving RPC requests, and starts + * the RPC dispatcher. Returns the number of started network transports. + */ +unsigned int +nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version, + void (*dispatch)(struct svc_req *, SVCXPRT *), + const uint16_t port) +{ + const struct sigaction create_sigaction = { + .sa_handler = SIG_IGN, + }; + int maxrec = RPC_MAXDATASIZE; + unsigned int visible, up, servport; + struct netconfig *nconf; + void *handlep; + + /* + * Ignore SIGPIPE to avoid exiting sideways when peers + * close their TCP connection while we're trying to reply + * to them. + */ + (void)sigaction(SIGPIPE, &create_sigaction, NULL); + + /* + * Setting MAXREC also enables non-blocking mode for tcp connections. + * This avoids DOS attacks by a client sending many requests but never + * reading the reply: + * - if a second request already is present for reading in the socket, + * after the first request just was read, libtirpc will break the + * connection. Thus an attacker can't simply send requests as fast as + * he can without waiting for the response. + * - if the write buffer of the socket is full, the next write() will + * fail with EAGAIN. libtirpc will retry the write in a loop for max. + * 2 seconds. If write still fails, the connection will be closed. + */ + rpc_control(RPC_SVC_CONNMAXREC_SET, &maxrec); + + handlep = setnetconfig(); + if (handlep == NULL) { + xlog(L_ERROR, "Failed to access local netconfig database: %s", + nc_sperror()); + return 0; + } + + visible = 0; + up = 0; + while ((nconf = getnetconfig(handlep)) != NULL) { + if (!(nconf->nc_flag & NC_VISIBLE)) + continue; + visible++; + + if (!strcmp(nconf->nc_proto, NC_UDP) && !NFSCTL_UDPISSET(_rpcprotobits)) + continue; + + if (!strcmp(nconf->nc_proto, NC_TCP) && !NFSCTL_TCPISSET(_rpcprotobits)) + continue; + + if (port == 0) + servport = getservport(program, nconf->nc_proto); + else + servport = port; + + up += svc_create_nconf(name, program, version, dispatch, + servport, nconf); + } + + if (visible == 0) + xlog(L_ERROR, "Failed to find any visible netconfig entries"); + + if (endnetconfig(handlep) == -1) + xlog(L_ERROR, "Failed to close local netconfig database: %s", + nc_sperror()); + + return up; +} + +/** + * nfs_svc_unregister - remove service registrations from local rpcbind database + * @program: RPC program number to unregister + * @version: RPC version number to unregister + * + * Removes all registrations for [ @program, @version ] . + */ +void +nfs_svc_unregister(const rpcprog_t program, const rpcvers_t version) +{ + if (rpcb_unset(program, version, NULL) == FALSE) + xlog(D_GENERAL, "Failed to unregister program %lu, version %lu", + (unsigned long)program, (unsigned long)version); +} + +#else /* !HAVE_LIBTIRPC */ + +/** + * nfs_svc_create - start up RPC svc listeners + * @name: C string containing name of new service + * @program: RPC program number to register + * @version: RPC version number to register + * @dispatch: address of function that handles incoming RPC requests + * @port: if not zero, transport listens on this port + * + * Sets up network transports for receiving RPC requests, and starts + * the RPC dispatcher. Returns the number of started network transports. + */ +unsigned int +nfs_svc_create(char *name, const rpcprog_t program, const rpcvers_t version, + void (*dispatch)(struct svc_req *, SVCXPRT *), + const uint16_t port) +{ + rpc_init(name, (int)program, (int)version, dispatch, (int)port); + return 1; +} + +/** + * nfs_svc_unregister - remove service registrations from local rpcbind database + * @program: RPC program number to unregister + * @version: RPC version number to unregister + * + * Removes all registrations for [ @program, @version ] . + */ +void +nfs_svc_unregister(const rpcprog_t program, const rpcvers_t version) +{ + if (pmap_unset((unsigned long)program, (unsigned long)version) == FALSE) + xlog(D_GENERAL, "Failed to unregister program %lu, version %lu", + (unsigned long)program, (unsigned long)version); +} + +#endif /* !HAVE_LIBTIRPC */ diff --git a/support/nfs/svc_socket.c b/support/nfs/svc_socket.c new file mode 100644 index 0000000..2e8fe1a --- /dev/null +++ b/support/nfs/svc_socket.c @@ -0,0 +1,218 @@ +/* Copyright (C) 2002 Free Software Foundation, Inc. + This file is part of the GNU C Library. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 0211-1301 USA */ + +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <netdb.h> +#include <rpc/rpc.h> +#include <sys/socket.h> +#include <fcntl.h> +#include <errno.h> +#include "xlog.h" +#include "rpcmisc.h" +#include "nfslib.h" + +#include "config.h" + +#ifdef _LIBC +# include <libintl.h> +#else +# ifndef _ +# define _(s) (s) +# endif +# define __socket(d, t, p) socket ((d), (t), (p)) +# define __close(f) close ((f)) +#endif + +int getservport(u_long number, const char *proto) +{ + char servdata[1024]; + struct rpcent *rpcp; + struct servent servbuf, *servp = NULL; + int ret = 0; +#ifdef HAVE_GETRPCBYNUMBER_R + char rpcdata[1024]; + struct rpcent rpcbuf; + + ret = getrpcbynumber_r(number, &rpcbuf, rpcdata, sizeof rpcdata, + &rpcp); +#else + rpcp = getrpcbynumber(number); +#endif + + if (ret == 0 && rpcp != NULL) { + /* First try name. */ + ret = getservbyname_r(rpcp->r_name, proto, &servbuf, servdata, + sizeof servdata, &servp); + if ((ret != 0 || servp == NULL) && rpcp->r_aliases) { + const char **a; + + /* Then we try aliases. */ + for (a = (const char **) rpcp->r_aliases; *a != NULL; a++) { + ret = getservbyname_r(*a, proto, &servbuf, servdata, + sizeof servdata, &servp); + if (ret == 0 && servp != NULL) + break; + } + } + } + + if (ret == 0 && servp != NULL) + return ntohs(servp->s_port); + + return 0; +} + +int +svcsock_nonblock(int sock) +{ + int flags; + + if (sock < 0) + return sock; + + /* This socket might be shared among multiple processes + * if mountd is run multi-threaded. So it is safest to + * make it non-blocking, else all threads might wake + * one will get the data, and the others will block + * indefinitely. + * In all cases, transaction on this socket are atomic + * (accept for TCP, packet-read and packet-write for UDP) + * so O_NONBLOCK will not confuse unprepared code causing + * it to corrupt messages. + * It generally safest to have O_NONBLOCK when doing an accept + * as if we get a RST after the SYN and before accept runs, + * we can block despite being told there was an acceptable + * connection. + */ + if ((flags = fcntl(sock, F_GETFL)) < 0) + xlog(L_ERROR, "svc_socket: can't get socket flags: %m"); + else if (fcntl(sock, F_SETFL, flags|O_NONBLOCK) < 0) + xlog(L_ERROR, "svc_socket: can't set socket flags: %m"); + else + return sock; + + (void) __close(sock); + return -1; +} + +static int +svc_socket (u_long number, int type, int protocol, int reuse) +{ + struct sockaddr_in addr; + socklen_t len = sizeof (struct sockaddr_in); + int sock, ret; + const char *proto = protocol == IPPROTO_TCP ? "tcp" : "udp"; + + if ((sock = __socket (AF_INET, type, protocol)) < 0) + { + xlog(L_ERROR, "svc_socket: socket creation problem: %m"); + return sock; + } + + if (reuse) + { + ret = 1; + ret = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, &ret, + sizeof (ret)); + if (ret < 0) + { + xlog(L_ERROR, "svc_socket: socket reuse problem: %m"); + (void) __close(sock); + return ret; + } + } + + memset (&addr, 0, sizeof (addr)); + addr.sin_family = AF_INET; + addr.sin_port = htons(getservport(number, proto)); + + if (bind(sock, (struct sockaddr *) &addr, len) < 0) + { + xlog(L_ERROR, "svc_socket: bind problem: %m"); + (void) __close(sock); + sock = -1; + } + + return svcsock_nonblock(sock); +} + +/* + * Create and bind a TCP socket based on program number + */ +int +svctcp_socket (u_long number, int reuse) +{ + return svc_socket (number, SOCK_STREAM, IPPROTO_TCP, reuse); +} + +/* + * Create and bind a UDP socket based on program number + */ +int +svcudp_socket (u_long number) +{ + return svc_socket (number, SOCK_DGRAM, IPPROTO_UDP, FALSE); +} + +#ifdef TEST +static int +check (u_long number, u_short port, int protocol, int reuse) +{ + int socket; + int result; + struct sockaddr_in addr; + socklen_t len = sizeof (struct sockaddr_in); + + if (protocol == IPPROTO_TCP) + socket = svctcp_socket (number, reuse); + else + socket = svcudp_socket (number); + + if (socket < 0) + return 1; + + result = getsockname (socket, (struct sockaddr *) &addr, &len); + if (result == 0) + { + if (port != 0 && ntohs (addr.sin_port) != port) + printf ("Program: %ld, expect port: %d, got: %d\n", + number, port, ntohs (addr.sin_port)); + else + printf ("Program: %ld, port: %d\n", + number, ntohs (addr.sin_port)); + } + + close (socket); + return result; +} + +int +main (void) +{ + int result = 0; + + result += check (100001, 0, IPPROTO_TCP, 0); + result += check (100001, 0, IPPROTO_UDP, 0); + result += check (100003, 2049, IPPROTO_TCP, 1); + result += check (100003, 2049, IPPROTO_UDP, 1); + + return result; +} +#endif diff --git a/support/nfs/wildmat.c b/support/nfs/wildmat.c new file mode 100644 index 0000000..437b2d1 --- /dev/null +++ b/support/nfs/wildmat.c @@ -0,0 +1,182 @@ +/* $Revision: 0.2.18.1 $ +** +** Do shell-style pattern matching for ?, \, [], and * characters. +** Might not be robust in face of malformed patterns; e.g., "foo[a-" +** could cause a segmentation violation. It is 8bit clean. +** +** Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986. +** Rich $alz is now <rsalz@osf.org>. +** April, 1991: Replaced mutually-recursive calls with in-line code +** for the star character. +** +** Special thanks to Lars Mathiesen <thorinn@diku.dk> for the ABORT code. +** This can greatly speed up failing wildcard patterns. For example: +** pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-* +** text 1: -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1 +** text 2: -adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1 +** Text 1 matches with 51 calls, while text 2 fails with 54 calls. Without +** the ABORT code, it takes 22310 calls to fail. Ugh. The following +** explanation is from Lars: +** The precondition that must be fulfilled is that DoMatch will consume +** at least one character in text. This is true if *p is neither '*' nor +** '\0'.) The last return has ABORT instead of FALSE to avoid quadratic +** behaviour in cases like pattern "*a*b*c*d" with text "abcxxxxx". With +** FALSE, each star-loop has to run to the end of the text; with ABORT +** only the last one does. +** +** Once the control of one instance of DoMatch enters the star-loop, that +** instance will return either TRUE or ABORT, and any calling instance +** will therefore return immediately after (without calling recursively +** again). In effect, only one star-loop is ever active. It would be +** possible to modify the code to maintain this context explicitly, +** eliminating all recursive calls at the cost of some complication and +** loss of clarity (and the ABORT stuff seems to be unclear enough by +** itself). I think it would be unwise to try to get this into a +** released version unless you have a good test data base to try it out +** on. +*/ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <ctype.h> +#include "nfslib.h" + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#define ABORT -1 + + + /* What character marks an inverted character class? */ +#define NEGATE_CLASS '^' + /* Is "*" a common pattern? */ +#define OPTIMIZE_JUST_STAR + /* Do tar(1) matching rules, which ignore a trailing slash? */ +#undef MATCH_TAR_PATTERN + + +/* +** Match text and p, return TRUE, FALSE, or ABORT. +*/ +static int +DoMatch(char *text, char *p) +{ + register int last; + register int matched; + register int reverse; + + for ( ; *p; text++, p++) { + if (*text == '\0' && *p != '*') + return ABORT; + switch (*p) { + case '\\': + /* Literal match with following character. */ + p++; + /* FALLTHROUGH */ + default: + if (toupper (*text) != toupper (*p)) + return FALSE; + continue; + case '?': + /* Match anything. */ + continue; + case '*': + while (*++p == '*') + /* Consecutive stars act just like one. */ + continue; + if (*p == '\0') + /* Trailing star matches everything. */ + return TRUE; + while (*text) + if ((matched = DoMatch(text++, p)) != FALSE) + return matched; + return ABORT; + case '[': + reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE; + if (reverse) + /* Inverted character class. */ + p++; + matched = FALSE; + if (p[1] == ']' || p[1] == '-') + if (toupper (*++p) == toupper(*text)) + matched = TRUE; + for (last = *p; *++p && *p != ']'; last = *p) + /* This next line requires a good C compiler. */ + if (*p == '-' && p[1] != ']' + ? *text <= *++p && *text >= last + : toupper (*text) == toupper (*p)) + matched = TRUE; + if (matched == reverse) + return FALSE; + continue; + } + } + +#ifdef MATCH_TAR_PATTERN + if (*text == '/') + return TRUE; +#endif /* MATCH_TAR_ATTERN */ + return *text == '\0'; +} + + +/* +** User-level routine. Returns TRUE or FALSE. +*/ +int +wildmat(char *text, char *p) +{ +#ifdef OPTIMIZE_JUST_STAR + if (p[0] == '*' && p[1] == '\0') + return TRUE; +#endif /* OPTIMIZE_JUST_STAR */ + return DoMatch(text, p) == TRUE; +} + + + +#if defined(TEST) +#include <stdio.h> + +/* Yes, we use gets not fgets. Sue me. */ +extern char *gets(); + + +int +main() +{ + char p[80]; + char text[80]; + + printf("Wildmat tester. Enter pattern, then strings to test.\n"); + printf("A blank line gets prompts for a new pattern; a blank pattern\n"); + printf("exits the program.\n"); + + for ( ; ; ) { + printf("\nEnter pattern: "); + (void)fflush(stdout); + if (gets(p) == NULL || p[0] == '\0') + break; + for ( ; ; ) { + printf("Enter text: "); + (void)fflush(stdout); + if (gets(text) == NULL) + exit(0); + if (text[0] == '\0') + /* Blank line; go back and get a new pattern. */ + break; + printf(" %s\n", wildmat(text, p) ? "YES" : "NO"); + } + } + + exit(0); + /* NOTREACHED */ +} +#endif /* defined(TEST) */ diff --git a/support/nfs/xcommon.c b/support/nfs/xcommon.c new file mode 100644 index 0000000..3989f0b --- /dev/null +++ b/support/nfs/xcommon.c @@ -0,0 +1,191 @@ +/* + * xcommon.c - various functions put together to avoid basic error checking. + * + * added fcntl locking by Kjetil T. (kjetilho@math.uio.no) - aeb, 950927 + * + * 1999-02-22 Arkadiusz Miskiewicz <misiek@pld.ORG.PL> + * - added Native Language Support + * + * 2006-06-06 Amit Gud <agud@redhat.com> + * - Moved code snippets here from mount/sundries.c of util-linux + * and merged code from support/nfs/xmalloc.c by Olaf Kirch <okir@monad.swb.de> here. + */ + +#include <unistd.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "xcommon.h" +#include "nls.h" /* _() */ + +void (*at_die)(void ) = NULL; + +char * +xstrndup (const char *s, int n) { + char *t; + + if (s == NULL) + die (EX_SOFTWARE, _("bug in xstrndup call")); + + t = xmalloc(n+1); + strncpy(t,s,n); + t[n] = 0; + + return t; +} + +char * +xstrconcat2 (const char *s, const char *t) { + char *res; + + if (!s) s = ""; + if (!t) t = ""; + res = xmalloc(strlen(s) + strlen(t) + 1); + strcpy(res, s); + strcat(res, t); + return res; +} + +/* frees its first arg - typical use: s = xstrconcat3(s,t,u); */ +char * +xstrconcat3 (const char *s, const char *t, const char *u) { + char *res; + + int dofree = 1; + + if (!s) s = "", dofree=0; + if (!t) t = ""; + if (!u) u = ""; + res = xmalloc(strlen(s) + strlen(t) + strlen(u) + 1); + strcpy(res, s); + strcat(res, t); + strcat(res, u); + if (dofree) + free((void *) s); + return res; +} + +/* frees its first arg - typical use: s = xstrconcat4(s,t,u,v); */ +char * +xstrconcat4 (const char *s, const char *t, const char *u, const char *v) { + char *res; + + int dofree = 1; + + if (!s) s = "", dofree=0; + if (!t) t = ""; + if (!u) u = ""; + if (!v) v = ""; + res = xmalloc(strlen(s) + strlen(t) + strlen(u) + strlen(v) + 1); + strcpy(res, s); + strcat(res, t); + strcat(res, u); + strcat(res, v); + if (dofree) + free((void *) s); + return res; +} + +/* Non-fatal error. Print message and return. */ +/* (print the message in a single printf, in an attempt + to avoid mixing output of several threads) */ +void +nfs_error (const char *fmt, ...) { + va_list args; + char *fmt2; + + fmt2 = xstrconcat2 (fmt, "\n"); + va_start (args, fmt); + vfprintf (stderr, fmt2, args); + va_end (args); + free (fmt2); +} + +/* Make a canonical pathname from PATH. Returns a freshly malloced string. + It is up the *caller* to ensure that the PATH is sensible. i.e. + canonicalize ("/dev/fd0/.") returns "/dev/fd0" even though ``/dev/fd0/.'' + is not a legal pathname for ``/dev/fd0''. Anything we cannot parse + we return unmodified. */ +char *canonicalize (const char *path) { + char canonical[PATH_MAX+2]; + + if (path == NULL) + return NULL; + +#if 1 + if (streq(path, "none") || + streq(path, "proc") || + streq(path, "devpts")) + return xstrdup(path); +#endif + if (realpath (path, canonical)) + return xstrdup(canonical); + + return xstrdup(path); +} + +/* Fatal error. Print message and exit. */ +void +die(int err, const char *fmt, ...) { + va_list args; + + va_start(args, fmt); + vfprintf(stderr, fmt, args); + fprintf(stderr, "\n"); + va_end(args); + + if (at_die) + (*at_die)(); + + exit(err); +} + +static void +die_if_null(void *t) { + if (t == NULL) + die(EX_SYSERR, _("not enough memory")); +} + +void * +xmalloc (size_t size) { + void *t; + + if (size == 0) + return NULL; + + t = malloc(size); + die_if_null(t); + + return t; +} + +void * +xrealloc (void *p, size_t size) { + void *t; + + t = realloc(p, size); + die_if_null(t); + + return t; +} + +void +xfree(void *ptr) +{ + free(ptr); +} + +char * +xstrdup (const char *s) { + char *t; + + if (s == NULL) + return NULL; + + t = strdup(s); + die_if_null(t); + + return t; +} diff --git a/support/nfs/xio.c b/support/nfs/xio.c new file mode 100644 index 0000000..6962751 --- /dev/null +++ b/support/nfs/xio.c @@ -0,0 +1,170 @@ +/* + * support/nfs/xio.c + * + * Simple I/O functions for the parsing of /etc/exports and /etc/nfsclients. + * + * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de> + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <fcntl.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> +#include <signal.h> +#include <unistd.h> +#include <errno.h> +#include "xmalloc.h" +#include "xlog.h" +#include "xio.h" + +XFILE * +xfopen(char *fname, char *type) +{ + XFILE *xfp; + FILE *fp; + + if (!(fp = fopen(fname, type))) + return NULL; + xfp = (XFILE *) xmalloc(sizeof(*xfp)); + xfp->x_fp = fp; + xfp->x_line = 1; + + return xfp; +} + +void +xfclose(XFILE *xfp) +{ + fclose(xfp->x_fp); + xfree(xfp); +} + +int +xflock(char *fname, char *type) +{ + int readonly = !strcmp(type, "r"); + struct flock fl = { readonly? F_RDLCK : F_WRLCK, SEEK_SET, 0, 0, 0 }; + int fd; + + if (readonly) + fd = open(fname, (O_RDONLY|O_CREAT), 0600); + else + fd = open(fname, (O_RDWR|O_CREAT), 0600); + if (fd < 0) { + xlog(L_WARNING, "could not open %s for locking: errno %d (%s)", + fname, errno, strerror(errno)); + return -1; + } + + if (fcntl(fd, F_SETLKW, &fl) < 0) { + xlog(L_WARNING, "failed to lock %s: errno %d (%s)", + fname, errno, strerror(errno)); + close(fd); + fd = -1; + } + + return fd; +} + +void +xfunlock(int fd) +{ + close(fd); +} + +#define isoctal(x) (isdigit(x) && ((x)<'8')) +int +xgettok(XFILE *xfp, char sepa, char *tok, int len) +{ + int i = 0; + int c = 0; + int quoted=0; + + while (i < len && (c = xgetc(xfp)) != EOF && + (quoted || (c != sepa && !isspace(c)))) { + if (c == '"') { + quoted = !quoted; + continue; + } + tok[i++] = c; + if (i >= 4 && + tok[i-4] == '\\' && + isoctal(tok[i-3]) && + isoctal(tok[i-2]) && + isoctal(tok[i-1]) && + ((tok[i]=0), + (c = strtol(tok+i-3,NULL, 8)) < 256)) { + i -= 4; + tok[i++] = c; + } + } + if (c == '\n') + xungetc(c, xfp); + if (!i) + return 0; + if (i >= len || (sepa && c != sepa)) + return -1; + tok[i] = '\0'; + return 1; +} + +int +xgetc(XFILE *xfp) +{ + int c = getc(xfp->x_fp); + + if (c == EOF) + return c; + if (c == '\\') { + if ((c = getc(xfp->x_fp)) != '\n') { + ungetc(c, xfp->x_fp); + return '\\'; + } + xfp->x_line++; + while ((c = getc(xfp->x_fp)) == ' ' || c == '\t'); + ungetc(c, xfp->x_fp); + return ' '; + } + if (c == '\n') + xfp->x_line++; + return c; +} + +void +xungetc(int c, XFILE *xfp) +{ + if (c == EOF) + return; + + ungetc(c, xfp->x_fp); + if (c == '\n') + xfp->x_line--; +} + +void +xskip(XFILE *xfp, char *str) +{ + int c; + + while ((c = xgetc(xfp)) != EOF) { + if (c == '#') + c = xskipcomment(xfp); + if (strchr(str, c) == NULL) + break; + } + xungetc(c, xfp); +} + +char +xskipcomment(XFILE *xfp) +{ + int c; + + while ((c = getc(xfp->x_fp)) != EOF && c != '\n'); + return c; +} diff --git a/support/nfs/xlog.c b/support/nfs/xlog.c new file mode 100644 index 0000000..fa125ce --- /dev/null +++ b/support/nfs/xlog.c @@ -0,0 +1,254 @@ +/* + * support/nfs/xlog.c + * + * This module handles the logging of requests. + * + * TODO: Merge the two "XXX_log() calls. + * + * Authors: Donald J. Becker, <becker@super.org> + * Rick Sladkey, <jrs@world.std.com> + * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> + * Olaf Kirch, <okir@monad.swb.de> + * + * This software maybe be used for any purpose provided + * the above copyright notice is retained. It is supplied + * as is, with no warranty expressed or implied. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <unistd.h> +#include <signal.h> +#include <time.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <stdarg.h> +#include <syslog.h> +#include <errno.h> +#include "nfslib.h" +#include "conffile.h" + +#undef VERBOSE_PRINTF + +#pragma GCC visibility push(hidden) + +static int log_stderr = 1; +static int log_syslog = 1; +static int logging = 0; /* enable/disable DEBUG logs */ +static int logmask = 0; /* What will be logged */ +static char log_name[256]; /* name of this program */ +static int log_pid = -1; /* PID of this program */ + +int export_errno = 0; + +static void xlog_toggle(int sig); +static struct xlog_debugfac debugnames[] = { + { "0", 0, }, + { "general", D_GENERAL, }, + { "call", D_CALL, }, + { "auth", D_AUTH, }, + { "parse", D_PARSE, }, + { "all", D_ALL, }, + { "1", D_ALL, }, + { NULL, 0, }, +}; + +void +xlog_open(char *progname) +{ + openlog(progname, LOG_PID, LOG_DAEMON); + + strncpy(log_name, progname, sizeof (log_name) - 1); + log_name [sizeof (log_name) - 1] = '\0'; + log_pid = getpid(); + + signal(SIGUSR1, xlog_toggle); + signal(SIGUSR2, xlog_toggle); +} + +void +xlog_stderr(int on) +{ + log_stderr = on; +} + +void +xlog_syslog(int on) +{ + log_syslog = on; +} + +static void +xlog_toggle(int sig) +{ + unsigned int tmp, i; + + if (sig == SIGUSR1) { + if ((logmask & D_ALL) && !logging) { + xlog(D_GENERAL, "turned on logging"); + logging = 1; + return; + } + tmp = ~logmask; + logmask |= ((logmask & D_ALL) << 1) | D_GENERAL; + for (i = -1, tmp &= logmask; tmp; tmp >>= 1, i++) + if (tmp & 1) + xlog(D_GENERAL, + "turned on logging level %d", i); + } else { + xlog(D_GENERAL, "turned off logging"); + logging = 0; + } + signal(sig, xlog_toggle); +} + +void +xlog_config(int fac, int on) +{ + if (on) + logmask |= fac; + else + logmask &= ~fac; + if (on) + logging = 1; +} + +void +xlog_sconfig(char *kind, int on) +{ + struct xlog_debugfac *tbl = debugnames; + + while (tbl->df_name != NULL && strcasecmp(tbl->df_name, kind)) + tbl++; + if (!tbl->df_name) { + xlog (L_WARNING, "Invalid debug facility: %s\n", kind); + return; + } + if (tbl->df_fac) + xlog_config(tbl->df_fac, on); +} + +void +xlog_set_debug(char *service) +{ + struct conf_list *kinds; + struct conf_list_node *n; + + kinds = conf_get_list(service, "debug"); + if (!kinds || !kinds->cnt) { + free(kinds); + return; + } + TAILQ_FOREACH(n, &(kinds->fields), link) + xlog_sconfig(n->field, 1); + + conf_free_list(kinds); +} + +int +xlog_enabled(int fac) +{ + return (logging && (fac & logmask)); +} + + +/* Write something to the system logfile and/or stderr */ +void +xlog_backend(int kind, const char *fmt, va_list args) +{ + if (!(kind & (L_ALL)) && !(logging && (kind & logmask))) + return; + + if (log_stderr) { + va_list args2; +#ifdef VERBOSE_PRINTF + time_t now; + struct tm *tm; + + time(&now); + tm = localtime(&now); + fprintf(stderr, "%s[%d] %04d-%02d-%02d %02d:%02d:%02d ", + log_name, log_pid, + tm->tm_year+1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); +#else + fprintf(stderr, "%s: ", log_name); +#endif + va_copy(args2, args); + vfprintf(stderr, fmt, args2); + fprintf(stderr, "\n"); + va_end(args2); + } + + if (log_syslog) { + switch (kind) { + case L_FATAL: + vsyslog(LOG_ERR, fmt, args); + break; + case L_ERROR: + vsyslog(LOG_ERR, fmt, args); + break; + case L_WARNING: + vsyslog(LOG_WARNING, fmt, args); + break; + case L_NOTICE: + vsyslog(LOG_NOTICE, fmt, args); + break; + default: + if (!log_stderr) + vsyslog(LOG_INFO, fmt, args); + break; + } + } + + if (kind == L_FATAL) + exit(1); +} + +void +xlog(int kind, const char* fmt, ...) +{ + va_list args; + + if (kind & (L_ERROR|D_GENERAL)) + export_errno = 1; + + va_start(args, fmt); + xlog_backend(kind, fmt, args); + va_end(args); +} + +void +xlog_warn(const char* fmt, ...) +{ + va_list args; + + va_start(args, fmt); + xlog_backend(L_WARNING, fmt, args); + va_end(args); +} + + +void +xlog_err(const char* fmt, ...) +{ + va_list args; + + va_start(args, fmt); + xlog_backend(L_FATAL, fmt, args); + va_end(args); +} + +void +xlog_errno(int err, const char *fmt, ...) +{ + va_list args; + + errno = err; + va_start(args, fmt); + xlog_backend(L_FATAL, fmt, args); + va_end(args); +} diff --git a/support/nfsidmap/AUTHORS b/support/nfsidmap/AUTHORS new file mode 100644 index 0000000..1101630 --- /dev/null +++ b/support/nfsidmap/AUTHORS @@ -0,0 +1 @@ +J. Bruce Fields <bfields@citi.umich.edu> diff --git a/support/nfsidmap/COPYING b/support/nfsidmap/COPYING new file mode 100644 index 0000000..7571bb7 --- /dev/null +++ b/support/nfsidmap/COPYING @@ -0,0 +1,30 @@ +Copyright (c) 2004 The Regents of the University of Michigan. +All rights reserved. + +Marius Aamodt Eriksen <marius@umich.edu> +J. Bruce Fields <bfields@umich.edu> + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the University nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/support/nfsidmap/Makefile.am b/support/nfsidmap/Makefile.am new file mode 100644 index 0000000..f5b9de0 --- /dev/null +++ b/support/nfsidmap/Makefile.am @@ -0,0 +1,75 @@ +if PATH_PLUGINS +pkgplugindir=$(PATH_PLUGINS) +else +pkgplugindir=$(libdir)/libnfsidmap +endif + +if ENABLE_LDAP +UMICH_LDAP_LIB = umich_ldap.la +else +UMICH_LDAP_LIB = +endif +if ENABLE_GUMS +GUMS_MAPPING_LIB = gums.la +else +GUMS_MAPPING_LIB = +endif +if ENABLE_LDAP_SASL +KRB5_GSS_LIB=-lgssapi_krb5 +endif +lib_LTLIBRARIES = libnfsidmap.la +pkgplugin_LTLIBRARIES = nsswitch.la static.la regex.la $(UMICH_LDAP_LIB) $(GUMS_MAPPING_LIB) + +# Library versioning notes from: +# http://sources.redhat.com/autobook/autobook/autobook_91.html +# +# -version-info <current>:<revision>:<age> +# <current> The number of the current interface exported by library. +# <revision> The implementation number of the most recent interface +# exported by the library. (i.e. revision should be updated +# with each new release of the library, and reset to zero +# when <current> is updated.) +# <age> The number of previous additional interfaces supported +# by this library. + +libnfsidmap_la_SOURCES = libnfsidmap.c nfsidmap_common.c +libnfsidmap_la_LDFLAGS = -version-info 1:0:0 +libnfsidmap_la_LIBADD = -ldl ../../support/nfs/libnfsconf.la + +nsswitch_la_SOURCES = nss.c nfsidmap_common.c +nsswitch_la_LDFLAGS = -module -avoid-version +nsswitch_la_LIBADD = ../../support/nfs/libnfsconf.la + +static_la_SOURCES = static.c +static_la_LDFLAGS = -module -avoid-version +static_la_LIBADD = ../../support/nfs/libnfsconf.la + +regex_la_SOURCES = regex.c +regex_la_LDFLAGS = -module -avoid-version +regex_la_LIBADD = ../../support/nfs/libnfsconf.la + +umich_ldap_la_SOURCES = umich_ldap.c +umich_ldap_la_LDFLAGS = -module -avoid-version +umich_ldap_la_LIBADD = -lldap $(KRB5_GSS_LIB) ../../support/nfs/libnfsconf.la + +gums_la_SOURCES = gums.c +gums_la_LDFLAGS = -module -avoid-version + +man3_MANS = nfs4_uid_to_name.3 +man5_MANS = idmapd.conf.5 +include_HEADERS = nfsidmap.h nfsidmap_plugin.h + +EXTRA_DIST = $(man3_MANS) \ + $(man5_MANS) \ + libtest.c \ + idmapd.conf + +# XXX: also exclude debian/files and debian/files.new ? do a clean?? +dist-hook: + mkdir $(distdir)/debian/ + find $(srcdir)/debian -maxdepth 1 -not -type d |xargs -i cp {} $(distdir)/debian/ + +pkgconfigdir=$(libdir)/pkgconfig +pkgconfig_DATA = libnfsidmap.pc + +$(pkgconfig_DATA): $(top_builddir)/config.status diff --git a/support/nfsidmap/Makefile.in b/support/nfsidmap/Makefile.in new file mode 100644 index 0000000..45ff4d6 --- /dev/null +++ b/support/nfsidmap/Makefile.in @@ -0,0 +1,1060 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = support/nfsidmap +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ax_gcc_func_attribute.m4 \ + $(top_srcdir)/aclocal/bsdsignals.m4 \ + $(top_srcdir)/aclocal/getrandom.m4 \ + $(top_srcdir)/aclocal/ipv6.m4 \ + $(top_srcdir)/aclocal/kerberos5.m4 \ + $(top_srcdir)/aclocal/keyutils.m4 \ + $(top_srcdir)/aclocal/libblkid.m4 \ + $(top_srcdir)/aclocal/libcap.m4 \ + $(top_srcdir)/aclocal/libevent.m4 \ + $(top_srcdir)/aclocal/libpthread.m4 \ + $(top_srcdir)/aclocal/libsqlite3.m4 \ + $(top_srcdir)/aclocal/libtirpc.m4 \ + $(top_srcdir)/aclocal/libxml2.m4 \ + $(top_srcdir)/aclocal/nfs-utils.m4 \ + $(top_srcdir)/aclocal/rpcsec_vers.m4 \ + $(top_srcdir)/aclocal/tcp-wrappers.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(include_HEADERS) \ + $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/support/include/config.h +CONFIG_CLEAN_FILES = libnfsidmap.pc +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgplugindir)" \ + "$(DESTDIR)$(man3dir)" "$(DESTDIR)$(man5dir)" \ + "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(includedir)" +LTLIBRARIES = $(lib_LTLIBRARIES) $(pkgplugin_LTLIBRARIES) +gums_la_LIBADD = +am_gums_la_OBJECTS = gums.lo +gums_la_OBJECTS = $(am_gums_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +gums_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(gums_la_LDFLAGS) $(LDFLAGS) -o $@ +@ENABLE_GUMS_TRUE@am_gums_la_rpath = -rpath $(pkgplugindir) +libnfsidmap_la_DEPENDENCIES = ../../support/nfs/libnfsconf.la +am_libnfsidmap_la_OBJECTS = libnfsidmap.lo nfsidmap_common.lo +libnfsidmap_la_OBJECTS = $(am_libnfsidmap_la_OBJECTS) +libnfsidmap_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libnfsidmap_la_LDFLAGS) $(LDFLAGS) -o \ + $@ +nsswitch_la_DEPENDENCIES = ../../support/nfs/libnfsconf.la +am_nsswitch_la_OBJECTS = nss.lo nfsidmap_common.lo +nsswitch_la_OBJECTS = $(am_nsswitch_la_OBJECTS) +nsswitch_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(nsswitch_la_LDFLAGS) $(LDFLAGS) -o $@ +regex_la_DEPENDENCIES = ../../support/nfs/libnfsconf.la +am_regex_la_OBJECTS = regex.lo +regex_la_OBJECTS = $(am_regex_la_OBJECTS) +regex_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(regex_la_LDFLAGS) $(LDFLAGS) -o $@ +static_la_DEPENDENCIES = ../../support/nfs/libnfsconf.la +am_static_la_OBJECTS = static.lo +static_la_OBJECTS = $(am_static_la_OBJECTS) +static_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(static_la_LDFLAGS) $(LDFLAGS) -o $@ +am__DEPENDENCIES_1 = +umich_ldap_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \ + ../../support/nfs/libnfsconf.la +am_umich_ldap_la_OBJECTS = umich_ldap.lo +umich_ldap_la_OBJECTS = $(am_umich_ldap_la_OBJECTS) +umich_ldap_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(umich_ldap_la_LDFLAGS) $(LDFLAGS) -o $@ +@ENABLE_LDAP_TRUE@am_umich_ldap_la_rpath = -rpath $(pkgplugindir) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/support/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/gums.Plo ./$(DEPDIR)/libnfsidmap.Plo \ + ./$(DEPDIR)/nfsidmap_common.Plo ./$(DEPDIR)/nss.Plo \ + ./$(DEPDIR)/regex.Plo ./$(DEPDIR)/static.Plo \ + ./$(DEPDIR)/umich_ldap.Plo +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(gums_la_SOURCES) $(libnfsidmap_la_SOURCES) \ + $(nsswitch_la_SOURCES) $(regex_la_SOURCES) \ + $(static_la_SOURCES) $(umich_ldap_la_SOURCES) +DIST_SOURCES = $(gums_la_SOURCES) $(libnfsidmap_la_SOURCES) \ + $(nsswitch_la_SOURCES) $(regex_la_SOURCES) \ + $(static_la_SOURCES) $(umich_ldap_la_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +man3dir = $(mandir)/man3 +man5dir = $(mandir)/man5 +NROFF = nroff +MANS = $(man3_MANS) $(man5_MANS) +DATA = $(pkgconfig_DATA) +HEADERS = $(include_HEADERS) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/libnfsidmap.pc.in \ + $(top_srcdir)/depcomp AUTHORS COPYING README +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GREP = @GREP@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GSSD = @GSSD@ +GSSGLUE_CFLAGS = @GSSGLUE_CFLAGS@ +GSSGLUE_LIBS = @GSSGLUE_LIBS@ +GSSKRB_CFLAGS = @GSSKRB_CFLAGS@ +GSSKRB_LIBS = @GSSKRB_LIBS@ +HAVE_GETRANDOM = @HAVE_GETRANDOM@ +HAVE_LIBWRAP = @HAVE_LIBWRAP@ +HAVE_TCP_WRAPPER = @HAVE_TCP_WRAPPER@ +IDMAPD = @IDMAPD@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +K5VERS = @K5VERS@ +KRBCFLAGS = @KRBCFLAGS@ +KRBDIR = @KRBDIR@ +KRBLDFLAGS = @KRBLDFLAGS@ +KRBLIBS = @KRBLIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ +LIBBLKID = @LIBBLKID@ +LIBBSD = @LIBBSD@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBEVENT = @LIBEVENT@ +LIBKEYUTILS = @LIBKEYUTILS@ +LIBMOUNT = @LIBMOUNT@ +LIBMOUNT_CFLAGS = @LIBMOUNT_CFLAGS@ +LIBMOUNT_LIBS = @LIBMOUNT_LIBS@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPTHREAD = @LIBPTHREAD@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSQLITE = @LIBSQLITE@ +LIBTIRPC = @LIBTIRPC@ +LIBTOOL = @LIBTOOL@ +LIBWRAP = @LIBWRAP@ +LIBXML2 = @LIBXML2@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_PLUGINS = @PATH_PLUGINS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +RELEASE = @RELEASE@ +RPCGEN_PATH = @RPCGEN_PATH@ +RPCSECGSS_CFLAGS = @RPCSECGSS_CFLAGS@ +RPCSECGSS_LIBS = @RPCSECGSS_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SVCGSSD = @SVCGSSD@ +TIRPC_CFLAGS = @TIRPC_CFLAGS@ +TIRPC_LIBS = @TIRPC_LIBS@ +VERSION = @VERSION@ +XML2_CFLAGS = @XML2_CFLAGS@ +XML2_LIBS = @XML2_LIBS@ +_rpc_pipefsmount = @_rpc_pipefsmount@ +_statedir = @_statedir@ +_sysconfdir = @_sysconfdir@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_gss = @enable_gss@ +enable_ipv6 = @enable_ipv6@ +enable_mountconfig = @enable_mountconfig@ +enable_nfsv4 = @enable_nfsv4@ +enable_nfsv41 = @enable_nfsv41@ +enable_svcgss = @enable_svcgss@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +kprefix = @kprefix@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +mountfile = @mountfile@ +nfsconfig = @nfsconfig@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rpc_pipefsmount = @rpc_pipefsmount@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +startstatd = @startstatd@ +statdpath = @statdpath@ +statduser = @statduser@ +statedir = @statedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +unitdir = @unitdir@ +@PATH_PLUGINS_FALSE@pkgplugindir = $(libdir)/libnfsidmap +@PATH_PLUGINS_TRUE@pkgplugindir = $(PATH_PLUGINS) +@ENABLE_LDAP_FALSE@UMICH_LDAP_LIB = +@ENABLE_LDAP_TRUE@UMICH_LDAP_LIB = umich_ldap.la +@ENABLE_GUMS_FALSE@GUMS_MAPPING_LIB = +@ENABLE_GUMS_TRUE@GUMS_MAPPING_LIB = gums.la +@ENABLE_LDAP_SASL_TRUE@KRB5_GSS_LIB = -lgssapi_krb5 +lib_LTLIBRARIES = libnfsidmap.la +pkgplugin_LTLIBRARIES = nsswitch.la static.la regex.la $(UMICH_LDAP_LIB) $(GUMS_MAPPING_LIB) + +# Library versioning notes from: +# http://sources.redhat.com/autobook/autobook/autobook_91.html +# +# -version-info <current>:<revision>:<age> +# <current> The number of the current interface exported by library. +# <revision> The implementation number of the most recent interface +# exported by the library. (i.e. revision should be updated +# with each new release of the library, and reset to zero +# when <current> is updated.) +# <age> The number of previous additional interfaces supported +# by this library. +libnfsidmap_la_SOURCES = libnfsidmap.c nfsidmap_common.c +libnfsidmap_la_LDFLAGS = -version-info 1:0:0 +libnfsidmap_la_LIBADD = -ldl ../../support/nfs/libnfsconf.la +nsswitch_la_SOURCES = nss.c nfsidmap_common.c +nsswitch_la_LDFLAGS = -module -avoid-version +nsswitch_la_LIBADD = ../../support/nfs/libnfsconf.la +static_la_SOURCES = static.c +static_la_LDFLAGS = -module -avoid-version +static_la_LIBADD = ../../support/nfs/libnfsconf.la +regex_la_SOURCES = regex.c +regex_la_LDFLAGS = -module -avoid-version +regex_la_LIBADD = ../../support/nfs/libnfsconf.la +umich_ldap_la_SOURCES = umich_ldap.c +umich_ldap_la_LDFLAGS = -module -avoid-version +umich_ldap_la_LIBADD = -lldap $(KRB5_GSS_LIB) ../../support/nfs/libnfsconf.la +gums_la_SOURCES = gums.c +gums_la_LDFLAGS = -module -avoid-version +man3_MANS = nfs4_uid_to_name.3 +man5_MANS = idmapd.conf.5 +include_HEADERS = nfsidmap.h nfsidmap_plugin.h +EXTRA_DIST = $(man3_MANS) \ + $(man5_MANS) \ + libtest.c \ + idmapd.conf + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = libnfsidmap.pc +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu support/nfsidmap/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu support/nfsidmap/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +libnfsidmap.pc: $(top_builddir)/config.status $(srcdir)/libnfsidmap.pc.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ + +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +install-pkgpluginLTLIBRARIES: $(pkgplugin_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(pkgplugin_LTLIBRARIES)'; test -n "$(pkgplugindir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkgplugindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkgplugindir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkgplugindir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkgplugindir)"; \ + } + +uninstall-pkgpluginLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(pkgplugin_LTLIBRARIES)'; test -n "$(pkgplugindir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkgplugindir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkgplugindir)/$$f"; \ + done + +clean-pkgpluginLTLIBRARIES: + -test -z "$(pkgplugin_LTLIBRARIES)" || rm -f $(pkgplugin_LTLIBRARIES) + @list='$(pkgplugin_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +gums.la: $(gums_la_OBJECTS) $(gums_la_DEPENDENCIES) $(EXTRA_gums_la_DEPENDENCIES) + $(AM_V_CCLD)$(gums_la_LINK) $(am_gums_la_rpath) $(gums_la_OBJECTS) $(gums_la_LIBADD) $(LIBS) + +libnfsidmap.la: $(libnfsidmap_la_OBJECTS) $(libnfsidmap_la_DEPENDENCIES) $(EXTRA_libnfsidmap_la_DEPENDENCIES) + $(AM_V_CCLD)$(libnfsidmap_la_LINK) -rpath $(libdir) $(libnfsidmap_la_OBJECTS) $(libnfsidmap_la_LIBADD) $(LIBS) + +nsswitch.la: $(nsswitch_la_OBJECTS) $(nsswitch_la_DEPENDENCIES) $(EXTRA_nsswitch_la_DEPENDENCIES) + $(AM_V_CCLD)$(nsswitch_la_LINK) -rpath $(pkgplugindir) $(nsswitch_la_OBJECTS) $(nsswitch_la_LIBADD) $(LIBS) + +regex.la: $(regex_la_OBJECTS) $(regex_la_DEPENDENCIES) $(EXTRA_regex_la_DEPENDENCIES) + $(AM_V_CCLD)$(regex_la_LINK) -rpath $(pkgplugindir) $(regex_la_OBJECTS) $(regex_la_LIBADD) $(LIBS) + +static.la: $(static_la_OBJECTS) $(static_la_DEPENDENCIES) $(EXTRA_static_la_DEPENDENCIES) + $(AM_V_CCLD)$(static_la_LINK) -rpath $(pkgplugindir) $(static_la_OBJECTS) $(static_la_LIBADD) $(LIBS) + +umich_ldap.la: $(umich_ldap_la_OBJECTS) $(umich_ldap_la_DEPENDENCIES) $(EXTRA_umich_ldap_la_DEPENDENCIES) + $(AM_V_CCLD)$(umich_ldap_la_LINK) $(am_umich_ldap_la_rpath) $(umich_ldap_la_OBJECTS) $(umich_ldap_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gums.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libnfsidmap.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nfsidmap_common.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nss.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/regex.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/static.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/umich_ldap.Plo@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-man3: $(man3_MANS) + @$(NORMAL_INSTALL) + @list1='$(man3_MANS)'; \ + list2=''; \ + test -n "$(man3dir)" \ + && test -n "`echo $$list1$$list2`" \ + || exit 0; \ + echo " $(MKDIR_P) '$(DESTDIR)$(man3dir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(man3dir)" || exit 1; \ + { for i in $$list1; do echo "$$i"; done; \ + if test -n "$$list2"; then \ + for i in $$list2; do echo "$$i"; done \ + | sed -n '/\.3[a-z]*$$/p'; \ + fi; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man3dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man3dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man3dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man3dir)" || exit $$?; }; \ + done; } + +uninstall-man3: + @$(NORMAL_UNINSTALL) + @list='$(man3_MANS)'; test -n "$(man3dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^3][0-9a-z]*$$,3,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + dir='$(DESTDIR)$(man3dir)'; $(am__uninstall_files_from_dir) +install-man5: $(man5_MANS) + @$(NORMAL_INSTALL) + @list1='$(man5_MANS)'; \ + list2=''; \ + test -n "$(man5dir)" \ + && test -n "`echo $$list1$$list2`" \ + || exit 0; \ + echo " $(MKDIR_P) '$(DESTDIR)$(man5dir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(man5dir)" || exit 1; \ + { for i in $$list1; do echo "$$i"; done; \ + if test -n "$$list2"; then \ + for i in $$list2; do echo "$$i"; done \ + | sed -n '/\.5[a-z]*$$/p'; \ + fi; \ + } | while read p; do \ + if test -f $$p; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; echo "$$p"; \ + done | \ + sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \ + sed 'N;N;s,\n, ,g' | { \ + list=; while read file base inst; do \ + if test "$$base" = "$$inst"; then list="$$list $$file"; else \ + echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man5dir)/$$inst'"; \ + $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man5dir)/$$inst" || exit $$?; \ + fi; \ + done; \ + for i in $$list; do echo "$$i"; done | $(am__base_list) | \ + while read files; do \ + test -z "$$files" || { \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man5dir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(man5dir)" || exit $$?; }; \ + done; } + +uninstall-man5: + @$(NORMAL_UNINSTALL) + @list='$(man5_MANS)'; test -n "$(man5dir)" || exit 0; \ + files=`{ for i in $$list; do echo "$$i"; done; \ + } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^5][0-9a-z]*$$,5,;x' \ + -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \ + dir='$(DESTDIR)$(man5dir)'; $(am__uninstall_files_from_dir) +install-pkgconfigDATA: $(pkgconfig_DATA) + @$(NORMAL_INSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgconfigdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgconfigdir)" || exit $$?; \ + done + +uninstall-pkgconfigDATA: + @$(NORMAL_UNINSTALL) + @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir) +install-includeHEADERS: $(include_HEADERS) + @$(NORMAL_INSTALL) + @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includedir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includedir)" || exit $$?; \ + done + +uninstall-includeHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(includedir)'; $(am__uninstall_files_from_dir) + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$(top_distdir)" distdir="$(distdir)" \ + dist-hook +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(MANS) $(DATA) $(HEADERS) +install-pkgpluginLTLIBRARIES: install-libLTLIBRARIES + +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pkgplugindir)" "$(DESTDIR)$(man3dir)" "$(DESTDIR)$(man5dir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(includedir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + clean-pkgpluginLTLIBRARIES mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/gums.Plo + -rm -f ./$(DEPDIR)/libnfsidmap.Plo + -rm -f ./$(DEPDIR)/nfsidmap_common.Plo + -rm -f ./$(DEPDIR)/nss.Plo + -rm -f ./$(DEPDIR)/regex.Plo + -rm -f ./$(DEPDIR)/static.Plo + -rm -f ./$(DEPDIR)/umich_ldap.Plo + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-includeHEADERS install-man \ + install-pkgconfigDATA install-pkgpluginLTLIBRARIES + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: install-man3 install-man5 + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/gums.Plo + -rm -f ./$(DEPDIR)/libnfsidmap.Plo + -rm -f ./$(DEPDIR)/nfsidmap_common.Plo + -rm -f ./$(DEPDIR)/nss.Plo + -rm -f ./$(DEPDIR)/regex.Plo + -rm -f ./$(DEPDIR)/static.Plo + -rm -f ./$(DEPDIR)/umich_ldap.Plo + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-includeHEADERS uninstall-libLTLIBRARIES \ + uninstall-man uninstall-pkgconfigDATA \ + uninstall-pkgpluginLTLIBRARIES + +uninstall-man: uninstall-man3 uninstall-man5 + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libLTLIBRARIES clean-libtool \ + clean-pkgpluginLTLIBRARIES cscopelist-am ctags ctags-am \ + dist-hook distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am \ + install-includeHEADERS install-info install-info-am \ + install-libLTLIBRARIES install-man install-man3 install-man5 \ + install-pdf install-pdf-am install-pkgconfigDATA \ + install-pkgpluginLTLIBRARIES install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ + uninstall-includeHEADERS uninstall-libLTLIBRARIES \ + uninstall-man uninstall-man3 uninstall-man5 \ + uninstall-pkgconfigDATA uninstall-pkgpluginLTLIBRARIES + +.PRECIOUS: Makefile + + +# XXX: also exclude debian/files and debian/files.new ? do a clean?? +dist-hook: + mkdir $(distdir)/debian/ + find $(srcdir)/debian -maxdepth 1 -not -type d |xargs -i cp {} $(distdir)/debian/ + +$(pkgconfig_DATA): $(top_builddir)/config.status + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/support/nfsidmap/README b/support/nfsidmap/README new file mode 100644 index 0000000..5a448ef --- /dev/null +++ b/support/nfsidmap/README @@ -0,0 +1,126 @@ +Library to help mapping id's, mainly for NFSv4. + +When NFSv4 is using AUTH_GSS (which currently only supports Kerberos v5), the +NFSv4 server mapping functions MUST use secure communications. + +We provide several mapping functions, configured using /etc/idmapd.conf + +As of the 0.21 version of this library, mapping methods are separate +dynamically-loaded libaries. This allows the separation of any +LDAP requirements from the main libnfsidmap library. The main library +now basically loads and calls the functions in the method-specific +libaries. The method libraries are expected to be named +"libnfsidmap_<method>.so", for example, "libnfsidmap_nsswitch.so". + +Several methods may be specified in the /etc/idmapd.conf configuration +file. Each method is called until a mapping is found. + +The following translation methods are delivered in the default distribution: + +nsswitch +-------- + +The default method is called nsswitch. This method uses the get password +file entry functions getpwname(), getpwid(), and the get group file entry +functions getgrnam(), getgrgid(). The nsswitch method can therefore be +configured by the /etc/nss_switch.conf passwd data base stanza. If secure +communications are required (AUTH_GSS), the passwd data base stanza can contain +the 'file' entry because the rpc.idmapd and rpc.svcgssd run as root, and/or the +'ldap' entry if the ldap service is configured to use SASL in /etc/ldap.conf. +The 'nis' entry is NOT recommended, it does not have a secure communications +mode. + + +static +------ + +This method works only for translating GSS authenticated names to local +names. It uses a static mapping setup defined in the [Static] section +of the idmapd.conf file. The form of the entries are: + <GSS-Authenticated name> = <localuser> + +For example: + nfs/host.domain.org@DOMAIN.ORG = root + +It is recommended that this module be used in combination with another +module (e.g. the nsswitch module). + +umich_ldap +---------- +An experimental method, umich_ldap uses an LDAP schema and ldap functions +to perform translations. This method is designed to service remote users, +allowing remote users to set and get ACLs as well as map GSS principals +to id's. The functions are LDAP based, and the ldap search filters look +for attribute names set by idmapd.conf [UMICH_SCHEMA] +NFSv4_name_attr, NFSv4_group_attr, and GSS_principal_attr. + +It is assumed that the LDAP server will index these attributes, and that these +attributes will be associated with the nss.schema posixAccount uidNumber and +gidNumber. We expect that the uidNumber and gidNumber attribute will be +configurable via the idmapd.conf file soon. + +NFSv4_name_attr holds an NFSv4 name of the form user@domain, where the domain +portion of the name is a valid NFSv4 domain name. There is a one-to-one +mapping between the NFSv4_name_attr name and a UID. + +NFSv4_group_attr holds an NFSv4 name of the form group@domain, where the domain +portion of the name is a valid NFSv4 domain name. There is a one-to-one +mapping between the NFSv4_group_attr name and a GID. + +GSS_principal_attr holds a GSS security mechanism specific context principal +name. For Kerberos v5, it is a Kerberos principal <service/>principal@REALM. +For SPKM3, it is a PKI DN such as (line is split):` +"/C=US/ST=Michigan/O=University of Michigan/OU=UMICH Kerberos + Certification Authority/CN=andros/USERID=andros/Email=andros@UMICH.EDU". +There is a many-to-one relationship between the GSS_principal_attr +name and a UID plus GID. + +We have defined LDAP object classes for our experimental NFSv4 id mapping. +We made the attribute names configurable so that other sites could still use +the TR_UMICH_LDAP translation functions with different LDAP attribute names. + +We use the same attribute name, NFSv4Name for the NFSv4_name_attr and the +NFSv4_group_attr. For local users and remote users that we wish to give +a local machine account, we add the NFSv4Name attribute and the GSSAuthName +attribute to the existing inetorgPerson and posixAccount schema. +For remote users that we do not wish to give a local machine account, +we use the NFSv4RemotePerson object to contain the NFSv4Name, uidNumber, +gidNumber, and GSSAuthName. + +nfsv4.schema +------------ +attributetype ( 1.3.6.1.4.1.250.1.61 + NAME ( 'NFSv4Name') + DESC 'NFS version 4 Name' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26 + SINGLE-VALUE) + +attributetype ( 1.3.6.1.4.1.250.1.62 + NAME ( 'GSSAuthName') + DESC 'RPCSEC GSS authenticated user name' + EQUALITY caseIgnoreIA5Match + SYNTAX 1.3.6.1.4.1.1466.115.121.1.26) + +# +# minimal information for NFSv4 access. used when local filesystem +# access is not permitted (nsswitch ldap calls fail), or when +# inetorgPerson is too much info. +# +objectclass ( 1.3.6.1.4.1.250.1.60 NAME 'NFSv4RemotePerson' + DESC 'NFS version4 person from remote NFSv4 Domain' + SUP top STRUCTURAL + MUST ( uidNumber $ gidNumber $ NFSv4Name ) + MAY ( cn $ GSSAuthName $ description) ) + +# +# minimal information for NFSv4 access. used when local filesystem +# access is not permitted (nsswitch ldap calls fail), or when +# inetorgPerson is too much info. +# +objectclass ( 1.3.6.1.4.1.250.1.63 NAME 'NFSv4RemoteGroup' + DESC 'NFS version4 group from remote NFSv4 Domain' + SUP top STRUCTURAL + MUST ( gidNumber $ NFSv4Name ) + MAY ( cn $ memberUid $ description) ) + diff --git a/support/nfsidmap/gums.c b/support/nfsidmap/gums.c new file mode 100644 index 0000000..1d6eb31 --- /dev/null +++ b/support/nfsidmap/gums.c @@ -0,0 +1,787 @@ +/* + * gums.c + * + * Copyright (c) 2004 The Regents of the University of Michigan. + * All rights reserved. + * + * Olga Kornievskaia <aglo@umich.edu> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <pwd.h> +#include <grp.h> +#include <err.h> +#include <syslog.h> +#include "nfsidmap.h" +#include "nfsidmap_plugin.h" + +#include <voms_apic.h> + +#include <prima_logger.h> +#include <prima_soap_client.h> +#include <prima_saml_support.h> + +#define DEFAULT_PRIMA_CONF_LOCATION "/etc/grid-security/prima-authz.conf" +#define DEFAULT_VOMSDIR "/etc/grid-security/vomsdir" +#define DEFAULT_CADIR "/etc/grid-security/certificates" +#define X509_DN_SIZE 1024 + +//#define DEBUG_PRINT_VOMS + +#define USING_TEST_PROGRAM +#ifdef USING_TEST_PROGRAM +nfs4_idmap_log_function_t idmap_log_func = printf; +int idmap_verbosity = 10; +#endif + +/* + * GUMS Translation Methods + * + */ + +/* global variables. voms/gums configuration attributes*/ +static char prima_conf[] = DEFAULT_PRIMA_CONF_LOCATION; +typedef struct _plugin_config_params { + char *saml_schema_dir; + int saml_log_level; + char *server_cert; + char *server_key; + char *ca_dir; + char *gums_server_location; + char *voms_dir; +} plugin_config_params; +plugin_config_params conf; + +#ifdef VOMS_BUG +static void my_VOMS_Delete(struct voms *v) +{ + int i; + + if (!v) return; + if (v->user) + free(v->user); + if (v->server) + free(v->server); + if (v->fqan) { + for (i = 0; v->fqan[i] != NULL; i++) + free(v->fqan[i]); + free(v->fqan); + } + free(v); +} + +static struct voms *my_VOMS_Copy(struct voms *v, int *err) +{ + struct voms *cv; + int i; + + cv = calloc(1, sizeof(struct voms)); + if (cv == NULL) + goto out; + cv->user = strdup(v->user); + if (cv->user == NULL) + goto out; + cv->server = strdup(v->server); + if (cv->server == NULL) + goto out; + for (i = 0; v->fqan[i] != NULL; i++) { + if (v->fqan[i] == NULL) + break; + } + cv->fqan = calloc(i+1, sizeof(char *)); + if (cv->fqan == NULL) + goto out; + cv->fqan[i] = NULL; + for (i = 0; v->fqan[i] != NULL; i++) { + cv->fqan[i] = strdup(v->fqan[i]); + if (cv->fqan[i] == NULL) + goto out; + } + return cv; +out: + if (cv) + my_VOMS_Delete(cv); + + return NULL; +} +#endif + + +#ifdef DEBUG_PRINT_VOMS +void printvoms(struct voms *v) +{ + int j; + + printf("SIGLEN: %d\nUSER: %s\n", v->siglen, v->user); + printf("UCA: %s\nSERVER: %s\n", v->userca, v->server); + printf("SCA: %s\nVO: %s\n", v->serverca, v->voname); + printf("URI: %s\nDATE1: %s\n", v->uri, v->date1); + printf("DATE2: %s\n", v->date2); + + switch (v->type) { + case TYPE_NODATA: + printf("NO DATA\n"); + break; + case TYPE_CUSTOM: + printf("%*s\n", v->datalen - 10, v->custom); + break; + case TYPE_STD: + j = 0; + while (v->std[j]) { + printf("GROUP: %s\nROLE: %s\nCAP: %s\n",v->std[j]->group, + v->std[j]->role,v->std[j]->cap); + j++; + } + } +} + +void print(struct vomsdata *d) +{ + struct voms **vo = d->data; + struct voms *v; + int k = 0; + + while(vo[k]) { + v = vo[k++]; + printf("%d *******************************************\n",k); + printvoms(v); + } + + if (d->workvo) + printf("WORKVO: %s\n", d->workvo); + + if (d->extra_data) + printf("EXTRA: %s\n", d->extra_data); +} +#endif + +static void free_plugin_config_params() +{ + if (conf.saml_schema_dir) + free(conf.saml_schema_dir); + conf.saml_schema_dir = NULL; + if (conf.server_cert) + free(conf.server_cert); + conf.server_cert = NULL; + if (conf.server_key) + free(conf.server_key); + conf.server_key = NULL; + if (conf.ca_dir) + free(conf.ca_dir); + conf.ca_dir = NULL; + if (conf.voms_dir) + free(conf.voms_dir); + conf.voms_dir = NULL; +} + +static int validate_plugin_config_params() +{ + if (conf.saml_schema_dir == NULL || + conf.server_cert == NULL || + conf.server_key == NULL || + conf.gums_server_location == NULL) + return -1; + + if (conf.ca_dir == NULL) { + conf.ca_dir = strdup(DEFAULT_CADIR); + if (conf.ca_dir == NULL) + return -1; + } + if (conf.voms_dir == NULL) { + conf.voms_dir = strdup(DEFAULT_VOMSDIR); + if (conf.voms_dir == NULL) + return -1; + } + return 0; +} + +static int gums_init(void) +{ + FILE *f = NULL; + int ret = -1, i = 0; + char buf[512], type[128], value[256]; + char *alt_conf = NULL; + + alt_conf = nfsidmap_config_get("GUMS", "Conf_File"); + if (alt_conf == NULL) + f = fopen(prima_conf, "r"); + else + f = fopen(alt_conf, "r"); + if (f == NULL) + goto out; + + while (fgets(buf, 512, f)) { + i = 0; + while(buf[i] == ' ' || buf[i] == '\t') + i++; + if (buf[i] == '#' || buf[i] == '\0' || buf[i] == '\n') + continue; + if (sscanf(&buf[i], "%127s%255s",type,value) < 2) { + IDMAP_LOG(0, ("ERROR: malformed line: %s\n", &buf[i])); + goto out; + } + IDMAP_LOG(1, ("PRIMA conf: type=%s value=%s\n", type, value)); + if (strncmp(type, "imsContact", 10) == 0) { + conf.gums_server_location = strdup(value); + } else if (strncmp(type, "serviceCert", 11) == 0) { + conf.server_cert = strdup(value); + } else if (strncmp(type, "serviceKey", 10) == 0) { + conf.server_key = strdup(value); + } else if (strncmp(type, "caCertDir", 9) == 0) { + conf.ca_dir = strdup(value); + } else if (strncmp(type, "samlSchemaDir", 13) == 0) { + conf.saml_schema_dir = strdup(value); + } else if (strncmp(type, "logLevel", 8) == 0) { + if (strncmp(value, "debug", 5) == 0) + conf.saml_log_level = PRIMA_LOG_DEBUG; + else if (strncmp(value, "error", 5) == 0) + conf.saml_log_level = PRIMA_LOG_ERROR; + else if (strncmp(value, "none", 4) == 0) + conf.saml_log_level = PRIMA_LOG_NONE; + else + conf.saml_log_level = PRIMA_LOG_INFO; + } + } + + if (validate_plugin_config_params() != 0) + goto out; + + ret = 0; +out: + if (f) + fclose(f); + if (ret) + free_plugin_config_params(); + + return ret; +} + +static int retrieve_attributes(X509 *cert, STACK_OF(X509) *cas, + struct voms **attrs) +{ + int ret = -1, err = 0; + struct vomsdata *vd = NULL; + + vd = VOMS_Init(conf.voms_dir, conf.ca_dir); + if (vd == NULL) { + IDMAP_LOG(0, ("VOMS_Init failed\n")); + return -1; + } + ret = VOMS_Retrieve(cert, cas, RECURSE_CHAIN, vd, &err); + if (err) { + char *err_msg; + err_msg = VOMS_ErrorMessage(vd, err, NULL, 0); + if (err == VERR_NOEXT) + ret = 0; + else + IDMAP_LOG(0, ("VOMS error %s\n", err_msg)); + goto out; + } else if (ret) { + struct voms *v, *v2; +#ifdef DEBUG_PRINT_VOMS + print(vd); +#endif + v = VOMS_DefaultData(vd, &err); + if (err == VERR_NONE) { +#ifdef DEBUG_PRINT_VOMS + printvoms(v); + while (v->fqan[i] != NULL) + IDMAP_LOG(1, ("user's fqan: %s\n", v->fqan[i++])); +#endif +#ifdef VOMS_BUG + v2 = my_VOMS_Copy(v, &err); +#else + v2 = VOMS_Copy(v, &err); +#endif + if (v2 == NULL) { + IDMAP_LOG(0, ("VOMS_Copy failed err=%d\n", err)); + goto out; + } + *attrs = v2; + } + } + ret = 0; +out: + if (vd) + VOMS_Destroy(vd); + return ret; +} + +static int get_server_dn(unsigned char **server_dn) +{ + BIO *tmp = NULL; + X509 *cert = NULL; + int ret = -1; + char dn[X509_DN_SIZE]; + + tmp = BIO_new(BIO_s_file()); + if (tmp == NULL) + goto out; + + ret = BIO_read_filename(tmp, conf.server_cert); + if (ret == 0) { + ret = errno; + goto out; + } + + cert = (X509 *) PEM_read_bio_X509(tmp, NULL, NULL, NULL); + if (cert == NULL) + goto out; + + X509_NAME_oneline(X509_get_subject_name(cert), dn, sizeof(dn)); + + *server_dn = strdup(dn); + if (*server_dn == NULL) + goto out; + + ret = 0; +out: + if (tmp) + BIO_free(tmp); + if (cert) + X509_free(cert); + + return ret; +} + +static int create_saml_request(char *dn, struct voms *attrs, char **saml_req) +{ + int ret = -1, i; + char *req = NULL; + unsigned char *server_dn = NULL; + prima_saml_fqans fqans; + + IDMAP_LOG(2, ("create_saml_request start\n")); + ret = initPrimaSAMLFQANs(&fqans); + if (ret) { + IDMAP_LOG(0, ("initPrimaSAMLFQANs failed with %d\n", ret)); + goto out; + } + + if (attrs) { + for (i = 0; attrs->fqan[i] != NULL; i++) { + ret = addPrimaSAMLFQAN(&fqans, attrs->server, attrs->fqan[i]); + IDMAP_LOG(1, ("addPrimaSAMLFQAN returned %d\n", ret)); + } + dn = attrs->user; + } else + IDMAP_LOG(1, ("No VOMS attributes present in the cert\n")); + + if (get_server_dn(&server_dn) != 0) + goto out; + req = createSAMLQueryAndRequest(server_dn, dn, &fqans); + if (req == NULL) { + IDMAP_LOG(0, ("createSAMLQueryAndRequest failed to create " + "SAML request\n")); + goto out; + } + IDMAP_LOG(1, ("SAML Request %s\n", req)); + + ret = 0; + *saml_req = req; +out: + cleanupPrimaSAMLFQANs(&fqans); + + if (server_dn) + free(server_dn); + + IDMAP_LOG(2, ("create_saml_request returning %d\n", ret)); + return ret; +} + +static int process_parameters(extra_mapping_params **ex, X509 **user_cert, + STACK_OF(X509) **user_chain) +{ + + int ret = -1, i; + X509 *cert = NULL, *x; + STACK_OF(X509) *chain = NULL; + unsigned char *p; + + if (ex[0]->content_type != X509_CERT) + return -1; + + /* get user's x509 certificate */ + p = ex[0]->content; + cert = d2i_X509(NULL, &p, ex[0]->content_len); + if (cert == NULL) + goto out; + + /* get user's other certificates */ + chain = sk_X509_new_null(); + if (chain == NULL) + goto out; + for (i = 1; ex[i] != NULL; i++) { + if (ex[i]->content_type != X509_CERT) + continue; + p = ex[i]->content; + x = d2i_X509(NULL, &p, ex[i]->content_len); + if (x == NULL) + goto out; + sk_X509_push(chain, x); + } + ret = 0; + + *user_cert = cert; + *user_chain = chain; +out: + if (ret) { + int num; + if (cert) + X509_free(cert); + if (chain) + sk_X509_pop_free(chain, X509_free); + } + + return ret; +} + +struct pwbuf { + struct passwd pwbuf; + char buf[1]; +}; + +static int translate_to_uid(char *local_uid, uid_t *uid, uid_t *gid) +{ + int ret = -1; + struct passwd *pw = NULL; + struct pwbuf *buf = NULL; + size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); + + buf = malloc(sizeof(*buf) + buflen); + if (buf == NULL) + goto out; + + ret = getpwnam_r(local_uid, &buf->pwbuf, buf->buf, buflen, &pw); + if (pw == NULL) { + IDMAP_LOG(0, ("getpwnam: name %s not found\n", local_uid)); + goto out; + } + *uid = pw->pw_uid; + *gid = pw->pw_gid; + + ret = 0; +out: + if (buf) + free(buf); + return ret; +} + +static int translate_to_gid(char *local_gid, uid_t *gid) +{ + struct group *gr = NULL; + struct group grbuf; + char *buf = NULL; + size_t buflen = sysconf(_SC_GETGR_R_SIZE_MAX); + int ret = -1; + + do { + buf = malloc(buflen); + if (buf == NULL) + goto out; + + ret = -getgrnam_r(local_gid, &grbuf, buf, buflen, &gr); + if (gr == NULL && !ret) + ret = -ENOENT; + if (ret == -ERANGE) { + buflen *= 2; + free(buf); + } + } while (ret == -ERANGE); + + if (ret) + goto out; + + *gid = gr->gr_gid; + + ret = 0; +out: + if (buf) + free(buf); + return ret; +} + +static int gums_gss_princ_to_ids(char *secname, char *princ, + uid_t *uid, uid_t *gid, + extra_mapping_params **ex) +{ + int ret = -1, size, i; + X509 *cert = NULL; + STACK_OF(X509) *cas = NULL; + char dn[X509_DN_SIZE]; + struct voms *attrs = NULL; + char *saml_req = NULL, *saml_resp = NULL; + int saml_result; + char *local_uid = NULL, *local_gid = NULL, *p; + + /* accept only spkm3 translations */ + if (strcmp(secname, "spkm3")) + return -EINVAL; + + /* must supply either a DN and/or at least 1 binary blob */ + if (princ == NULL && (ex == NULL || (ex && ex[0] == NULL))) + return -EINVAL; + + /* process extra parameters */ + if (process_parameters(ex, &cert, &cas) != 0) + goto out; + + IDMAP_LOG(1, ("Processing name translation of client\n")); + X509_NAME_oneline(X509_get_subject_name(cert), dn, sizeof(dn)); + IDMAP_LOG(1, ("DN=%s\n", dn)); + size = sk_X509_num(cas); + IDMAP_LOG(1, ("Including following CAs (%d)\n", size)); + for (i=0; i < size; i++) { + X509_NAME_oneline(X509_get_subject_name(sk_X509_value(cas, i)), + dn, sizeof(dn)); + IDMAP_LOG(1, ("DN=%s\n", dn)); + } + + /* retrieve VOMS attributes */ + if (retrieve_attributes(cert, cas, &attrs) != 0) + goto out; + if (attrs == NULL) + X509_NAME_oneline(X509_get_subject_name(cert), dn, sizeof(dn)); + + /* initialize SAML library */ + if (initPrimaSAMLSupport(conf.saml_schema_dir, + conf.saml_log_level) != 0) { + IDMAP_LOG(0, ("initPrimaSAMLSupport failed\n")); + goto out; + } + + /* create SAML request */ + if (create_saml_request(dn, attrs, &saml_req) != 0) + goto out; + + /* contact GUMS server */ + saml_resp = queryIdentityMappingService(conf.gums_server_location, + saml_req, conf.server_cert, conf.server_key, + conf.ca_dir); + if (saml_resp != NULL) { + saml_result = processResponse(saml_resp, saml_req, &local_uid, + &local_gid); + IDMAP_LOG(1, ("processResponse returned %d\n", saml_result)); + if (saml_result || local_uid == NULL) { + IDMAP_LOG(0, ("processResponse failed to return " + "local id\n")); + ret = -ENOENT; + goto out; + } + IDMAP_LOG(1, ("GUMS returned uid=%s gid=%s\n", local_uid, + local_gid)); + } + + /* translate account name to uid */ + if (translate_to_uid(local_uid, uid, gid)) + goto out; + if (local_gid) + if (translate_to_gid(local_gid, gid)) + goto out; + + ret = 0; +out: + if (cert) + X509_free(cert); + + if (cas) + sk_X509_pop_free(cas, X509_free); + + if (attrs) +#ifdef VOMS_BUG + my_VOMS_Delete(attrs); +#else + VOMS_Delete(attrs); +#endif + + if (saml_req) + free(saml_req); + + if (saml_resp) + free(saml_resp); + + cleanupPrimaSAMLSupport(); + + return ret; +} + +struct trans_func gums_trans = { + .name = "gums", + .init = gums_init, + .princ_to_ids = gums_gss_princ_to_ids, + .name_to_uid = NULL, + .name_to_gid = NULL, + .uid_to_name = NULL, + .gid_to_name = NULL, + .gss_princ_to_grouplist = NULL, +}; + +struct trans_func *libnfsidmap_plugin_init() +{ + return (&gums_trans); +} + +#ifdef USING_TEST_PROGRAM +static STACK_OF(X509) *load_chain(char *certfile) +{ + STACK_OF(X509_INFO) *sk=NULL; + STACK_OF(X509) *stack=NULL, *ret=NULL; + BIO *in=NULL; + X509_INFO *xi; + int first = 1; + + if (!(stack = sk_X509_new_null())) { + printf("memory allocation failure\n"); + goto end; + } + + if (!(in=BIO_new_file(certfile, "r"))) { + printf("error opening the file, %s\n",certfile); + goto end; + } + + /* This loads from a file, a stack of x509/crl/pkey sets */ + if (!(sk=(STACK_OF(X509_INFO) *)PEM_X509_INFO_read_bio(in,NULL,NULL,NULL))) { + /* if (!(sk=PEM_X509_read_bio(in,NULL,NULL,NULL))) { */ + printf("error reading the file, %s\n",certfile); + goto end; + } + + /* scan over it and pull out the certs */ + while (sk_X509_INFO_num(sk)) { + /* skip first cert */ + if (first) { + xi=sk_X509_INFO_shift(sk); + X509_INFO_free(xi); + first = 0; + continue; + } + xi=sk_X509_INFO_shift(sk); + if (xi->x509 != NULL) { + sk_X509_push(stack,xi->x509); + xi->x509=NULL; + } + X509_INFO_free(xi); + } + if (!sk_X509_num(stack)) { + printf("no certificates in file, %s\n",certfile); + sk_X509_free(stack); + goto end; + } + ret=stack; +end: + BIO_free(in); + sk_X509_INFO_free(sk); + return(ret); +} + +void create_params(X509 *cert, STACK_OF(X509) *cas, + extra_mapping_params ***ret_params) +{ + int len = 0, i, size = 0; + unsigned char *p, *buf = NULL; + extra_mapping_params **params = NULL; + X509 *x; + + if (cas) + size = sk_X509_num(cas); + params = malloc((size+2)*sizeof(extra_mapping_params *)); + params[size+1] = NULL; + + /* 1st element is user's certificate */ + len = i2d_X509(cert, NULL); + p = buf = malloc(len); + i2d_X509(cert, &p); + params[0] = malloc(sizeof(extra_mapping_params)); + params[0]->content_type = X509_CERT; + params[0]->content = buf; + params[0]->content_len = len; + + /* add other certificates to the array */ + for (i = 0; i < size; i++) { + x = sk_X509_value(cas, i); + params[i+1] = malloc(sizeof(extra_mapping_params)); + len = i2d_X509(x, NULL); + p = buf = malloc(len); + i2d_X509(x, &p); + params[i+1]->content_type = X509_CERT; + params[i+1]->content = buf; + params[i+1]->content_len = len; + } + *ret_params = params; +} + +int main(void) +{ + int uid, gid, ret, i; + extra_mapping_params **params = NULL; + BIO *tmp = NULL; + X509 *cert = NULL, *x; + STACK_OF(X509) *cas = NULL; + unsigned char *proxy_file; + + if (gums_init()) + return -1; + proxy_file = getenv("X509_USER_PROXY"); + if (proxy_file == NULL) { + fprintf(stderr, "X509_USER_PROXY is not set\n"); + return -1; + } + tmp = BIO_new(BIO_s_file()); + BIO_read_filename(tmp, proxy_file); + cert = (X509 *) PEM_read_bio_X509(tmp, NULL, NULL, NULL); + cas = load_chain(proxy_file); + create_params(cert, cas, ¶ms); + ret = gums_gss_princ_to_ids("spkm3", NULL, &uid, &gid, params); + fprintf(stderr, "gums_gss_princ_to_ids returns %d uid=%d gid=%d\n", + ret, uid, gid); + + if (tmp) + BIO_free(tmp); + if (cert) + X509_free(cert); + if (cas) + sk_X509_pop_free(cas, X509_free); + + free_plugin_config_params(); + + if (params) { + for (i=0; params[i] != NULL; i++) { + free(params[i]->content); + free(params[i]); + } + free(params); + } + + return 0; +} +#endif diff --git a/support/nfsidmap/idmapd.conf b/support/nfsidmap/idmapd.conf new file mode 100644 index 0000000..2a2f79a --- /dev/null +++ b/support/nfsidmap/idmapd.conf @@ -0,0 +1,169 @@ +[General] +#Verbosity = 0 +# The following should be set to the local NFSv4 domain name +# The default is the host's DNS domain name. +#Domain = local.domain.edu + +# In multi-domain environments, some NFS servers will append the identity +# management domain to the owner and owner_group in lieu of a true NFSv4 +# domain. This option can facilitate lookups in such environments. If +# set to a value other than "none", the nsswitch plugin will first pass +# the name to the password/group lookup function without stripping the +# domain off. If that mapping fails then the plugin will try again using +# the old method (comparing the domain in the string to the Domain value, +# stripping it if it matches, and passing the resulting short name to the +# lookup function). Valid values are "user", "group", "both", and +# "none". The default is "none". +#No-Strip = none + +# Winbind has a quirk whereby doing a group lookup in UPN format +# (e.g. staff@americas.example.com) will cause the group to be +# displayed prefixed with the full domain in uppercase +# (e.g. AMERICAS.EXAMPLE.COM\staff) instead of in the familiar netbios +# name format (e.g. AMERICAS\staff). Setting this option to true +# causes the name to be reformatted before passing it to the group +# lookup function in order to work around this. This setting is +# ignored unless No-Strip is set to either "both" or "group". +# The default is "false". +#Reformat-Group = false + +# The following is a comma-separated list of Kerberos realm +# names that should be considered to be equivalent to the +# local realm, such that <user>@REALM.A can be assumed to +# be the same user as <user>@REALM.B +# If not specified, the default local realm is the domain name, +# which defaults to the host's DNS domain name, +# translated to upper-case. +# Note that if this value is specified, the local realm name +# must be included in the list! +#Local-Realms = + +[Mapping] + +#Nobody-User = nobody +#Nobody-Group = nobody + +[Translation] + +# Translation Method is an comma-separated, ordered list of +# translation methods that can be used. Distributed methods +# include "nsswitch", "umich_ldap", and "static". Each method +# is a dynamically loadable plugin library. +# New methods may be defined and inserted in the list. +# The default is "nsswitch". +#Method = nsswitch + +# Optional. This is a comma-separated, ordered list of +# translation methods to be used for translating GSS +# authenticated names to ids. +# If this option is omitted, the same methods as those +# specified in "Method" are used. +#GSS-Methods = <alternate method list for translating GSS names> + +#-------------------------------------------------------------------# +# The following are used only for the "static" Translation Method. +#-------------------------------------------------------------------# +[Static] + +# A "static" list of GSS-Authenticated names to +# local user name mappings + +#someuser@REALM = localuser + + +#-------------------------------------------------------------------# +# The following are used only for the "umich_ldap" Translation Method. +#-------------------------------------------------------------------# + +[UMICH_SCHEMA] + +# server information (REQUIRED) +LDAP_server = ldap-server.local.domain.edu + +# the default search base (REQUIRED) +LDAP_base = dc=local,dc=domain,dc=edu + +#-----------------------------------------------------------# +# The remaining options have defaults (as shown) +# and are therefore not required. +#-----------------------------------------------------------# + +# whether or not to perform canonicalization on the +# name given as LDAP_server +#LDAP_canonicalize_name = true + +# absolute search base for (people) accounts +#LDAP_people_base = <LDAP_base> + +# absolute search base for groups +#LDAP_group_base = <LDAP_base> + +# Whether to follow ldap referrals +#LDAP_follow_referrals = true + +# Set to true to enable SSL - anything else is not enabled +#LDAP_use_ssl = false + +# Controls the LDAP server certificate validation behavior +# It can take the same values as ldap.conf(5)'s TLS_REQCERT +# tunable +#LDAP_tls_reqcert = "hard" + +# Location of CA certificate, mandatory if LDAP_tls_reqcert +# is not set to "never" +#LDAP_ca_cert = /etc/ldapca.cert + +# SASL mechanism to use while binding to LDAP +#LDAP_sasl_mech = <SASL mech> + +# SASL realm to be used for SASL auth +#LDAP_sasl_realm = <SASL realm> + +# Authentication identity to be used for SASL auth +#LDAP_sasl_authcid = <SASL authcid> + +# Authorization identity for SASL auth +#LDAP_sasl_authzid = <SASL authzid> + +# Cyrus SASL security properties +#LDAP_sasl_secprops = <secprops> + +# Specifies whether the LDAP server hostname should be canonicalised. +# If set to yes LDAP lib with do a reverse hostname lookup. +# If this is not set the LDAP library's default will be used. +#LDAP_sasl_canonicalize <yes | no> + +# Specifies the kerberos ticket cache to be used +#LDAP_sasl_krb5_ccname = <kerberos ticket cache> + +# Objectclass mapping information + +# Mapping for the person (account) object class +#NFSv4_person_objectclass = NFSv4RemotePerson + +# Mapping for the nfsv4name attribute the person object +#NFSv4_name_attr = NFSv4Name + +# Mapping for the UID number +#NFSv4_uid_attr = UIDNumber + +# Mapping for the GSSAPI Principal name +#GSS_principal_attr = GSSAuthName + +# Mapping for the account name attribute (usually uid) +# The value for this attribute must match the value of +# the group member attribute - NFSv4_member_attr +#NFSv4_acctname_attr = uid + +# Mapping for the group object class +#NFSv4_group_objectclass = NFSv4RemoteGroup + +# Mapping for the GID attribute +#NFSv4_gid_attr = GIDNumber + +# Mapping for the Group NFSv4 name +#NFSv4_group_attr = NFSv4Name + +# Mapping for the Group member attribute (usually memberUID) +# The value of this attribute must match the value of NFSv4_acctname_attr +#NFSv4_member_attr = memberUID diff --git a/support/nfsidmap/idmapd.conf.5 b/support/nfsidmap/idmapd.conf.5 new file mode 100644 index 0000000..87e39bb --- /dev/null +++ b/support/nfsidmap/idmapd.conf.5 @@ -0,0 +1,411 @@ +.\" +.\" idmapd.conf(5) +.\" +.\" COPYRIGHT (c) 2008 +.\" The Regents of the University of Michigan +.\" ALL RIGHTS RESERVED +.\" +.\" Permission is granted to use, copy, create derivative works +.\" and redistribute this software and such derivative works +.\" for any purpose, so long as the name of The University of +.\" Michigan is not used in any advertising or publicity +.\" pertaining to the use of distribution of this software +.\" without specific, written prior authorization. If the +.\" above copyright notice or any other identification of the +.\" University of Michigan is included in any copy of any +.\" portion of this software, then the disclaimer below must +.\" also be included. +.\" +.\" THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION +.\" FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY +.\" PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF +.\" MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING +.\" WITHOUT LIMITATION THE IMPLIED WARRANTIES OF +.\" MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE +.\" REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE +.\" FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR +.\" CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING +.\" OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN +.\" IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGES. +.\" +.TH idmapd.conf 5 "19 Nov 2008" +.SH NAME +idmapd.conf \- configuration file for libnfsidmap +.SH SYNOPSIS +Configuration file for libnfsidmap. Used by idmapd and svcgssd to map NFSv4 name to and from ids. +.SH DESCRIPTION +The +.B idmapd.conf +configuration file consists of several sections, initiated by strings of the +form [General] and [Mapping]. Each section may contain lines of the form +.nf + variable = value +.fi +The recognized sections and their recognized variables are as follows: +.\" +.\" ------------------------------------------------------------------- +.\" The [General] section +.\" ------------------------------------------------------------------- +.\" +.SS "[General] section variables" +.nf + + +.fi +.TP +.B Verbosity +Verbosity level of debugging +(Default: 0) +.TP +.B Domain +The local NFSv4 domain name. An NFSv4 domain is a namespace with +a unique username<->UID and groupname<->GID mapping. +(Default: Host's fully-qualified DNS domain name) +.TP +.B No-Strip +In multi-domain environments, some NFS servers will append the identity +management domain to the owner and owner_group in lieu of a true NFSv4 +domain. This option can facilitate lookups in such environments. If +set to a value other than "none", the nsswitch plugin will first pass +the name to the password/group lookup function without stripping the +domain off. If that mapping fails then the plugin will try again using +the old method (comparing the domain in the string to the Domain value, +stripping it if it matches, and passing the resulting short name to the +lookup function). Valid values are "user", "group", "both", and +"none". +(Default: "none") +.TP +.B Reformat-Group +Winbind has a quirk whereby doing a group lookup in UPN format +(e.g. staff@americas.example.com) will cause the group to be +displayed prefixed with the full domain in uppercase +(e.g. AMERICAS.EXAMPLE.COM\\staff) instead of in the familiar netbios +name format (e.g. AMERICAS\\staff). Setting this option to true +causes the name to be reformatted before passing it to the group +lookup function in order to work around this. This setting is +ignored unless No-Strip is set to either "both" or "group". +(Default: "false") +.TP +.B Local-Realms +A comma-separated list of Kerberos realm names that may be considered equivalent to the +local realm name. For example, users juser@ORDER.EDU and juser@MAIL.ORDER.EDU +may be considered to be the same user in the specified +.B Domain. +(Default: the host's default realm name) +.br +.B Note: +If a value is specified here, the default local realm must be included as well. +.\" +.\" ------------------------------------------------------------------- +.\" The [Mapping] section +.\" ------------------------------------------------------------------- +.\" +.SS "[Mapping] section variables" +.nf + +.fi +.TP +.B Nobody-User +Local user name to be used when a mapping cannot be completed. +.TP +.B Nobody-Group +Local group name to be used when a mapping cannot be completed. +.\" +.\" ------------------------------------------------------------------- +.\" The [Translation] section +.\" ------------------------------------------------------------------- +.\" +.SS "[Translation] section variables" +.nf + +.fi +.TP +.B Method +A comma-separated, ordered list of mapping methods (plug-ins) +to use when mapping between NFSv4 names and local IDs. Each +specified method is tried in order until a mapping is found, +or there are no more methods to try. The methods included in +the default distribution include "nsswitch", "umich_ldap", and +"static". +(Default: nsswitch) +.TP +.B GSS-Methods +An optional comma-separated, ordered list of mapping methods (plug-ins) +to use when mapping between GSS Authenticated names and local IDs. +(Default: the same list as specified for +.B Method) +.\" +.\" ------------------------------------------------------------------- +.\" The [Static] section +.\" ------------------------------------------------------------------- +.\" +.SS "[Static] section variables" +.nf + +.fi +The "static" translation method uses a static list of GSS-Authenticated +names to local user names. Entries in the list are of the form: +.nf + principal@REALM = localusername +.fi +.\" +.\" ------------------------------------------------------------------- +.\" The [REGEX] section +.\" ------------------------------------------------------------------- +.\" +.SS "[REGEX] section variables" +.nf + +.fi +If the "regex" translation method is specified, the following +variables within the [REGEX] section are used to map between NFS4 names and local IDs. +.TP +.B User-Regex +Case-insensitive regular expression that extracts the local user name from an NFSv4 name. Multiple expressions may be concatenated with '|'. The first match will be used. +There is no default. A basic regular expression for domain DOMAIN.ORG and realm MY.DOMAIN.ORG would be: +.nf +^DOMAIN\\([^@]+)@MY.DOMAIN.ORG$ +.fi +.TP +.B Group-Regex +Case-insensitive regular expression that extracts the local group name from an NFSv4 name. Multiple expressions may be concatenated with '|'. The first match will be used. +There is no default. A basic regular expression for domain DOMAIN.ORG and realm MY.DOMAIN.ORG would be: +.nf +^([^@]+)@DOMAIN.ORG@MY.DOMAIN.ORG$|^DOMAIN\\([^@]+)@MY.DOMAIN.ORG$ +.fi +.TP +.B Prepend-Before-User +Constant string to put before a local user name when building an NFSv4 name. Usually this is the short domain name followed by '\'. +(Default: none) +.TP +.B Append-After-User +Constant string to put after a local user name when building an NFSv4 name. Usually this is '@' followed by the default realm. +(Default: none) +.TP +.B Prepend-Before-Group +Constant string to put before a local group name when building an NFSv4 name. Usually not used. +(Default: none) +.TP +.B Append-After-Group +Constant string to put before a local group name when building an NFSv4 name. Usually this is '@' followed by the domain name followed by another '@' and the default realm. +(Default: none) +.TP +.B Group-Name-Prefix +Constant string that is prepended to a local group name when converting it to an NFSv4 name. If an NFSv4 group name has this prefix it is removed when converting it to a local group name. +With this group names of a central directory can be shortened for an isolated organizational unit if all groups have a common prefix. +(Default: none) +.TP +.B Group-Name-No-Prefix-Regex +Case-insensitive regular expression to exclude groups from adding and removing the prefix set by +.BR Group-Name-Prefix . +The regular expression must match both the remote and local group names. Multiple expressions may be concatenated with '|'. +(Default: none) +.\" +.\" ------------------------------------------------------------------- +.\" The [UMICH_SCHEMA] section +.\" ------------------------------------------------------------------- +.\" +.SS "[UMICH_SCHEMA] section variables" +.nf + +.fi +If the "umich_ldap" translation method is specified, the following +variables within the [UMICH_SCHEMA] section are used. +.TP +.B LDAP_server +LDAP server name or address +(Required if using UMICH_LDAP) +.TP +.B LDAP_base +Absolute LDAP search base. +(Required if using UMICH_LDAP) +.TP +.B LDAP_people_base +Absolute LDAP search base for people accounts. +(Default: The +.B LDAP_base +value) +.TP +.B LDAP_group_base +Absolute LDAP search base for group accounts. +(Default: The +.B LDAP_base +value) +.TP +.B LDAP_canonicalize_name +Whether or not to perform name canonicalization on the +name given as +.B LDAP_server +(Default: "true") +.TP +.B LDAP_follow_referrals +Whether or not to follow ldap referrals. (Default: "true") +.TP +.B LDAP_use_ssl +Set to "true" to enable SSL communication with the LDAP server. +(Default: "false") +.TP +.B LDAP_ca_cert +Location of a trusted CA certificate used when SSL is enabled +(Required if +.B LDAP_use_ssl +is true and +.B LDAP_tls_reqcert +is not set to never) +.TP +.B LDAP_tls_reqcert +Controls the LDAP server certificate validation behavior. +It can take the same values as ldap.conf(5)'s +.B TLS_REQCERT +tunable. +(Default: "hard") +.TP +.B LDAP_timeout_seconds +Number of seconds before timing out an LDAP request +(Default: 4) +.TP +.B LDAP_sasl_mech +SASL mechanism to be used for sasl authentication. Required +if SASL auth is to be used (Default: None) +.TP +.B LDAP_realm +SASL realm to be used for sasl authentication. (Default: None) +.TP +.B LDAP_sasl_authcid +Authentication identity to be used for sasl authentication. (Default: None) +.TP +.B LDAP_sasl_authzid +Authorization identity to be used for sasl authentication. (Default: None) +.TP +.B LDAP_sasl_secprops +Cyrus SASL security properties. It can the same values as ldap.conf(5)'s +sasl_secprops. +.TP +.B LDAP_sasl_canonicalize +Specifies whether the LDAP server hostname should be canonicalised. +If set to yes LDAP lib with do a reverse hostname lookup. +If this is not set the LDAP library's default will be used. (Default: +None) +.TP +.B LDAP_sasl_krb5_ccname +Path to kerberos credential cache. If it is not set then the value +of environment variable KRB5CCNAME will be used. If the environment +variable is not set then the default mechanism of kerberos library +will be used. +.TP +.B NFSv4_person_objectclass +The object class name for people accounts in your local LDAP schema +(Default: NFSv4RemotePerson) +.TP +.B NFSv4_name_attr +Your local schema's attribute name to be used for NFSv4 user names +(Default: NFSv4Name) +.TP +.B NFSv4_uid_attr +Your local schema's attribute name to be used for uidNumber +(Default: uidNumber) +.TP +.B GSS_principal_attr +Your local schema's attribute name for GSSAPI Principal names +(Default: GSSAuthName) +.TP +.B NFSv4_acctname_attr +Your local schema's attribute name to be used for account names +(Default: uid) +.TP +.B NFSv4_group_objectclass +The object class name for group accounts in your local LDAP schema +(Default: NFSv4RemoteGroup) +.TP +.B NFSv4_gid_attr +Your local schema's attribute name to be used for gidNumber +(Default: gidNumber) +.TP +.B NFSv4_group_attr +Your local schema's attribute name to be used for NFSv4 group names +(Default: NFSv4Name) +.TP +.B LDAP_use_memberof_for_groups +Some LDAP servers do a better job with indexing where searching +through all the groups searching for the user in the memberuid +list. Others like SunOne directory that search can takes minutes +if there are thousands of groups. So setting +.B LDAP_use_memberof_for_groups +to true in the configuration file will use the memberof lists of +the account and search through only those groups to obtain gids. +(Default: false) +.TP +.B NFSv4_member_attr +If +.B LDAP_use_memberof_for_groups +is true, this is the attribute to be searched for. +(Default: memberUid) +.TP +.B NFSv4_grouplist_filter +An optional search filter for determining group membership. +(No Default) +.\" +.\" ------------------------------------------------------------------- +.\" An Example +.\" ------------------------------------------------------------------- +.\" +.SH EXAMPLES +An example +.I /etc/idmapd.conf +file: +.nf + + +[General] + +Verbosity = 0 +Domain = domain.org +Local-Realms = DOMAIN.ORG,MY.DOMAIN.ORG,YOUR.DOMAIN.ORG + +[Mapping] + +Nobody-User = nfsnobody +Nobody-Group = nfsnobody + +[Translation] + +Method = umich_ldap,regex,nsswitch +GSS-Methods = umich_ldap,regex,static + +[Static] + +johndoe@OTHER.DOMAIN.ORG = johnny + +[Regex] + +User-Regex = ^DOMAIN\\([^@]+)@DOMAIN.ORG$ +Group-Regex = ^([^@]+)@DOMAIN.ORG@DOMAIN.ORG$|^DOMAIN\\([^@]+)@DOMAIN.ORG$ +Prepend-Before-User = DOMAIN\ +Append-After-User = @DOMAIN.ORG +Append-After-Group = @domain.org@domain.org +Group-Name-Prefix = sales- +Group-Name-No-Prefix-Regex = -personal-group$ + +[UMICH_SCHEMA] + +LDAP_server = ldap.domain.org +LDAP_base = dc=org,dc=domain + +.fi +.\" +.\" ------------------------------------------------------------------- +.\" Additional sections +.\" ------------------------------------------------------------------- +.\" +.SH SEE ALSO +.BR idmapd (8) +.BR svcgssd (8) +.\".SH COMPATIBILITY +.\".SH STANDARDS +.\".SH ACKNOWLEDGEMENTS +.\".SH AUTHORS +.\".SH HISTORY +.SH BUGS +Report bugs to <nfsv4@linux-nfs.org> +.\".SH CAVEATS diff --git a/support/nfsidmap/libnfsidmap.c b/support/nfsidmap/libnfsidmap.c new file mode 100644 index 0000000..f8c3648 --- /dev/null +++ b/support/nfsidmap/libnfsidmap.c @@ -0,0 +1,712 @@ +/* + * libnfsidmap.c + * + * nfs idmapping library, primarily for nfs4 client/server kernel idmapping + * and for userland nfs4 idmapping by acl libraries. + * + * Copyright (c) 2004 The Regents of the University of Michigan. + * All rights reserved. + * + * Marius Aamodt Eriksen <marius@umich.edu> + * J. Bruce Fields <bfields@umich.edu> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#include <sys/types.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <pwd.h> +#include <grp.h> +#include <netdb.h> +#include <err.h> +#include <syslog.h> +#include <stdarg.h> +#include <dlfcn.h> +#include <ctype.h> +#include <resolv.h> +#include <arpa/nameser.h> +#include <arpa/nameser_compat.h> + +#include "nfsidmap.h" +#include "nfsidmap_private.h" +#include "nfsidmap_plugin.h" +#include "conffile.h" + +#pragma GCC visibility push(hidden) + +void nfs4_cleanup_name_mapping(void); +static char *default_domain; +static struct mapping_plugin **nfs4_plugins = NULL; +static struct mapping_plugin **gss_plugins = NULL; +uid_t nobody_uid = (uid_t)-1; +gid_t nobody_gid = (gid_t)-1; + +#ifndef PATH_PLUGINS +#define PATH_PLUGINS "/usr/lib/libnfsidmap" +#endif +#define PLUGIN_INIT_FUNC "libnfsidmap_plugin_init" + + +#ifndef PATH_IDMAPDCONF +#define PATH_IDMAPDCONF "/etc/idmapd.conf" +#endif + +#ifndef IDMAPD_DEFAULT_DOMAIN +#define IDMAPD_DEFAULT_DOMAIN "localdomain" +#endif + +#ifndef NFS4DNSTXTREC +#define NFS4DNSTXTREC "_nfsv4idmapdomain" +#endif + +#ifndef NS_MAXMSG +#define NS_MAXMSG 65535 +#endif + +/* Default logging fuction */ +static void default_logger(const char *fmt, ...) +{ + va_list vp; + + va_start(vp, fmt); + vsyslog(LOG_WARNING, fmt, vp); + va_end(vp); +} + +#pragma GCC visibility pop +nfs4_idmap_log_function_t idmap_log_func = default_logger; +int idmap_verbosity = 0; +#pragma GCC visibility push(hidden) + +static int id_as_chars(char *name, uid_t *id) +{ + long int value; + + if (name == NULL) + return 0; + value = strtol(name, NULL, 10); + if (value == 0) { + /* zero value ids are valid */ + if (strcmp(name, "0") != 0) + return 0; + } + *id = (int)value; + return 1; +} + +static int dns_txt_query(char *domain, char **nfs4domain) +{ + char *txtname = NFS4DNSTXTREC; + unsigned char *msg, *eom, *mptr; + char *answ; + int len, status = -1; + HEADER *hdr; + + msg = calloc(1, NS_MAXMSG); + if (msg == NULL) + return -1; + + answ = calloc(1, NS_MAXMSG); + if (answ == NULL) { + free(msg); + return -1; + } + + if (res_init() < 0) { + IDMAP_LOG(2, ("libnfsidmap: res_init() failed for %s.%s: %s\n", + txtname, domain, hstrerror(h_errno))); + goto freemem; + } + len = res_querydomain(txtname, domain, C_IN, T_TXT, msg, NS_MAXMSG); + if (len < 0) { + IDMAP_LOG(2, ("libnfsidmap: res_querydomain() failed for %s.%s: %s\n", + txtname, domain, hstrerror(h_errno))); + goto freemem; + } + hdr = (HEADER *)msg; + + /* See if there is an answer */ + if (ntohs(hdr->ancount) < 1) { + IDMAP_LOG(2, ("libnfsidmap: No TXT record for %s.%s\n", + txtname, domain)); + goto freemem; + } + /* find the EndOfMessage */ + eom = msg + len; + + /* skip header */ + mptr = &msg[HFIXEDSZ]; + + /* skip name field in question section */ + mptr += dn_skipname(mptr, eom) + QFIXEDSZ; + + /* read in the question */ + len = dn_expand(msg, eom, mptr, answ, NS_MAXDNAME); + if (len < 0) { /* does this really matter?? */ + IDMAP_LOG(2, ("libnfsidmap: No question section for %s.%s: %s\n", + txtname, domain, hstrerror(h_errno))); + goto freemem; + } + + /* + * Now, dissect the answer section, Note: if there + * are more than one answer only the first + * one will be used. + */ + + /* skip passed the name field */ + mptr += dn_skipname(mptr, eom); + /* skip pass the type class and ttl fields */ + mptr += 2 + 2 + 4; + + /* make sure there is some data */ + GETSHORT(len, mptr); + if (len < 0) { + IDMAP_LOG(2, ("libnfsidmap: No data in answer for %s.%s\n", + txtname, domain)); + goto freemem; + } + /* get the lenght field */ + len = (int)*mptr++; + /* copy the data */ + memcpy(answ, mptr, len); + answ[len] = '\0'; + + *nfs4domain = strdup(answ); + status = 0; + +freemem: + free(msg); + free(answ); + + return (status); +} + +static int domain_from_dns(char **domain) +{ + struct hostent *he; + char hname[64], *c; + + if (gethostname(hname, sizeof(hname)) == -1) + return -1; + if ((he = gethostbyname(hname)) == NULL) { + IDMAP_LOG(1, ("libnfsidmap: DNS lookup of hostname failed. Attempting to use domain from hostname as is.")); + if ((c = strchr(hname, '.')) == NULL || *++c == '\0') + return -1; + } + else { + if ((c = strchr(he->h_name, '.')) == NULL || *++c == '\0') + return -1; + } + /* + * Query DNS to see if the _nfsv4idmapdomain TXT record exists + * If so use it... + */ + if (dns_txt_query(c, domain) < 0) + *domain = strdup(c); + + return 0; +} + +static int load_translation_plugin(char *method, struct mapping_plugin *plgn) +{ + void *dl = NULL; + struct trans_func *trans = NULL; + libnfsidmap_plugin_init_t init_func = NULL; + char plgname[128]; + int ret = 0; + + /* Look for library using search path first to allow overriding */ + snprintf(plgname, sizeof(plgname), "%s.so", method); + + dl = dlopen(plgname, RTLD_NOW | RTLD_LOCAL); + if (dl != NULL) { + /* Is it really one of our libraries */ + init_func = (libnfsidmap_plugin_init_t) dlsym(dl, PLUGIN_INIT_FUNC); + if (init_func == NULL) { + dlclose(dl); + dl = NULL; + } + } + + if (dl == NULL) { + /* Fallback to hard-coded path */ + snprintf(plgname, sizeof(plgname), "%s/%s.so", PATH_PLUGINS, method); + + dl = dlopen(plgname, RTLD_NOW | RTLD_LOCAL); + if (dl == NULL) { + IDMAP_LOG(1, ("libnfsidmap: Unable to load plugin: %s: %s", + plgname, dlerror())); + return -1; + } + init_func = (libnfsidmap_plugin_init_t) dlsym(dl, PLUGIN_INIT_FUNC); + if (init_func == NULL) { + IDMAP_LOG(1, ("libnfsidmap: Unable to get init function: %s: %s", + plgname, dlerror())); + dlclose(dl); + return -1; + } + } + trans = init_func(); + if (trans == NULL) { + IDMAP_LOG(1, ("libnfsidmap: Failed to initialize plugin %s", + PLUGIN_INIT_FUNC, plgname)); + dlclose(dl); + return -1; + } + if (trans->init) { + ret = trans->init(); + if (ret) { + IDMAP_LOG(1, ("libnfsidmap: Failed in %s's init(), " + "returned %d", plgname, ret)); + dlclose(dl); + return -1; + } + } + plgn->dl_handle = dl; + plgn->trans = trans; + IDMAP_LOG(1, ("libnfsidmap: loaded plugin %s for method %s", + plgname, method)); + + return 0; +} + +static void unload_plugins(struct mapping_plugin **plgns) +{ + int i; + for (i = 0; plgns[i] != NULL; i++) { + if (plgns[i]->dl_handle && dlclose(plgns[i]->dl_handle)) + IDMAP_LOG(1, ("libnfsidmap: failed to " + "unload plugin for method = %s", + plgns[i]->trans->name)); + free(plgns[i]); + } + free(plgns); +} + +static int load_plugins(struct conf_list *methods, + struct mapping_plugin ***plugins) +{ + int ret = -1, i = 0; + struct mapping_plugin **plgns; + struct conf_list_node *m; + + plgns = calloc(methods->cnt + 1, sizeof(struct mapping_plugin *)); + if (plgns == NULL) + return -1; + plgns[methods->cnt] = NULL; + for (m = TAILQ_FIRST(&methods->fields), i = 0; m; + m = TAILQ_NEXT(m, link), i++) { + plgns[i] = calloc(1, sizeof(struct mapping_plugin)); + if (plgns[i] == NULL) + goto out; + if (load_translation_plugin(m->field, plgns[i]) == -1) { + IDMAP_LOG(0, ("libnfsidmap: requested translation " + "method, '%s', is not available", + m->field)); + goto out; + } + } + ret = 0; + *plugins = plgns; +out: + if (ret) + unload_plugins(plgns); + return ret; +} + +static char *get_default_domain(void) +{ + int ret; + + if (default_domain) + return default_domain; + ret = domain_from_dns(&default_domain); + if (ret) { + IDMAP_LOG(0, ("Unable to determine a default nfsv4 domain; " + " consider specifying one in idmapd.conf")); + default_domain = ""; + } + return default_domain; +} + +void nfs4_cleanup_name_mapping(void) +{ + if (nfs4_plugins) + unload_plugins(nfs4_plugins); + if (gss_plugins) + unload_plugins(gss_plugins); + nfs4_plugins = gss_plugins = NULL; +} + +#pragma GCC visibility pop + +const char * nfsidmap_conf_path = PATH_IDMAPDCONF; + +int nfs4_init_name_mapping(char *conffile) +{ + int ret = -ENOENT; + int dflt = 0; + struct conf_list *nfs4_methods, *gss_methods; + char *nobody_user, *nobody_group; + + /* XXX: need to be able to reload configurations... */ + if (nfs4_plugins) /* already succesfully initialized */ + return 0; + if (conffile) + nfsidmap_conf_path = conffile; + conf_init_file(nfsidmap_conf_path); + + default_domain = conf_get_str("General", "Domain"); + if (default_domain == NULL) { + dflt = 1; + ret = domain_from_dns(&default_domain); + if (ret) { + IDMAP_LOG(0, ("libnfsidmap: Unable to determine " + "the NFSv4 domain; Using '%s' as the NFSv4 domain " + "which means UIDs will be mapped to the 'Nobody-User' " + "user defined in %s", + IDMAPD_DEFAULT_DOMAIN, PATH_IDMAPDCONF)); + default_domain = IDMAPD_DEFAULT_DOMAIN; + } + } + IDMAP_LOG(1, ("libnfsidmap: using%s domain: %s", + (dflt ? " (default)" : ""), default_domain)); + + struct conf_list *local_realms = get_local_realms(); + if (local_realms == NULL) return -ENOMEM; + + if (idmap_verbosity >= 1) { + struct conf_list_node *r; + char *buf = NULL; + int siz=0; + + if (local_realms) { + TAILQ_FOREACH(r, &local_realms->fields, link) { + siz += (strlen(r->field)+4); + } + buf = malloc(siz); + if (buf) { + *buf = 0; + TAILQ_FOREACH(r, &local_realms->fields, link) { + sprintf(buf+strlen(buf), "'%s' ", r->field); + } + IDMAP_LOG(1, ("libnfsidmap: Realms list: %s", buf)); + free(buf); + } + } else + IDMAP_LOG(1, ("libnfsidmap: Realms list: <NULL> ")); + } + + nfs4_methods = conf_get_list("Translation", "Method"); + if (nfs4_methods) { + IDMAP_LOG(1, ("libnfsidmap: processing 'Method' list")); + if (load_plugins(nfs4_methods, &nfs4_plugins) == -1) { + conf_free_list(nfs4_methods); + return -ENOENT; + } + } else { + struct conf_list list; + struct conf_list_node node; + + TAILQ_INIT(&list.fields); + list.cnt = 1; + node.field = "nsswitch"; + TAILQ_INSERT_TAIL (&list.fields, &node, link); + + if (load_plugins(&list, &nfs4_plugins) == -1) + return -ENOENT; + } + + gss_methods = conf_get_list("Translation", "GSS-Methods"); + if (gss_methods) { + IDMAP_LOG(1, ("libnfsidmap: processing 'GSS-Methods' list")); + if (load_plugins(gss_methods, &gss_plugins) == -1) + goto out; + } + + nobody_user = conf_get_str("Mapping", "Nobody-User"); + if (nobody_user) { + size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); + struct passwd *buf; + struct passwd *pw = NULL; + int err; + + buf = malloc(sizeof(*buf) + buflen); + if (buf) { + err = getpwnam_r(nobody_user, buf, ((char *)buf) + sizeof(*buf), buflen, &pw); + if (err == 0 && pw != NULL) + nobody_uid = pw->pw_uid; + else + IDMAP_LOG(1, ("libnfsidmap: Nobody-User (%s) not found: %s", + nobody_user, strerror(errno))); + free(buf); + } else + IDMAP_LOG(0,("libnfsidmap: Nobody-User: no memory : %s", + nobody_user, strerror(errno))); + } + + nobody_group = conf_get_str("Mapping", "Nobody-Group"); + if (nobody_group) { + size_t buflen = sysconf(_SC_GETGR_R_SIZE_MAX); + struct group *buf; + struct group *gr = NULL; + int err; + + buf = malloc(sizeof(*buf) + buflen); + if (buf) { + err = getgrnam_r(nobody_group, buf, ((char *)buf) + sizeof(*buf), buflen, &gr); + if (err == 0 && gr != NULL) + nobody_gid = gr->gr_gid; + else + IDMAP_LOG(1, ("libnfsidmap: Nobody-Group (%s) not found: %s", + nobody_group, strerror(errno))); + free(buf); + } else + IDMAP_LOG(0,("libnfsidmap: Nobody-Group: no memory : %s", + nobody_group, strerror(errno))); + } + + ret = 0; +out: + if (ret) { + if (nfs4_plugins) + unload_plugins(nfs4_plugins); + if (gss_plugins) { + unload_plugins(gss_plugins); + } + nfs4_plugins = gss_plugins = NULL; + } + + if (gss_methods) + conf_free_list(gss_methods); + + if (nfs4_methods) + conf_free_list(nfs4_methods); + + return ret ? -ENOENT: 0; +} + +void nfs4_term_name_mapping(void) +{ + if (nfs4_plugins) + unload_plugins(nfs4_plugins); + if (gss_plugins) + unload_plugins(gss_plugins); + + nfs4_plugins = gss_plugins = NULL; + + free_local_realms(); + conf_cleanup(); +} + +int +nfs4_get_default_domain(char *UNUSED(server), char *domain, size_t len) +{ + char *d = get_default_domain(); + + if (strlen(d) + 1 > len) + return -ERANGE; + strcpy(domain, d); + return 0; +} + +/* + * Run through each configured translation method for + * function "funcname". + * If "prefer_gss" is true, then use the gss_plugins list, + * if present. Otherwise, use the default nfs4_plugins list. + * + * If the plugin function returns -ENOENT, then continue + * to the next plugin. + */ +#define RUN_TRANSLATIONS(funcname, prefer_gss, args...) \ + do { \ + int ret, i; \ + struct mapping_plugin **plgns; \ + \ + ret = nfs4_init_name_mapping(NULL); \ + if (ret) \ + return ret; \ + \ + if ((prefer_gss) && gss_plugins) \ + plgns = gss_plugins; \ + else \ + plgns = nfs4_plugins; \ + \ + for (i = 0; plgns[i] != NULL; i++) { \ + if (plgns[i]->trans->funcname == NULL) \ + continue; \ + \ + IDMAP_LOG(4, ("%s: calling %s->%s", __func__, \ + plgns[i]->trans->name, #funcname)); \ + \ + ret = plgns[i]->trans->funcname(args); \ + \ + IDMAP_LOG(4, ("%s: %s->%s returned %d", \ + __func__, plgns[i]->trans->name, \ + #funcname, ret)); \ + \ + if (ret == -ENOENT) \ + continue; \ + \ + break; \ + } \ + IDMAP_LOG(4, ("%s: final return value is %d", \ + __func__, ret)); \ + return ret; \ + } while (0) + +int nfs4_uid_to_name(uid_t uid, char *domain, char *name, size_t len) +{ + RUN_TRANSLATIONS(uid_to_name, 0, uid, domain, name, len); +} + +int nfs4_gid_to_name(gid_t gid, char *domain, char *name, size_t len) +{ + RUN_TRANSLATIONS(gid_to_name, 0, gid, domain, name, len); +} + +int nfs4_uid_to_owner(uid_t uid, char *domain, char *name, size_t len) +{ + if (nfs4_uid_to_name(uid, domain, name, len)) + sprintf(name, "%u", uid); + return 0; +} + +int nfs4_gid_to_group_owner(gid_t gid, char *domain, char *name, size_t len) +{ + if (nfs4_gid_to_name(gid, domain, name, len)) + sprintf(name, "%u", gid); + return 0; +} + +int nfs4_name_to_uid(char *name, uid_t *uid) +{ + RUN_TRANSLATIONS(name_to_uid, 0, name, uid); +} + +int nfs4_name_to_gid(char *name, gid_t *gid) +{ + RUN_TRANSLATIONS(name_to_gid, 0, name, gid); +} + +static int set_id_to_nobody(uid_t *id, uid_t is_uid) +{ + int rc = 0; + const char name[] = "nobody@"; + char nobody[strlen(name) + strlen(get_default_domain()) + 1]; + + /* First try to see whether a Nobody-User/Nobody-Group was + * configured, before we try to do a full lookup for the + * NFS nobody user. */ + if (is_uid && nobody_uid != (uid_t)-1) { + *id = (uid_t)nobody_uid; + return 0; + } else if (!is_uid && nobody_gid != (gid_t)-1) { + *id = (uid_t)nobody_gid; + return 0; + } + + strcpy(nobody, name); + strcat(nobody, get_default_domain()); + + if (is_uid) + rc = nfs4_name_to_uid(nobody, id); + else + rc = nfs4_name_to_gid(nobody, id); + + if (rc) { + *id = -2; + rc = 0; + } + return rc; +} + +int nfs4_owner_to_uid(char *name, uid_t *uid) +{ + int rc = nfs4_name_to_uid(name, uid); + if (rc && id_as_chars(name, uid)) + rc = 0; + else if (rc) + rc = set_id_to_nobody(uid, 1); + return rc; +} + +int nfs4_group_owner_to_gid(char *name, gid_t *gid) +{ + int rc = nfs4_name_to_gid(name, gid); + if (rc && id_as_chars(name, gid)) + rc = 0; + else if (rc) + rc = set_id_to_nobody((uid_t *)gid, 0); + return rc; +} + +int nfs4_gss_princ_to_ids(char *secname, char *princ, uid_t *uid, gid_t *gid) +{ + RUN_TRANSLATIONS(princ_to_ids, 1, secname, princ, uid, gid, NULL); +} + +int nfs4_gss_princ_to_grouplist(char *secname, char *princ, + gid_t *groups, int *ngroups) +{ + RUN_TRANSLATIONS(gss_princ_to_grouplist, 1, secname, princ, + groups, ngroups, NULL); +} + +int nfs4_gss_princ_to_ids_ex(char *secname, char *princ, uid_t *uid, + gid_t *gid, extra_mapping_params **ex) +{ + RUN_TRANSLATIONS(princ_to_ids, 1, secname, princ, uid, gid, ex); +} + +int nfs4_gss_princ_to_grouplist_ex(char *secname, char *princ, gid_t *groups, + int *ngroups, extra_mapping_params **ex) +{ + RUN_TRANSLATIONS(gss_princ_to_grouplist, 1, secname, princ, + groups, ngroups, ex); +} + +void nfs4_set_debug(int dbg_level, void (*logger)(const char *, ...)) +{ + if (logger) + idmap_log_func = logger; + idmap_verbosity = dbg_level; + IDMAP_LOG(0, ("Setting log level to %d\n", idmap_verbosity)); +} + +const char *nfsidmap_config_get(const char *section, const char *tag) +{ + return conf_get_section(section, NULL, tag); +} diff --git a/support/nfsidmap/libnfsidmap.pc.in b/support/nfsidmap/libnfsidmap.pc.in new file mode 100644 index 0000000..a11dbec --- /dev/null +++ b/support/nfsidmap/libnfsidmap.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: libnfsidmap +Description: Library that handles mapping between names and ids for NFSv4. +Requires: +Version: @PACKAGE_VERSION@ +Libs: -L@libdir@ -lnfsidmap +Cflags: -I@includedir@ diff --git a/support/nfsidmap/libtest.c b/support/nfsidmap/libtest.c new file mode 100644 index 0000000..1c717b8 --- /dev/null +++ b/support/nfsidmap/libtest.c @@ -0,0 +1,160 @@ +/* + * libtest.c + * + * nfs idmapping library, primarily for nfs4 client/server kernel idmapping + * and for userland nfs4 idmapping by acl libraries. + * + * Copyright (c) 2004 The Regents of the University of Michigan. + * All rights reserved. + * + * Andy Adamson <andros@umich.edu> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * + * libtest: Test the translation table functions + * Reads /etc/idmapd.conf + * + * To compile: + * gcc -g libtest.c -lnfsidmap -o libtest + * + */ + +#include <stdio.h> +#include <string.h> +#include <sys/types.h> +#include <nfsidmap.h> + +#define QUIT_ON_ERROR 1 +#define PATH_IDMAPDCONF "/etc/idmapd.conf" +char *conf_path = PATH_IDMAPDCONF; + +main(int ac, char **av) +{ + char *name, *princ; + int err, uid = 0, gid = 0; + char name_buf[32]; + int gids[1000]; + int i, ngids; + + if (ac != 3) { + printf("Usage: %s <user@nfsv4domain> <k5princ@REALM>\n",av[0]); + return 1; + } + + nfs4_set_debug(3, NULL); + + name = av[1]; + princ = av[2]; + err = nfs4_init_name_mapping(NULL); + if (err) { + printf("nfs4_init_name_mapping: error %d\n", err); + return 1; + } + + err = nfs4_gss_princ_to_ids("krb5", princ, &uid, &gid); + if (err) + printf("nfs4_gss_princ_to_ids: error %d\n", err); + else + printf("nfs4_gss_princ_to_ids: princ %s has uid %d gid %d\n", + princ, uid, gid); +#if QUIT_ON_ERROR + if (err) { + printf("calling it quits!\n"); + return err; + } +#endif + + err = nfs4_name_to_uid(name, &uid); + if (err) + printf("nfs4_name_to_uid: error %d\n", err); + else + printf("nfs4_name_to_uid: name %s has uid %d\n", + name, uid); + +#if QUIT_ON_ERROR + if (err) { + printf("calling it quits!\n"); + return err; + } +#endif + err = nfs4_name_to_gid(name, &gid); + if (err) + printf("nfs4_name_to_gid: error %d\n", err); + else + printf("nfs4_name_to_gid: name %s has gid %d\n", + name, gid); + + ngids = 1000; + err = nfs4_gss_princ_to_grouplist("krb5", princ, gids, &ngids); + if (err){ + printf(" nfs4_gss_princ_to_grouplist: error %d\n", err); + } else { + printf(" nfs4_gss_princ_to_grouplist: princ %s has gids ", + princ); + for (i = 0; i < ngids; i++) printf("%d ", gids[i]); + printf("\n"); + } + +#if QUIT_ON_ERROR + if (err) { + printf("calling it quits!\n"); + return err; + } +#endif + /* uid is set by nfs4_name_to_uid() */ + memset(name_buf, 0, 32); + err = nfs4_uid_to_name(uid, NULL, name_buf, 32); + if (err) + printf("nfs4_uid_to_name: error %d\n", err); + else + printf("nfs4_uid_to_name: uid %d has name %s\n", + uid, name_buf); + +#if QUIT_ON_ERROR + if (err) { + printf("calling it quits!\n"); + return err; + } +#endif + /* gid is set by nfs4_name_to_gid() */ + memset(name_buf, 0, 32); + err = nfs4_gid_to_name(gid, NULL, name_buf, 32); + if (err) + printf("nfs4_gid_to_name: error %d\n", err); + else + printf("nfs4_gid_to_name: gid %d has name %s\n", + gid, name_buf); + +#if QUIT_ON_ERROR + if (err) { + printf("calling it quits!\n"); + return err; + } +#endif + return 0; +} diff --git a/support/nfsidmap/nfs4_uid_to_name.3 b/support/nfsidmap/nfs4_uid_to_name.3 new file mode 100644 index 0000000..8a62d8a --- /dev/null +++ b/support/nfsidmap/nfs4_uid_to_name.3 @@ -0,0 +1,174 @@ +.TH nfs4_uid_to_name 3 2004-08-05 +.SH NAME +nfs4_uid_to_name, nfs4_gid_to_name, nfs4_name_to_uid, nfs4_name_to_gid, +nfs4_init_name_mapping, nfs4_get_default_domain, +nfs4_gss_princ_to_ids, nfs4_gss_princ_to_grouplist, +nfs4_gss_princ_to_ids_ex, +nfs4_gss_princ_to_grouplist_ex, +nfs4_set_debug \- ID mapping routines used for NFSv4 +.SH SYNOPSIS +.B #include <nfs4_idmap.h> +.sp +.BI "int nfs4_init_name_mapping(char *conffile);" +.sp +.BI "int nfs4_get_default_domain(char *server, char *domain, size_t len);" +.sp +.BI "int nfs4_uid_to_name(uid_t uid, char *domain, char *name, size_t len);" +.sp +.BI "int nfs4_uid_to_owner(uid_t uid, char *domain, char *name, size_t len);" +.sp +.BI "int nfs4_gid_to_name(gid_t gid, char *domain, char *name, size_t len);" +.sp +.BI "int nfs4_gid_to_owner(gid_t gid, char *domain, char *name, size_t len);" +.sp +.BI "int nfs4_name_to_uid(char *name, uid_t *uid);" +.sp +.BI "int nfs4_name_to_gid(char *name, gid_t *gid);" +.sp +.BI "int nfs4_owner_to_uid(char *name, uid_t *uid);" +.sp +.BI "int nfs4_owner_to_gid(char *name, gid_t *gid);" +.sp +.BI "int nfs4_gss_princ_to_ids(char *secname, char *princ, uid_t *uid, gid_t *gid);" +.sp +.BI "int nfs4_gss_princ_to_grouplist(char *secname, char *princ, gid_t *groups, int *ngroups);" +.sp +.BI "int nfs4_gss_princ_to_ids_ex(char *secname, char *princ, uid_t *uid, gid_t *gid, extra_mapping_params **ex);" +.sp +.BI "int nfs4_gss_princ_to_grouplist_ex(char *secname, char *princ, gid_t *groups, int *ngroups, extra_mapping_params **ex);" +.sp +.BI "void nfs4_set_debug(int dbg_level, void (*logger)(const char *, ...));" +.sp +.fi +.SH DESCRIPTION +NFSv4 uses names of the form +.IR user@domain . +To write code that helps the kernel map uid's (as +rpc.idmapd +does) or that processes NFSv4 ACLs, you need to be able to convert between +NFSv4 names and local uids and gids. +.PP +The +.B nfs4_uid_to_name() +and +.B nfs4_gid_to_name() +functions, given +.I uid +or +.I gid +and +.I domain +(as a null-terminated string), +write the corresponding nfsv4 name into the buffer provided in +.IR name , +which must be of length at least +.IR len . +.PP +The +.B nfs4_uid_to_owner() +and +.B nfs4_gid_to_group_owner() +functions, given +.I uid +or +.I gid +and +.I domain +(as a null-terminated string), +write the corresponding nfsv4 name into the buffer provided in +.IR name , +which must be of length at least +.IR len . +If there is no valid mapping from +.I uid +or +.I gid +to +.IR name , +then the numerical string representing uid or gid is returned instead. +.PP +The +.B nfs4_name_to_uid() +and +.B nfs4_name_to_gid() +functions, given +.I name +(as a null-terminated string), return the corresponding uid or gid in +the second parameter. +.PP +The +.B nfs4_owner_to_uid() +and +.B nfs4_group_owner_to_gid() +functions, given +.I name +(as a null-terminated string), return the corresponding uid or gid in +the second parameter. +If there is no valid mapping from +.I name +to +.I uid +or +.I gid +the value for the user or group "nobody" will be returned instead. +. PP +The +.B nfs4_init_name_mapping() +function must be called before using any of these functions. It reads +defaults from the configuration file at the provided path, usually +"etc/idmapd.conf". +.PP +The +.I domain +argument to the id-to-name functions is there to provide a hint to the name +mapper in the case where an id might be mapped to names in multiple domains. +In most cases, this argument should just be the name returned in the +.I domain +argument to +.B nfs4_get_default_domain() +which should be called with +.I server +set to NULL. The +.I domain +should be a buffer of length +.IR len . +The constant NFS4_MAX_DOMAIN_LEN may be used to determine a reasonable +value for that length. +.PP +The function +.BR nfs4_get_grouplist() , +given a +.IR name , +fills the provided array +.I groups +with up to +.I *ngroups +group IDs corresponding to which the user +.I name +belongs to, setting +.I *ngroups +to the actual number of such groups. If the user belongs to more than +.I *ngroups +groups, then an error is returned and the actual number of groups is stored in +*ngroups. +.PP +Functions +.BR nfs4_gss_princ_to_ids() , +.BR nfs4_gss_princ_to_grouplist() , +.BR nfs4_gss_princ_to_ids_ex() , +and +.B nfs4_gss_princ_to_grouplist_ex() +are used to convert from a gss principal name (as returned by +.BR gss_display_name() ) +to a uid and gid, or list of gids. +.PP +Finally, +.B nfs4_set_debug() +allows the application to set a debugging level to produce extra +debugging information from within the library. The optional +.I logger +function specifies an alternative logging function to call for +the debug messages rather than the default internal function +within the library. +.SH RETURN VALUE +All functions return 0 or, in the case of error, -ERRNO. diff --git a/support/nfsidmap/nfsidmap.h b/support/nfsidmap/nfsidmap.h new file mode 100644 index 0000000..5a79568 --- /dev/null +++ b/support/nfsidmap/nfsidmap.h @@ -0,0 +1,68 @@ +/* + * nfsidmap.h + * + * nfs idmapping library, primarily for nfs4 client/server kernel idmapping + * and for userland nfs4 idmapping by acl libraries. + * + * Copyright (c) 2004 The Regents of the University of Michigan. + * All rights reserved. + * + * J. Bruce Fields <bfields@umich.edu> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* XXX arbitrary */ +#define NFS4_MAX_DOMAIN_LEN 512 +typedef enum { + X509_CERT = 1 +} extra_mapping_types; + +typedef struct _extra_mapping_params { + void *content; + int content_type; + int content_len; +} extra_mapping_params; + +typedef void (*nfs4_idmap_log_function_t)(const char *, ...); + +int nfs4_init_name_mapping(char *conffile); +void nfs4_term_name_mapping(void); +int nfs4_get_default_domain(char *server, char *domain, size_t len); +int nfs4_uid_to_name(uid_t uid, char *domain, char *name, size_t len); +int nfs4_gid_to_name(gid_t gid, char *domain, char *name, size_t len); +int nfs4_uid_to_owner(uid_t uid, char *domain, char *name, size_t len); +int nfs4_gid_to_group_owner(gid_t gid, char *domain, char *name, size_t len); +int nfs4_name_to_uid(char *name, uid_t *uid); +int nfs4_name_to_gid(char *name, gid_t *gid); +int nfs4_owner_to_uid(char *name, uid_t *uid); +int nfs4_owner_to_gid(char *name, gid_t *gid); +int nfs4_group_owner_to_gid(char *name, gid_t *gid); +int nfs4_gss_princ_to_ids(char *secname, char *princ, uid_t *uid, gid_t *gid); +int nfs4_gss_princ_to_grouplist(char *secname, char *princ, gid_t *groups, int *ngroups); +int nfs4_gss_princ_to_ids_ex(char *secname, char *princ, uid_t *uid, gid_t *gid, extra_mapping_params **ex); +int nfs4_gss_princ_to_grouplist_ex(char *secname, char *princ, gid_t *groups, int *ngroups, extra_mapping_params **ex); +void nfs4_set_debug(int dbg_level, nfs4_idmap_log_function_t dbg_logfunc); diff --git a/support/nfsidmap/nfsidmap_common.c b/support/nfsidmap/nfsidmap_common.c new file mode 100644 index 0000000..4d2cb14 --- /dev/null +++ b/support/nfsidmap/nfsidmap_common.c @@ -0,0 +1,118 @@ +/* + * nfsidmap_common.c + * + * nfs idmapping library, primarily for nfs4 client/server kernel idmapping + * and for userland nfs4 idmapping by acl libraries. + * + * Code common to libnfsidmap and some of its bundled plugins + * + * If you make use of these functions you must initialise your own + * copy of the config file data using: conf_init_file(nfsidmap_conf_path) + * failure to do so will appear as if the config was empty + */ + +#include "config.h" + +#include <sys/types.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <string.h> + +#include "nfsidmap.h" +#include "nfsidmap_private.h" +#include "nfsidmap_plugin.h" +#include "conffile.h" + +#pragma GCC visibility push(hidden) + +static char * toupper_str(char *s) +{ + size_t i; + for (i=0; i < strlen(s); i++) + s[i] = toupper(s[i]); + return s; +} + +static struct conf_list *local_realms = NULL; + +void free_local_realms(void) +{ + if (local_realms) { + conf_free_list(local_realms); + local_realms = NULL; + } +} + +/* Get list of "local equivalent" realms. Meaning the list of realms + * where john@REALM.A is considered the same user as john@REALM.B + * If not specified, default to upper-case of local domain name */ +struct conf_list *get_local_realms(void) +{ + if (local_realms) return local_realms; + + local_realms = conf_get_list("General", "Local-Realms"); + if (local_realms == NULL) { + struct conf_list_node *node; + + local_realms = malloc(sizeof *local_realms); + if (local_realms == NULL) + return NULL; + local_realms->cnt = 0; + TAILQ_INIT(&local_realms->fields); + + node = calloc(1, sizeof *node); + if (node == NULL) + return NULL; + + node->field = calloc(1, NFS4_MAX_DOMAIN_LEN); + if (node->field == NULL) { + free(node); + return NULL; + } + + nfs4_get_default_domain(NULL, node->field, NFS4_MAX_DOMAIN_LEN); + toupper_str(node->field); + + TAILQ_INSERT_TAIL(&local_realms->fields, node, link); + local_realms->cnt++; + } + return local_realms; +} + +static int no_strip = -1; +static int reformat_group = 0; + +int get_nostrip(void) +{ + if (no_strip != -1) return no_strip; + + char * nostrip = conf_get_str_with_def("General", "No-Strip", "none"); + if (strcasecmp(nostrip, "both") == 0) + no_strip = IDTYPE_USER|IDTYPE_GROUP; + else if (strcasecmp(nostrip, "group") == 0) + no_strip = IDTYPE_GROUP; + else if (strcasecmp(nostrip, "user") == 0) + no_strip = IDTYPE_USER; + else + no_strip = 0; + + if (no_strip & IDTYPE_GROUP) { + char * reformatgroup = conf_get_str_with_def("General", "Reformat-Group", "false"); + if ((strcasecmp(reformatgroup, "true") == 0) || + (strcasecmp(reformatgroup, "on") == 0) || + (strcasecmp(reformatgroup, "yes") == 0)) + reformat_group = 1; + else + reformat_group = 0; + } + + return no_strip; +} + +int get_reformat_group(void) +{ + if (no_strip != -1) return reformat_group; + + return reformat_group; +} diff --git a/support/nfsidmap/nfsidmap_plugin.h b/support/nfsidmap/nfsidmap_plugin.h new file mode 100644 index 0000000..66fcdaa --- /dev/null +++ b/support/nfsidmap/nfsidmap_plugin.h @@ -0,0 +1,70 @@ +/* + * nfsidmap_plugin.h + * + * Essentials functions and structs required when building + * plugins for libnfsidmap that are otherwise not exposed + * in the public API + * + * Copyright (c) 2004 The Regents of the University of Michigan. + * All rights reserved. + * + * Andy Adamson <andros@umich.edu> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +struct trans_func { + char *name; + int (*init)(void); + int (*princ_to_ids)(char *secname, char *princ, uid_t *uid, gid_t *gid, + extra_mapping_params **ex); + int (*name_to_uid)(char *name, uid_t *uid); + int (*name_to_gid)(char *name, gid_t *gid); + int (*uid_to_name)(uid_t uid, char *domain, char *name, size_t len); + int (*gid_to_name)(gid_t gid, char *domain, char *name, size_t len); + int (*gss_princ_to_grouplist)(char *secname, char *princ, gid_t *groups, + int *ngroups, extra_mapping_params **ex); +}; + +extern int idmap_verbosity; +extern nfs4_idmap_log_function_t idmap_log_func; +struct trans_func *libnfsidmap_plugin_init(void); + +/* Level zero always prints, others print depending on verbosity level */ +#define IDMAP_LOG(LVL, MSG) \ + do { if (LVL <= idmap_verbosity) (*idmap_log_func)MSG; } while (0) + +#ifndef UNUSED +#ifdef __GNUC__ +#define UNUSED(foo) UNUSED_ ## foo __attribute__((__unused__)) +#else +#define UNUSED(foo) UNUSED_ ## foo +#endif +#endif + +extern const char *nfsidmap_conf_path; +extern const char *nfsidmap_config_get(const char *section, const char *tag); + diff --git a/support/nfsidmap/nfsidmap_private.h b/support/nfsidmap/nfsidmap_private.h new file mode 100644 index 0000000..a5cb6dd --- /dev/null +++ b/support/nfsidmap/nfsidmap_private.h @@ -0,0 +1,54 @@ +/* + * nfsidmap_private.h + * + * For use only by bundled plugins, not for external use + * + * Copyright (c) 2004 The Regents of the University of Michigan. + * All rights reserved. + * + * Andy Adamson <andros@umich.edu> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "conffile.h" + +struct conf_list *get_local_realms(void); +void free_local_realms(void); +int get_nostrip(void); +int get_reformat_group(void); + +typedef enum { + IDTYPE_USER = 1, + IDTYPE_GROUP = 2 +} idtypes; + +typedef struct trans_func * (*libnfsidmap_plugin_init_t)(void); + +struct mapping_plugin { + void *dl_handle; + struct trans_func *trans; +}; diff --git a/support/nfsidmap/nss.c b/support/nfsidmap/nss.c new file mode 100644 index 0000000..0f43076 --- /dev/null +++ b/support/nfsidmap/nss.c @@ -0,0 +1,494 @@ +/* + * nss.c + * + * nsswitch idmapping functions. + * + * Copyright (c) 2004 The Regents of the University of Michigan. + * All rights reserved. + * + * J. Bruce Fields <bfields@umich.edu> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <sys/types.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <pwd.h> +#include <grp.h> +#include <netdb.h> +#include <err.h> +#include <grp.h> +#include <limits.h> +#include <ctype.h> +#include "nfsidmap.h" +#include "nfsidmap_plugin.h" +#include "nfsidmap_private.h" +#include <syslog.h> + +static char *get_default_domain(void) +{ + static char default_domain[NFS4_MAX_DOMAIN_LEN] = ""; + if (default_domain[0] == 0) { + nfs4_get_default_domain(NULL, default_domain, NFS4_MAX_DOMAIN_LEN); + } + return default_domain; +} + +/* + * NSS Translation Methods + * + * These are all just wrappers around getpwnam and friends; + * we tack on the given domain to the results of getpwnam when looking up a uid, + * and ignore the domain entirely when looking up a name. + */ + +static int write_name(char *dest, char *localname, char *domain, size_t len, + int doappend) +{ + if (doappend || !strchr(localname,'@')) { + if (strlen(localname) + 1 + strlen(domain) + 1 > len) + return -ENOMEM; /* XXX: Is there an -ETOOLONG? */ + strcpy(dest, localname); + strcat(dest, "@"); + strcat(dest, domain); + } else { + if (strlen(localname) + 1 > len) + return -ENOMEM; + strcpy(dest, localname); + } + return 0; +} + +static int nss_uid_to_name(uid_t uid, char *domain, char *name, size_t len) +{ + struct passwd *pw = NULL; + struct passwd pwbuf; + char *buf; + size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); + int err = -ENOMEM; + + buf = malloc(buflen); + if (!buf) + goto out; + if (domain == NULL) + domain = get_default_domain(); + err = -getpwuid_r(uid, &pwbuf, buf, buflen, &pw); + if (pw == NULL) + err = -ENOENT; + if (err) + goto out_buf; + if (get_nostrip() & IDTYPE_USER) + err = write_name(name, pw->pw_name, domain, len, 0); + else + err = write_name(name, pw->pw_name, domain, len, 1); +out_buf: + free(buf); +out: + return err; +} + +static int nss_gid_to_name(gid_t gid, char *domain, char *name, size_t len) +{ + struct group *gr = NULL; + struct group grbuf; + char *buf; + size_t buflen = sysconf(_SC_GETGR_R_SIZE_MAX); + int err; + + if (domain == NULL) + domain = get_default_domain(); + + do { + err = -ENOMEM; + buf = malloc(buflen); + if (!buf) + goto out; + err = -getgrgid_r(gid, &grbuf, buf, buflen, &gr); + if (gr == NULL && !err) + err = -ENOENT; + if (err == -ERANGE) { + buflen *= 2; + free(buf); + } + } while (err == -ERANGE); + + if (err) + goto out_buf; + if (get_nostrip() & IDTYPE_GROUP) + err = write_name(name, gr->gr_name, domain, len, 0); + else + err = write_name(name, gr->gr_name, domain, len, 1); +out_buf: + free(buf); +out: + return err; +} + +/* XXX: actually should return error, so can distinguish between + * memory allocation failure and failure to match domain */ +static char *strip_domain(const char *name, const char *domain) +{ + const char *c; + char *l = NULL; + int len; + + if (name == NULL) + goto out; + + c = strrchr(name, '@'); + if (c == NULL && domain != NULL) + goto out; + if (c == NULL && domain == NULL) { + len = strlen(name) + 1; + } else { + if (domain && strcasecmp(c + 1, domain) != 0) + goto out; + len = c - name; + } + + l = malloc(len + 1); + if (l == NULL) + goto out; + memcpy(l, name, len); + l[len] = '\0'; +out: + return l; +} + +struct pwbuf { + struct passwd pwbuf; + char buf[1]; +}; + +static struct passwd *nss_getpwnam(const char *name, const char *domain, + int *err_p, int dostrip) +{ + struct passwd *pw; + struct pwbuf *buf; + size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); + char *localname; + int err = ENOMEM; + + if (buflen > UINT_MAX) + goto err; + + buf = malloc(sizeof(*buf) + buflen); + if (buf == NULL) + goto err; + + err = EINVAL; + if (dostrip) { + localname = strip_domain(name, domain); + IDMAP_LOG(4, ("nss_getpwnam: name '%s' domain '%s': " + "resulting localname '%s'", name, domain, localname)); + if (localname == NULL) { + IDMAP_LOG(0, ("nss_getpwnam: name '%s' does not map " + "into domain '%s'", name, + domain ? domain : "<not-provided>")); + goto err_free_buf; + } + + err = getpwnam_r(localname, &buf->pwbuf, buf->buf, buflen, &pw); + if (pw == NULL && domain != NULL) + IDMAP_LOG(1, + ("nss_getpwnam: name '%s' not found in domain '%s'", + localname, domain)); + free(localname); + } else { + err = getpwnam_r(name, &buf->pwbuf, buf->buf, buflen, &pw); + if (pw == NULL) + IDMAP_LOG(1, + ("nss_getpwnam: name '%s' not found (domain not stripped)", name)); + } + if (err == 0 && pw != NULL) { + *err_p = 0; + return pw; + } else if (err == 0 && pw == NULL) { + err = ENOENT; + } + +err_free_buf: + free(buf); +err: + *err_p = -err; + return NULL; +} + +static int nss_name_to_uid(char *name, uid_t *uid) +{ + struct passwd *pw = NULL; + char *domain; + int err = -ENOENT; + + domain = get_default_domain(); + if (get_nostrip() & IDTYPE_USER) { + pw = nss_getpwnam(name, domain, &err, 0); + if (pw != NULL) + goto out_uid; + } + pw = nss_getpwnam(name, domain, &err, 1); + if (pw == NULL) + goto out; +out_uid: + *uid = pw->pw_uid; + IDMAP_LOG(4, ("nss_name_to_uid: name '%s' uid %u", name, *uid)); + free(pw); + err = 0; +out: + return err; +} + +static char *reformat_name(const char *name) +{ + const char *domain; + const char *c; + const char *d; + char *l = NULL; + int len; + int dlen = 0; + int i; + + c = strchr(name, '@'); + if (c == NULL) + goto out; + len = c - name; + domain = ++c; + d = strchr(domain, '.'); + if (d == NULL) + goto out; + dlen = d - domain; + l = malloc(dlen + 1 + len + 1); + if (l == NULL) + goto out; + for (i = 0; i < dlen; i++) + l[i] = toupper(domain[i]); + l[dlen] = '\\'; + memcpy(l + dlen + 1, name, len); + l[dlen + 1 + len] = '\0'; +out: + return l; +} + +static int _nss_name_to_gid(char *name, gid_t *gid, int dostrip) +{ + struct group *gr = NULL; + struct group grbuf; + char *buf, *domain; + size_t buflen = sysconf(_SC_GETGR_R_SIZE_MAX); + int err = -EINVAL; + char *localname = NULL; + char *ref_name = NULL; + + domain = get_default_domain(); + if (dostrip) { + localname = strip_domain(name, domain); + IDMAP_LOG(4, ("nss_name_to_gid: name '%s' domain '%s': " + "resulting localname '%s'", name, domain, localname)); + if (!localname) { + IDMAP_LOG(0, ("nss_name_to_gid: name '%s' does not map " + "into domain '%s'", name, domain)); + goto out; + } + } else if (get_reformat_group()) { + ref_name = reformat_name(name); + if (ref_name == NULL) { + IDMAP_LOG(1, ("nss_name_to_gid: failed to reformat name '%s'", + name)); + err = -ENOENT; + goto out; + } + } + + err = -ENOMEM; + if (buflen > UINT_MAX) + goto out_name; + + do { + buf = malloc(buflen); + if (!buf) + goto out_name; + if (dostrip) + err = -getgrnam_r(localname, &grbuf, buf, buflen, &gr); + else if (get_reformat_group()) + err = -getgrnam_r(ref_name, &grbuf, buf, buflen, &gr); + else + err = -getgrnam_r(name, &grbuf, buf, buflen, &gr); + if (gr == NULL && !err) { + if (dostrip) + IDMAP_LOG(1, ("nss_name_to_gid: name '%s' not found " + "in domain '%s'", localname, domain)); + else if (get_reformat_group()) + IDMAP_LOG(1, ("nss_name_to_gid: name '%s' not found " + "(reformatted)", ref_name)); + else + IDMAP_LOG(1, ("nss_name_to_gid: name '%s' not found " + "(domain not stripped)", name)); + err = -ENOENT; + } + if (err == -ERANGE) { + buflen *= 2; + free(buf); + } + } while (err == -ERANGE); + + if (err) + goto out_buf; + *gid = gr->gr_gid; + IDMAP_LOG(4, ("nss_name_to_gid: name '%s' gid %u", name, *gid)); +out_buf: + free(buf); +out_name: + free(localname); + free(ref_name); +out: + return err; +} + +static int nss_name_to_gid(char *name, gid_t *gid) +{ + int err = 0; + + if (get_nostrip() & IDTYPE_GROUP) { + err = _nss_name_to_gid(name, gid, 0); + if (!err) + goto out; + } + err = _nss_name_to_gid(name, gid, 1); +out: + return err; +} + +static int nss_gss_princ_to_ids(char *secname, char *princ, + uid_t *uid, uid_t *gid, + extra_mapping_params **UNUSED(ex)) +{ + struct passwd *pw; + int err = 0; + char *princ_realm; + struct conf_list *realms; + struct conf_list_node *r; + int found = 0; + + if (strcmp(secname, "spkm3") == 0) + return -ENOENT; + + if (strcmp(secname, "krb5") != 0) + return -EINVAL; + + /* get princ's realm */ + princ_realm = strstr(princ, "@"); + if (princ_realm == NULL) + return -EINVAL; + princ_realm++; + + /* get list of "local-equivalent" realms and + * check against the principal's realm */ + realms = get_local_realms(); + TAILQ_FOREACH(r, &realms->fields, link) { + if (strcmp(r->field, princ_realm) == 0) { + found = 1; + break; + } + } + if (!found) { + IDMAP_LOG(1, ("nss_gss_princ_to_ids: Local-Realm '%s': NOT FOUND", + princ_realm)); + return -ENOENT; + } + /* XXX: this should call something like getgssauthnam instead? */ + pw = nss_getpwnam(princ, NULL, &err, 1); + if (pw == NULL) { + err = -ENOENT; + goto out; + } + *uid = pw->pw_uid; + *gid = pw->pw_gid; + free(pw); +out: + return err; +} + +static int nss_gss_princ_to_grouplist(char *secname, char *princ, + gid_t *groups, int *ngroups, + extra_mapping_params **UNUSED(ex)) +{ + struct passwd *pw; + int ret = -EINVAL; + + if (strcmp(secname, "krb5") != 0) + goto out; + /* XXX: not quite right? Need to know default realm? */ + /* XXX: this should call something like getgssauthnam instead? */ + pw = nss_getpwnam(princ, NULL, &ret, 1); + if (pw == NULL) { + ret = -ENOENT; + goto out; + } + if (getgrouplist(pw->pw_name, pw->pw_gid, groups, ngroups) < 0) + ret = -ERANGE; + free(pw); +out: + return ret; +} + +static int nss_plugin_init(void) +{ + if (nfsidmap_conf_path) + conf_init_file(nfsidmap_conf_path); + return 0; +} + +/* + * Called by dlclose(). See dlopen(3) man page + */ +__attribute__((destructor)) +static int nss_plugin_term(void) +{ + free_local_realms(); + conf_cleanup(); + return 0; +} + + +struct trans_func nss_trans = { + .name = "nsswitch", + .init = nss_plugin_init, + .princ_to_ids = nss_gss_princ_to_ids, + .name_to_uid = nss_name_to_uid, + .name_to_gid = nss_name_to_gid, + .uid_to_name = nss_uid_to_name, + .gid_to_name = nss_gid_to_name, + .gss_princ_to_grouplist = nss_gss_princ_to_grouplist, +}; + +struct trans_func *libnfsidmap_plugin_init(void) +{ + return (&nss_trans); +} diff --git a/support/nfsidmap/regex.c b/support/nfsidmap/regex.c new file mode 100644 index 0000000..8424179 --- /dev/null +++ b/support/nfsidmap/regex.c @@ -0,0 +1,549 @@ +/* + * regex.c + * + * regex idmapping functions. + * + * Copyright (c) 2017-2020 Stefan Walter <stefan.walter@inf.ethz.ch>. + * Copyright (c) 2008 David H?rdeman <david@hardeman.nu>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <pwd.h> +#include <grp.h> +#include <errno.h> +#include <err.h> +#include <regex.h> + +#include "nfsidmap.h" +#include "nfsidmap_plugin.h" + +#define CONFIG_GET_STRING nfsidmap_config_get +extern const char *nfsidmap_config_get(const char *, const char *); + +#define MAX_MATCHES 100 + +regex_t group_re; +regex_t user_re; +regex_t gpx_re; +int use_gpx; +const char * group_prefix; +const char * group_name_prefix; +const char * group_suffix; +const char * user_prefix; +const char * user_suffix; +const char * group_map_file; +const char * group_map_section; +char empty = '\0'; +size_t group_name_prefix_length; + +struct pwbuf { + struct passwd pwbuf; + char buf[1]; +}; + +struct grbuf { + struct group grbuf; + char buf[1]; +}; + +static char *get_default_domain(void) +{ + static char default_domain[NFS4_MAX_DOMAIN_LEN] = ""; + if (default_domain[0] == 0) { + nfs4_get_default_domain(NULL, default_domain, NFS4_MAX_DOMAIN_LEN); + } + return default_domain; +} + +/* + * Regexp Translation Methods + * + */ + +static struct passwd *regex_getpwnam(const char *name, const char *UNUSED(domain), + int *err_p) +{ + struct passwd *pw; + struct pwbuf *buf; + size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); + char *localname; + size_t namelen; + int err; + int status; + int index; + regmatch_t matches[MAX_MATCHES]; + + buf = malloc(sizeof(*buf) + buflen); + if (!buf) { + err = ENOMEM; + goto err; + } + + status = regexec(&user_re, name, MAX_MATCHES, matches, 0); + if (status) { + IDMAP_LOG(4, ("regexp_getpwnam: user '%s' did not match regex", name)); + err = ENOENT; + goto err_free_buf; + } + + for (index = 1; index < MAX_MATCHES ; index++) + { + if (matches[index].rm_so >= 0) + break; + } + + if (index == MAX_MATCHES) { + IDMAP_LOG(4, ("regexp_getpwnam: user '%s' did not match regex", name)); + err = ENOENT; + goto err_free_buf; + } + + namelen = matches[index].rm_eo - matches[index].rm_so; + localname= malloc(namelen + 1); + if (!localname) + { + err = ENOMEM; + goto err_free_buf; + } + strncpy(localname, name+matches[index].rm_so, namelen); + localname[namelen] = '\0'; + +again: + err = getpwnam_r(localname, &buf->pwbuf, buf->buf, buflen, &pw); + + if (err == EINTR) + goto again; + + if (!pw) { + if (err == 0) + err = ENOENT; + + IDMAP_LOG(4, ("regex_getpwnam: local user '%s' for '%s' not found", + localname, name)); + + goto err_free_name; + } + + IDMAP_LOG(4, ("regexp_getpwnam: name '%s' mapped to '%s'", + name, localname)); + + free(localname); + *err_p = 0; + return pw; + +err_free_name: + free(localname); +err_free_buf: + free(buf); +err: + *err_p = err; + return NULL; +} + +static struct group *regex_getgrnam(const char *name, const char *UNUSED(domain), + int *err_p) +{ + struct group *gr; + struct grbuf *buf; + size_t buflen = sysconf(_SC_GETGR_R_SIZE_MAX); + char *localgroup; + char *groupname; + size_t namelen; + int err = 0; + int index; + int status; + regmatch_t matches[MAX_MATCHES]; + + buf = malloc(sizeof(*buf) + buflen); + if (!buf) { + err = ENOMEM; + goto err; + } + + status = regexec(&group_re, name, MAX_MATCHES, matches, 0); + if (status) { + IDMAP_LOG(4, ("regexp_getgrnam: group '%s' did not match regex", name)); + err = ENOENT; + goto err_free_buf; + } + + for (index = 1; index < MAX_MATCHES ; index++) + { + if (matches[index].rm_so >= 0) + break; + } + + if (index == MAX_MATCHES) { + IDMAP_LOG(4, ("regexp_getgrnam: group '%s' did not match regex", name)); + err = ENOENT; + goto err_free_buf; + } + + namelen = matches[index].rm_eo - matches[index].rm_so; + localgroup = malloc(namelen + 1); + if (!localgroup) + { + err = ENOMEM; + goto err_free_buf; + } + strncpy(localgroup, name+matches[index].rm_so, namelen); + localgroup[namelen] = '\0'; + + IDMAP_LOG(4, ("regexp_getgrnam: group '%s' after match of regex", localgroup)); + + groupname = localgroup; + if (group_name_prefix_length && ! strncmp(group_name_prefix, localgroup, group_name_prefix_length)) + { + err = 1; + if (use_gpx) + err = regexec(&gpx_re, localgroup, 0, NULL, 0); + + if (err) + { + IDMAP_LOG(4, ("regexp_getgrnam: removing prefix '%s' (%d long) from group '%s'", group_name_prefix, group_name_prefix_length, localgroup)); + groupname += group_name_prefix_length; + } + else + { + IDMAP_LOG(4, ("regexp_getgrnam: not removing prefix from group '%s'", localgroup)); + } + } + + IDMAP_LOG(4, ("regexp_getgrnam: will use '%s'", groupname)); + +again: + err = getgrnam_r(groupname, &buf->grbuf, buf->buf, buflen, &gr); + + if (err == EINTR) + goto again; + + if (!gr) { + if (err == 0) + err = ENOENT; + + IDMAP_LOG(4, ("regex_getgrnam: local group '%s' for '%s' not found", groupname, name)); + + goto err_free_name; + } + + IDMAP_LOG(4, ("regex_getgrnam: group '%s' mapped to '%s'", name, groupname)); + + free(localgroup); + + *err_p = 0; + return gr; + +err_free_name: + free(localgroup); +err_free_buf: + free(buf); +err: + *err_p = err; + return NULL; +} + +static int regex_gss_princ_to_ids(char *secname, char *princ, + uid_t *uid, uid_t *gid, + extra_mapping_params **UNUSED(ex)) +{ + struct passwd *pw; + int err; + + /* XXX: Is this necessary? */ + if (strcmp(secname, "krb5") != 0 && strcmp(secname, "spkm3") != 0) + return -EINVAL; + + pw = regex_getpwnam(princ, NULL, &err); + + if (pw) { + *uid = pw->pw_uid; + *gid = pw->pw_gid; + free(pw); + } + + return -err; +} + +static int regex_gss_princ_to_grouplist(char *secname, char *princ, + gid_t *groups, int *ngroups, + extra_mapping_params **UNUSED(ex)) +{ + struct passwd *pw; + int err; + + /* XXX: Is this necessary? */ + if (strcmp(secname, "krb5") != 0 && strcmp(secname, "spkm3") != 0) + return -EINVAL; + + pw = regex_getpwnam(princ, NULL, &err); + + if (pw) { + if (getgrouplist(pw->pw_name, pw->pw_gid, groups, ngroups) < 0) + err = -ERANGE; + free(pw); + } + + return -err; +} + +static int regex_name_to_uid(char *name, uid_t *uid) +{ + struct passwd *pw; + int err; + + pw = regex_getpwnam(name, NULL, &err); + + if (pw) { + *uid = pw->pw_uid; + free(pw); + } + + return -err; +} + +static int regex_name_to_gid(char *name, gid_t *gid) +{ + struct group *gr; + int err; + + gr = regex_getgrnam(name, NULL, &err); + + if (gr) { + *gid = gr->gr_gid; + free(gr); + } + + return -err; +} + +static int write_name(char *dest, char *localname, const char* name_prefix, const char *prefix, const char *suffix, size_t len) +{ + if (strlen(localname) + strlen(name_prefix) + strlen(prefix) + strlen(suffix) + 1 > len) { + return -ENOMEM; /* XXX: Is there an -ETOOLONG? */ + } + strcpy(dest, prefix); + strcat(dest, name_prefix); + strcat(dest, localname); + strcat(dest, suffix); + + IDMAP_LOG(4, ("write_name: will use '%s'", dest)); + + return 0; +} + +static int regex_uid_to_name(uid_t uid, char *domain, char *name, size_t len) +{ + struct passwd *pw = NULL; + struct passwd pwbuf; + char *buf; + size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); + int err = -ENOMEM; + + buf = malloc(buflen); + if (!buf) + goto out; + if (domain == NULL) + domain = get_default_domain(); + err = -getpwuid_r(uid, &pwbuf, buf, buflen, &pw); + if (pw == NULL) + err = -ENOENT; + if (err) + goto out_buf; + err = write_name(name, pw->pw_name, &empty, user_prefix, user_suffix, len); +out_buf: + free(buf); +out: + return err; +} + +static int regex_gid_to_name(gid_t gid, char *UNUSED(domain), char *name, size_t len) +{ + struct group *gr = NULL; + struct group grbuf; + char *buf; + const char *name_prefix; + size_t buflen = sysconf(_SC_GETGR_R_SIZE_MAX); + int err; + char * groupname = NULL; + + do { + err = -ENOMEM; + buf = malloc(buflen); + if (!buf) + goto out; + err = -getgrgid_r(gid, &grbuf, buf, buflen, &gr); + if (gr == NULL && !err) + err = -ENOENT; + if (err == -ERANGE) { + buflen *= 2; + free(buf); + } + } while (err == -ERANGE); + + if (err) + goto out_buf; + + groupname = gr->gr_name; + name_prefix = group_name_prefix; + if (group_name_prefix_length) + { + if(! strncmp(group_name_prefix, groupname, group_name_prefix_length)) + { + name_prefix = ∅ + } + else if (use_gpx) + { + err = regexec(&gpx_re, groupname, 0, NULL, 0); + if (!err) + { + IDMAP_LOG(4, ("regex_gid_to_name: not adding prefix to group '%s'", groupname)); + name_prefix = ∅ + } + } + } + + err = write_name(name, groupname, name_prefix, group_prefix, group_suffix, len); + +out_buf: + free(buf); +out: + return err; +} + +static int regex_init(void) { + const char *string; + int status; + + + string = CONFIG_GET_STRING("Regex", "User-Regex"); + if (!string) + { + warnx("regex_init: regex for user mapping missing"); + goto error1; + } + + status = regcomp(&user_re, string, REG_EXTENDED|REG_ICASE); + if (status) + { + warnx("regex_init: compiling regex for user mapping failed with status %u", status); + goto error1; + } + + string = CONFIG_GET_STRING("Regex", "Group-Regex"); + if (!string) + { + warnx("regex_init: regex for group mapping missing"); + goto error2; + } + + status = regcomp(&group_re, string, REG_EXTENDED|REG_ICASE); + if (status) + { + warnx("regex_init: compiling regex for group mapping failed with status %u", status); + goto error2; + } + + group_name_prefix = CONFIG_GET_STRING("Regex", "Group-Name-Prefix"); + if (!group_name_prefix) + { + group_name_prefix = ∅ + } + group_name_prefix_length = strlen(group_name_prefix); + + user_prefix = CONFIG_GET_STRING("Regex", "Prepend-Before-User"); + if (!user_prefix) + { + user_prefix = ∅ + } + + user_suffix = CONFIG_GET_STRING("Regex", "Append-After-User"); + if (!user_suffix) + { + user_suffix = ∅ + } + + group_prefix = CONFIG_GET_STRING("Regex", "Prepend-Before-Group"); + if (!group_prefix) + { + group_prefix = ∅ + } + + group_suffix = CONFIG_GET_STRING("Regex", "Append-After-Group"); + if (!group_suffix) + { + group_suffix = ∅ + } + + string = CONFIG_GET_STRING("Regex", "Group-Name-No-Prefix-Regex"); + use_gpx = 0; + if (string) + { + status = regcomp(&gpx_re, string, REG_EXTENDED|REG_ICASE); + + if (status) + { + warnx("regex_init: compiling regex for group prefix exclusion failed with status %u", status); + goto error3; + } + + use_gpx = 1; + } + + return 0; + +error3: + regfree(&group_re); +error2: + regfree(&user_re); +error1: + return 0; + /* return -EINVAL; */ +} + + +struct trans_func regex_trans = { + .name = "regex", + .init = regex_init, + .name_to_uid = regex_name_to_uid, + .name_to_gid = regex_name_to_gid, + .uid_to_name = regex_uid_to_name, + .gid_to_name = regex_gid_to_name, + .princ_to_ids = regex_gss_princ_to_ids, + .gss_princ_to_grouplist = regex_gss_princ_to_grouplist, +}; + +struct trans_func *libnfsidmap_plugin_init(void) +{ + return (®ex_trans); +} + diff --git a/support/nfsidmap/static.c b/support/nfsidmap/static.c new file mode 100644 index 0000000..8ac4a39 --- /dev/null +++ b/support/nfsidmap/static.c @@ -0,0 +1,426 @@ +/* + * static.c + * + * static idmapping functions for gss principals. + * + * Copyright (c) 2008 David Härdeman <david@hardeman.nu>. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <pwd.h> +#include <grp.h> +#include <errno.h> +#include <err.h> + +#include "conffile.h" +#include "nfsidmap.h" +#include "nfsidmap_plugin.h" + +/* + * Static Translation Methods + * + * These functions use getpwnam to find uid/gid(s) for gss principals + * which are first mapped to local user names using static mappings + * in idmapd.conf. + */ + +struct pwbuf { + struct passwd pwbuf; + char buf[1]; +}; + +struct grbuf { + struct group grbuf; + char buf[1]; +}; + +struct uid_mapping { + LIST_ENTRY (uid_mapping) link; + uid_t uid; + char * principal; + char * localname; +}; + +struct gid_mapping { + LIST_ENTRY (gid_mapping) link; + gid_t gid; + char * principal; + char * localgroup; +}; + +static __inline__ u_int8_t uid_hash (uid_t uid) +{ + return uid % 256; +} + +static __inline__ u_int8_t gid_hash (gid_t gid) +{ + return gid % 256; +} + +//Hash tables of uid and guids to principals mappings. +//We reuse some queue/hash functions from cfg.c. +LIST_HEAD (uid_mappings, uid_mapping) uid_mappings[256]; +LIST_HEAD (gid_mappings, gid_mapping) gid_mappings[256]; + +static struct passwd *static_getpwnam(const char *name, + const char *UNUSED(domain), + int *err_p) +{ + struct passwd *pw; + struct pwbuf *buf; + size_t buflen = sysconf(_SC_GETPW_R_SIZE_MAX); + char *localname; + int err; + + buf = malloc(sizeof(*buf) + buflen); + if (!buf) { + err = ENOMEM; + goto err; + } + + localname = conf_get_str("Static", (char *)name); + if (!localname) { + err = ENOENT; + goto err_free_buf; + } + +again: + err = getpwnam_r(localname, &buf->pwbuf, buf->buf, buflen, &pw); + + if (err == EINTR) + goto again; + + if (!pw) { + if (err == 0) + err = ENOENT; + + IDMAP_LOG(0, ("static_getpwnam: localname '%s' for '%s' not found", + localname, name)); + + goto err_free_buf; + } + + IDMAP_LOG(4, ("static_getpwnam: name '%s' mapped to '%s'", + name, localname)); + + *err_p = 0; + return pw; + +err_free_buf: + free(buf); +err: + *err_p = err; + return NULL; +} + +static struct group *static_getgrnam(const char *name, + const char *UNUSED(domain), + int *err_p) +{ + struct group *gr; + struct grbuf *buf; + size_t buflen = sysconf(_SC_GETGR_R_SIZE_MAX); + char *localgroup; + int err; + + buf = malloc(sizeof(*buf) + buflen); + if (!buf) { + err = ENOMEM; + goto err; + } + + localgroup = conf_get_str("Static", (char *)name); + if (!localgroup) { + err = ENOENT; + goto err_free_buf; + } + +again: + err = getgrnam_r(localgroup, &buf->grbuf, buf->buf, buflen, &gr); + + if (err == EINTR) + goto again; + + if (!gr) { + if (err == 0) + err = ENOENT; + + IDMAP_LOG(0, ("static_getgrnam: local group '%s' for '%s' not found", + localgroup, name)); + + goto err_free_buf; + } + + IDMAP_LOG(4, ("static_getgrnam: group '%s' mapped to '%s'", + name, localgroup)); + + *err_p = 0; + return gr; + +err_free_buf: + free(buf); +err: + *err_p = err; + return NULL; +} + +static int static_gss_princ_to_ids(char *secname, char *princ, + uid_t *uid, uid_t *gid, + extra_mapping_params **UNUSED(ex)) +{ + struct passwd *pw; + int err; + + /* XXX: Is this necessary? */ + if (strcmp(secname, "krb5") != 0 && strcmp(secname, "spkm3") != 0) + return -EINVAL; + + pw = static_getpwnam(princ, NULL, &err); + + if (pw) { + *uid = pw->pw_uid; + *gid = pw->pw_gid; + free(pw); + } + + return -err; +} + +static int static_gss_princ_to_grouplist(char *secname, char *princ, + gid_t *groups, int *ngroups, + extra_mapping_params **UNUSED(ex)) +{ + struct passwd *pw; + int err; + + /* XXX: Is this necessary? */ + if (strcmp(secname, "krb5") != 0 && strcmp(secname, "spkm3") != 0) + return -EINVAL; + + pw = static_getpwnam(princ, NULL, &err); + + if (pw) { + if (getgrouplist(pw->pw_name, pw->pw_gid, groups, ngroups) < 0) + err = -ERANGE; + free(pw); + } + + return -err; +} + +static int static_name_to_uid(char *name, uid_t *uid) +{ + struct passwd *pw; + int err; + + pw = static_getpwnam(name, NULL, &err); + + if (pw) { + *uid = pw->pw_uid; + free(pw); + } + + return -err; +} + +static int static_name_to_gid(char *name, gid_t *gid) +{ + struct group *gr; + int err; + + gr = static_getgrnam(name, NULL, &err); + + if (gr) { + *gid = gr->gr_gid; + free(gr); + } + + return -err; +} + +static int static_uid_to_name(uid_t uid, char *UNUSED(domain), char *name, size_t UNUSED(len)) +{ + struct uid_mapping * um; + + for (um = LIST_FIRST (&uid_mappings[uid_hash (uid)]); um; + um = LIST_NEXT (um, link)) { + if (um->uid == uid) { + strcpy(name, um->principal); + return 0; + } + } + + return -ENOENT; +} + +static int static_gid_to_name(gid_t gid, char *UNUSED(domain), char *name, size_t UNUSED(len)) +{ + struct gid_mapping * gm; + + for (gm = LIST_FIRST (&gid_mappings[gid_hash (gid)]); gm; + gm = LIST_NEXT (gm, link)) { + if (gm->gid == gid) { + strcpy(name, gm->principal); + return 0; + } + } + + return -ENOENT; +} + +/* + * We buffer all UID's for which static mappings is defined in advance, so the + * uid_to_name functions will be fast enough. + */ + +static int static_init(void) { + int err; + struct conf_list * princ_list = NULL; + struct conf_list_node * cln, *next; + struct uid_mapping * unode; + struct gid_mapping * gnode; + struct passwd * pw = NULL; + struct group * gr = NULL; + unsigned int i; + + //init hash_table first + for (i = 0; i < sizeof uid_mappings / sizeof uid_mappings[0]; i++) + LIST_INIT (&uid_mappings[i]); + + if (nfsidmap_conf_path) + conf_init_file(nfsidmap_conf_path); + + //get all principals for which we have mappings + princ_list = conf_get_tag_list("Static", NULL); + + if (!princ_list) { + return -ENOENT; + } + + /* As we can not distinguish between mappings for users and groups, we try to + * resolve all mappings for both cases. + */ + + //resolve uid of localname account for all such principals and cache it + for (cln = TAILQ_FIRST (&princ_list->fields); cln; cln = next) + { + next = TAILQ_NEXT (cln, link); + + pw = static_getpwnam(cln->field, NULL, &err); + if (!pw) { + continue; + } + + unode = calloc (1, sizeof *unode); + if (!unode) + { + warnx("static_init: calloc (1, %lu) failed", + (unsigned long)sizeof *unode); + free(pw); + conf_free_list(princ_list); + return -ENOMEM; + } + unode->uid = pw->pw_uid; + unode->principal = strdup(cln->field); + + unode->localname = conf_get_str("Static", cln->field); + if (!unode->localname) { + free(pw); + free(unode->principal); + free(unode); + conf_free_list(princ_list); + return -ENOENT; + } + + free(pw); + + LIST_INSERT_HEAD (&uid_mappings[uid_hash(unode->uid)], unode, link); + } + + //resolve gid of localgroup accounts and cache it + for (cln = TAILQ_FIRST (&princ_list->fields); cln; cln = next) + { + next = TAILQ_NEXT (cln, link); + + gr = static_getgrnam(cln->field, NULL, &err); + if (!gr) { + continue; + } + + gnode = calloc (1, sizeof *gnode); + if (!gnode) + { + warnx("static_init: calloc (1, %lu) failed", + (unsigned long)sizeof *gnode); + free(gr); + conf_free_list(princ_list); + return -ENOMEM; + } + gnode->gid = gr->gr_gid; + gnode->principal = strdup(cln->field); + + gnode->localgroup = conf_get_str("Static", cln->field); + if (!gnode->localgroup) { + free(gr); + free(gnode->principal); + free(gnode); + conf_free_list(princ_list); + return -ENOENT; + } + + free(gr); + + LIST_INSERT_HEAD (&gid_mappings[gid_hash(gnode->gid)], gnode, link); + } + + conf_free_list(princ_list); + return 0; +} + + +struct trans_func static_trans = { + .name = "static", + .init = static_init, + .name_to_uid = static_name_to_uid, + .name_to_gid = static_name_to_gid, + .uid_to_name = static_uid_to_name, + .gid_to_name = static_gid_to_name, + .princ_to_ids = static_gss_princ_to_ids, + .gss_princ_to_grouplist = static_gss_princ_to_grouplist, +}; + +struct trans_func *libnfsidmap_plugin_init(void) +{ + return (&static_trans); +} + diff --git a/support/nfsidmap/umich_ldap.c b/support/nfsidmap/umich_ldap.c new file mode 100644 index 0000000..1aa2af4 --- /dev/null +++ b/support/nfsidmap/umich_ldap.c @@ -0,0 +1,1615 @@ +/* + * umich_ldap.c + * + * Copyright (c) 2000 The Regents of the University of Michigan. + * All rights reserved. + * + * Copyright (c) 2004 Andy Adamson <andros@UMICH.EDU> + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR + * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF + * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +#include "config.h" + +#include <sys/types.h> +#include <sys/socket.h> +#include <netdb.h> +#include <errno.h> +#include <unistd.h> +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <limits.h> +#include <pwd.h> +#include <err.h> +#ifdef HAVE_GSSAPI_GSSAPI_KRB5_H +#include <gssapi/gssapi_krb5.h> +#endif /* HAVE_GSSAPI_GSSAPI_KRB5_H */ +#ifdef HAVE_SASL_H +#include <sasl.h> +#endif /* HAVE_SASL_H */ +#ifdef HAVE_SASL_SASL_H +#include <sasl/sasl.h> +#endif /* HAVE_SASL_SASL_H */ +/* We are using deprecated functions, get the prototypes... */ +#define LDAP_DEPRECATED 1 +#include <ldap.h> +#include "nfslib.h" +#include "nfsidmap.h" +#include "nfsidmap_plugin.h" +#include "nfsidmap_private.h" +#include "conffile.h" + +/* attribute/objectclass default mappings */ +#define DEFAULT_UMICH_OBJCLASS_REMOTE_PERSON "NFSv4RemotePerson" +#define DEFAULT_UMICH_OBJCLASS_REMOTE_GROUP "NFSv4RemoteGroup" +#define DEFAULT_UMICH_ATTR_NFSNAME "NFSv4Name" +#define DEFAULT_UMICH_ATTR_ACCTNAME "uid" +#define DEFAULT_UMICH_ATTR_UIDNUMBER "uidNumber" +#define DEFAULT_UMICH_ATTR_GROUP_NFSNAME "NFSv4Name" +#define DEFAULT_UMICH_ATTR_GIDNUMBER "gidNumber" +#define DEFAULT_UMICH_ATTR_MEMBERUID "memberUid" +#define DEFAULT_UMICH_ATTR_GSSAUTHNAME "GSSAuthName" +#define DEFAULT_UMICH_ATTR_MEMBEROF "memberof" + +#define DEFAULT_UMICH_SEARCH_TIMEOUT 4 + +/* config section */ +#define LDAP_SECTION "UMICH_SCHEMA" + +#ifndef LDAP_FILT_MAXSIZ +#define LDAP_FILT_MAXSIZ 1024 +#endif + + +/* Local structure definitions */ + +struct ldap_map_names{ + char *NFSv4_person_objcls; + char *NFSv4_nfsname_attr; + char *NFSv4_acctname_attr; + char *NFSv4_uid_attr; + char *NFSv4_group_objcls; + char *NFSv4_group_nfsname_attr; + char *NFSv4_gid_attr; + char *NFSv4_member_attr; + char *NFSv4_member_of_attr; + char *GSS_principal_attr; + char *NFSv4_grouplist_filter; /* Filter for grouplist lookups */ +}; + +struct umich_ldap_info { + char *server; /* server name/address */ + int port; /* server port */ + char *base; /* base DN */ + char *people_tree; /* base DN to start searches for people */ + char *group_tree; /* base DN to start searches for groups */ + char *user_dn; /* optional DN for user account when binding */ + char *passwd; /* Password to use when binding to directory */ + int use_ssl; /* SSL flag */ + char *ca_cert; /* File location of the ca_cert */ + int tls_reqcert; /* req and validate server cert */ + int memberof_for_groups;/* Use 'memberof' attribute when + looking up user groups */ + int ldap_timeout; /* Timeout in seconds for searches + by ldap_search_st */ + int follow_referrals; /* whether to follow ldap referrals */ + char *sasl_mech; /* sasl mech to be used */ + char *sasl_realm; /* SASL realm for SASL authentication */ + char *sasl_authcid; /* authentication identity to be used */ + char *sasl_authzid; /* authorization identity to be used */ + char *sasl_secprops; /* Cyrus SASL security properties. */ + int sasl_canonicalize; /* canonicalize LDAP server host name */ + char *sasl_krb5_ccname; /* krb5 ticket cache */ +}; + +/* GLOBAL data */ + +static struct umich_ldap_info ldap_info = { + .server = NULL, + .port = 0, + .base = NULL, + .people_tree = NULL, + .group_tree = NULL, + .user_dn = NULL, + .passwd = NULL, + .use_ssl = 0, + .ca_cert = NULL, + .tls_reqcert = LDAP_OPT_X_TLS_HARD, + .memberof_for_groups = 0, + .ldap_timeout = DEFAULT_UMICH_SEARCH_TIMEOUT, + .follow_referrals = 1, + .sasl_mech = NULL, + .sasl_realm = NULL, + .sasl_authcid = NULL, + .sasl_authzid = NULL, + .sasl_secprops = NULL, + .sasl_canonicalize = -1, /* leave to the LDAP lib */ + .sasl_krb5_ccname = NULL, +}; + +static struct ldap_map_names ldap_map = { + .NFSv4_person_objcls = NULL, + .NFSv4_nfsname_attr = NULL, + .NFSv4_uid_attr = NULL, + .NFSv4_acctname_attr = NULL, + .NFSv4_group_objcls = NULL, + .NFSv4_group_nfsname_attr = NULL, + .NFSv4_gid_attr = NULL, + .NFSv4_member_attr = NULL, + .NFSv4_member_of_attr = NULL, + .GSS_principal_attr = NULL, + .NFSv4_grouplist_filter = NULL, +}; + +#ifdef ENABLE_LDAP_SASL + +/** + * Set the path of the krb5 ticket cache + * use gss_krb5_ccache_name if available else set the env var + */ +static int set_krb5_ccname(const char *krb5_ccache_name) +{ + int retval = 0; +#ifdef HAVE_GSS_KRB5_CCACHE_NAME + OM_uint32 status; + + if (gss_krb5_ccache_name(&status, krb5_ccache_name, NULL) != + GSS_S_COMPLETE) { + IDMAP_LOG(5, + ("Failed to set creds cache for kerberos, minor_status(%d)", + status)); + retval = status; + goto out; + } +#else /* HAVE_GSS_KRB5_CCACHE_NAME */ + char *env; + int buflen = 0; + + buflen = strlen("KRB5CCNAME=") + strlen(krb5_ccache_name) + 1; + env = malloc(buflen); + if (env == NULL) { + retval = ENOMEM; + goto out; + } + snprintf(env, buflen, "KRB5CCNAME=%s", krb5_ccache_name); + if (putenv(env) != 0) { + retval = errno; + IDMAP_LOG(5, ("Failed to set creds cache for kerberos, err(%d)", + retval)); + } +#endif /* else HAVE_GSS_KRB5_CCACHE_NAME */ +out: + return retval; +} + +/** + * SASL interact callback + */ +static int sasl_interact_cb(__attribute__((unused)) LDAP * ld, + __attribute__((unused)) unsigned int flags, void *defaults, + void *ctx) +{ + struct umich_ldap_info *linfo = defaults; + sasl_interact_t *interact = ctx; + + while (interact->id != SASL_CB_LIST_END) { + switch (interact->id) { + case SASL_CB_AUTHNAME: + if (linfo->sasl_authcid == NULL || + linfo->sasl_authcid[0] == '\0') { + IDMAP_LOG(2, ("SASL_CB_AUTHNAME asked in " + "callback but not found in conf")); + } else { + IDMAP_LOG(5, + ("Setting SASL_CB_AUTHNAME to %s", + linfo->sasl_authcid)); + interact->result = linfo->sasl_authcid; + interact->len = strlen(linfo->sasl_authcid); + } + break; + case SASL_CB_PASS: + if (linfo->passwd == NULL || linfo->passwd[0] == '\0') { + IDMAP_LOG(2, ("SASL_CB_PASS asked in callback " + "but not found in conf")); + } else { + IDMAP_LOG(5, + ("Setting SASL_CB_PASS to ***")); + interact->result = linfo->passwd; + interact->len = strlen(linfo->passwd); + } + break; + case SASL_CB_GETREALM: + if (linfo->sasl_realm == NULL || + linfo->sasl_realm[0] == '\0') { + IDMAP_LOG(2, ("SASL_CB_GETREALM asked in " + "callback but not found in conf")); + } else { + IDMAP_LOG(5, + ("Setting SASL_CB_GETREALM to %s", + linfo->sasl_realm)); + interact->result = linfo->sasl_realm; + interact->len = strlen(linfo->sasl_realm); + } + break; + case SASL_CB_USER: + if (linfo->sasl_authzid == NULL || + linfo->sasl_authzid[0] == '\0') { + IDMAP_LOG(2, ("SASL_CB_USER asked in callback " + "but not found in conf")); + } else { + IDMAP_LOG(5, ("Setting SASL_CB_USER to %s", + linfo->sasl_authzid)); + interact->result = linfo->sasl_authzid; + interact->len = strlen(linfo->sasl_authzid); + } + break; + default: + IDMAP_LOG(2, ("Undefined value requested %d", + interact->id)); + break; + } + interact++; + } + return LDAP_SUCCESS; +} +#endif /* ENABLE_LDAP_SASL */ + +/* Local routines */ + +static int +ldap_init_and_bind(LDAP **pld, + int *sizelimit, + struct umich_ldap_info *linfo) +{ + LDAP *ld; + int lerr; + int err = -1; + int current_version, new_version; + char server_url[1024]; + int debug_level = 65535; + int i; + LDAPAPIInfo apiinfo = {.ldapai_info_version = LDAP_API_INFO_VERSION}; + + snprintf(server_url, sizeof(server_url), "%s://%s:%d", + (linfo->use_ssl) ? "ldaps" : "ldap", + linfo->server, linfo->port); + + /* + * XXX We really, REALLY only want to initialize once, not for + * each request. Figure out how to do that! + */ + if ((lerr = ldap_initialize(&ld, server_url)) != LDAP_SUCCESS) { + IDMAP_LOG(0, ("ldap_init_and_bind: ldap_initialize() failed " + "to [%s]: %s (%d)", server_url, + ldap_err2string(lerr), lerr)); + goto out; + } + + if ((ldap_set_option(ld, LDAP_OPT_DEBUG_LEVEL, &debug_level) + != LDAP_SUCCESS)) { + IDMAP_LOG(0, ("ldap_init_and_bind: error setting ldap " + "library debugging level")); + goto out; + } + + /* + * Get LDAP API information and compare the protocol version there + * to the protocol version returned directly from get_option. + */ + ldap_get_option(ld, LDAP_OPT_API_INFO, &apiinfo); + if (apiinfo.ldapai_info_version != LDAP_API_INFO_VERSION) { + IDMAP_LOG(0, ("ldap_init_and_bind: APIInfo version mismatch: " + "library %d, header %d", + apiinfo.ldapai_info_version, LDAP_API_INFO_VERSION)); + goto out; + } + ldap_get_option(ld, LDAP_OPT_PROTOCOL_VERSION, ¤t_version); + if (apiinfo.ldapai_protocol_version == LDAP_VERSION3 && + current_version != LDAP_VERSION3) { + new_version = LDAP_VERSION3; + IDMAP_LOG(4, ("ldap_init_and_bind: version mismatch between " + "API information and protocol version. Setting " + "protocol version to %d", new_version)); + ldap_set_option(ld, LDAP_OPT_PROTOCOL_VERSION, &new_version); + } + + for (i = 0; apiinfo.ldapai_extensions[i]; i++) { + char *extension = apiinfo.ldapai_extensions[i]; + ldap_memfree (extension); + } + ldap_memfree (apiinfo.ldapai_extensions); + ldap_memfree(apiinfo.ldapai_vendor_name); + + /* Set sizelimit option if requested */ + if (sizelimit) { + ldap_set_option(ld, LDAP_OPT_SIZELIMIT, (void *)sizelimit); + } + + lerr = ldap_set_option(ld, LDAP_OPT_REFERRALS, + linfo->follow_referrals ? (void *)LDAP_OPT_ON : + (void *)LDAP_OPT_OFF); + if (lerr != LDAP_SUCCESS) { + IDMAP_LOG(2, ("ldap_init_and_bind: setting LDAP_OPT_REFERRALS " + "failed: %s (%d)", ldap_err2string(lerr), lerr)); + goto out; + } + + /* Set option to to use SSL/TLS if requested */ + if (linfo->use_ssl) { + int tls_type = LDAP_OPT_X_TLS_HARD; + lerr = ldap_set_option(ld, LDAP_OPT_X_TLS, &tls_type); + if (lerr != LDAP_SUCCESS) { + IDMAP_LOG(2, ("ldap_init_and_bind: setting SSL " + "failed : %s (%d)", + ldap_err2string(lerr), lerr)); + goto out; + } + + if (linfo->ca_cert != NULL) { + lerr = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, + linfo->ca_cert); + if (lerr != LDAP_SUCCESS) { + IDMAP_LOG(2, ("ldap_init_and_bind: setting CA " + "certificate file failed : %s (%d)", + ldap_err2string(lerr), lerr)); + goto out; + } + } + + lerr = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, + &linfo->tls_reqcert); + if (lerr != LDAP_SUCCESS) { + IDMAP_LOG(2, ("ldap_init_and_bind: setting " + "req CA cert failed : %s(%d)", + ldap_err2string(lerr), lerr)); + goto out; + } + } + + /* If we have a DN (and password) attempt an authenticated bind */ + if (linfo->user_dn) { +retry_bind: +#ifdef ENABLE_LDAP_SASL + if (linfo->sasl_mech != NULL && linfo->sasl_mech[0] != '\0') { + /* use sasl bind */ + if (linfo->sasl_canonicalize != -1) { + lerr = ldap_set_option(ld, + LDAP_OPT_X_SASL_NOCANON, + linfo->sasl_canonicalize ? + LDAP_OPT_OFF : LDAP_OPT_ON); + if (lerr != LDAP_SUCCESS) { + IDMAP_LOG(2, ("ldap_init_and_bind: " + "setting sasl_canonicalize" + " failed: %s (%d)", + ldap_err2string(lerr), + lerr)); + goto out; + } + } + if (linfo->sasl_secprops != NULL && + linfo->sasl_secprops[0] != '\0') { + lerr = ldap_set_option(ld, + LDAP_OPT_X_SASL_SECPROPS, + (void *) linfo->sasl_secprops); + if (lerr != LDAP_SUCCESS) { + IDMAP_LOG(2, ("ldap_init_and_bind: " + "setting sasl_secprops" + " failed: %s (%d)", + ldap_err2string(lerr), + lerr)); + goto out; + } + } + if (linfo->sasl_krb5_ccname != NULL && + linfo->sasl_krb5_ccname[0] != '\0') { + lerr = set_krb5_ccname(linfo->sasl_krb5_ccname); + if (lerr != 0) { + IDMAP_LOG(2, + ("ldap_init_and_bind: Failed " + "to set krb5 ticket cache, " + "err=%d", lerr)); + } + } + lerr = ldap_sasl_interactive_bind_s(ld, linfo->user_dn, + linfo->sasl_mech, NULL, NULL, LDAP_SASL_QUIET, + sasl_interact_cb, linfo); + } else { + lerr = ldap_simple_bind_s(ld, linfo->user_dn, + linfo->passwd); + } +#else /* ENABLE_LDAP_SASL */ + lerr = ldap_simple_bind_s(ld, linfo->user_dn, linfo->passwd); +#endif /* else ENABLE_LDAP_SASL */ + if (lerr) { + char *errmsg; + if (lerr == LDAP_PROTOCOL_ERROR) { + ldap_get_option(ld, LDAP_OPT_PROTOCOL_VERSION, + ¤t_version); + new_version = current_version == LDAP_VERSION2 ? + LDAP_VERSION3 : LDAP_VERSION2; + ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, + &new_version); + IDMAP_LOG(2, ("ldap_init_and_bind: " + "got protocol error while attempting " + "bind with protocol version %d, " + "trying protocol version %d", + current_version, new_version)); + if ((ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &errmsg) == LDAP_SUCCESS) + && (errmsg != NULL) && (*errmsg != '\0')) { + IDMAP_LOG(2, ("ldap_init_and_bind: " + "Additional info: %s", errmsg)); + ldap_memfree(errmsg); + } + goto retry_bind; + } +#ifdef ENABLE_LDAP_SASL + IDMAP_LOG(2, ("ldap_init_and_bind: %s " + "to [%s] as user '%s': %s (%d)", + (linfo->sasl_mech != NULL && + linfo->sasl_mech[0] != '\0') ? + "ldap_sasl_interactive_bind_s" : + "ldap_simple_bind_s", + server_url, linfo->user_dn, + ldap_err2string(lerr), lerr)); +#else /* ENABLE_LDAP_SASL */ + IDMAP_LOG(2, ("ldap_init_and_bind: ldap_simple_bind_s" + "to [%s] as user '%s': %s (%d)", + server_url, linfo->user_dn, + ldap_err2string(lerr), lerr)); + +#endif /* else ENABLE_LDAP_SASL */ + if ((ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &errmsg) == LDAP_SUCCESS) + && (errmsg != NULL)&& (*errmsg != '\0')) { + IDMAP_LOG(2, ("ldap_init_and_bind: " + "Additional info: %s", errmsg)); + ldap_memfree(errmsg); + } + goto out; + } + } +#ifdef LDAP_ANONYMOUS_BIND_REQUIRED + else { + lerr = ldap_simple_bind_s(ld, NULL, NULL); + if (lerr) { + char *errmsg; + + IDMAP_LOG(2, ("ldap_init_and_bind: ldap_simple_bind_s " + "to [%s] as anonymous: %s (%d)", server_url, + ldap_err2string(lerr), lerr)); + if ((ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &errmsg) == LDAP_SUCCESS) + && (errmsg != NULL) && (*errmsg != '\0')) { + IDMAP_LOG(2, ("ldap_init_and_bind: " + "Additional info: %s", errmsg)); + ldap_memfree(errmsg); + } + goto out; + } + } +#endif + + *pld = ld; + err = 0; +out: + return err; +} + +static int +umich_name_to_ids(char *name, int idtype, uid_t *uid, gid_t *gid, + char *attrtype, struct umich_ldap_info *linfo) +{ + LDAP *ld = NULL; + struct timeval timeout = { + .tv_sec = linfo->ldap_timeout, + }; + LDAPMessage *result = NULL, *entry; + BerElement *ber = NULL; + char **idstr, filter[LDAP_FILT_MAXSIZ], *base; + char *attrs[3]; + char *attr_res; + int count = 0, err, lerr, f_len; + int sizelimit = 1; + + err = -EINVAL; + if (uid == NULL || gid == NULL || name == NULL || + attrtype == NULL || linfo == NULL || linfo->server == NULL || + linfo->people_tree == NULL || linfo->group_tree == NULL) + goto out; + + *uid = -1; + *gid = -1; + + if (idtype == IDTYPE_USER) { + if ((f_len = snprintf(filter, LDAP_FILT_MAXSIZ, + "(&(objectClass=%s)(%s=%s))", + ldap_map.NFSv4_person_objcls, + attrtype, name)) + == LDAP_FILT_MAXSIZ) { + IDMAP_LOG(0, ("ERROR: umich_name_to_ids: filter " + "too long!")); + goto out; + } + base = linfo->people_tree; + } + else if (idtype == IDTYPE_GROUP) { + if ((f_len = snprintf(filter, LDAP_FILT_MAXSIZ, + "(&(objectClass=%s)(%s=%s))", + ldap_map.NFSv4_group_objcls, + attrtype, name)) + == LDAP_FILT_MAXSIZ) { + IDMAP_LOG(0, ("ERROR: umich_name_to_ids: filter " + "too long!")); + goto out; + } + base = linfo->group_tree; + } + else { + IDMAP_LOG(0, ("ERROR: umich_name_to_ids: invalid idtype (%d)", + idtype)); + goto out; + } + + if (ldap_init_and_bind(&ld, &sizelimit, linfo)) + goto out; + + attrs[0] = ldap_map.NFSv4_uid_attr; + attrs[1] = ldap_map.NFSv4_gid_attr; + attrs[2] = NULL; + + err = ldap_search_st(ld, base, LDAP_SCOPE_SUBTREE, + filter, (char **)attrs, + 0, &timeout, &result); + if (err) { + char *errmsg; + + IDMAP_LOG(2, ("umich_name_to_ids: ldap_search_st for " + "base '%s', filter '%s': %s (%d)", + base, filter, ldap_err2string(err), err)); + if ((ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &errmsg) == LDAP_SUCCESS) + && (errmsg != NULL) && (*errmsg != '\0')) { + IDMAP_LOG(2, ("umich_name_to_ids: " + "Additional info: %s", errmsg)); + ldap_memfree(errmsg); + } + err = -ENOENT; + goto out_unbind; + } + + err = -ENOENT; + count = ldap_count_entries(ld, result); + if (count != 1) { + goto out_unbind; + } + + if (!(entry = ldap_first_entry(ld, result))) { + lerr = ldap_result2error(ld, result, 0); + IDMAP_LOG(2, ("umich_name_to_ids: ldap_first_entry: " + "%s (%d)", ldap_err2string(lerr), lerr)); + goto out_unbind; + } + + /* + * Attributes come back in no particular order, so we need + * to check each one to see what it is before assigning values. + * XXX There must be a better way than comparing the + * name of each attribute? + */ + for (attr_res = ldap_first_attribute(ld, result, &ber); + attr_res != NULL; + attr_res = ldap_next_attribute(ld, result, ber)) { + + unsigned long tmp_u, tmp_g; + uid_t tmp_uid; + gid_t tmp_gid; + + if ((idstr = ldap_get_values(ld, result, attr_res)) == NULL) { + lerr = ldap_result2error(ld, result, 0); + IDMAP_LOG(2, ("umich_name_to_ids: ldap_get_values: " + "%s (%d)", ldap_err2string(lerr), lerr)); + goto out_memfree; + } + if (strcasecmp(attr_res, ldap_map.NFSv4_uid_attr) == 0) { + tmp_u = strtoul(*idstr, (char **)NULL, 10); + tmp_uid = tmp_u; + if (tmp_uid != tmp_u || + (errno == ERANGE && tmp_u == ULONG_MAX)) { + IDMAP_LOG(0, ("ERROR: umich_name_to_ids: " + "uidNumber too long converting '%s'", + *idstr)); + ldap_memfree(attr_res); + ldap_value_free(idstr); + goto out_memfree; + } + *uid = tmp_uid; + err = 0; + } else if (strcasecmp(attr_res, ldap_map.NFSv4_gid_attr) == 0) { + tmp_g = strtoul(*idstr, (char **)NULL, 10); + tmp_gid = tmp_g; + if (tmp_gid != tmp_g || + (errno == ERANGE && tmp_g == ULONG_MAX)) { + IDMAP_LOG(0, ("ERROR: umich_name_to_ids: " + "gidNumber too long converting '%s'", + *idstr)); + ldap_memfree(attr_res); + ldap_value_free(idstr); + goto out_memfree; + } + *gid = tmp_gid; + err = 0; + } else { + IDMAP_LOG(0, ("umich_name_to_ids: received attr " + "'%s' ???", attr_res)); + ldap_memfree(attr_res); + ldap_value_free(idstr); + goto out_memfree; + } + ldap_memfree(attr_res); + ldap_value_free(idstr); + } + +out_memfree: + ber_free(ber, 0); +out_unbind: + if (result) + ldap_msgfree(result); + ldap_unbind(ld); +out: + return err; +} + +static int +umich_id_to_name(uid_t id, int idtype, char **name, size_t len, + struct umich_ldap_info *linfo) +{ + LDAP *ld = NULL; + struct timeval timeout = { + .tv_sec = linfo->ldap_timeout, + }; + LDAPMessage *result = NULL, *entry; + BerElement *ber; + char **names = NULL, filter[LDAP_FILT_MAXSIZ], *base; + char idstr[16]; + char *attrs[2]; + char *attr_res; + int count = 0, err, lerr, f_len; + int sizelimit = 1; + + err = -EINVAL; + if (name == NULL || linfo == NULL || linfo->server == NULL || + linfo->people_tree == NULL || linfo->group_tree == NULL) + goto out; + + snprintf(idstr, sizeof(idstr), "%d", id); + + + if (idtype == IDTYPE_USER) { + if ((f_len = snprintf(filter, LDAP_FILT_MAXSIZ, + "(&(objectClass=%s)(%s=%s))", + ldap_map.NFSv4_person_objcls, + ldap_map.NFSv4_uid_attr, idstr)) + == LDAP_FILT_MAXSIZ) { + IDMAP_LOG(0, ("ERROR: umich_id_to_name: " + "uid filter too long!")); + goto out; + } + base = linfo->people_tree; + } else if (idtype == IDTYPE_GROUP) { + if ((f_len = snprintf(filter, LDAP_FILT_MAXSIZ, + "(&(objectClass=%s)(%s=%s))", + ldap_map.NFSv4_group_objcls, + ldap_map.NFSv4_gid_attr,idstr)) + == LDAP_FILT_MAXSIZ) { + IDMAP_LOG(0, ("ERROR: umich_id_to_name: " + "gid filter too long!")); + goto out; + } + base = linfo->group_tree; + } else { + IDMAP_LOG(0, ("ERROR: umich_id_to_name: invalid idtype (%d)", + idtype)); + err = -EINVAL; + goto out; + } + + if (ldap_init_and_bind(&ld, &sizelimit, linfo)) + goto out; + + if (idtype == IDTYPE_USER) + attrs[0] = ldap_map.NFSv4_nfsname_attr; + else + attrs[0] = ldap_map.NFSv4_group_nfsname_attr; + attrs[1] = NULL; + + err = ldap_search_st(ld, base, LDAP_SCOPE_SUBTREE, + filter, (char **)attrs, + 0, &timeout, &result); + if (err) { + char * errmsg; + + IDMAP_LOG(2, ("umich_id_to_name: ldap_search_st for " + "base '%s, filter '%s': %s (%d)", base, filter, + ldap_err2string(err), err)); + if ((ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &errmsg) == LDAP_SUCCESS) + && (errmsg != NULL) && (*errmsg != '\0')) { + IDMAP_LOG(2, ("umich_id_to_name: " + "Additional info: %s", errmsg)); + ldap_memfree(errmsg); + } + + err = -ENOENT; + goto out_unbind; + } + + err = -ENOENT; + count = ldap_count_entries(ld, result); + if (count != 1) + goto out_unbind; + + if (!(entry = ldap_first_entry(ld, result))) { + lerr = ldap_result2error(ld, result, 0); + IDMAP_LOG(2, ("umich_id_to_name: ldap_first_entry: " + "%s (%d)", ldap_err2string(lerr), lerr)); + goto out_unbind; + } + + if (!(attr_res = ldap_first_attribute(ld, result, &ber))) { + lerr = ldap_result2error(ld, result, 0); + IDMAP_LOG(2, ("umich_id_to_name: ldap_first_attribute: " + "%s (%d)", ldap_err2string(lerr), lerr)); + goto out_unbind; + } + + if ((names = ldap_get_values(ld, result, attr_res)) == NULL) { + lerr = ldap_result2error(ld, result, 0); + IDMAP_LOG(2, ("umich_id_to_name: ldap_get_values: " + "%s (%d)", ldap_err2string(lerr), lerr)); + goto out_memfree; + } + + /* + * Verify there is enough room in the output buffer before + * copying returned string. (strlen doesn't count the null, + * we make sure there is room for the null also, therefore + * we use ">=" not just ">") + */ + if (strlen(names[0]) >= len) { + /* not enough space to return the name */ + IDMAP_LOG(1, ("umich_id_to_name: output buffer size (%d) " + "too small to return string, '%s', of length %d", + len, names[0], strlen(names[0]))); + goto out_memfree; + } + strcpy(*name, names[0]); + + err = 0; +out_memfree: + if (names) + ldap_value_free(names); + ldap_memfree(attr_res); + ber_free(ber, 0); +out_unbind: + if (result) + ldap_msgfree(result); + ldap_unbind(ld); +out: + return err; +} + +static int +umich_gss_princ_to_grouplist(char *principal, gid_t *groups, int *ngroups, + struct umich_ldap_info *linfo) +{ + LDAP *ld = NULL; + struct timeval timeout = { + .tv_sec = linfo->ldap_timeout, + }; + LDAPMessage *result, *entry; + char **names, filter[LDAP_FILT_MAXSIZ]; + char *attrs[2]; + int count = 0, err = -ENOMEM, lerr, f_len; + int i, num_gids; + gid_t *curr_group = groups; + + err = -EINVAL; + if (linfo == NULL || linfo->server == NULL || + linfo->people_tree == NULL || linfo->group_tree == NULL) + goto out; + + + if (ldap_init_and_bind(&ld, NULL, linfo)) + goto out; + + /* + * First we need to map the gss principal name to a uid (name) string + */ + err = -EINVAL; + if ((f_len = snprintf(filter, LDAP_FILT_MAXSIZ, + "(&(objectClass=%s)(%s=%s))", + ldap_map.NFSv4_person_objcls, + ldap_map.GSS_principal_attr, principal)) + == LDAP_FILT_MAXSIZ) { + IDMAP_LOG(0, ("ERROR: umich_gss_princ_to_grouplist: " + "filter too long!")); + goto out; + } + + attrs[0] = ldap_map.NFSv4_acctname_attr; + attrs[1] = NULL; + + err = ldap_search_st(ld, linfo->people_tree, LDAP_SCOPE_SUBTREE, + filter, attrs, 0, &timeout, &result); + if (err) { + char *errmsg; + + IDMAP_LOG(2, ("umich_gss_princ_to_grouplist: ldap_search_st " + "for tree '%s, filter '%s': %s (%d)", + linfo->people_tree, filter, + ldap_err2string(err), err)); + if ((ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &errmsg) == LDAP_SUCCESS) + && (errmsg != NULL) && (*errmsg != '\0')) { + IDMAP_LOG(2, ("umich_gss_princ_to_grouplist: " + "Additional info: %s", errmsg)); + ldap_memfree(errmsg); + } + err = -ENOENT; + goto out_unbind; + } + + err = -ENOENT; + count = ldap_count_entries(ld, result); + if (count != 1) { + IDMAP_LOG(2, ("umich_gss_princ_to_grouplist: " + "ldap account lookup of gssauthname %s returned %d accounts", + principal,count)); + goto out_unbind; + } + + if (!(entry = ldap_first_entry(ld, result))) { + lerr = ldap_result2error(ld, result, 0); + IDMAP_LOG(2, ("umich_gss_princ_to_grouplist: ldap_first_entry: " + "%s (%d)", ldap_err2string(lerr), lerr)); + goto out_unbind; + } + + if ((names = ldap_get_values(ld, result, attrs[0])) == NULL) { + lerr = ldap_result2error(ld, result, 0); + IDMAP_LOG(2, ("umich_gss_princ_to_grouplist: ldap_get_values: " + "%s (%d)", ldap_err2string(lerr), lerr)); + goto out_unbind; + } + + if (ldap_info.memberof_for_groups) { + + /* + * Collect the groups the user belongs to + */ + if ((f_len = snprintf(filter, LDAP_FILT_MAXSIZ, + "(&(objectClass=%s)(%s=%s))", + ldap_map.NFSv4_person_objcls, + ldap_map.NFSv4_acctname_attr, + names[0])) == LDAP_FILT_MAXSIZ ) { + IDMAP_LOG(2, ("ERROR: umich_gss_princ_to_grouplist: " + "filter too long!")); + ldap_value_free(names); + goto out_unbind; + } + + ldap_value_free(names); + + attrs[0] = ldap_map.NFSv4_member_of_attr; + attrs[1] = NULL; + + err = ldap_search_st(ld, linfo->people_tree, LDAP_SCOPE_SUBTREE, + filter, attrs, 0, &timeout, &result); + + if (err) { + char *errmsg; + + IDMAP_LOG(2, ("umich_gss_princ_to_grouplist: ldap_search_st " + "for tree '%s, filter '%s': %s (%d)", + linfo->people_tree, filter, + ldap_err2string(err), err)); + if ((ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &errmsg) == LDAP_SUCCESS) + && (errmsg != NULL) && (*errmsg != '\0')) { + IDMAP_LOG(2, ("umich_gss_princ_to_grouplist: " + "Additional info: %s", errmsg)); + ldap_memfree(errmsg); + } + err = -ENOENT; + goto out_unbind; + } + err = -ENOENT; + + /* pull the list of groups and place into names */ + count = ldap_count_entries(ld, result); + if (count != 1) { + IDMAP_LOG(2, ("umich_gss_princ_to_grouplist: " + "ldap group member lookup of gssauthname %s returned %d multiple entries", + principal,count)); + goto out_unbind; + } + + if (!(entry = ldap_first_entry(ld, result))) { + lerr = ldap_result2error(ld, result, 0); + IDMAP_LOG(2, ("umich_gss_princ_to_grouplist: ldap_first_entry: " + "%s (%d)", ldap_err2string(lerr), lerr)); + goto out_unbind; + } + + if ((names = ldap_get_values(ld, result, attrs[0])) == NULL) { + lerr = ldap_result2error(ld, result, 0); + IDMAP_LOG(2, ("umich_gss_princ_to_grouplist: ldap_get_values: " + "%s (%d)", ldap_err2string(lerr), lerr)); + goto out_unbind; + } + + /* Count the groups first before doing a lookup of the group. + If it exceeds the desired number of groups set the needed value + and abort. */ + for (i = 0; names[i] != NULL; i++); + if ( i > *ngroups ) { + ldap_value_free(names); + err = -EINVAL; + IDMAP_LOG(2, ("umich_gss_princ_to_grouplist: User %s, " + "number of groups %d, exceeds requested number %d", + principal, i, *ngroups)); + *ngroups = i; + goto out_unbind; + } + + /* Loop through the groupnames (names) and get the group gid */ + num_gids = 0; + for (i = 0; names[i] != NULL; i++){ + char **vals; + int valcount; + unsigned long tmp_g; + gid_t tmp_gid; + char *cnptr = NULL; + + cnptr = strchr(names[i],','); + if (cnptr) *cnptr = '\0'; + + err = -ENOENT; + if (ldap_map.NFSv4_grouplist_filter) + f_len = snprintf(filter, LDAP_FILT_MAXSIZ, + "(&(objectClass=%s)(%s)%s)", + ldap_map.NFSv4_group_objcls, + names[i], + ldap_map.NFSv4_grouplist_filter); + else + f_len = snprintf(filter, LDAP_FILT_MAXSIZ, + "(&(objectClass=%s)(%s))", + ldap_map.NFSv4_group_objcls, + names[i]); + + if ( f_len == LDAP_FILT_MAXSIZ ) { + IDMAP_LOG(2, ("ERROR: umich_gss_princ_to_grouplist: " + "filter too long!")); + ldap_value_free(names); + goto out_unbind; + } + attrs[0] = ldap_map.NFSv4_gid_attr; + attrs[1] = NULL; + + err = ldap_search_st(ld, linfo->group_tree, LDAP_SCOPE_SUBTREE, + filter, attrs, 0, &timeout, &result); + if (err) { + char *errmsg; + + IDMAP_LOG(2, ("umich_gss_princ_to_grouplist: ldap_search_st " + "for tree '%s, filter '%s': %s (%d)", + linfo->group_tree, filter, + ldap_err2string(err), err)); + if ((ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &errmsg)==LDAP_SUCCESS) + && + (errmsg != NULL) && (*errmsg != '\0')) { + IDMAP_LOG(2, ("umich_gss_princ_to_grouplist: " + "Additional info: %s", errmsg)); + ldap_memfree(errmsg); + } + continue; + } + + count = ldap_count_entries(ld, result); + if (count == 0) + continue; + if (count != 1 ){ + IDMAP_LOG(2, ("umich_gss_princ_to_grouplist:" + "Group %s has %d gids defined - aborting", names[i], count)); + ldap_value_free(names); + err = -ENOENT; + goto out_unbind; + } + + vals = ldap_get_values(ld, result, ldap_map.NFSv4_gid_attr); + + /* There should be only one gidNumber attribute per group */ + if ((valcount = ldap_count_values(vals)) != 1) { + IDMAP_LOG(2, ("DB problem getting gidNumber of " + "posixGroup! (count was %d)", valcount)); + ldap_value_free(vals); + continue; + } + + tmp_g = strtoul(vals[0], (char **)NULL, 10); + tmp_gid = tmp_g; + if (tmp_gid != tmp_g || + (errno == ERANGE && tmp_g == ULONG_MAX)) { + IDMAP_LOG(2, ("ERROR: umich_gss_princ_to_grouplist: " + "gidNumber too long converting '%s'", + vals[0])); + ldap_value_free(vals); + continue; + } + *curr_group++ = tmp_gid; + num_gids++; + ldap_value_free(vals); + } + ldap_value_free(names); + *ngroups = num_gids; + err = 0; + } else { + + /* + * Then determine the groups that uid (name) string is a member of + */ + err = -EINVAL; + if (ldap_map.NFSv4_grouplist_filter) + f_len = snprintf(filter, LDAP_FILT_MAXSIZ, + "(&(objectClass=%s)(%s=%s)%s)", + ldap_map.NFSv4_group_objcls, + ldap_map.NFSv4_member_attr, + names[0], + ldap_map.NFSv4_grouplist_filter); + + else + f_len = snprintf(filter, LDAP_FILT_MAXSIZ, + "(&(objectClass=%s)(%s=%s))", + ldap_map.NFSv4_group_objcls, + ldap_map.NFSv4_member_attr, + names[0]); + + if ( f_len == LDAP_FILT_MAXSIZ ) { + IDMAP_LOG(0, ("ERROR: umich_gss_princ_to_grouplist: " + "filter too long!")); + ldap_value_free(names); + goto out_unbind; + } + + ldap_value_free(names); + + attrs[0] = ldap_map.NFSv4_gid_attr; + attrs[1] = NULL; + + err = ldap_search_st(ld, linfo->group_tree, LDAP_SCOPE_SUBTREE, + filter, attrs, 0, &timeout, &result); + + if (err) { + char *errmsg; + + IDMAP_LOG(2, ("umich_gss_princ_to_grouplist: ldap_search_st " + "for tree '%s, filter '%s': %s (%d)", + linfo->group_tree, filter, + ldap_err2string(err), err)); + if ((ldap_get_option(ld, LDAP_OPT_ERROR_STRING, &errmsg) == LDAP_SUCCESS) && + (errmsg != NULL) && (*errmsg != '\0')) { + IDMAP_LOG(2, ("umich_gss_princ_to_grouplist: " + "Additional info: %s", errmsg)); + ldap_memfree(errmsg); + } + err = -ENOENT; + goto out_unbind; + } + + /* + * If we can't determine count, return that error + * If we have nothing to return, return success + * If we have more than they asked for, tell them the + * number required and return an error + */ + count = ldap_count_entries(ld, result); + + if (count < 0) { + err = count; + goto out_unbind; + } + if (count == 0) { + *ngroups = 0; + err = 0; + goto out_unbind; + } + if (count > *ngroups) { + *ngroups = count; + err = -EINVAL; + goto out_unbind; + } + *ngroups = count; + + curr_group = groups; + + err = -ENOENT; + for (entry = ldap_first_entry(ld, result); + entry != NULL; + entry = ldap_next_entry(ld, entry)) { + + char **vals; + int valcount; + unsigned long tmp_g; + gid_t tmp_gid; + + vals = ldap_get_values(ld, entry, ldap_map.NFSv4_gid_attr); + + /* There should be only one gidNumber attribute per group */ + if ((valcount = ldap_count_values(vals)) != 1) { + IDMAP_LOG(0, ("DB problem getting gidNumber of " + "posixGroup! (count was %d)", valcount)); + goto out_unbind; + } + tmp_g = strtoul(vals[0], (char **)NULL, 10); + tmp_gid = tmp_g; + if (tmp_gid != tmp_g || + (errno == ERANGE && tmp_g == ULONG_MAX)) { + IDMAP_LOG(0, ("ERROR: umich_gss_princ_to_grouplist: " + "gidNumber too long converting '%s'", + vals[0])); + ldap_value_free(vals); + goto out_unbind; + } + *curr_group++ = tmp_gid; + ldap_value_free(vals); + } + err = 0; + } + +out_unbind: + ldap_unbind(ld); +out: + return err; +} + + +/* + * principal: krb5 - princ@realm, use KrbName ldap attribute + * spkm3 - X.509 dn, use X509Name ldap attribute + */ +static int +umichldap_gss_princ_to_ids(char *secname, char *principal, + uid_t *uid, gid_t *gid, + extra_mapping_params **UNUSED(ex)) +{ + uid_t rtnd_uid = -1; + gid_t rtnd_gid = -1; + int err = -EINVAL; + + if ((strcmp(secname, "krb5") != 0) && (strcmp(secname, "spkm3") != 0)) { + IDMAP_LOG(0, ("ERROR: umichldap_gss_princ_to_ids: " + "invalid secname '%s'", secname)); + return err; + } + + err = umich_name_to_ids(principal, IDTYPE_USER, &rtnd_uid, &rtnd_gid, + ldap_map.GSS_principal_attr, &ldap_info); + if (err < 0) + goto out; + + *uid = rtnd_uid; + *gid = rtnd_gid; +out: + return err; +} + +static int +umichldap_name_to_uid(char *name, uid_t *uid) +{ + gid_t gid; + + return umich_name_to_ids(name, IDTYPE_USER, uid, + &gid, ldap_map.NFSv4_nfsname_attr, &ldap_info); +} + +static int +umichldap_name_to_gid(char *name, gid_t *gid) +{ + uid_t uid; + + return umich_name_to_ids(name, IDTYPE_GROUP, &uid, gid, + ldap_map.NFSv4_group_nfsname_attr, &ldap_info); +} + +static int +umichldap_uid_to_name(uid_t uid, char *UNUSED(domain), char *name, size_t len) +{ + return umich_id_to_name(uid, IDTYPE_USER, &name, len, &ldap_info); +} + +static int +umichldap_gid_to_name(gid_t gid, char *UNUSED(domain), char *name, size_t len) +{ + return umich_id_to_name(gid, IDTYPE_GROUP, &name, len, &ldap_info); +} + +static int +umichldap_gss_princ_to_grouplist(char *secname, char *principal, + gid_t *groups, int *ngroups, extra_mapping_params **UNUSED(ex)) +{ + int err = -EINVAL; + + if ((strcmp(secname, "krb5") != 0) && (strcmp(secname, "spkm3") != 0)) { + IDMAP_LOG(0, ("ERROR: umichldap_gss_princ_to_grouplist: " + "invalid secname '%s'", secname)); + return err; + } + + return umich_gss_princ_to_grouplist(principal, groups, ngroups, + &ldap_info); +} + +/* + * TLS connections require that the hostname we specify matches + * the hostname in the certificate that the server uses. + * Get a canonical name for the host specified in the config file. + */ +static char * +get_canonical_hostname(const char *inname) +{ + int aierr, error; + struct addrinfo *ap, aihints; + char *return_name = NULL; + char tmphost[NI_MAXHOST]; + + memset(&aihints, 0, sizeof(aihints)); + aihints.ai_socktype = SOCK_STREAM; + aihints.ai_flags = AI_CANONNAME; + aihints.ai_family = PF_INET; + aierr = getaddrinfo(inname, NULL, &aihints, &ap); + if (aierr) { + const char *msg; + /* We want to customize some messages. */ + switch (aierr) { + case EAI_NONAME: + msg = "host unknown"; + break; + default: + msg = gai_strerror(aierr); + break; + } + IDMAP_LOG(1, ("%s: '%s': %s", __FUNCTION__, inname, msg)); + goto out_err; + } + if (ap == 0) { + IDMAP_LOG(1, ("%s: no addresses for host '%s'?", + __FUNCTION__, inname)); + goto out_err; + } + + error = getnameinfo (ap->ai_addr, ap->ai_addrlen, tmphost, + sizeof(tmphost), NULL, 0, 0); + if (error) { + IDMAP_LOG(1, ("%s: getnameinfo for host '%s' failed (%d)", + __FUNCTION__, inname)); + goto out_free; + } + return_name = strdup (tmphost); + +out_free: + nfs_freeaddrinfo(ap); +out_err: + return return_name; +} + +static int +umichldap_init(void) +{ + char *tssl, *canonicalize, *memberof, *cert_req, *follow_referrals; + char missing_msg[128] = ""; + char *server_in, *canon_name; + + if (nfsidmap_conf_path) + conf_init_file(nfsidmap_conf_path); + + server_in = conf_get_str(LDAP_SECTION, "LDAP_server"); + ldap_info.base = conf_get_str(LDAP_SECTION, "LDAP_base"); + ldap_info.people_tree = conf_get_str(LDAP_SECTION, "LDAP_people_base"); + ldap_info.group_tree = conf_get_str(LDAP_SECTION, "LDAP_group_base"); + ldap_info.user_dn = conf_get_str(LDAP_SECTION, "LDAP_user_dn"); + ldap_info.passwd = conf_get_str(LDAP_SECTION, "LDAP_passwd"); + tssl = conf_get_str_with_def(LDAP_SECTION, "LDAP_use_ssl", "false"); + if ((strcasecmp(tssl, "true") == 0) || + (strcasecmp(tssl, "on") == 0) || + (strcasecmp(tssl, "yes") == 0)) + ldap_info.use_ssl = 1; + else + ldap_info.use_ssl = 0; + ldap_info.ca_cert = conf_get_str(LDAP_SECTION, "LDAP_CA_CERT"); + cert_req = conf_get_str(LDAP_SECTION, "LDAP_tls_reqcert"); + if (cert_req != NULL) { + if (strcasecmp(cert_req, "hard") == 0) + ldap_info.tls_reqcert = LDAP_OPT_X_TLS_HARD; + else if (strcasecmp(cert_req, "demand") == 0) + ldap_info.tls_reqcert = LDAP_OPT_X_TLS_DEMAND; + else if (strcasecmp(cert_req, "try") == 0) + ldap_info.tls_reqcert = LDAP_OPT_X_TLS_TRY; + else if (strcasecmp(cert_req, "allow") == 0) + ldap_info.tls_reqcert = LDAP_OPT_X_TLS_ALLOW; + else if (strcasecmp(cert_req, "never") == 0) + ldap_info.tls_reqcert = LDAP_OPT_X_TLS_NEVER; + else { + IDMAP_LOG(0, ("umichldap_init: Invalid value(%s) for " + "LDAP_tls_reqcert.")); + goto fail; + } + } + /* vary the default port depending on whether they use SSL or not */ + ldap_info.port = conf_get_num(LDAP_SECTION, "LDAP_port", + (ldap_info.use_ssl) ? + LDAPS_PORT : LDAP_PORT); + + ldap_info.sasl_mech = conf_get_str(LDAP_SECTION, "LDAP_sasl_mech"); + ldap_info.sasl_realm = conf_get_str(LDAP_SECTION, "LDAP_sasl_realm"); + ldap_info.sasl_authcid = conf_get_str(LDAP_SECTION, + "LDAP_sasl_authcid"); + ldap_info.sasl_authzid = conf_get_str(LDAP_SECTION, + "LDAP_sasl_authzid"); + ldap_info.sasl_secprops = conf_get_str(LDAP_SECTION, + "LDAP_sasl_secprops"); + + /* If it is not set let the ldap lib work with the lib default */ + canonicalize = conf_get_str_with_def(LDAP_SECTION, + "LDAP_sasl_canonicalize", "undef"); + if ((strcasecmp(canonicalize, "true") == 0) || + (strcasecmp(canonicalize, "on") == 0) || + (strcasecmp(canonicalize, "yes") == 0)) { + ldap_info.sasl_canonicalize = 1; + } else if ((strcasecmp(canonicalize, "false") == 0) || + (strcasecmp(canonicalize, "off") == 0) || + (strcasecmp(canonicalize, "no") == 0)) { + ldap_info.sasl_canonicalize = 0; + } + ldap_info.sasl_krb5_ccname = conf_get_str(LDAP_SECTION, + "LDAP_sasl_krb5_ccname"); + + follow_referrals = conf_get_str_with_def(LDAP_SECTION, + "LDAP_follow_referrals", + "true"); + if ((strcasecmp(follow_referrals, "true") == 0) || + (strcasecmp(follow_referrals, "on") == 0) || + (strcasecmp(follow_referrals, "yes") == 0)) + ldap_info.follow_referrals = 1; + else + ldap_info.follow_referrals = 0; + + /* Verify required information is supplied */ + if (server_in == NULL || strlen(server_in) == 0) + strncat(missing_msg, "LDAP_server ", sizeof(missing_msg)-1); + if (ldap_info.base == NULL || strlen(ldap_info.base) == 0) + strncat(missing_msg, "LDAP_base ", sizeof(missing_msg)-1); + if (strlen(missing_msg) != 0) { + IDMAP_LOG(0, ("umichldap_init: Missing required information: " + "%s", missing_msg)); + goto fail; + } + + ldap_info.server = server_in; + canonicalize = conf_get_str_with_def(LDAP_SECTION, + "LDAP_canonicalize_name", "yes"); + if ((strcasecmp(canonicalize, "true") == 0) || + (strcasecmp(canonicalize, "on") == 0) || + (strcasecmp(canonicalize, "yes") == 0)) { + canon_name = get_canonical_hostname(server_in); + if (canon_name == NULL) + IDMAP_LOG(0, ("umichldap_init: Warning! Unable to " + "canonicalize server name '%s' as requested.", + server_in)); + else + ldap_info.server = canon_name; + } + + /* get the ldap mapping attributes/objectclasses (all have defaults) */ + ldap_map.NFSv4_person_objcls = + conf_get_str_with_def(LDAP_SECTION, "NFSv4_person_objectclass", + DEFAULT_UMICH_OBJCLASS_REMOTE_PERSON); + + ldap_map.NFSv4_group_objcls = + conf_get_str_with_def(LDAP_SECTION, "NFSv4_group_objectclass", + DEFAULT_UMICH_OBJCLASS_REMOTE_GROUP); + + ldap_map.NFSv4_nfsname_attr = + conf_get_str_with_def(LDAP_SECTION, "NFSv4_name_attr", + DEFAULT_UMICH_ATTR_NFSNAME); + + ldap_map.NFSv4_uid_attr = + conf_get_str_with_def(LDAP_SECTION, "NFSv4_uid_attr", + DEFAULT_UMICH_ATTR_UIDNUMBER); + + ldap_map.NFSv4_acctname_attr = + conf_get_str_with_def(LDAP_SECTION, "NFSv4_acctname_attr", + DEFAULT_UMICH_ATTR_ACCTNAME); + + ldap_map.NFSv4_group_nfsname_attr = + conf_get_str_with_def(LDAP_SECTION, "NFSv4_group_attr", + DEFAULT_UMICH_ATTR_GROUP_NFSNAME); + + ldap_map.NFSv4_gid_attr = + conf_get_str_with_def(LDAP_SECTION, "NFSv4_gid_attr", + DEFAULT_UMICH_ATTR_GIDNUMBER); + + ldap_map.NFSv4_member_attr = + conf_get_str_with_def(LDAP_SECTION, "NFSv4_member_attr", + DEFAULT_UMICH_ATTR_MEMBERUID); + + ldap_map.GSS_principal_attr = + conf_get_str_with_def(LDAP_SECTION, "GSS_principal_attr", + DEFAULT_UMICH_ATTR_GSSAUTHNAME); + + ldap_map.NFSv4_grouplist_filter = + conf_get_str_with_def(LDAP_SECTION, "NFSv4_grouplist_filter", + NULL); + + ldap_map.NFSv4_member_of_attr = + conf_get_str_with_def(LDAP_SECTION, "NFSv4_member_of_attr", + DEFAULT_UMICH_ATTR_MEMBEROF); + + ldap_info.ldap_timeout = + conf_get_num(LDAP_SECTION, "LDAP_timeout_seconds", + DEFAULT_UMICH_SEARCH_TIMEOUT); + + + /* + * Some LDAP servers do a better job with indexing where searching + * through all the groups searching for the user in the memberuid + * list. Others like SunOne directory that search can takes minutes + * if there are thousands of groups. So setting + * LDAP_use_memberof_for_groups to true in the configuration file + * will use the memberof lists of the account and search through + * only those groups to obtain gids. + */ + memberof = conf_get_str_with_def(LDAP_SECTION, + "LDAP_use_memberof_for_groups", "false"); + if ((strcasecmp(memberof, "true") == 0) || + (strcasecmp(memberof, "on") == 0) || + (strcasecmp(memberof, "yes") == 0)) + ldap_info.memberof_for_groups = 1; + else + ldap_info.memberof_for_groups = 0; + + /* + * If they specified a search base for the + * people tree or group tree we use that. + * Otherwise we use the default search base. + * Note: We no longer append the default base to the tree -- + * that should already be specified. + * this functions much like the NSS_LDAP modules + */ + if (ldap_info.people_tree == NULL || strlen(ldap_info.people_tree) == 0) + ldap_info.people_tree = ldap_info.base; + if (ldap_info.group_tree == NULL || strlen(ldap_info.group_tree) == 0) + ldap_info.group_tree = ldap_info.base; + + if (ldap_info.use_ssl && + ldap_info.tls_reqcert != LDAP_OPT_X_TLS_NEVER && + ldap_info.ca_cert == NULL) { + IDMAP_LOG(0, ("umichldap_init: You must specify LDAP_ca_cert " + "with LDAP_use_ssl=yes and " + "LDAP_tls_reqcert not set to \"never\"")); + goto fail; + } + + + /* print out some good debugging info */ + IDMAP_LOG(1, ("umichldap_init: canonicalize_name: %s", + canonicalize)); + IDMAP_LOG(1, ("umichldap_init: server : %s (from config value '%s')", + ldap_info.server, server_in)); + IDMAP_LOG(1, ("umichldap_init: port : %d", ldap_info.port)); + IDMAP_LOG(1, ("umichldap_init: people : %s", ldap_info.people_tree)); + IDMAP_LOG(1, ("umichldap_init: groups : %s", ldap_info.group_tree)); + + IDMAP_LOG(1, ("umichldap_init: user_dn : %s", + (ldap_info.user_dn && strlen(ldap_info.user_dn) != 0) + ? ldap_info.user_dn : "<not-supplied>")); + /* Don't print actual password into the log. */ + IDMAP_LOG(1, ("umichldap_init: passwd : %s", + (ldap_info.passwd && strlen(ldap_info.passwd) != 0) ? + "<supplied>" : "<not-supplied>")); + IDMAP_LOG(1, ("umichldap_init: use_ssl : %s", + ldap_info.use_ssl ? "yes" : "no")); + IDMAP_LOG(1, ("umichldap_init: ca_cert : %s", + ldap_info.ca_cert ? ldap_info.ca_cert : "<not-supplied>")); + IDMAP_LOG(1, ("umichldap_init: tls_reqcert : %s(%d)", + cert_req ? cert_req : "<not-supplied>", + ldap_info.tls_reqcert)); + IDMAP_LOG(1, ("umichldap_init: use_memberof_for_groups : %s", + ldap_info.memberof_for_groups ? "yes" : "no")); + IDMAP_LOG(1, ("umichldap_init: sasl_mech: %s", + (ldap_info.sasl_mech && strlen(ldap_info.sasl_mech) != 0) ? + ldap_info.sasl_mech : "<not-supplied>")); + IDMAP_LOG(1, ("umichldap_init: sasl_realm: %s", + (ldap_info.sasl_realm && strlen(ldap_info.sasl_realm) != 0) ? + ldap_info.sasl_realm : "<not-supplied>")); + IDMAP_LOG(1, ("umichldap_init: sasl_authcid: %s", + (ldap_info.sasl_authcid && + strlen(ldap_info.sasl_authcid) != 0) ? + ldap_info.sasl_authcid : "<not-supplied>")); + IDMAP_LOG(1, ("umichldap_init: sasl_authzid: %s", + (ldap_info.sasl_authzid && + strlen(ldap_info.sasl_authzid) != 0) ? + ldap_info.sasl_authzid : "<not-supplied>")); + IDMAP_LOG(1, ("umichldap_init: sasl_secprops: %s", + (ldap_info.sasl_secprops && + strlen(ldap_info.sasl_secprops) != 0) ? + ldap_info.sasl_secprops : "<not-supplied>")); + IDMAP_LOG(1, ("umichldap_init: sasl_canonicalize: %d", + ldap_info.sasl_canonicalize)); + IDMAP_LOG(1, ("umichldap_init: sasl_krb5_ccname: %s", + ldap_info.sasl_krb5_ccname)); + IDMAP_LOG(1, ("umichldap_init: follow_referrals: %s", + ldap_info.follow_referrals ? "yes" : "no")); + + IDMAP_LOG(1, ("umichldap_init: NFSv4_person_objectclass : %s", + ldap_map.NFSv4_person_objcls)); + IDMAP_LOG(1, ("umichldap_init: NFSv4_nfsname_attr : %s", + ldap_map.NFSv4_nfsname_attr)); + IDMAP_LOG(1, ("umichldap_init: NFSv4_acctname_attr : %s", + ldap_map.NFSv4_acctname_attr)); + IDMAP_LOG(1, ("umichldap_init: NFSv4_uid_attr : %s", + ldap_map.NFSv4_uid_attr)); + IDMAP_LOG(1, ("umichldap_init: NFSv4_group_objectclass : %s", + ldap_map.NFSv4_group_objcls)); + IDMAP_LOG(1, ("umichldap_init: NFSv4_gid_attr : %s", + ldap_map.NFSv4_gid_attr)); + IDMAP_LOG(1, ("umichldap_init: NFSv4_group_nfsname_attr : %s", + ldap_map.NFSv4_group_nfsname_attr)); + IDMAP_LOG(1, ("umichldap_init: NFSv4_member_attr : %s", + ldap_map.NFSv4_member_attr)); + IDMAP_LOG(1, ("umichldap_init: NFSv4_member_of_attr : %s", + ldap_map.NFSv4_member_of_attr)); + IDMAP_LOG(1, ("umichldap_init: NFSv4_grouplist_filter : %s", + ldap_map.NFSv4_grouplist_filter ? + ldap_map.NFSv4_grouplist_filter : "<not-specified>")); + IDMAP_LOG(1, ("umichldap_init: GSS_principal_attr : %s", + ldap_map.GSS_principal_attr)); + return 0; +fail: + return -1; +} + + +/* The external interface */ + +struct trans_func umichldap_trans = { + .name = "umich_ldap", + .init = umichldap_init, + .princ_to_ids = umichldap_gss_princ_to_ids, + .name_to_uid = umichldap_name_to_uid, + .name_to_gid = umichldap_name_to_gid, + .uid_to_name = umichldap_uid_to_name, + .gid_to_name = umichldap_gid_to_name, + .gss_princ_to_grouplist = umichldap_gss_princ_to_grouplist, +}; + +struct trans_func *libnfsidmap_plugin_init(void) +{ + return (&umichldap_trans); +} diff --git a/support/nsm/Makefile.am b/support/nsm/Makefile.am new file mode 100644 index 0000000..8f5874e --- /dev/null +++ b/support/nsm/Makefile.am @@ -0,0 +1,46 @@ +## Process this file with automake to produce Makefile.in + +GENFILES_CLNT = sm_inter_clnt.c +GENFILES_SVC = sm_inter_svc.c +GENFILES_XDR = sm_inter_xdr.c +GENFILES_H = sm_inter.h + +GENFILES = $(GENFILES_CLNT) $(GENFILES_SVC) $(GENFILES_XDR) $(GENFILES_H) + +EXTRA_DIST = sm_inter.x + +noinst_LIBRARIES = libnsm.a +libnsm_a_SOURCES = $(GENFILES) file.c rpc.c + +BUILT_SOURCES = $(GENFILES) + +if CONFIG_RPCGEN +RPCGEN = $(top_builddir)/tools/rpcgen/rpcgen +$(RPCGEN): + make -C ../../tools/rpcgen all +else +RPCGEN = @RPCGEN_PATH@ +endif + +$(GENFILES_CLNT): %_clnt.c: %.x $(RPCGEN) + test -f $@ && rm -rf $@ || true + $(RPCGEN) -l -o $@ $< + +$(GENFILES_SVC): %_svc.c: %.x $(RPCGEN) + test -f $@ && rm -rf $@ || true + $(RPCGEN) -m -o $@ $< + +$(GENFILES_XDR): %_xdr.c: %.x $(RPCGEN) + test -f $@ && rm -rf $@ || true + $(RPCGEN) -c -i 0 -o $@ $< + +$(GENFILES_H): %.h: %.x $(RPCGEN) + test -f $@ && rm -rf $@ || true + $(RPCGEN) -h -o $@ $< + echo "void sm_prog_1(struct svc_req *, SVCXPRT *);" >> $@ + rm -f $(top_builddir)/support/include/sm_inter.h + $(LN_S) ../nsm/sm_inter.h $(top_builddir)/support/include/sm_inter.h + +MAINTAINERCLEANFILES = Makefile.in + +CLEANFILES = $(GENFILES) $(top_builddir)/support/include/sm_inter.h diff --git a/support/nsm/Makefile.in b/support/nsm/Makefile.in new file mode 100644 index 0000000..54eaea9 --- /dev/null +++ b/support/nsm/Makefile.in @@ -0,0 +1,744 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = support/nsm +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ax_gcc_func_attribute.m4 \ + $(top_srcdir)/aclocal/bsdsignals.m4 \ + $(top_srcdir)/aclocal/getrandom.m4 \ + $(top_srcdir)/aclocal/ipv6.m4 \ + $(top_srcdir)/aclocal/kerberos5.m4 \ + $(top_srcdir)/aclocal/keyutils.m4 \ + $(top_srcdir)/aclocal/libblkid.m4 \ + $(top_srcdir)/aclocal/libcap.m4 \ + $(top_srcdir)/aclocal/libevent.m4 \ + $(top_srcdir)/aclocal/libpthread.m4 \ + $(top_srcdir)/aclocal/libsqlite3.m4 \ + $(top_srcdir)/aclocal/libtirpc.m4 \ + $(top_srcdir)/aclocal/libxml2.m4 \ + $(top_srcdir)/aclocal/nfs-utils.m4 \ + $(top_srcdir)/aclocal/rpcsec_vers.m4 \ + $(top_srcdir)/aclocal/tcp-wrappers.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/support/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +AM_V_AR = $(am__v_AR_@AM_V@) +am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) +am__v_AR_0 = @echo " AR " $@; +am__v_AR_1 = +libnsm_a_AR = $(AR) $(ARFLAGS) +libnsm_a_LIBADD = +am__objects_1 = sm_inter_clnt.$(OBJEXT) +am__objects_2 = sm_inter_svc.$(OBJEXT) +am__objects_3 = sm_inter_xdr.$(OBJEXT) +am__objects_4 = +am__objects_5 = $(am__objects_1) $(am__objects_2) $(am__objects_3) \ + $(am__objects_4) +am_libnsm_a_OBJECTS = $(am__objects_5) file.$(OBJEXT) rpc.$(OBJEXT) +libnsm_a_OBJECTS = $(am_libnsm_a_OBJECTS) +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/support/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/file.Po ./$(DEPDIR)/rpc.Po \ + ./$(DEPDIR)/sm_inter_clnt.Po ./$(DEPDIR)/sm_inter_svc.Po \ + ./$(DEPDIR)/sm_inter_xdr.Po +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libnsm_a_SOURCES) +DIST_SOURCES = $(libnsm_a_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GREP = @GREP@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GSSD = @GSSD@ +GSSGLUE_CFLAGS = @GSSGLUE_CFLAGS@ +GSSGLUE_LIBS = @GSSGLUE_LIBS@ +GSSKRB_CFLAGS = @GSSKRB_CFLAGS@ +GSSKRB_LIBS = @GSSKRB_LIBS@ +HAVE_GETRANDOM = @HAVE_GETRANDOM@ +HAVE_LIBWRAP = @HAVE_LIBWRAP@ +HAVE_TCP_WRAPPER = @HAVE_TCP_WRAPPER@ +IDMAPD = @IDMAPD@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +K5VERS = @K5VERS@ +KRBCFLAGS = @KRBCFLAGS@ +KRBDIR = @KRBDIR@ +KRBLDFLAGS = @KRBLDFLAGS@ +KRBLIBS = @KRBLIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ +LIBBLKID = @LIBBLKID@ +LIBBSD = @LIBBSD@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBEVENT = @LIBEVENT@ +LIBKEYUTILS = @LIBKEYUTILS@ +LIBMOUNT = @LIBMOUNT@ +LIBMOUNT_CFLAGS = @LIBMOUNT_CFLAGS@ +LIBMOUNT_LIBS = @LIBMOUNT_LIBS@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPTHREAD = @LIBPTHREAD@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSQLITE = @LIBSQLITE@ +LIBTIRPC = @LIBTIRPC@ +LIBTOOL = @LIBTOOL@ +LIBWRAP = @LIBWRAP@ +LIBXML2 = @LIBXML2@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_PLUGINS = @PATH_PLUGINS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +RELEASE = @RELEASE@ +RPCGEN_PATH = @RPCGEN_PATH@ +RPCSECGSS_CFLAGS = @RPCSECGSS_CFLAGS@ +RPCSECGSS_LIBS = @RPCSECGSS_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SVCGSSD = @SVCGSSD@ +TIRPC_CFLAGS = @TIRPC_CFLAGS@ +TIRPC_LIBS = @TIRPC_LIBS@ +VERSION = @VERSION@ +XML2_CFLAGS = @XML2_CFLAGS@ +XML2_LIBS = @XML2_LIBS@ +_rpc_pipefsmount = @_rpc_pipefsmount@ +_statedir = @_statedir@ +_sysconfdir = @_sysconfdir@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_gss = @enable_gss@ +enable_ipv6 = @enable_ipv6@ +enable_mountconfig = @enable_mountconfig@ +enable_nfsv4 = @enable_nfsv4@ +enable_nfsv41 = @enable_nfsv41@ +enable_svcgss = @enable_svcgss@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +kprefix = @kprefix@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +mountfile = @mountfile@ +nfsconfig = @nfsconfig@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rpc_pipefsmount = @rpc_pipefsmount@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +startstatd = @startstatd@ +statdpath = @statdpath@ +statduser = @statduser@ +statedir = @statedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +unitdir = @unitdir@ +GENFILES_CLNT = sm_inter_clnt.c +GENFILES_SVC = sm_inter_svc.c +GENFILES_XDR = sm_inter_xdr.c +GENFILES_H = sm_inter.h +GENFILES = $(GENFILES_CLNT) $(GENFILES_SVC) $(GENFILES_XDR) $(GENFILES_H) +EXTRA_DIST = sm_inter.x +noinst_LIBRARIES = libnsm.a +libnsm_a_SOURCES = $(GENFILES) file.c rpc.c +BUILT_SOURCES = $(GENFILES) +@CONFIG_RPCGEN_FALSE@RPCGEN = @RPCGEN_PATH@ +@CONFIG_RPCGEN_TRUE@RPCGEN = $(top_builddir)/tools/rpcgen/rpcgen +MAINTAINERCLEANFILES = Makefile.in +CLEANFILES = $(GENFILES) $(top_builddir)/support/include/sm_inter.h +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu support/nsm/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu support/nsm/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +libnsm.a: $(libnsm_a_OBJECTS) $(libnsm_a_DEPENDENCIES) $(EXTRA_libnsm_a_DEPENDENCIES) + $(AM_V_at)-rm -f libnsm.a + $(AM_V_AR)$(libnsm_a_AR) libnsm.a $(libnsm_a_OBJECTS) $(libnsm_a_LIBADD) + $(AM_V_at)$(RANLIB) libnsm.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/file.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rpc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sm_inter_clnt.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sm_inter_svc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sm_inter_xdr.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(LIBRARIES) +installdirs: +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/file.Po + -rm -f ./$(DEPDIR)/rpc.Po + -rm -f ./$(DEPDIR)/sm_inter_clnt.Po + -rm -f ./$(DEPDIR)/sm_inter_svc.Po + -rm -f ./$(DEPDIR)/sm_inter_xdr.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/file.Po + -rm -f ./$(DEPDIR)/rpc.Po + -rm -f ./$(DEPDIR)/sm_inter_clnt.Po + -rm -f ./$(DEPDIR)/sm_inter_svc.Po + -rm -f ./$(DEPDIR)/sm_inter_xdr.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: all check install install-am install-exec install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-noinstLIBRARIES \ + cscopelist-am ctags ctags-am distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + +@CONFIG_RPCGEN_TRUE@$(RPCGEN): +@CONFIG_RPCGEN_TRUE@ make -C ../../tools/rpcgen all + +$(GENFILES_CLNT): %_clnt.c: %.x $(RPCGEN) + test -f $@ && rm -rf $@ || true + $(RPCGEN) -l -o $@ $< + +$(GENFILES_SVC): %_svc.c: %.x $(RPCGEN) + test -f $@ && rm -rf $@ || true + $(RPCGEN) -m -o $@ $< + +$(GENFILES_XDR): %_xdr.c: %.x $(RPCGEN) + test -f $@ && rm -rf $@ || true + $(RPCGEN) -c -i 0 -o $@ $< + +$(GENFILES_H): %.h: %.x $(RPCGEN) + test -f $@ && rm -rf $@ || true + $(RPCGEN) -h -o $@ $< + echo "void sm_prog_1(struct svc_req *, SVCXPRT *);" >> $@ + rm -f $(top_builddir)/support/include/sm_inter.h + $(LN_S) ../nsm/sm_inter.h $(top_builddir)/support/include/sm_inter.h + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/support/nsm/file.c b/support/nsm/file.c new file mode 100644 index 0000000..f5b4480 --- /dev/null +++ b/support/nsm/file.c @@ -0,0 +1,1092 @@ +/* + * Copyright 2009 Oracle. All rights reserved. + * + * This file is part of nfs-utils. + * + * nfs-utils is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * nfs-utils is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with nfs-utils. If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * NSM for Linux. + * + * Callback information and NSM state is stored in files, usually + * under /var/lib/nfs. A database of information contained in local + * files stores NLM callback data and what remote peers to notify of + * reboots. + * + * For each monitored remote peer, a text file is created under the + * directory specified by NSM_MONITOR_DIR. The name of the file + * is a valid DNS hostname. The hostname string must be a valid + * ASCII DNS name, and must not contain slash characters, white space, + * or '\0' (ie. anything that might have some special meaning in a + * path name). + * + * The contents of each file include seven blank-separated fields of + * text, finished with '\n'. The first field contains the network + * address of the NLM service to call back. The current implementation + * supports using only IPv4 addresses, so the only contents of this + * field are a network order IPv4 address expressed in 8 hexadecimal + * characters. + * + * The next four fields are text strings of hexadecimal characters, + * representing: + * + * 2. A 4 byte RPC program number of the NLM service to call back + * 3. A 4 byte RPC version number of the NLM service to call back + * 4. A 4 byte RPC procedure number of the NLM service to call back + * 5. A 16 byte opaque cookie that the NLM service uses to identify + * the monitored host + * + * The sixth field is the monitored host's mon_name, passed to statd + * via an SM_MON request. + * + * The seventh field is the my_name for this peer, which is the + * hostname of the local NLM (currently on Linux, the result of + * `uname -n`). This can be used as the source address/hostname + * when sending SM_NOTIFY requests. + * + * The NSM protocol does not limit the contents of these strings + * in any way except that they must fit into 1024 bytes. Our + * implementation requires that these strings not contain + * white space or '\0'. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sys/types.h> +#ifdef HAVE_SYS_CAPABILITY_H +#include <sys/capability.h> +#endif +#include <sys/prctl.h> +#include <sys/stat.h> + +#include <ctype.h> +#include <string.h> +#include <stdint.h> +#ifndef S_SPLINT_S +#include <unistd.h> +#endif +#include <libgen.h> +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <dirent.h> +#include <grp.h> + +#include "xlog.h" +#include "nsm.h" +#include "misc.h" + +#define RPCARGSLEN (4 * (8 + 1)) +#define LINELEN (RPCARGSLEN + SM_PRIV_SIZE * 2 + 1) + +#define NSM_KERNEL_STATE_FILE "/proc/sys/fs/nfs/nsm_local_state" + +static char nsm_base_dirname[PATH_MAX] = NSM_DEFAULT_STATEDIR; + +#define NSM_MONITOR_DIR "sm" +#define NSM_NOTIFY_DIR "sm.bak" +#define NSM_STATE_FILE "state" + + +static _Bool +error_check(const int len, const size_t buflen) +{ + return (len < 0) || ((size_t)len >= buflen); +} + +static _Bool +exact_error_check(const ssize_t len, const size_t buflen) +{ + return (len < 0) || ((size_t)len != buflen); +} + +/* + * Returns a dynamically allocated, '\0'-terminated buffer + * containing an appropriate pathname, or NULL if an error + * occurs. Caller must free the returned result with free(3). + */ +__attribute__((__malloc__)) +static char * +nsm_make_record_pathname(const char *directory, const char *hostname) +{ + const char *c; + size_t size; + char *path; + int len; + + /* + * Block hostnames that contain characters that have + * meaning to the file system (like '/'), or that can + * be confusing on visual inspection (like ' '). + */ + for (c = hostname; *c != '\0'; c++) + if (*c == '/' || isspace((int)*c) != 0) { + xlog(D_GENERAL, "Hostname contains invalid characters"); + return NULL; + } + + size = strlen(nsm_base_dirname) + strlen(directory) + strlen(hostname) + 3; + if (size > PATH_MAX) { + xlog(D_GENERAL, "Hostname results in pathname that is too long"); + return NULL; + } + + path = malloc(size); + if (path == NULL) { + xlog(D_GENERAL, "Failed to allocate memory for pathname"); + return NULL; + } + + len = snprintf(path, size, "%s/%s/%s", + nsm_base_dirname, directory, hostname); + if (error_check(len, size)) { + xlog(D_GENERAL, "Pathname did not fit in specified buffer"); + free(path); + return NULL; + } + + return path; +} + +/* + * Returns a dynamically allocated, '\0'-terminated buffer + * containing an appropriate pathname, or NULL if an error + * occurs. Caller must free the returned result with free(3). + */ +__attribute__((__malloc__)) +static char * +nsm_make_pathname(const char *directory) +{ + return generic_make_pathname(nsm_base_dirname, directory); +} + +/* + * Returns a dynamically allocated, '\0'-terminated buffer + * containing an appropriate pathname, or NULL if an error + * occurs. Caller must free the returned result with free(3). + */ +__attribute__((__malloc__)) +static char * +nsm_make_temp_pathname(const char *pathname) +{ + size_t size; + char *path; + int len; + + size = strlen(pathname) + sizeof(".new") + 2; + if (size > PATH_MAX) + return NULL; + + path = malloc(size); + if (path == NULL) + return NULL; + + len = snprintf(path, size, "%s.new", pathname); + if (error_check(len, size)) { + free(path); + return NULL; + } + + return path; +} + +/* + * Use "mktemp, write, rename" to update the contents of a file atomically. + * + * Returns true if completely successful, or false if some error occurred. + */ +static _Bool +nsm_atomic_write(const char *path, const void *buf, const size_t buflen) +{ + _Bool result = false; + ssize_t len; + char *temp; + int fd; + + temp = nsm_make_temp_pathname(path); + if (temp == NULL) { + xlog(L_ERROR, "Failed to create new path for %s", path); + goto out; + } + + fd = open(temp, O_CREAT | O_TRUNC | O_SYNC | O_WRONLY, 0644); + if (fd == -1) { + xlog(L_ERROR, "Failed to create %s: %m", temp); + goto out; + } + + len = write(fd, buf, buflen); + if (exact_error_check(len, buflen)) { + xlog(L_ERROR, "Failed to write %s: %m", temp); + (void)close(fd); + (void)unlink(temp); + goto out; + } + + if (close(fd) == -1) { + xlog(L_ERROR, "Failed to close %s: %m", temp); + (void)unlink(temp); + goto out; + } + + if (rename(temp, path) == -1) { + xlog(L_ERROR, "Failed to rename %s -> %s: %m", + temp, path); + (void)unlink(temp); + goto out; + } + + /* Ostensibly, a sync(2) is not needed here because + * open(O_CREAT), write(O_SYNC), and rename(2) are + * already synchronous with persistent storage, for + * any file system we care about. */ + + result = true; + +out: + free(temp); + return result; +} + +/** + * nsm_setup_pathnames - set up pathname + * @progname: C string containing name of program, for error messages + * @parentdir: C string containing pathname to on-disk state, or NULL + * + * This runs before logging is set up, so error messages are directed + * to stderr. + * + * Returns true and sets up our pathnames, if @parentdir was valid + * and usable; otherwise false is returned. + */ +_Bool +nsm_setup_pathnames(const char *progname, const char *parentdir) +{ + return generic_setup_basedir(progname, parentdir, nsm_base_dirname, + PATH_MAX); +} + +/** + * nsm_is_default_parentdir - check if parent directory is default + * + * Returns true if the active statd parent directory, set by + * nsm_change_pathname(), is the same as the built-in default + * parent directory; otherwise false is returned. + */ +_Bool +nsm_is_default_parentdir(void) +{ + return strcmp(nsm_base_dirname, NSM_DEFAULT_STATEDIR) == 0; +} + +/* + * Clear all capabilities but CAP_NET_BIND_SERVICE. This permits + * callers to acquire privileged source ports, but all other root + * capabilities are disallowed. + * + * Returns true if successful, or false if some error occurred. + */ +#ifdef HAVE_SYS_CAPABILITY_H +static _Bool +nsm_clear_capabilities(void) +{ + cap_t caps; + + caps = cap_from_text("cap_net_bind_service=ep"); + if (caps == NULL) { + xlog(L_ERROR, "Failed to allocate capability: %m"); + return false; + } + + if (cap_set_proc(caps) == -1) { + xlog(L_ERROR, "Failed to set capability flags: %m"); + (void)cap_free(caps); + return false; + } + + (void)cap_free(caps); + return true; +} + +#define CAP_BOUND_PROCFILE "/proc/sys/kernel/cap-bound" +static _Bool +prune_bounding_set(void) +{ +#ifdef PR_CAPBSET_DROP + int ret; + unsigned long i; + struct stat st; + + /* + * Prior to kernel 2.6.25, the capabilities bounding set was a global + * value. Check to see if /proc/sys/kernel/cap-bound exists and don't + * bother to clear the bounding set if it does. + */ + ret = stat(CAP_BOUND_PROCFILE, &st); + if (!ret) { + xlog(L_WARNING, "%s exists. Not attempting to clear " + "capabilities bounding set.", + CAP_BOUND_PROCFILE); + return true; + } else if (errno != ENOENT) { + /* Warn, but attempt to clear the bounding set anyway. */ + xlog(L_WARNING, "Unable to stat %s: %m", CAP_BOUND_PROCFILE); + } + + /* prune the bounding set to nothing */ + for (i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >=0 ; ++i) { + ret = prctl(PR_CAPBSET_DROP, i, 0, 0, 0); + if (ret) { + xlog(L_ERROR, "Unable to prune capability %lu from " + "bounding set: %m", i); + return false; + } + } +#endif /* PR_CAPBSET_DROP */ + return true; +} +#else /* !HAVE_SYS_CAPABILITY_H */ +static _Bool +nsm_clear_capabilities(void) +{ + return true; +} + +static _Bool +prune_bounding_set(void) +{ + return true; +} +#endif /* HAVE_SYS_CAPABILITY_H */ + +/** + * nsm_drop_privileges - drop root privileges + * @pidfd: file descriptor of a pid file + * + * Returns true if successful, or false if some error occurred. + * + * Set our effective UID and GID to that of our on-disk database. + */ +_Bool +nsm_drop_privileges(const int pidfd) +{ + struct stat st; + + (void)umask(S_IRWXO); + + if (chdir(nsm_base_dirname) == -1) { + xlog(L_ERROR, "Failed to change working directory to %s: %m", + nsm_base_dirname); + return false; + } + + if (lstat(NSM_MONITOR_DIR, &st) == -1) { + xlog(L_ERROR, "Failed to stat %s/%s: %m", nsm_base_dirname, NSM_MONITOR_DIR); + return false; + } + + if (!prune_bounding_set()) + return false; + + if (st.st_uid == 0) { + xlog_warn("Running as root. " + "chown %s to choose different user", nsm_base_dirname); + return true; + } + + /* + * If the pidfile happens to reside on NFS, dropping privileges + * will probably cause us to lose access, even though we are + * holding it open. Chown it to prevent this. + */ + if (pidfd >= 0) + if (fchown(pidfd, st.st_uid, st.st_gid) == -1) + xlog_warn("Failed to change owner of pidfile: %m"); + + /* + * Don't clear capabilities when dropping root. + */ + if (prctl(PR_SET_KEEPCAPS, 1, 0, 0, 0) == -1) { + xlog(L_ERROR, "prctl(PR_SET_KEEPCAPS) failed: %m"); + return false; + } + + if (setgroups(0, NULL) == -1) { + xlog(L_ERROR, "Failed to drop supplementary groups: %m"); + return false; + } + + /* + * ORDER + * + * setgid(2) first, as setuid(2) may remove privileges needed + * to set the group id. + */ + if (setgid(st.st_gid) == -1 || setuid(st.st_uid) == -1) { + xlog(L_ERROR, "Failed to drop privileges: %m"); + return false; + } + + xlog(D_CALL, "Effective UID, GID: %u, %u", st.st_uid, st.st_gid); + + return nsm_clear_capabilities(); +} + +/** + * nsm_get_state - retrieve on-disk NSM state number + * + * Returns an odd NSM state number read from disk, or an initial + * state number. Zero is returned if some error occurs. + */ +int +nsm_get_state(_Bool update) +{ + int fd, state = 0; + ssize_t result; + char *path = NULL; + + path = nsm_make_pathname(NSM_STATE_FILE); + if (path == NULL) { + xlog(L_ERROR, "Failed to allocate path for " NSM_STATE_FILE); + goto out; + } + + fd = open(path, O_RDONLY); + if (fd == -1) { + if (errno != ENOENT) { + xlog(L_ERROR, "Failed to open %s: %m", path); + goto out; + } + + xlog(L_NOTICE, "Initializing NSM state"); + state = 1; + update = true; + goto update; + } + + result = read(fd, &state, sizeof(state)); + if (exact_error_check(result, sizeof(state))) { + xlog_warn("Failed to read %s: %m", path); + + xlog(L_NOTICE, "Initializing NSM state"); + state = 1; + update = true; + goto update; + } + + if ((state & 1) == 0) + state++; + +update: + if(fd >= 0) + (void)close(fd); + + if (update) { + state += 2; + if (!nsm_atomic_write(path, &state, sizeof(state))) + state = 0; + } + +out: + free(path); + return state; +} + +/** + * nsm_update_kernel_state - attempt to post new NSM state to kernel + * @state: NSM state number + * + */ +void +nsm_update_kernel_state(const int state) +{ + ssize_t result; + char buf[20]; + int fd, len; + + fd = open(NSM_KERNEL_STATE_FILE, O_WRONLY); + if (fd == -1) { + xlog(D_GENERAL, "Failed to open " NSM_KERNEL_STATE_FILE ": %m"); + return; + } + + len = snprintf(buf, sizeof(buf), "%d", state); + if (error_check(len, sizeof(buf))) { + xlog_warn("Failed to form NSM state number string"); + close(fd); + return; + } + + result = write(fd, buf, strlen(buf)); + if (exact_error_check(result, strlen(buf))) + xlog_warn("Failed to write NSM state number: %m"); + + if (close(fd) == -1) + xlog(L_ERROR, "Failed to close NSM state file " + NSM_KERNEL_STATE_FILE ": %m"); +} + +/** + * nsm_retire_monitored_hosts - back up all hosts from "sm/" to "sm.bak/" + * + * Returns the count of host records that were moved. + * + * Note that if any error occurs during this process, some monitor + * records may be left in the "sm" directory. + */ +unsigned int +nsm_retire_monitored_hosts(void) +{ + unsigned int count = 0; + struct dirent *de; + char *path; + DIR *dir; + + path = nsm_make_pathname(NSM_MONITOR_DIR); + if (path == NULL) { + xlog(L_ERROR, "Failed to allocate path for " NSM_MONITOR_DIR); + return count; + } + + dir = opendir(path); + free(path); + if (dir == NULL) { + xlog_warn("Failed to open " NSM_MONITOR_DIR ": %m"); + return count; + } + + while ((de = readdir(dir)) != NULL) { + char *src, *dst; + struct stat stb; + + if (de->d_name[0] == '.') + continue; + + src = nsm_make_record_pathname(NSM_MONITOR_DIR, de->d_name); + if (src == NULL) { + xlog_warn("Bad monitor file name, skipping"); + continue; + } + + /* NB: not all file systems fill in d_type correctly */ + if (lstat(src, &stb) == -1) { + xlog_warn("Bad monitor file %s, skipping: %m", + de->d_name); + free(src); + continue; + } + if (!S_ISREG(stb.st_mode)) { + xlog(D_GENERAL, "Skipping non-regular file %s", + de->d_name); + free(src); + continue; + } + + dst = nsm_make_record_pathname(NSM_NOTIFY_DIR, de->d_name); + if (dst == NULL) { + free(src); + xlog_warn("Bad notify file name, skipping"); + continue; + } + + if (rename(src, dst) == -1) + xlog_warn("Failed to rename %s -> %s: %m", + src, dst); + else { + xlog(D_GENERAL, "Retired record for mon_name %s", + de->d_name); + count++; + } + + free(dst); + free(src); + } + + (void)closedir(dir); + return count; +} + +/* + * nsm_priv_to_hex - convert a NSM private cookie to a hex string. + * + * @priv: buffer holding the binary NSM private cookie + * @buf: output buffer for NULL terminated hex string + * @buflen: size of output buffer + * + * Returns the length of the resulting string or 0 on error + */ +size_t +nsm_priv_to_hex(const char *priv, char *buf, const size_t buflen) +{ + int i, len; + size_t remaining = buflen; + + for (i = 0; i < SM_PRIV_SIZE; i++) { + len = snprintf(buf, remaining, "%02x", + (unsigned int)(0xff & priv[i])); + if (error_check(len, remaining)) + return 0; + buf += len; + remaining -= (size_t)len; + } + + return buflen - remaining; +} + +/* + * Returns the length in bytes of the created record. + */ +__attribute__((__noinline__)) +static size_t +nsm_create_monitor_record(char *buf, const size_t buflen, + const struct sockaddr *sap, const struct mon *m) +{ + const struct sockaddr_in *sin = (const struct sockaddr_in *)sap; + size_t hexlen, remaining = buflen; + int len; + + len = snprintf(buf, remaining, "%08x %08x %08x %08x ", + (unsigned int)sin->sin_addr.s_addr, + (unsigned int)m->mon_id.my_id.my_prog, + (unsigned int)m->mon_id.my_id.my_vers, + (unsigned int)m->mon_id.my_id.my_proc); + if (error_check(len, remaining)) + return 0; + buf += len; + remaining -= (size_t)len; + + hexlen = nsm_priv_to_hex(m->priv, buf, remaining); + if (hexlen == 0) + return 0; + buf += hexlen; + remaining -= hexlen; + + len = snprintf(buf, remaining, " %s %s\n", + m->mon_id.mon_name, m->mon_id.my_id.my_name); + if (error_check(len, remaining)) + return 0; + remaining -= (size_t)len; + + return buflen - remaining; +} + +static _Bool +nsm_append_monitored_host(const char *path, const char *line) +{ + _Bool result = false; + char *buf = NULL; + struct stat stb; + size_t buflen; + ssize_t len; + int fd; + + if (stat(path, &stb) == -1) { + xlog(L_ERROR, "Failed to insert: " + "could not stat original file %s: %m", path); + goto out; + } + buflen = (size_t)stb.st_size + strlen(line); + + buf = malloc(buflen + 1); + if (buf == NULL) { + xlog(L_ERROR, "Failed to insert: no memory"); + goto out; + } + memset(buf, 0, buflen + 1); + + fd = open(path, O_RDONLY); + if (fd == -1) { + xlog(L_ERROR, "Failed to insert: " + "could not open original file %s: %m", path); + goto out; + } + + len = read(fd, buf, (size_t)stb.st_size); + if (exact_error_check(len, (size_t)stb.st_size)) { + xlog(L_ERROR, "Failed to insert: " + "could not read original file %s: %m", path); + (void)close(fd); + goto out; + } + (void)close(fd); + + strcat(buf, line); + + if (nsm_atomic_write(path, buf, buflen)) + result = true; + +out: + free(buf); + return result; +} + +/** + * nsm_insert_monitored_host - write callback data for one host to disk + * @hostname: C string containing a hostname + * @sap: sockaddr containing NLM callback address + * @mon: SM_MON arguments to save + * + * Returns true if successful, otherwise false if some error occurs. + */ +_Bool +nsm_insert_monitored_host(const char *hostname, const struct sockaddr *sap, + const struct mon *m) +{ + static char buf[LINELEN + 1 + SM_MAXSTRLEN + 2]; + char *path; + _Bool result = false; + ssize_t len; + size_t size; + int fd; + + path = nsm_make_record_pathname(NSM_MONITOR_DIR, hostname); + if (path == NULL) { + xlog(L_ERROR, "Failed to insert: bad monitor hostname '%s'", + hostname); + return false; + } + + size = nsm_create_monitor_record(buf, sizeof(buf), sap, m); + if (size == 0) { + xlog(L_ERROR, "Failed to insert: record too long"); + goto out; + } + + /* + * If exclusive create fails, we're adding a new line to an + * existing file. + */ + fd = open(path, O_WRONLY | O_CREAT | O_EXCL | O_SYNC, S_IRUSR | S_IWUSR); + if (fd == -1) { + if (errno != EEXIST) { + xlog(L_ERROR, "Failed to insert: creating %s: %m", path); + goto out; + } + + result = nsm_append_monitored_host(path, buf); + goto out; + } + result = true; + + len = write(fd, buf, size); + if (exact_error_check(len, size)) { + xlog_warn("Failed to insert: writing %s: %m", path); + (void)unlink(path); + result = false; + } + + if (close(fd) == -1) { + xlog(L_ERROR, "Failed to insert: closing %s: %m", path); + (void)unlink(path); + result = false; + } + +out: + free(path); + return result; +} + +__attribute__((__noinline__)) +static _Bool +nsm_parse_line(char *line, struct sockaddr_in *sin, struct mon *m) +{ + unsigned int i, tmp; + int count; + char *c; + + c = strchr(line, '\n'); + if (c != NULL) + *c = '\0'; + + count = sscanf(line, "%8x %8x %8x %8x ", + (unsigned int *)&sin->sin_addr.s_addr, + (unsigned int *)&m->mon_id.my_id.my_prog, + (unsigned int *)&m->mon_id.my_id.my_vers, + (unsigned int *)&m->mon_id.my_id.my_proc); + if (count != 4) + return false; + + c = line + RPCARGSLEN; + for (i = 0; i < SM_PRIV_SIZE; i++) { + if (sscanf(c, "%2x", &tmp) != 1) + return false; + m->priv[i] = (char)tmp; + c += 2; + } + + c++; + m->mon_id.mon_name = c; + while (*c != '\0' && *c != ' ') + c++; + if (*c != '\0') + *c++ = '\0'; + while (*c == ' ') + c++; + m->mon_id.my_id.my_name = c; + + return true; +} + +/* + * Stuff a 'struct mon' with callback data, and call @func. + * + * Returns the count of in-core records created. + */ +static unsigned int +nsm_read_line(const char *hostname, const time_t timestamp, char *line, + nsm_populate_t func) +{ + struct sockaddr_in sin = { + .sin_family = AF_INET, + }; + struct mon m; + + if (!nsm_parse_line(line, &sin, &m)) + return 0; + + return func(hostname, (struct sockaddr *)(char *)&sin, &m, timestamp); +} + +/* + * Given a filename, reads data from a file under "directory" + * and invokes @func so caller can populate their in-core + * database with this data. + */ +static unsigned int +nsm_load_host(const char *directory, const char *filename, nsm_populate_t func) +{ + char buf[LINELEN + 1 + SM_MAXSTRLEN + 2]; + unsigned int result = 0; + struct stat stb; + char *path; + FILE *f; + + path = nsm_make_record_pathname(directory, filename); + if (path == NULL) + goto out_err; + + if (lstat(path, &stb) == -1) { + xlog(L_ERROR, "Failed to stat %s: %m", path); + goto out_freepath; + } + if (!S_ISREG(stb.st_mode)) { + xlog(D_GENERAL, "Skipping non-regular file %s", + path); + goto out_freepath; + } + + f = fopen(path, "r"); + if (f == NULL) { + xlog(L_ERROR, "Failed to open %s: %m", path); + goto out_freepath; + } + + while (fgets(buf, (int)sizeof(buf), f) != NULL) { + buf[sizeof(buf) - 1] = '\0'; + result += nsm_read_line(filename, stb.st_mtime, buf, func); + } + if (result == 0) + xlog(L_ERROR, "Failed to read monitor data from %s", path); + + (void)fclose(f); + +out_freepath: + free(path); +out_err: + return result; +} + +static unsigned int +nsm_load_dir(const char *directory, nsm_populate_t func) +{ + unsigned int count = 0; + struct dirent *de; + char *path; + DIR *dir; + + path = nsm_make_pathname(directory); + if (path == NULL) { + xlog(L_ERROR, "Failed to allocate path for directory %s", + directory); + return 0; + } + + dir = opendir(path); + free(path); + if (dir == NULL) { + xlog(L_ERROR, "Failed to open directory %s: %m", + directory); + return 0; + } + + while ((de = readdir(dir)) != NULL) { + if (de->d_name[0] == '.') + continue; + + count += nsm_load_host(directory, de->d_name, func); + } + + (void)closedir(dir); + return count; +} + +/** + * nsm_load_monitor_list - load list of hosts to monitor + * @func: callback function to create entry for one host + * + * Returns the count of hosts that were found in the directory. + */ +unsigned int +nsm_load_monitor_list(nsm_populate_t func) +{ + return nsm_load_dir(NSM_MONITOR_DIR, func); +} + +/** + * nsm_load_notify_list - load list of hosts to notify + * @func: callback function to create entry for one host + * + * Returns the count of hosts that were found in the directory. + */ +unsigned int +nsm_load_notify_list(nsm_populate_t func) +{ + return nsm_load_dir(NSM_NOTIFY_DIR, func); +} + +static void +nsm_delete_host(const char *directory, const char *hostname, + const char *mon_name, const char *my_name, const int chatty) +{ + char line[LINELEN + 1 + SM_MAXSTRLEN + 2]; + char *outbuf = NULL; + struct stat stb; + char *path, *next; + size_t remaining; + FILE *f; + + path = nsm_make_record_pathname(directory, hostname); + if (path == NULL) { + xlog(L_ERROR, "Bad filename, not deleting"); + return; + } + + if (stat(path, &stb) == -1) { + if (chatty) + xlog(L_ERROR, "Failed to delete: " + "could not stat original file %s: %m", path); + goto out; + } + remaining = (size_t)stb.st_size + 1; + + outbuf = malloc(remaining); + if (outbuf == NULL) { + xlog(L_ERROR, "Failed to delete: no memory"); + goto out; + } + + f = fopen(path, "r"); + if (f == NULL) { + xlog(L_ERROR, "Failed to delete: " + "could not open original file %s: %m", path); + goto out; + } + + /* + * Walk the records in the file, and copy the non-matching + * ones to our output buffer. + */ + next = outbuf; + while (fgets(line, (int)sizeof(line), f) != NULL) { + struct sockaddr_in sin; + struct mon m; + size_t len; + + if (!nsm_parse_line(line, &sin, &m)) { + xlog(L_ERROR, "Failed to delete: " + "could not parse original file %s", path); + (void)fclose(f); + goto out; + } + + if (strcmp(mon_name, m.mon_id.mon_name) == 0 && + strcmp(my_name, m.mon_id.my_id.my_name) == 0) + continue; + + /* nsm_parse_line destroys the contents of line[], so + * reconstruct the copy in our output buffer. */ + len = nsm_create_monitor_record(next, remaining, + (struct sockaddr *)(char *)&sin, &m); + if (len == 0) { + xlog(L_ERROR, "Failed to delete: " + "could not construct output record"); + (void)fclose(f); + goto out; + } + next += len; + remaining -= len; + } + + (void)fclose(f); + + /* + * If nothing was copied when we're done, then unlink the file. + * Otherwise, atomically update the contents of the file. + */ + if (next != outbuf) { + if (!nsm_atomic_write(path, outbuf, strlen(outbuf))) + xlog(L_ERROR, "Failed to delete: " + "could not write new file %s: %m", path); + } else { + if (unlink(path) == -1) + xlog(L_ERROR, "Failed to delete: " + "could not unlink file %s: %m", path); + } + +out: + free(outbuf); + free(path); +} + +/** + * nsm_delete_monitored_host - delete on-disk record for monitored host + * @hostname: '\0'-terminated C string containing hostname of record to delete + * @mon_name: '\0'-terminated C string containing monname of record to delete + * @my_name: '\0'-terminated C string containing myname of record to delete + * @chatty: should an error be logged if the monitor file doesn't exist? + * + */ +void +nsm_delete_monitored_host(const char *hostname, const char *mon_name, + const char *my_name, const int chatty) +{ + nsm_delete_host(NSM_MONITOR_DIR, hostname, mon_name, my_name, chatty); +} + +/** + * nsm_delete_notified_host - delete on-disk host record after notification + * @hostname: '\0'-terminated C string containing hostname of record to delete + * @mon_name: '\0'-terminated C string containing monname of record to delete + * @my_name: '\0'-terminated C string containing myname of record to delete + * + */ +void +nsm_delete_notified_host(const char *hostname, const char *mon_name, + const char *my_name) +{ + nsm_delete_host(NSM_NOTIFY_DIR, hostname, mon_name, my_name, 1); +} diff --git a/support/nsm/rpc.c b/support/nsm/rpc.c new file mode 100644 index 0000000..08b4746 --- /dev/null +++ b/support/nsm/rpc.c @@ -0,0 +1,536 @@ +/* + * Copyright 2009 Oracle. All rights reserved. + * + * This file is part of nfs-utils. + * + * nfs-utils is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * nfs-utils is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with nfs-utils. If not, see <http://www.gnu.org/licenses/>. + */ + +/* + * NSM for Linux. + * + * Instead of using ONC or TI RPC library calls, statd constructs + * RPC calls directly in socket buffers. This allows a single + * socket to be concurrently shared among several different RPC + * programs and versions using a simple RPC request dispatcher. + * + * This file contains the details of RPC header and call + * construction and reply parsing, and a method for creating a + * socket for use with these functions. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif /* HAVE_CONFIG_H */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/time.h> + +#include <stdint.h> +#include <time.h> +#include <stdbool.h> +#include <stdint.h> +#include <string.h> +#include <unistd.h> +#include <fcntl.h> + +#include <netinet/in.h> +#include <net/if.h> +#include <arpa/inet.h> +#include <netdb.h> + +#include <rpc/rpc.h> +#include <rpc/pmap_prot.h> +#include <rpc/pmap_rmt.h> + +#ifdef HAVE_LIBTIRPC +#include <netconfig.h> +#include <rpc/rpcb_prot.h> +#endif /* HAVE_LIBTIRPC */ + +#include "xlog.h" +#include "nfsrpc.h" +#include "nsm.h" +#include "sm_inter.h" + +/* + * Returns a fresh XID appropriate for RPC over UDP -- never zero. + */ +static uint32_t +nsm_next_xid(void) +{ + static uint32_t nsm_xid = 0; + struct timeval now; + + if (nsm_xid == 0) { + (void)gettimeofday(&now, NULL); + nsm_xid = (uint32_t)getpid() ^ + (uint32_t)now.tv_sec ^ (uint32_t)now.tv_usec; + } + + return nsm_xid++; +} + +/* + * Select a fresh XID and construct an RPC header in @mesg. + * Always use AUTH_NULL credentials and verifiers. + * + * Returns the new XID. + */ +static uint32_t +nsm_init_rpc_header(const rpcprog_t program, const rpcvers_t version, + const rpcproc_t procedure, struct rpc_msg *mesg) +{ + struct call_body *cb = &mesg->rm_call; + uint32_t xid = nsm_next_xid(); + + memset(mesg, 0, sizeof(*mesg)); + + mesg->rm_xid = (unsigned long)xid; + mesg->rm_direction = CALL; + + cb->cb_rpcvers = RPC_MSG_VERSION; + cb->cb_prog = program; + cb->cb_vers = version; + cb->cb_proc = procedure; + + cb->cb_cred.oa_flavor = AUTH_NULL; + cb->cb_cred.oa_base = (caddr_t) NULL; + cb->cb_cred.oa_length = 0; + cb->cb_verf.oa_flavor = AUTH_NULL; + cb->cb_verf.oa_base = (caddr_t) NULL; + cb->cb_verf.oa_length = 0; + + return xid; +} + +/* + * Initialize the network send buffer and XDR memory for encoding. + */ +static void +nsm_init_xdrmem(char *msgbuf, const unsigned int msgbuflen, + XDR *xdrp) +{ + memset(msgbuf, 0, (size_t)msgbuflen); + memset(xdrp, 0, sizeof(*xdrp)); + xdrmem_create(xdrp, msgbuf, msgbuflen, XDR_ENCODE); +} + +/* + * Send a completed RPC call on a socket. + * + * Returns true if all the bytes were sent successfully; otherwise + * false if any error occurred. + */ +static _Bool +nsm_rpc_sendto(const int sock, const struct sockaddr *sap, + const socklen_t salen, XDR *xdrs, void *buf) +{ + const size_t buflen = (size_t)xdr_getpos(xdrs); + ssize_t err; + + err = sendto(sock, buf, buflen, 0, sap, salen); + if ((err < 0) || ((size_t)err != buflen)) { + xlog(L_ERROR, "%s: sendto failed: %m", __func__); + return false; + } + return true; +} + +/** + * nsm_xmit_getport - post a PMAP_GETPORT call on a socket descriptor + * @sock: datagram socket descriptor + * @sin: pointer to AF_INET socket address of server + * @program: RPC program number to query + * @version: RPC version number to query + * + * Send a PMAP_GETPORT call to the portmap daemon at @sin using + * socket descriptor @sock. This request queries the RPC program + * [program, version, IPPROTO_UDP]. + * + * NB: PMAP_GETPORT works only for IPv4 hosts. This implementation + * works only over UDP, and queries only UDP registrations. + * + * Returns the XID of the call, or zero if an error occurred. + */ +uint32_t +nsm_xmit_getport(const int sock, const struct sockaddr_in *sin, + const unsigned long program, + const unsigned long version) +{ + char msgbuf[NSM_MAXMSGSIZE]; + struct sockaddr_in addr; + struct rpc_msg mesg; + _Bool sent = false; + struct pmap parms = { + .pm_prog = program, + .pm_vers = version, + .pm_prot = (unsigned long)IPPROTO_UDP, + }; + uint32_t xid; + XDR xdr; + + xlog(D_CALL, "Sending PMAP_GETPORT for %lu, %lu, udp", program, version); + + nsm_init_xdrmem(msgbuf, NSM_MAXMSGSIZE, &xdr); + xid = nsm_init_rpc_header(PMAPPROG, PMAPVERS, + (rpcproc_t)PMAPPROC_GETPORT, &mesg); + + addr = *sin; + addr.sin_port = htons(PMAPPORT); + + if (xdr_callmsg(&xdr, &mesg) == TRUE && + xdr_pmap(&xdr, &parms) == TRUE) + sent = nsm_rpc_sendto(sock, (struct sockaddr *)(char *)&addr, + (socklen_t)sizeof(addr), &xdr, msgbuf); + else + xlog(L_ERROR, "%s: can't encode PMAP_GETPORT call", __func__); + + xdr_destroy(&xdr); + + if (sent == false) + return 0; + return xid; +} + +/** + * nsm_xmit_getaddr - post an RPCB_GETADDR call on a socket descriptor + * @sock: datagram socket descriptor + * @sin: pointer to AF_INET6 socket address of server + * @program: RPC program number to query + * @version: RPC version number to query + * + * Send an RPCB_GETADDR call to the rpcbind daemon at @sap using + * socket descriptor @sock. This request queries the RPC program + * [program, version, "udp6"]. + * + * NB: RPCB_GETADDR works for both IPv4 and IPv6 hosts. This + * implementation works only over UDP and AF_INET6, and queries + * only "udp6" registrations. + * + * Returns the XID of the call, or zero if an error occurred. + */ +#ifdef HAVE_LIBTIRPC +uint32_t +nsm_xmit_getaddr(const int sock, const struct sockaddr_in6 *sin6, + const rpcprog_t program, const rpcvers_t version) +{ + char msgbuf[NSM_MAXMSGSIZE]; + struct sockaddr_in6 addr; + struct rpc_msg mesg; + _Bool sent = false; + struct rpcb parms = { + .r_prog = program, + .r_vers = version, + .r_netid = "udp6", + .r_owner = "", + }; + uint32_t xid; + XDR xdr; + + xlog(D_CALL, "Sending RPCB_GETADDR for %u, %u, udp6", program, version); + + nsm_init_xdrmem(msgbuf, NSM_MAXMSGSIZE, &xdr); + xid = nsm_init_rpc_header(RPCBPROG, RPCBVERS, + (rpcproc_t)RPCBPROC_GETADDR, &mesg); + + addr = *sin6; + addr.sin6_port = htons(PMAPPORT); + parms.r_addr = nfs_sockaddr2universal((struct sockaddr *)(char *)&addr); + if (parms.r_addr == NULL) { + xlog(L_ERROR, "%s: can't encode socket address", __func__); + return 0; + } + + if (xdr_callmsg(&xdr, &mesg) == TRUE && + xdr_rpcb(&xdr, &parms) == TRUE) + sent = nsm_rpc_sendto(sock, (struct sockaddr *)(char *)&addr, + (socklen_t)sizeof(addr), &xdr, msgbuf); + else + xlog(L_ERROR, "%s: can't encode RPCB_GETADDR call", __func__); + + xdr_destroy(&xdr); + free(parms.r_addr); + + if (sent == false) + return 0; + return xid; +} +#else /* !HAVE_LIBTIRPC */ +uint32_t +nsm_xmit_getaddr(const int sock __attribute__((unused)), + const struct sockaddr_in6 *sin6 __attribute__((unused)), + const rpcprog_t program __attribute__((unused)), + const rpcvers_t version __attribute__((unused))) +{ + return 0; +} +#endif /* !HAVE_LIBTIRPC */ + +/** + * nsm_xmit_rpcbind - post an rpcbind request + * @sock: datagram socket descriptor + * @sap: pointer to socket address of server + * @program: RPC program number to query + * @version: RPC version number to query + * + * Send an rpcbind query to the rpcbind daemon at @sap using + * socket descriptor @sock. + * + * NB: This implementation works only over UDP, but can query IPv4 or IPv6 + * hosts. It queries only UDP registrations. + * + * Returns the XID of the call, or zero if an error occurred. + */ +uint32_t +nsm_xmit_rpcbind(const int sock, const struct sockaddr *sap, + const rpcprog_t program, const rpcvers_t version) +{ + switch (sap->sa_family) { + case AF_INET: + return nsm_xmit_getport(sock, (const struct sockaddr_in *)sap, + program, version); + case AF_INET6: + return nsm_xmit_getaddr(sock, (const struct sockaddr_in6 *)sap, + program, version); + } + return 0; +} + +/** + * nsm_xmit_notify - post an NSMPROC_NOTIFY call on a socket descriptor + * @sock: datagram socket descriptor + * @sap: pointer to socket address of peer to notify (port already filled in) + * @salen: length of socket address + * @program: RPC program number to use + * @mon_name: mon_name of local peer (ie the rebooting system) + * @state: state of local peer + * + * Send an NSMPROC_NOTIFY call to the peer at @sap using socket descriptor @sock. + * This request notifies the peer that we have rebooted. + * + * NB: This implementation works only over UDP, but supports both AF_INET + * and AF_INET6. + * + * Returns the XID of the call, or zero if an error occurred. + */ +uint32_t +nsm_xmit_notify(const int sock, const struct sockaddr *sap, + const socklen_t salen, const rpcprog_t program, + const char *mon_name, const int state) +{ + char msgbuf[NSM_MAXMSGSIZE]; + struct stat_chge state_change; + struct rpc_msg mesg; + _Bool sent = false; + uint32_t xid; + XDR xdr; + + state_change.mon_name = strdup(mon_name); + if (state_change.mon_name == NULL) { + xlog(L_ERROR, "%s: no memory", __func__); + return 0; + } + state_change.state = state; + + xlog(D_CALL, "Sending SM_NOTIFY for %s", mon_name); + + nsm_init_xdrmem(msgbuf, NSM_MAXMSGSIZE, &xdr); + xid = nsm_init_rpc_header(program, SM_VERS, SM_NOTIFY, &mesg); + + if (xdr_callmsg(&xdr, &mesg) == TRUE && + xdr_stat_chge(&xdr, &state_change) == TRUE) + sent = nsm_rpc_sendto(sock, sap, salen, &xdr, msgbuf); + else + xlog(L_ERROR, "%s: can't encode NSMPROC_NOTIFY call", + __func__); + + xdr_destroy(&xdr); + free(state_change.mon_name); + + if (sent == false) + return 0; + return xid; +} + +/** + * nsm_xmit_nlmcall - post an unnamed call to local NLM on a socket descriptor + * @sock: datagram socket descriptor + * @sap: address/port of NLM service to contact + * @salen: size of @sap + * @m: callback data defining RPC call to make + * @state: state of rebooting host + * + * Send an unnamed call (previously requested via NSMPROC_MON) to the + * specified local UDP-based RPC service using socket descriptor @sock. + * + * NB: This implementation works only over UDP, but supports both AF_INET + * and AF_INET6. + * + * Returns the XID of the call, or zero if an error occurred. + */ +uint32_t +nsm_xmit_nlmcall(const int sock, const struct sockaddr *sap, + const socklen_t salen, const struct mon *m, + const int state) +{ + const struct my_id *id = &m->mon_id.my_id; + char msgbuf[NSM_MAXMSGSIZE]; + struct status new_status; + struct rpc_msg mesg; + _Bool sent = false; + uint32_t xid; + XDR xdr; + + xlog(D_CALL, "Sending NLM downcall for %s", m->mon_id.mon_name); + + nsm_init_xdrmem(msgbuf, NSM_MAXMSGSIZE, &xdr); + xid = nsm_init_rpc_header((rpcprog_t)id->my_prog, + (rpcvers_t)id->my_vers, + (rpcproc_t)id->my_proc, &mesg); + + new_status.mon_name = m->mon_id.mon_name; + new_status.state = state; + memcpy(&new_status.priv, &m->priv, sizeof(new_status.priv)); + + if (xdr_callmsg(&xdr, &mesg) == TRUE && + xdr_status(&xdr, &new_status) == TRUE) + sent = nsm_rpc_sendto(sock, sap, salen, &xdr, msgbuf); + else + xlog(L_ERROR, "%s: can't encode NLM downcall", __func__); + + xdr_destroy(&xdr); + + if (sent == false) + return 0; + return xid; +} + +/** + * nsm_parse_reply - parse and validate the header in an RPC reply + * @xdrs: pointer to XDR + * + * Returns the XID of the reply, or zero if an error occurred. + */ +uint32_t +nsm_parse_reply(XDR *xdrs) +{ + struct rpc_msg mesg = { + .rm_reply.rp_acpt.ar_results.proc = (xdrproc_t)xdr_void, + }; + uint32_t xid; + + if (xdr_replymsg(xdrs, &mesg) == FALSE) { + xlog(L_ERROR, "%s: can't decode RPC reply", __func__); + return 0; + } + xid = (uint32_t)mesg.rm_xid; + + if (mesg.rm_reply.rp_stat != MSG_ACCEPTED) { + xlog(L_ERROR, "%s: [0x%x] RPC status %d", + __func__, xid, mesg.rm_reply.rp_stat); + return 0; + } + + if (mesg.rm_reply.rp_acpt.ar_stat != SUCCESS) { + xlog(L_ERROR, "%s: [0x%x] RPC accept status %d", + __func__, xid, mesg.rm_reply.rp_acpt.ar_stat); + return 0; + } + + return xid; +} + +/** + * nsm_recv_getport - parse PMAP_GETPORT reply + * @xdrs: pointer to XDR + * + * Returns the port number from the RPC reply, or zero + * if an error occurred. + */ +unsigned long +nsm_recv_getport(XDR *xdrs) +{ + unsigned long port = 0; + + if (xdr_u_long(xdrs, &port) == FALSE) + xlog(L_ERROR, "%s: can't decode pmap reply", + __func__); + if (port > UINT16_MAX) { + xlog(L_ERROR, "%s: bad port number", + __func__); + port = 0; + } + + xlog(D_CALL, "Received PMAP_GETPORT result: %lu", port); + return port; +} + +/** + * nsm_recv_getaddr - parse RPCB_GETADDR reply + * @xdrs: pointer to XDR + * + * Returns the port number from the RPC reply, or zero + * if an error occurred. + */ +uint16_t +nsm_recv_getaddr(XDR *xdrs) +{ + char *uaddr = NULL; + int port; + + if (xdr_wrapstring(xdrs, &uaddr) == FALSE) + xlog(L_ERROR, "%s: can't decode rpcb reply", + __func__); + + if ((uaddr == NULL) || (uaddr[0] == '\0')) { + xlog(D_CALL, "Received RPCB_GETADDR result: " + "program not registered"); + return 0; + } + + port = nfs_universal2port(uaddr); + + xdr_free((xdrproc_t)xdr_wrapstring, (char *)&uaddr); + + if (port < 0 || port > UINT16_MAX) { + xlog(L_ERROR, "%s: bad port number", + __func__); + return 0; + } + + xlog(D_CALL, "Received RPCB_GETADDR result: %d", port); + return (uint16_t)port; +} + +/** + * nsm_recv_rpcbind - parse rpcbind reply + * @af: address family of reply + * @xdrs: pointer to XDR + * + * Returns the port number from the RPC reply, or zero + * if an error occurred. + */ +uint16_t +nsm_recv_rpcbind(const sa_family_t family, XDR *xdrs) +{ + switch (family) { + case AF_INET: + return (uint16_t)nsm_recv_getport(xdrs); + case AF_INET6: + return nsm_recv_getaddr(xdrs); + } + return 0; +} diff --git a/support/nsm/sm_inter.x b/support/nsm/sm_inter.x new file mode 100644 index 0000000..d8e0ad7 --- /dev/null +++ b/support/nsm/sm_inter.x @@ -0,0 +1,131 @@ +/* + * Copyright (C) 1986 Sun Microsystems, Inc. + * Modified by Jeffrey A. Uphoff, 1995, 1997-1999. + * Modified by Olaf Kirch, 1996. + * Modified by H.J. Lu, 1998. + * + * NSM for Linux. + */ + +/* + * Copyright (c) 2009, Sun Microsystems, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * - Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * - Neither the name of Sun Microsystems, Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * Status monitor protocol specification + */ + +#ifdef RPC_CLNT +%#include <string.h> +#endif + +program SM_PROG { + version SM_VERS { + /* res_stat = stat_succ if status monitor agrees to monitor */ + /* res_stat = stat_fail if status monitor cannot monitor */ + /* if res_stat == stat_succ, state = state number of site sm_name */ + struct sm_stat_res SM_STAT(struct sm_name) = 1; + + /* res_stat = stat_succ if status monitor agrees to monitor */ + /* res_stat = stat_fail if status monitor cannot monitor */ + /* stat consists of state number of local site */ + struct sm_stat_res SM_MON(struct mon) = 2; + + /* stat consists of state number of local site */ + struct sm_stat SM_UNMON(struct mon_id) = 3; + + /* stat consists of state number of local site */ + struct sm_stat SM_UNMON_ALL(struct my_id) = 4; + + void SM_SIMU_CRASH(void) = 5; + + void SM_NOTIFY(struct stat_chge) = 6; + + } = 1; +} = 100024; + +const SM_MAXSTRLEN = 1024; +const SM_PRIV_SIZE = 16; + +struct sm_name { + string mon_name<SM_MAXSTRLEN>; +}; + +struct my_id { + string my_name<SM_MAXSTRLEN>; /* name of the site iniates the monitoring request*/ + int my_prog; /* rpc program # of the requesting process */ + int my_vers; /* rpc version # of the requesting process */ + int my_proc; /* rpc procedure # of the requesting process */ +}; + +struct mon_id { + string mon_name<SM_MAXSTRLEN>; /* name of the site to be monitored */ + struct my_id my_id; +}; + + +struct mon { + struct mon_id mon_id; + opaque priv[SM_PRIV_SIZE]; /* private information to store at monitor for requesting process */ +}; + +struct stat_chge { + string mon_name<SM_MAXSTRLEN>; /* name of the site that had the state change */ + int state; +}; + +/* + * state # of status monitor monitonically increases each time + * status of the site changes: + * an even number (>= 0) indicates the site is down and + * an odd number (> 0) indicates the site is up; + */ +struct sm_stat { + int state; /* state # of status monitor */ +}; + +enum res { + stat_succ = 0, /* status monitor agrees to monitor */ + stat_fail = 1 /* status monitor cannot monitor */ +}; + +struct sm_stat_res { + res res_stat; + int state; +}; + +/* + * structure of the status message sent back by the status monitor + * when monitor site status changes + */ +struct status { + string mon_name<SM_MAXSTRLEN>; + int state; + opaque priv[SM_PRIV_SIZE]; /* stored private information */ +}; + +%#define SM_INTER_X diff --git a/support/reexport/Makefile.am b/support/reexport/Makefile.am new file mode 100644 index 0000000..fbd66a2 --- /dev/null +++ b/support/reexport/Makefile.am @@ -0,0 +1,18 @@ +## Process this file with automake to produce Makefile.in + +noinst_LIBRARIES = libreexport.a +libreexport_a_SOURCES = reexport.c + +sbin_PROGRAMS = fsidd + +fsidd_SOURCES = fsidd.c backend_sqlite.c + +fsidd_LDADD = ../../support/misc/libmisc.a \ + ../../support/nfs/libnfs.la \ + $(LIBPTHREAD) $(LIBEVENT) $(LIBSQLITE) \ + $(OPTLIBS) + +fsidd_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) \ + -I$(top_builddir)/support/include + +MAINTAINERCLEANFILES = Makefile.in diff --git a/support/reexport/Makefile.in b/support/reexport/Makefile.in new file mode 100644 index 0000000..51d2424 --- /dev/null +++ b/support/reexport/Makefile.in @@ -0,0 +1,799 @@ +# Makefile.in generated by automake 1.16.5 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2021 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +sbin_PROGRAMS = fsidd$(EXEEXT) +subdir = support/reexport +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/aclocal/ax_gcc_func_attribute.m4 \ + $(top_srcdir)/aclocal/bsdsignals.m4 \ + $(top_srcdir)/aclocal/getrandom.m4 \ + $(top_srcdir)/aclocal/ipv6.m4 \ + $(top_srcdir)/aclocal/kerberos5.m4 \ + $(top_srcdir)/aclocal/keyutils.m4 \ + $(top_srcdir)/aclocal/libblkid.m4 \ + $(top_srcdir)/aclocal/libcap.m4 \ + $(top_srcdir)/aclocal/libevent.m4 \ + $(top_srcdir)/aclocal/libpthread.m4 \ + $(top_srcdir)/aclocal/libsqlite3.m4 \ + $(top_srcdir)/aclocal/libtirpc.m4 \ + $(top_srcdir)/aclocal/libxml2.m4 \ + $(top_srcdir)/aclocal/nfs-utils.m4 \ + $(top_srcdir)/aclocal/rpcsec_vers.m4 \ + $(top_srcdir)/aclocal/tcp-wrappers.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/support/include/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(sbindir)" +PROGRAMS = $(sbin_PROGRAMS) +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +AM_V_AR = $(am__v_AR_@AM_V@) +am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) +am__v_AR_0 = @echo " AR " $@; +am__v_AR_1 = +libreexport_a_AR = $(AR) $(ARFLAGS) +libreexport_a_LIBADD = +am_libreexport_a_OBJECTS = reexport.$(OBJEXT) +libreexport_a_OBJECTS = $(am_libreexport_a_OBJECTS) +am_fsidd_OBJECTS = fsidd-fsidd.$(OBJEXT) \ + fsidd-backend_sqlite.$(OBJEXT) +fsidd_OBJECTS = $(am_fsidd_OBJECTS) +am__DEPENDENCIES_1 = +fsidd_DEPENDENCIES = ../../support/misc/libmisc.a \ + ../../support/nfs/libnfs.la $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)/support/include +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = ./$(DEPDIR)/fsidd-backend_sqlite.Po \ + ./$(DEPDIR)/fsidd-fsidd.Po ./$(DEPDIR)/reexport.Po +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libreexport_a_SOURCES) $(fsidd_SOURCES) +DIST_SOURCES = $(libreexport_a_SOURCES) $(fsidd_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CC_FOR_BUILD = @CC_FOR_BUILD@ +CFLAGS = @CFLAGS@ +CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@ +CSCOPE = @CSCOPE@ +CTAGS = @CTAGS@ +CXX = @CXX@ +CXXCPP = @CXXCPP@ +CXXDEPMODE = @CXXDEPMODE@ +CXXFLAGS = @CXXFLAGS@ +CXXFLAGS_FOR_BUILD = @CXXFLAGS_FOR_BUILD@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +ETAGS = @ETAGS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +FILECMD = @FILECMD@ +GREP = @GREP@ +GSSAPI_CFLAGS = @GSSAPI_CFLAGS@ +GSSAPI_LIBS = @GSSAPI_LIBS@ +GSSD = @GSSD@ +GSSGLUE_CFLAGS = @GSSGLUE_CFLAGS@ +GSSGLUE_LIBS = @GSSGLUE_LIBS@ +GSSKRB_CFLAGS = @GSSKRB_CFLAGS@ +GSSKRB_LIBS = @GSSKRB_LIBS@ +HAVE_GETRANDOM = @HAVE_GETRANDOM@ +HAVE_LIBWRAP = @HAVE_LIBWRAP@ +HAVE_TCP_WRAPPER = @HAVE_TCP_WRAPPER@ +IDMAPD = @IDMAPD@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +K5VERS = @K5VERS@ +KRBCFLAGS = @KRBCFLAGS@ +KRBDIR = @KRBDIR@ +KRBLDFLAGS = @KRBLDFLAGS@ +KRBLIBS = @KRBLIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@ +LIBBLKID = @LIBBLKID@ +LIBBSD = @LIBBSD@ +LIBCAP = @LIBCAP@ +LIBCRYPT = @LIBCRYPT@ +LIBEVENT = @LIBEVENT@ +LIBKEYUTILS = @LIBKEYUTILS@ +LIBMOUNT = @LIBMOUNT@ +LIBMOUNT_CFLAGS = @LIBMOUNT_CFLAGS@ +LIBMOUNT_LIBS = @LIBMOUNT_LIBS@ +LIBNSL = @LIBNSL@ +LIBOBJS = @LIBOBJS@ +LIBPTHREAD = @LIBPTHREAD@ +LIBS = @LIBS@ +LIBSOCKET = @LIBSOCKET@ +LIBSQLITE = @LIBSQLITE@ +LIBTIRPC = @LIBTIRPC@ +LIBTOOL = @LIBTOOL@ +LIBWRAP = @LIBWRAP@ +LIBXML2 = @LIBXML2@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_PLUGINS = @PATH_PLUGINS@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +RANLIB = @RANLIB@ +RELEASE = @RELEASE@ +RPCGEN_PATH = @RPCGEN_PATH@ +RPCSECGSS_CFLAGS = @RPCSECGSS_CFLAGS@ +RPCSECGSS_LIBS = @RPCSECGSS_LIBS@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +SVCGSSD = @SVCGSSD@ +TIRPC_CFLAGS = @TIRPC_CFLAGS@ +TIRPC_LIBS = @TIRPC_LIBS@ +VERSION = @VERSION@ +XML2_CFLAGS = @XML2_CFLAGS@ +XML2_LIBS = @XML2_LIBS@ +_rpc_pipefsmount = @_rpc_pipefsmount@ +_statedir = @_statedir@ +_sysconfdir = @_sysconfdir@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_CXX = @ac_ct_CXX@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +enable_gss = @enable_gss@ +enable_ipv6 = @enable_ipv6@ +enable_mountconfig = @enable_mountconfig@ +enable_nfsv4 = @enable_nfsv4@ +enable_nfsv41 = @enable_nfsv41@ +enable_svcgss = @enable_svcgss@ +exec_prefix = @exec_prefix@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +kprefix = @kprefix@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +mountfile = @mountfile@ +nfsconfig = @nfsconfig@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +rpc_pipefsmount = @rpc_pipefsmount@ +runstatedir = @runstatedir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +startstatd = @startstatd@ +statdpath = @statdpath@ +statduser = @statduser@ +statedir = @statedir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +unitdir = @unitdir@ +noinst_LIBRARIES = libreexport.a +libreexport_a_SOURCES = reexport.c +fsidd_SOURCES = fsidd.c backend_sqlite.c +fsidd_LDADD = ../../support/misc/libmisc.a \ + ../../support/nfs/libnfs.la \ + $(LIBPTHREAD) $(LIBEVENT) $(LIBSQLITE) \ + $(OPTLIBS) + +fsidd_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) \ + -I$(top_builddir)/support/include + +MAINTAINERCLEANFILES = Makefile.in +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu support/reexport/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu support/reexport/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-sbinPROGRAMS: $(sbin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-sbinPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(sbindir)" && rm -f $$files + +clean-sbinPROGRAMS: + @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +libreexport.a: $(libreexport_a_OBJECTS) $(libreexport_a_DEPENDENCIES) $(EXTRA_libreexport_a_DEPENDENCIES) + $(AM_V_at)-rm -f libreexport.a + $(AM_V_AR)$(libreexport_a_AR) libreexport.a $(libreexport_a_OBJECTS) $(libreexport_a_LIBADD) + $(AM_V_at)$(RANLIB) libreexport.a + +fsidd$(EXEEXT): $(fsidd_OBJECTS) $(fsidd_DEPENDENCIES) $(EXTRA_fsidd_DEPENDENCIES) + @rm -f fsidd$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(fsidd_OBJECTS) $(fsidd_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsidd-backend_sqlite.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fsidd-fsidd.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reexport.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +fsidd-fsidd.o: fsidd.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fsidd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fsidd-fsidd.o -MD -MP -MF $(DEPDIR)/fsidd-fsidd.Tpo -c -o fsidd-fsidd.o `test -f 'fsidd.c' || echo '$(srcdir)/'`fsidd.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsidd-fsidd.Tpo $(DEPDIR)/fsidd-fsidd.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fsidd.c' object='fsidd-fsidd.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fsidd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fsidd-fsidd.o `test -f 'fsidd.c' || echo '$(srcdir)/'`fsidd.c + +fsidd-fsidd.obj: fsidd.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fsidd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fsidd-fsidd.obj -MD -MP -MF $(DEPDIR)/fsidd-fsidd.Tpo -c -o fsidd-fsidd.obj `if test -f 'fsidd.c'; then $(CYGPATH_W) 'fsidd.c'; else $(CYGPATH_W) '$(srcdir)/fsidd.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsidd-fsidd.Tpo $(DEPDIR)/fsidd-fsidd.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='fsidd.c' object='fsidd-fsidd.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fsidd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fsidd-fsidd.obj `if test -f 'fsidd.c'; then $(CYGPATH_W) 'fsidd.c'; else $(CYGPATH_W) '$(srcdir)/fsidd.c'; fi` + +fsidd-backend_sqlite.o: backend_sqlite.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fsidd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fsidd-backend_sqlite.o -MD -MP -MF $(DEPDIR)/fsidd-backend_sqlite.Tpo -c -o fsidd-backend_sqlite.o `test -f 'backend_sqlite.c' || echo '$(srcdir)/'`backend_sqlite.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsidd-backend_sqlite.Tpo $(DEPDIR)/fsidd-backend_sqlite.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='backend_sqlite.c' object='fsidd-backend_sqlite.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fsidd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fsidd-backend_sqlite.o `test -f 'backend_sqlite.c' || echo '$(srcdir)/'`backend_sqlite.c + +fsidd-backend_sqlite.obj: backend_sqlite.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fsidd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT fsidd-backend_sqlite.obj -MD -MP -MF $(DEPDIR)/fsidd-backend_sqlite.Tpo -c -o fsidd-backend_sqlite.obj `if test -f 'backend_sqlite.c'; then $(CYGPATH_W) 'backend_sqlite.c'; else $(CYGPATH_W) '$(srcdir)/backend_sqlite.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/fsidd-backend_sqlite.Tpo $(DEPDIR)/fsidd-backend_sqlite.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='backend_sqlite.c' object='fsidd-backend_sqlite.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(fsidd_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o fsidd-backend_sqlite.obj `if test -f 'backend_sqlite.c'; then $(CYGPATH_W) 'backend_sqlite.c'; else $(CYGPATH_W) '$(srcdir)/backend_sqlite.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) $(LIBRARIES) +installdirs: + for dir in "$(DESTDIR)$(sbindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + clean-sbinPROGRAMS mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/fsidd-backend_sqlite.Po + -rm -f ./$(DEPDIR)/fsidd-fsidd.Po + -rm -f ./$(DEPDIR)/reexport.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-sbinPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/fsidd-backend_sqlite.Po + -rm -f ./$(DEPDIR)/fsidd-fsidd.Po + -rm -f ./$(DEPDIR)/reexport.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-sbinPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-noinstLIBRARIES \ + clean-sbinPROGRAMS cscopelist-am ctags ctags-am distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-sbinPROGRAMS install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-am uninstall uninstall-am uninstall-sbinPROGRAMS + +.PRECIOUS: Makefile + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/support/reexport/backend_sqlite.c b/support/reexport/backend_sqlite.c new file mode 100644 index 0000000..0eb5ea3 --- /dev/null +++ b/support/reexport/backend_sqlite.c @@ -0,0 +1,283 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <sqlite3.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#ifdef HAVE_GETRANDOM +# include <sys/random.h> +# if !defined(SYS_getrandom) && defined(__NR_getrandom) + /* usable kernel-headers, but old glibc-headers */ +# define SYS_getrandom __NR_getrandom +# endif +#endif + +#include "conffile.h" +#include "reexport_backend.h" +#include "xlog.h" + +#define REEXPDB_DBFILE NFS_STATEDIR "/reexpdb.sqlite3" +#define REEXPDB_DBFILE_WAIT_USEC (5000) + +static sqlite3 *db; +static int init_done; + +#if !defined(HAVE_GETRANDOM) && defined(SYS_getrandom) +/* libc without function, but we have syscall */ +static int getrandom(void *buf, size_t buflen, unsigned int flags) +{ + return (syscall(SYS_getrandom, buf, buflen, flags)); +} +# define HAVE_GETRANDOM +#endif + +static int prng_init(void) +{ + int seed; + + if (getrandom(&seed, sizeof(seed), 0) != sizeof(seed)) { + xlog(L_ERROR, "Unable to obtain seed for PRNG via getrandom()"); + return -1; + } + + srand(seed); + return 0; +} + +static void wait_for_dbaccess(void) +{ + usleep(REEXPDB_DBFILE_WAIT_USEC + (rand() % REEXPDB_DBFILE_WAIT_USEC)); +} + +static bool sqlite_plug_init(void) +{ + char *sqlerr; + int ret; + + if (init_done) + return true; + + if (prng_init() != 0) + return false; + + ret = sqlite3_open_v2(conf_get_str_with_def("reexport", "sqlitedb", REEXPDB_DBFILE), + &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_FULLMUTEX, + NULL); + if (ret != SQLITE_OK) { + xlog(L_ERROR, "Unable to open reexport database: %s", sqlite3_errstr(ret)); + return false; + } + +again: + ret = sqlite3_exec(db, "CREATE TABLE IF NOT EXISTS fsidnums (num INTEGER PRIMARY KEY CHECK (num > 0 AND num < 4294967296), path TEXT UNIQUE); CREATE INDEX IF NOT EXISTS idx_ids_path ON fsidnums (path);", NULL, NULL, &sqlerr); + switch (ret) { + case SQLITE_OK: + init_done = 1; + ret = 0; + break; + case SQLITE_BUSY: + case SQLITE_LOCKED: + wait_for_dbaccess(); + goto again; + default: + xlog(L_ERROR, "Unable to init reexport database: %s", sqlite3_errstr(ret)); + sqlite3_free(sqlerr); + sqlite3_close_v2(db); + ret = -1; + } + + return ret == 0 ? true : false; +} + +static void sqlite_plug_destroy(void) +{ + if (!init_done) + return; + + sqlite3_close_v2(db); +} + +static bool get_fsidnum_by_path(char *path, uint32_t *fsidnum, bool *found) +{ + static const char fsidnum_by_path_sql[] = "SELECT num FROM fsidnums WHERE path = ?1;"; + sqlite3_stmt *stmt = NULL; + bool success = false; + int ret; + + *found = false; + + ret = sqlite3_prepare_v2(db, fsidnum_by_path_sql, sizeof(fsidnum_by_path_sql), &stmt, NULL); + if (ret != SQLITE_OK) { + xlog(L_WARNING, "Unable to prepare SQL query '%s': %s", fsidnum_by_path_sql, sqlite3_errstr(ret)); + goto out; + } + + ret = sqlite3_bind_text(stmt, 1, path, -1, NULL); + if (ret != SQLITE_OK) { + xlog(L_WARNING, "Unable to bind SQL query '%s': %s", fsidnum_by_path_sql, sqlite3_errstr(ret)); + goto out; + } + +again: + ret = sqlite3_step(stmt); + switch (ret) { + case SQLITE_ROW: + *fsidnum = sqlite3_column_int(stmt, 0); + success = true; + *found = true; + break; + case SQLITE_DONE: + /* No hit */ + success = true; + *found = false; + break; + case SQLITE_BUSY: + case SQLITE_LOCKED: + wait_for_dbaccess(); + goto again; + default: + xlog(L_WARNING, "Error while looking up '%s' in database: %s", path, sqlite3_errstr(ret)); + } + +out: + sqlite3_finalize(stmt); + return success; +} + +static bool sqlite_plug_path_by_fsidnum(uint32_t fsidnum, char **path, bool *found) +{ + static const char path_by_fsidnum_sql[] = "SELECT path FROM fsidnums WHERE num = ?1;"; + sqlite3_stmt *stmt = NULL; + bool success = false; + int ret; + + *found = false; + + ret = sqlite3_prepare_v2(db, path_by_fsidnum_sql, sizeof(path_by_fsidnum_sql), &stmt, NULL); + if (ret != SQLITE_OK) { + xlog(L_WARNING, "Unable to prepare SQL query '%s': %s", path_by_fsidnum_sql, sqlite3_errstr(ret)); + goto out; + } + + ret = sqlite3_bind_int(stmt, 1, fsidnum); + if (ret != SQLITE_OK) { + xlog(L_WARNING, "Unable to bind SQL query '%s': %s", path_by_fsidnum_sql, sqlite3_errstr(ret)); + goto out; + } + +again: + ret = sqlite3_step(stmt); + switch (ret) { + case SQLITE_ROW: + *path = strdup((char *)sqlite3_column_text(stmt, 0)); + if (*path) { + *found = true; + success = true; + } else { + xlog(L_WARNING, "Out of memory"); + } + break; + case SQLITE_DONE: + /* No hit */ + *found = false; + success = true; + break; + case SQLITE_BUSY: + case SQLITE_LOCKED: + wait_for_dbaccess(); + goto again; + default: + xlog(L_WARNING, "Error while looking up '%i' in database: %s", fsidnum, sqlite3_errstr(ret)); + } + +out: + sqlite3_finalize(stmt); + return success; +} + +static bool new_fsidnum_by_path(char *path, uint32_t *fsidnum) +{ + /* + * This query is a little tricky. We use SQL to find and claim the smallest free fsid number. + * To find a free fsid the fsidnums is left joined to itself but with an offset of 1. + * Everything after the UNION statement is to handle the corner case where fsidnums + * is empty. In this case we want 1 as first fsid number. + */ + static const char new_fsidnum_by_path_sql[] = "INSERT INTO fsidnums VALUES ((SELECT ids1.num + 1 FROM fsidnums AS ids1 LEFT JOIN fsidnums AS ids2 ON ids2.num = ids1.num + 1 WHERE ids2.num IS NULL UNION SELECT 1 WHERE NOT EXISTS (SELECT NULL FROM fsidnums WHERE num = 1) LIMIT 1), ?1) RETURNING num;"; + + sqlite3_stmt *stmt = NULL; + int ret, check = 0; + bool success = false; + + ret = sqlite3_prepare_v2(db, new_fsidnum_by_path_sql, sizeof(new_fsidnum_by_path_sql), &stmt, NULL); + if (ret != SQLITE_OK) { + xlog(L_WARNING, "Unable to prepare SQL query '%s': %s", new_fsidnum_by_path_sql, sqlite3_errstr(ret)); + goto out; + } + + ret = sqlite3_bind_text(stmt, 1, path, -1, NULL); + if (ret != SQLITE_OK) { + xlog(L_WARNING, "Unable to bind SQL query '%s': %s", new_fsidnum_by_path_sql, sqlite3_errstr(ret)); + goto out; + } + +again: + ret = sqlite3_step(stmt); + switch (ret) { + case SQLITE_ROW: + *fsidnum = sqlite3_column_int(stmt, 0); + success = true; + break; + case SQLITE_CONSTRAINT: + /* Maybe we lost the race against another writer and the path is now present. */ + check = 1; + break; + case SQLITE_BUSY: + case SQLITE_LOCKED: + wait_for_dbaccess(); + goto again; + default: + xlog(L_WARNING, "Error while looking up '%s' in database: %s", path, sqlite3_errstr(ret)); + } + +out: + sqlite3_finalize(stmt); + + if (check) { + bool found = false; + + get_fsidnum_by_path(path, fsidnum, &found); + if (!found) + xlog(L_WARNING, "SQLITE_CONSTRAINT error while inserting '%s' in database", path); + } + + return success; +} + +static bool sqlite_plug_fsidnum_by_path(char *path, uint32_t *fsidnum, int may_create, bool *found) +{ + bool success; + + success = get_fsidnum_by_path(path, fsidnum, found); + if (success) { + if (!*found && may_create) { + success = new_fsidnum_by_path(path, fsidnum); + if (success) + *found = true; + } + } + + return success; +} + +struct reexpdb_backend_plugin sqlite_plug_ops = { + .fsidnum_by_path = sqlite_plug_fsidnum_by_path, + .path_by_fsidnum = sqlite_plug_path_by_fsidnum, + .initdb = sqlite_plug_init, + .destroydb = sqlite_plug_destroy, +}; diff --git a/support/reexport/fsidd.c b/support/reexport/fsidd.c new file mode 100644 index 0000000..3e62b3f --- /dev/null +++ b/support/reexport/fsidd.c @@ -0,0 +1,196 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <assert.h> +#ifdef HAVE_DLFCN_H +#include <dlfcn.h> +#endif +#include <event2/event.h> + +#include "conffile.h" +#include "reexport_backend.h" +#include "reexport.h" +#include "xcommon.h" +#include "xlog.h" + +static struct event_base *evbase; +static struct reexpdb_backend_plugin *dbbackend = &sqlite_plug_ops; + +/* assert_safe() always evalutes it argument, as it might have + * a side-effect. assert() won't if compiled with NDEBUG + */ +#define assert_safe(__sideeffect) (__sideeffect ? 0 : ({assert(0) ; 0;})) + +static void client_cb(evutil_socket_t cl, short ev, void *d) +{ + struct event *me = d; + char buf[PATH_MAX * 2]; + int n; + + (void)ev; + + n = recv(cl, buf, sizeof(buf) - 1, 0); + if (n <= 0) { + event_del(me); + event_free(me); + close(cl); + return; + } + + buf[n] = '\0'; + + if (strncmp(buf, "get_fsidnum ", strlen("get_fsidnum ")) == 0) { + char *req_path = buf + strlen("get_fsidnum "); + uint32_t fsidnum; + char *answer = NULL; + bool found; + + assert(req_path < buf + n ); + + printf("client asks for %s\n", req_path); + + if (dbbackend->fsidnum_by_path(req_path, &fsidnum, false, &found)) { + if (found) + assert_safe(asprintf(&answer, "+ %u", fsidnum) != -1); + else + assert_safe(asprintf(&answer, "+ ") != -1); + } else { + assert_safe(asprintf(&answer, "- %s", "Command failed") != -1); + } + + (void)send(cl, answer, strlen(answer), 0); + + free(answer); + } else if (strncmp(buf, "get_or_create_fsidnum ", strlen("get_or_create_fsidnum ")) == 0) { + char *req_path = buf + strlen("get_or_create_fsidnum "); + uint32_t fsidnum; + char *answer = NULL; + bool found; + + assert(req_path < buf + n ); + + + if (dbbackend->fsidnum_by_path(req_path, &fsidnum, true, &found)) { + if (found) { + assert_safe(asprintf(&answer, "+ %u", fsidnum) != -1); + } else { + assert_safe(asprintf(&answer, "+ ") != -1); + } + + } else { + assert_safe(asprintf(&answer, "- %s", "Command failed") != -1); + } + + (void)send(cl, answer, strlen(answer), 0); + + free(answer); + } else if (strncmp(buf, "get_path ", strlen("get_path ")) == 0) { + char *req_fsidnum = buf + strlen("get_path "); + char *path = NULL, *answer = NULL, *endp; + bool bad_input = true; + uint32_t fsidnum; + bool found; + + assert(req_fsidnum < buf + n ); + + errno = 0; + fsidnum = strtoul(req_fsidnum, &endp, 10); + if (errno == 0 && *endp == '\0') { + bad_input = false; + } + + if (bad_input) { + assert_safe(asprintf(&answer, "- %s", "Command failed: Bad input") != -1); + } else { + if (dbbackend->path_by_fsidnum(fsidnum, &path, &found)) { + if (found) + assert_safe(asprintf(&answer, "+ %s", path) != -1); + else + assert_safe(asprintf(&answer, "+ ") != -1); + } else { + assert_safe(asprintf(&answer, "+ ") != -1); + } + } + + (void)send(cl, answer, strlen(answer), 0); + + free(path); + free(answer); + } else if (strcmp(buf, "version") == 0) { + char answer[] = "+ 1"; + + (void)send(cl, answer, strlen(answer), 0); + } else { + char *answer = NULL; + + assert_safe(asprintf(&answer, "- bad command") != -1); + (void)send(cl, answer, strlen(answer), 0); + + free(answer); + } +} + +static void srv_cb(evutil_socket_t fd, short ev, void *d) +{ + int cl = accept4(fd, NULL, NULL, SOCK_NONBLOCK); + struct event *client_ev; + + (void)ev; + (void)d; + + client_ev = event_new(evbase, cl, EV_READ | EV_PERSIST | EV_CLOSED, client_cb, event_self_cbarg()); + event_add(client_ev, NULL); +} + +int main(void) +{ + struct event *srv_ev; + struct sockaddr_un addr; + char *sock_file; + int srv; + + conf_init_file(NFS_CONFFILE); + + if (!dbbackend->initdb()) { + return 1; + } + + sock_file = conf_get_str_with_def("reexport", "fsidd_socket", FSID_SOCKET_NAME); + + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, sock_file, sizeof(addr.sun_path) - 1); + if (addr.sun_path[0] == '@') + /* "abstract" socket namespace */ + addr.sun_path[0] = 0; + else + unlink(sock_file); + + srv = socket(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK, 0); + if (srv == -1) { + xlog(L_WARNING, "Unable to create AF_UNIX socket for %s: %m\n", sock_file); + return 1; + } + + if (bind(srv, (const struct sockaddr *)&addr, sizeof(struct sockaddr_un)) == -1) { + xlog(L_WARNING, "Unable to bind %s: %m\n", sock_file); + return 1; + } + + if (listen(srv, 5) == -1) { + xlog(L_WARNING, "Unable to listen on %s: %m\n", sock_file); + return 1; + } + + evbase = event_base_new(); + + srv_ev = event_new(evbase, srv, EV_READ | EV_PERSIST, srv_cb, NULL); + event_add(srv_ev, NULL); + + event_base_dispatch(evbase); + + dbbackend->destroydb(); + + return 0; +} diff --git a/support/reexport/reexport.c b/support/reexport/reexport.c new file mode 100644 index 0000000..7851658 --- /dev/null +++ b/support/reexport/reexport.c @@ -0,0 +1,324 @@ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef HAVE_DLFCN_H +#include <dlfcn.h> +#endif +#include <sys/types.h> +#include <sys/vfs.h> +#include <errno.h> + +#include "nfsd_path.h" +#include "conffile.h" +#include "nfslib.h" +#include "reexport.h" +#include "xcommon.h" +#include "xlog.h" + +static int fsidd_srv = -1; + +static bool connect_fsid_service(void) +{ + struct sockaddr_un addr; + char *sock_file; + int ret; + int s; + + if (fsidd_srv != -1) + return true; + + sock_file = conf_get_str_with_def("reexport", "fsidd_socket", FSID_SOCKET_NAME); + + memset(&addr, 0, sizeof(struct sockaddr_un)); + addr.sun_family = AF_UNIX; + strncpy(addr.sun_path, sock_file, sizeof(addr.sun_path) - 1); + if (addr.sun_path[0] == '@') + /* "abstract" socket namespace */ + addr.sun_path[0] = 0; + + s = socket(AF_UNIX, SOCK_SEQPACKET, 0); + if (s == -1) { + xlog(L_WARNING, "Unable to create AF_UNIX socket for %s: %m\n", sock_file); + return false; + } + + ret = connect(s, (const struct sockaddr *)&addr, sizeof(struct sockaddr_un)); + if (ret == -1) { + xlog(L_WARNING, "Unable to connect %s: %m, is fsidd running?\n", sock_file); + return false; + } + + fsidd_srv = s; + + return true; +} + +int reexpdb_init(void) +{ + int try_count = 3; + + while (try_count > 0 && !connect_fsid_service()) { + sleep(1); + try_count--; + } + + return try_count > 0; +} + +void reexpdb_destroy(void) +{ + close(fsidd_srv); + fsidd_srv = -1; +} + +static bool parse_fsidd_reply(const char *cmd_info, char *buf, size_t len, char **result) +{ + if (len == 0) { + xlog(L_WARNING, "Unable to read %s result: server closed the connection", cmd_info); + return false; + } else if (len < 2) { + xlog(L_WARNING, "Unable to read %s result: server sent too few bytes", cmd_info); + return false; + } + + if (buf[0] == '-') { + if (len > 2) { + char *reason = buf + 2; + xlog(L_WARNING, "Command %s failed, server said: %s", cmd_info, reason); + } else { + xlog(L_WARNING, "Command %s failed at server side", cmd_info); + } + + return false; + } + + if (buf[0] != '+') { + xlog(L_WARNING, "Unable to read %s result: server sent malformed answer", cmd_info); + return false; + } + + if (len > 2) { + *result = strdup(buf + 2); + } else { + *result = NULL; + } + + return true; +} + +static bool do_fsidd_cmd(const char *cmd_info, char *msg, size_t len, char **result) +{ + char recvbuf[1024]; + int n; + + if (fsidd_srv == -1) { + xlog(L_NOTICE, "Reconnecting to fsid services"); + if (reexpdb_init() == false) + return false; + } + + xlog(D_GENERAL, "Request to fsidd: msg=\"%s\" len=%zd", msg, len); + + if (write(fsidd_srv, msg, len) == -1) { + xlog(L_WARNING, "Unable to send %s command: %m", cmd_info); + goto out_close; + } + + n = read(fsidd_srv, recvbuf, sizeof(recvbuf) - 1); + if (n <= -1) { + xlog(L_WARNING, "Unable to recv %s answer: %m", cmd_info); + goto out_close; + } else if (n == sizeof(recvbuf) - 1) { + //TODO: use better way to detect truncation + xlog(L_WARNING, "Unable to recv %s answer: answer truncated", cmd_info); + goto out_close; + } + recvbuf[n] = '\0'; + + xlog(D_GENERAL, "Answer from fsidd: msg=\"%s\" len=%i", recvbuf, n); + + if (parse_fsidd_reply(cmd_info, recvbuf, n, result) == false) { + goto out_close; + } + + return true; + +out_close: + close(fsidd_srv); + fsidd_srv = -1; + return false; +} + +static bool fsidnum_get_by_path(char *path, uint32_t *fsidnum, bool may_create) +{ + char *msg, *result; + bool ret = false; + int len; + + char *cmd = may_create ? "get_or_create_fsidnum" : "get_fsidnum"; + + len = asprintf(&msg, "%s %s", cmd, path); + if (len == -1) { + xlog(L_WARNING, "Unable to build %s command: %m", cmd); + goto out; + } + + if (do_fsidd_cmd(cmd, msg, len, &result) == false) { + goto out; + } + + if (result) { + bool bad_input = true; + char *endp; + + errno = 0; + *fsidnum = strtoul(result, &endp, 10); + if (errno == 0 && *endp == '\0') { + bad_input = false; + } + + free(result); + + if (!bad_input) { + ret = true; + } else { + xlog(L_NOTICE, "Got malformed fsid for path %s", path); + } + } else { + xlog(L_NOTICE, "No fsid found for path %s", path); + } + +out: + free(msg); + return ret; +} + +static bool path_by_fsidnum(uint32_t fsidnum, char **path) +{ + char *msg, *result; + bool ret = false; + int len; + + len = asprintf(&msg, "get_path %d", (unsigned int)fsidnum); + if (len == -1) { + xlog(L_WARNING, "Unable to build get_path command: %m"); + goto out; + } + + if (do_fsidd_cmd("get_path", msg, len, &result) == false) { + goto out; + } + + if (result) { + *path = result; + ret = true; + } else { + xlog(L_NOTICE, "No path found for fsid %u", (unsigned int)fsidnum); + } + +out: + free(msg); + return ret; +} + +/* + * reexpdb_fsidnum_by_path - Lookup a fsid by path. + * + * @path: File system path used as lookup key + * @fsidnum: Pointer where found fsid is written to + * @may_create: If non-zero, allocate new fsid if lookup failed + * + */ +int reexpdb_fsidnum_by_path(char *path, uint32_t *fsidnum, int may_create) +{ + return fsidnum_get_by_path(path, fsidnum, may_create); +} + +/* + * reexpdb_uncover_subvolume - Make sure a subvolume is present. + * + * @fsidnum: Numerical fsid number to look for + * + * Subvolumes (NFS cross mounts) get automatically mounted upon first + * access and can vanish after fs.nfs.nfs_mountpoint_timeout seconds. + * Also if the NFS server reboots, clients can still have valid file + * handles for such a subvolume. + * + * If kNFSd asks mountd for the path of a given fsidnum it can + * trigger an automount by calling statfs() on the given path. + */ +void reexpdb_uncover_subvolume(uint32_t fsidnum) +{ + struct statfs st; + char *path = NULL; + int ret; + + if (path_by_fsidnum(fsidnum, &path)) { + ret = nfsd_path_statfs(path, &st); + if (ret == -1) + xlog(L_WARNING, "statfs() failed"); + } + + free(path); +} + +/* + * reexpdb_apply_reexport_settings - Apply reexport specific settings to an exportent + * + * @ep: exportent to apply to + * @flname: Current export file, only useful for logging + * @flline: Current line, only useful for logging + * + * This is a helper function for applying reexport specific settings to an exportent. + * It searches a suitable fsid an sets @ep->e_fsid. + */ +int reexpdb_apply_reexport_settings(struct exportent *ep, char *flname, int flline) +{ + uint32_t fsidnum; + bool found, is_v4root = ((ep->e_flags & NFSEXP_FSID) && !ep->e_fsid); + int ret = 0; + + if (ep->e_reexport == REEXP_NONE) + goto out; + + if (ep->e_uuid) + goto out; + + if (is_v4root) + goto out; + + found = reexpdb_fsidnum_by_path(ep->e_path, &fsidnum, 0); + if (!found) { + if (ep->e_reexport == REEXP_AUTO_FSIDNUM) { + found = reexpdb_fsidnum_by_path(ep->e_path, &fsidnum, 1); + if (!found) { + xlog(L_ERROR, "%s:%i: Unable to generate fsid for %s", + flname, flline, ep->e_path); + ret = -1; + goto out; + } + } else { + if (!ep->e_fsid) { + xlog(L_ERROR, "%s:%i: Selected 'reexport=' mode requires either a UUID 'fsid=' or a numerical 'fsid=' or a reexport db entry %d", + flname, flline, ep->e_fsid); + ret = -1; + } + + goto out; + } + } + + if (ep->e_fsid) { + if (ep->e_fsid != fsidnum) { + xlog(L_ERROR, "%s:%i: Selected 'reexport=' mode requires configured numerical 'fsid=' to agree with reexport db entry", + flname, flline); + ret = -1; + } + } else { + ep->e_fsid = fsidnum; + } + +out: + return ret; +} diff --git a/support/reexport/reexport.h b/support/reexport/reexport.h new file mode 100644 index 0000000..85fd59c --- /dev/null +++ b/support/reexport/reexport.h @@ -0,0 +1,20 @@ +#ifndef REEXPORT_H +#define REEXPORT_H + +#include "nfslib.h" + +enum { + REEXP_NONE = 0, + REEXP_AUTO_FSIDNUM, + REEXP_PREDEFINED_FSIDNUM, +}; + +int reexpdb_init(void); +void reexpdb_destroy(void); +int reexpdb_fsidnum_by_path(char *path, uint32_t *fsidnum, int may_create); +int reexpdb_apply_reexport_settings(struct exportent *ep, char *flname, int flline); +void reexpdb_uncover_subvolume(uint32_t fsidnum); + +#define FSID_SOCKET_NAME "@/run/fsid.sock" + +#endif /* REEXPORT_H */ diff --git a/support/reexport/reexport_backend.h b/support/reexport/reexport_backend.h new file mode 100644 index 0000000..4940f06 --- /dev/null +++ b/support/reexport/reexport_backend.h @@ -0,0 +1,47 @@ +#ifndef REEXPORT_BACKEND_H +#define REEXPORT_BACKEND_H + +extern struct reexpdb_backend_plugin sqlite_plug_ops; + +struct reexpdb_backend_plugin { + /* + * Find or allocate a fsidnum for a given path. + * + * @path: Path to look for + * @fsidnum: Pointer to an uint32_t variable + * @may_create: If non-zero, a fsidnum will be allocated if none was found + * + * Returns true if either an fsidnum was found or successfully allocated, + * false otherwise. + * On success, the fsidnum will be stored into @fsidnum. + * Upon errors, false is returned and errors are logged. + */ + bool (*fsidnum_by_path)(char *path, uint32_t *fsidnum, int may_create, bool *found); + + /* + * Lookup path by a given fsidnum + * + * @fsidnum: fsidnum to look for + * @path: address of a char pointer + * + * Returns true if a path was found, false otherwise. + * Upon errors, false is returned and errors are logged. + * In case of success, the function returns the found path + * via @path, @path will point to a freshly allocated buffer + * which is free()'able. + */ + bool (*path_by_fsidnum)(uint32_t fsidnum, char **path, bool *found); + + /* + * Init database connection, can get called multiple times. + * Returns true on success, false otherwise. + */ + bool (*initdb)(void); + + /* + * Undoes initdb(). + */ + void (*destroydb)(void); +}; + +#endif /* REEXPORT_BACKEND_H */ |