4193 lines
117 KiB
Diff
4193 lines
117 KiB
Diff
|
diff --git a/.gitignore b/.gitignore
|
||
|
index 7bd9921..96f9750 100644
|
||
|
--- a/.gitignore
|
||
|
+++ b/.gitignore
|
||
|
@@ -49,6 +49,7 @@ utils/rquotad/rquotad
|
||
|
utils/rquotad/rquota.h
|
||
|
utils/rquotad/rquota_xdr.c
|
||
|
utils/showmount/showmount
|
||
|
+utils/nfsdcld/nfsdcld
|
||
|
utils/statd/statd
|
||
|
tools/locktest/testlk
|
||
|
tools/getiversion/getiversion
|
||
|
diff --git a/README b/README
|
||
|
index e7588cf..348f5d4 100644
|
||
|
--- a/README
|
||
|
+++ b/README
|
||
|
@@ -15,6 +15,8 @@ libraries. They are available from
|
||
|
http://www.citi.umich.edu/projects/nfsv4/linux/libnfsidmap/
|
||
|
Otherwise use --disable-nfsv4
|
||
|
|
||
|
+To use the nfsdcld tracking daemon, nfsv4 support must be enabled,
|
||
|
+and the libsqlite3 development libraries must be installed.
|
||
|
|
||
|
1. COMPILING
|
||
|
|
||
|
@@ -80,7 +82,7 @@ scripts can be written to work correctly.
|
||
|
and starting the nfsd server is not important.
|
||
|
idmapd is only needed for NFSv4 support.
|
||
|
svcgssd is only needed if exportfs NFS filesystem with crypto-
|
||
|
- security (Kerberos or SPKM3).
|
||
|
+ security (Kerberos).
|
||
|
|
||
|
C/ exportfs -av ; rpc.mountd
|
||
|
It is important that exportfs be run before mountd so that
|
||
|
@@ -106,12 +108,31 @@ scripts can be written to work correctly.
|
||
|
the lock.
|
||
|
rpc.statd is only needed for NFSv2 and NFSv3 support.
|
||
|
|
||
|
- E/ rpc.nfsd
|
||
|
+ E/ nfsdcld
|
||
|
+ This daemon is only needed on kernels that support the nfsdcld
|
||
|
+ upcall, and only if the legacy client ID tracking isn't used. It
|
||
|
+ is also not needed if the server does not support NFSv4.
|
||
|
+
|
||
|
+ To determine whether you need this or not, do the following:
|
||
|
+
|
||
|
+ # cat /proc/fs/nfsd/versions
|
||
|
+
|
||
|
+ That should yield a list of NFS versions that this kernel supports,
|
||
|
+ if "4" or later is not in that list, or they are prefixed with a "-"
|
||
|
+ then you don't need to run this daemon. Next:
|
||
|
+
|
||
|
+ # cat /proc/fs/nfsd/nfsv4recoverydir
|
||
|
+
|
||
|
+ If that file is not present, or the directory that the above command
|
||
|
+ outputs is not present, then this daemon is required in order to
|
||
|
+ support lock recovery by the clients when the server reboots.
|
||
|
+
|
||
|
+ F/ rpc.nfsd
|
||
|
Starting nfsd will automatically start lockd. The nfs server
|
||
|
will now be fully active and respond to any requests from
|
||
|
clients.
|
||
|
|
||
|
- F/ sm-notify
|
||
|
+ G/ sm-notify
|
||
|
This will notify any client which might have locks from before
|
||
|
a reboot to try to reclaim their locks. This should start
|
||
|
immediately after rpc.nfsd is started so that clients have a
|
||
|
@@ -130,7 +151,7 @@ scripts can be written to work correctly.
|
||
|
B/ gssd ; idmapd
|
||
|
idmapd should be started before mounting any NFSv4 filesystems.
|
||
|
gssd should be started before mounting any NFS filesystems
|
||
|
- securely (with Kerberos of SPKM3).
|
||
|
+ securely (with Kerberos).
|
||
|
|
||
|
C/ statd should be run before any NFSv2 or NFSv3 filesystem is
|
||
|
mounted with remote locking (i.e. without -o nolock).
|
||
|
diff --git a/aclocal/ipv6.m4 b/aclocal/ipv6.m4
|
||
|
index 5ee8fb6..75a8582 100644
|
||
|
--- a/aclocal/ipv6.m4
|
||
|
+++ b/aclocal/ipv6.m4
|
||
|
@@ -2,11 +2,6 @@ dnl Checks for IPv6 support
|
||
|
dnl
|
||
|
AC_DEFUN([AC_IPV6], [
|
||
|
|
||
|
- AC_CHECK_DECL([AI_ADDRCONFIG],
|
||
|
- [AC_DEFINE([HAVE_DECL_AI_ADDRCONFIG], 1,
|
||
|
- [Define this to 1 if AI_ADDRCONFIG macro is defined])], ,
|
||
|
- [ #include <netdb.h> ])
|
||
|
-
|
||
|
if test "$enable_ipv6" = yes; then
|
||
|
|
||
|
dnl TI-RPC required for IPv6
|
||
|
@@ -15,15 +10,11 @@ AC_DEFUN([AC_IPV6], [
|
||
|
fi
|
||
|
|
||
|
dnl IPv6-enabled networking functions required for IPv6
|
||
|
- AC_CHECK_FUNCS([getifaddrs getnameinfo bindresvport_sa], ,
|
||
|
+ AC_CHECK_FUNCS([getifaddrs getnameinfo], ,
|
||
|
[AC_MSG_ERROR([Missing library functions needed for IPv6.])])
|
||
|
|
||
|
- dnl Need to detect presence of IPv6 networking at run time via
|
||
|
- dnl getaddrinfo(3); old versions of glibc do not support ADDRCONFIG
|
||
|
- AC_CHECK_DECL([AI_ADDRCONFIG], ,
|
||
|
- [AC_MSG_ERROR([full getaddrinfo(3) implementation needed for IPv6 support])],
|
||
|
- [ #include <netdb.h> ])
|
||
|
-
|
||
|
+ AC_CHECK_LIB([tirpc], [bindresvport_sa], [:],
|
||
|
+ [AC_MSG_ERROR([Missing library functions needed for IPv6.])])
|
||
|
fi
|
||
|
|
||
|
])dnl
|
||
|
diff --git a/aclocal/kerberos5.m4 b/aclocal/kerberos5.m4
|
||
|
index dfa5738..7574e2d 100644
|
||
|
--- a/aclocal/kerberos5.m4
|
||
|
+++ b/aclocal/kerberos5.m4
|
||
|
@@ -31,7 +31,7 @@ AC_DEFUN([AC_KERBEROS_V5],[
|
||
|
fi
|
||
|
if test "$K5CONFIG" != ""; then
|
||
|
KRBCFLAGS=`$K5CONFIG --cflags`
|
||
|
- KRBLIBS=`$K5CONFIG --libs gssapi`
|
||
|
+ KRBLIBS=`$K5CONFIG --libs`
|
||
|
K5VERS=`$K5CONFIG --version | head -n 1 | awk '{split($(4),v,"."); if (v@<:@"3"@:>@ == "") v@<:@"3"@:>@ = "0"; print v@<:@"1"@:>@v@<:@"2"@:>@v@<:@"3"@:>@ }'`
|
||
|
AC_DEFINE_UNQUOTED(KRB5_VERSION, $K5VERS, [Define this as the Kerberos version number])
|
||
|
if test -f $dir/include/gssapi/gssapi_krb5.h -a \
|
||
|
diff --git a/aclocal/libevent.m4 b/aclocal/libevent.m4
|
||
|
index 3c962b3..b5ac00f 100644
|
||
|
--- a/aclocal/libevent.m4
|
||
|
+++ b/aclocal/libevent.m4
|
||
|
@@ -2,8 +2,9 @@ dnl Checks for libevent
|
||
|
AC_DEFUN([AC_LIBEVENT], [
|
||
|
|
||
|
dnl Check for libevent, but do not add -levent to LIBS
|
||
|
- AC_CHECK_LIB([event], [event_dispatch], [libevent=1],
|
||
|
+ AC_CHECK_LIB([event], [event_dispatch], [LIBEVENT=-levent],
|
||
|
[AC_MSG_ERROR([libevent not found.])])
|
||
|
+ AC_SUBST(LIBEVENT)
|
||
|
|
||
|
AC_CHECK_HEADERS([event.h], ,
|
||
|
[AC_MSG_ERROR([libevent headers not found.])])
|
||
|
diff --git a/aclocal/libnfsidmap.m4 b/aclocal/libnfsidmap.m4
|
||
|
index 484b1ec..ae697e8 100644
|
||
|
--- a/aclocal/libnfsidmap.m4
|
||
|
+++ b/aclocal/libnfsidmap.m4
|
||
|
@@ -3,7 +3,7 @@ dnl
|
||
|
AC_DEFUN([AC_LIBNFSIDMAP], [
|
||
|
|
||
|
dnl Check for libnfsidmap, but do not add -lnfsidmap to LIBS
|
||
|
- AC_CHECK_LIB([nfsidmap], [nfs4_init_name_mapping], [libnfsidmap=1],
|
||
|
+ AC_CHECK_LIB([nfsidmap], [nfs4_init_name_mapping], [LIBNFSIDMAP=-lnfsidmap],
|
||
|
[AC_MSG_ERROR([libnfsidmap not found.])])
|
||
|
|
||
|
AC_CHECK_HEADERS([nfsidmap.h], ,
|
||
|
@@ -14,7 +14,10 @@ AC_DEFUN([AC_LIBNFSIDMAP], [
|
||
|
[AC_DEFINE([HAVE_NFS4_SET_DEBUG], 1,
|
||
|
[Define to 1 if you have the `nfs4_set_debug' function.])])
|
||
|
|
||
|
- dnl only enable nfsidmap when libnfsidmap supports it
|
||
|
- AC_CHECK_LIB([nfsidmap], [nfs4_owner_to_uid])
|
||
|
+ dnl nfs4_owner_to_uid() doesn't appear in all versions of libnfsidmap
|
||
|
+ dnl We just need this test to set $ac_cv_lib_nfsidmap_nfs4_owner_to_uid
|
||
|
+ AC_CHECK_LIB([nfsidmap], [nfs4_owner_to_uid], [:])
|
||
|
+
|
||
|
+ AC_SUBST(LIBNFSIDMAP)
|
||
|
|
||
|
])dnl
|
||
|
diff --git a/aclocal/libsqlite3.m4 b/aclocal/libsqlite3.m4
|
||
|
new file mode 100644
|
||
|
index 0000000..73d1e46
|
||
|
--- /dev/null
|
||
|
+++ b/aclocal/libsqlite3.m4
|
||
|
@@ -0,0 +1,33 @@
|
||
|
+dnl Checks for matching sqlite3 header and library, and
|
||
|
+dnl sufficient sqlite3 version.
|
||
|
+dnl
|
||
|
+AC_DEFUN([AC_SQLITE3_VERS], [
|
||
|
+ AC_CHECK_HEADERS([sqlite3.h], ,)
|
||
|
+
|
||
|
+ dnl look for the library; do not add to LIBS if found
|
||
|
+ AC_CHECK_LIB([sqlite3], [sqlite3_libversion_number], [LIBSQLITE=-lsqlite3], ,)
|
||
|
+ AC_SUBST(LIBSQLITE)
|
||
|
+
|
||
|
+ AC_MSG_CHECKING(for suitable sqlite3 version)
|
||
|
+
|
||
|
+ AC_CACHE_VAL([libsqlite3_cv_is_recent],
|
||
|
+ [
|
||
|
+ saved_LIBS="$LIBS"
|
||
|
+ LIBS=-lsqlite3
|
||
|
+ AC_TRY_RUN([
|
||
|
+ #include <stdio.h>
|
||
|
+ #include <sqlite3.h>
|
||
|
+ int main()
|
||
|
+ {
|
||
|
+ int vers = sqlite3_libversion_number();
|
||
|
+
|
||
|
+ return vers != SQLITE_VERSION_NUMBER ||
|
||
|
+ vers < 3003000;
|
||
|
+ }
|
||
|
+ ], [libsqlite3_cv_is_recent=yes], [libsqlite3_cv_is_recent=no],
|
||
|
+ [libsqlite3_cv_is_recent=unknown])
|
||
|
+ LIBS="$saved_LIBS"])
|
||
|
+
|
||
|
+ AC_MSG_RESULT($libsqlite3_cv_is_recent)
|
||
|
+ AM_CONDITIONAL(CONFIG_SQLITE3, [test "$libsqlite3_cv_is_recent" = "yes"])
|
||
|
+])dnl
|
||
|
diff --git a/aclocal/libtirpc.m4 b/aclocal/libtirpc.m4
|
||
|
index 9f0fde0..19b8361 100644
|
||
|
--- a/aclocal/libtirpc.m4
|
||
|
+++ b/aclocal/libtirpc.m4
|
||
|
@@ -13,8 +13,8 @@ AC_DEFUN([AC_LIBTIRPC], [
|
||
|
|
||
|
if test "$enable_tirpc" != "no"; then
|
||
|
|
||
|
- dnl look for the library; add to LIBS if found
|
||
|
- AC_CHECK_LIB([tirpc], [clnt_tli_create], ,
|
||
|
+ dnl look for the library
|
||
|
+ AC_CHECK_LIB([tirpc], [clnt_tli_create], [:],
|
||
|
[if test "$enable_tirpc" = "yes"; then
|
||
|
AC_MSG_ERROR([libtirpc not found.])
|
||
|
else
|
||
|
@@ -37,4 +37,15 @@ AC_DEFUN([AC_LIBTIRPC], [
|
||
|
|
||
|
fi
|
||
|
|
||
|
+ dnl now set $LIBTIRPC accordingly
|
||
|
+ if test "$enable_tirpc" != "no"; then
|
||
|
+ AC_DEFINE([HAVE_LIBTIRPC], 1,
|
||
|
+ [Define to 1 if you have and wish to use libtirpc.])
|
||
|
+ LIBTIRPC="-ltirpc"
|
||
|
+ else
|
||
|
+ LIBTIRPC=""
|
||
|
+ fi
|
||
|
+
|
||
|
+ AC_SUBST(LIBTIRPC)
|
||
|
+
|
||
|
])dnl
|
||
|
diff --git a/configure.ac b/configure.ac
|
||
|
index 80fb39d..20c452b 100644
|
||
|
--- a/configure.ac
|
||
|
+++ b/configure.ac
|
||
|
@@ -24,9 +24,8 @@ AC_ARG_WITH(statedir,
|
||
|
statedir=/var/lib/nfs)
|
||
|
AC_SUBST(statedir)
|
||
|
AC_ARG_WITH(statdpath,
|
||
|
- [AC_HELP_STRING([--with-statdpath=/foo @<:@default=/var/lib/nfs@:>@],
|
||
|
- [define statd's state dir as /foo instead of the NFS statedir]
|
||
|
- )],
|
||
|
+ [AC_HELP_STRING([--with-statdpath=/foo],
|
||
|
+ [define the statd state dir as /foo instead of the NFS statedir @<:@default=/var/lib/nfs@:>@])],
|
||
|
statdpath=$withval,
|
||
|
statdpath=$statedir
|
||
|
)
|
||
|
@@ -186,6 +185,12 @@ else
|
||
|
AM_CONDITIONAL(MOUNT_CONFIG, [test "$enable_mount" = "yes"])
|
||
|
fi
|
||
|
|
||
|
+AC_ARG_ENABLE(nfsdcld,
|
||
|
+ [AC_HELP_STRING([--enable-nfsdcld],
|
||
|
+ [Create nfsdcld NFSv4 clientid tracking daemon. @<:@default=no@:>@])],
|
||
|
+ enable_nfsdcld=$enableval,
|
||
|
+ enable_nfsdcld="no")
|
||
|
+
|
||
|
dnl Check for TI-RPC library and headers
|
||
|
AC_LIBTIRPC
|
||
|
|
||
|
@@ -249,6 +254,8 @@ AC_CHECK_FUNC([getservbyname], ,
|
||
|
|
||
|
AC_CHECK_LIB([crypt], [crypt], [LIBCRYPT="-lcrypt"])
|
||
|
|
||
|
+AC_CHECK_LIB([dl], [dlclose], [LIBDL="-ldl"])
|
||
|
+
|
||
|
if test "$enable_nfsv4" = yes; then
|
||
|
dnl check for libevent libraries and headers
|
||
|
AC_LIBEVENT
|
||
|
@@ -259,12 +266,32 @@ if test "$enable_nfsv4" = yes; then
|
||
|
dnl check for the keyutils libraries and headers
|
||
|
AC_KEYUTILS
|
||
|
|
||
|
+ dnl Check for sqlite3
|
||
|
+ AC_SQLITE3_VERS
|
||
|
+
|
||
|
+ if test "$enable_nfsdcld" = "yes"; then
|
||
|
+ AC_CHECK_HEADERS([libgen.h sys/inotify.h], ,
|
||
|
+ AC_MSG_ERROR([Cannot find header needed for nfsdcld]))
|
||
|
+
|
||
|
+ if test "$libsqlite3_cv_is_recent" != "yes" ; then
|
||
|
+ AC_MSG_ERROR([nfsdcld requires sqlite3])
|
||
|
+ fi
|
||
|
+ fi
|
||
|
+
|
||
|
+ AM_CONDITIONAL(CONFIG_NFSDCLD, [test "$enable_nfsdcld" = "yes" ])
|
||
|
+
|
||
|
dnl librpcsecgss already has a dependency on libgssapi,
|
||
|
dnl but we need to make sure we get the right version
|
||
|
if test "$enable_gss" = yes; then
|
||
|
AC_RPCSEC_VERSION
|
||
|
fi
|
||
|
fi
|
||
|
+
|
||
|
+if test "$enable_nfsv41" = yes; then
|
||
|
+ AC_CHECK_LIB([devmapper], [dm_task_create], [LIBDEVMAPPER="-ldevmapper"], AC_MSG_ERROR([libdevmapper needed]))
|
||
|
+ AC_CHECK_HEADER(libdevmapper.h, , AC_MSG_ERROR([Cannot find devmapper header file libdevmapper.h]))
|
||
|
+fi
|
||
|
+
|
||
|
dnl enable nfsidmap when its support by libnfsidmap
|
||
|
AM_CONDITIONAL(CONFIG_NFSIDMAP, [test "$ac_cv_header_keyutils_h$ac_cv_lib_nfsidmap_nfs4_owner_to_uid" = "yesyes"])
|
||
|
|
||
|
@@ -293,6 +320,7 @@ AC_SUBST(LIBSOCKET)
|
||
|
AC_SUBST(LIBCRYPT)
|
||
|
AC_SUBST(LIBBSD)
|
||
|
AC_SUBST(LIBBLKID)
|
||
|
+AC_SUBST(LIBDL)
|
||
|
|
||
|
if test "$enable_libmount" != no; then
|
||
|
AC_CHECK_LIB(mount, mnt_context_do_mount, [LIBMOUNT="-lmount"], AC_MSG_ERROR([libmount needed]))
|
||
|
@@ -308,9 +336,6 @@ if test "$enable_gss" = yes; then
|
||
|
dnl 'gss' also depends on nfsidmap.h - at least for svcgssd_proc.c
|
||
|
AC_LIBNFSIDMAP
|
||
|
|
||
|
- AC_CHECK_HEADERS([spkm3.h], ,
|
||
|
- [AC_MSG_WARN([Could not locate SPKM3 header; will not have SPKM3 support])])
|
||
|
-
|
||
|
dnl Check for Kerberos V5
|
||
|
AC_KERBEROS_V5
|
||
|
|
||
|
@@ -330,7 +355,7 @@ AC_CHECK_HEADERS([arpa/inet.h fcntl.h libintl.h limits.h \
|
||
|
stdlib.h string.h sys/file.h sys/ioctl.h sys/mount.h \
|
||
|
sys/param.h sys/socket.h sys/time.h sys/vfs.h \
|
||
|
syslog.h unistd.h com_err.h et/com_err.h \
|
||
|
- ifaddrs.h])
|
||
|
+ ifaddrs.h nfs-plugin.h])
|
||
|
|
||
|
dnl *************************************************************
|
||
|
dnl Checks for typedefs, structures, and compiler characteristics
|
||
|
@@ -452,6 +477,7 @@ AC_CONFIG_FILES([
|
||
|
tools/nfs-iostat/Makefile
|
||
|
utils/Makefile
|
||
|
utils/blkmapd/Makefile
|
||
|
+ utils/nfsdcld/Makefile
|
||
|
utils/exportfs/Makefile
|
||
|
utils/gssd/Makefile
|
||
|
utils/idmapd/Makefile
|
||
|
@@ -462,6 +488,7 @@ AC_CONFIG_FILES([
|
||
|
utils/nfsidmap/Makefile
|
||
|
utils/showmount/Makefile
|
||
|
utils/statd/Makefile
|
||
|
+ utils/osd_login/Makefile
|
||
|
tests/Makefile
|
||
|
tests/nsm_client/Makefile])
|
||
|
AC_OUTPUT
|
||
|
diff --git a/support/include/cld.h b/support/include/cld.h
|
||
|
new file mode 100644
|
||
|
index 0000000..f14a9ab
|
||
|
--- /dev/null
|
||
|
+++ b/support/include/cld.h
|
||
|
@@ -0,0 +1,56 @@
|
||
|
+/*
|
||
|
+ * 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 1
|
||
|
+
|
||
|
+/* defined by RFC3530 */
|
||
|
+#define NFS4_OPAQUE_LIMIT 1024
|
||
|
+
|
||
|
+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 */
|
||
|
+};
|
||
|
+
|
||
|
+/* 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));
|
||
|
+
|
||
|
+/* 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;
|
||
|
+ } __attribute__((packed)) cm_u;
|
||
|
+} __attribute__((packed));
|
||
|
+
|
||
|
+#endif /* !_NFSD_CLD_H */
|
||
|
diff --git a/support/include/exportfs.h b/support/include/exportfs.h
|
||
|
index 01e87dd..99916e5 100644
|
||
|
--- a/support/include/exportfs.h
|
||
|
+++ b/support/include/exportfs.h
|
||
|
@@ -32,6 +32,10 @@ enum {
|
||
|
FSLOC_STUB
|
||
|
};
|
||
|
|
||
|
+#ifndef EXP_LOCKFILE
|
||
|
+#define EXP_LOCKFILE "/var/lib/nfs/export-lock"
|
||
|
+#endif
|
||
|
+
|
||
|
typedef struct mclient {
|
||
|
struct mclient * m_next;
|
||
|
char * m_hostname;
|
||
|
diff --git a/support/include/nfs/debug.h b/support/include/nfs/debug.h
|
||
|
index d391e91..dbec5ba 100644
|
||
|
--- a/support/include/nfs/debug.h
|
||
|
+++ b/support/include/nfs/debug.h
|
||
|
@@ -76,6 +76,9 @@ enum {
|
||
|
#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_ALL 0xFFFF
|
||
|
|
||
|
#endif /* _NFS_DEBUG_H */
|
||
|
diff --git a/support/include/pseudoflavors.h b/support/include/pseudoflavors.h
|
||
|
index c21087b..deb052b 100644
|
||
|
--- a/support/include/pseudoflavors.h
|
||
|
+++ b/support/include/pseudoflavors.h
|
||
|
@@ -4,9 +4,6 @@
|
||
|
#define RPC_AUTH_GSS_LKEY 390006
|
||
|
#define RPC_AUTH_GSS_LKEYI 390007
|
||
|
#define RPC_AUTH_GSS_LKEYP 390008
|
||
|
-#define RPC_AUTH_GSS_SPKM 390009
|
||
|
-#define RPC_AUTH_GSS_SPKMI 390010
|
||
|
-#define RPC_AUTH_GSS_SPKMP 390011
|
||
|
|
||
|
struct flav_info {
|
||
|
char *flavour;
|
||
|
diff --git a/support/nfs/conffile.c b/support/nfs/conffile.c
|
||
|
index fa0dc6b..5015e94 100644
|
||
|
--- a/support/nfs/conffile.c
|
||
|
+++ b/support/nfs/conffile.c
|
||
|
@@ -49,6 +49,8 @@
|
||
|
#include "conffile.h"
|
||
|
#include "xlog.h"
|
||
|
|
||
|
+#pragma GCC visibility push(hidden)
|
||
|
+
|
||
|
static void conf_load_defaults(void);
|
||
|
static int conf_set(int , char *, char *, char *,
|
||
|
char *, int , int );
|
||
|
@@ -211,7 +213,7 @@ static void
|
||
|
conf_parse_line(int trans, char *line, size_t sz)
|
||
|
{
|
||
|
char *val, *ptr;
|
||
|
- size_t i;
|
||
|
+ size_t i, valsize;
|
||
|
size_t j;
|
||
|
static char *section = 0;
|
||
|
static char *arg = 0;
|
||
|
@@ -256,13 +258,14 @@ conf_parse_line(int trans, char *line, size_t sz)
|
||
|
val++, j++;
|
||
|
if (*val)
|
||
|
i = j;
|
||
|
- section = malloc(i);
|
||
|
+ section = malloc(i+1);
|
||
|
if (!section) {
|
||
|
xlog_warn("conf_parse_line: %d: malloc (%lu) failed", ln,
|
||
|
(unsigned long)i);
|
||
|
return;
|
||
|
}
|
||
|
strncpy(section, line, i);
|
||
|
+ section[i] = '\0';
|
||
|
|
||
|
if (arg)
|
||
|
free(arg);
|
||
|
@@ -297,23 +300,16 @@ conf_parse_line(int trans, char *line, size_t sz)
|
||
|
}
|
||
|
line[strcspn (line, " \t=")] = '\0';
|
||
|
val = line + i + 1 + strspn (line + i + 1, " \t");
|
||
|
+ valsize = 0;
|
||
|
+ while (val[valsize++]);
|
||
|
|
||
|
- /* Skip trailing comments, if any */
|
||
|
- for (j = 0; j < sz - (val - line); j++) {
|
||
|
- if (val[j] == '#' || val[j] == ';') {
|
||
|
+ /* Skip trailing spaces and comments */
|
||
|
+ for (j = 0; j < valsize; j++) {
|
||
|
+ if (val[j] == '#' || val[j] == ';' || isspace(val[j])) {
|
||
|
val[j] = '\0';
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
-
|
||
|
- /* Skip trailing whitespace, if any */
|
||
|
- for (j--; j > 0; j--) {
|
||
|
- if (isspace(val[j]))
|
||
|
- val[j] = '\0';
|
||
|
- else
|
||
|
- break;
|
||
|
- }
|
||
|
-
|
||
|
/* XXX Perhaps should we not ignore errors? */
|
||
|
conf_set(trans, section, arg, line, val, 0, 0);
|
||
|
return;
|
||
|
diff --git a/support/nfs/exports.c b/support/nfs/exports.c
|
||
|
index c96500f..84a2b08 100644
|
||
|
--- a/support/nfs/exports.c
|
||
|
+++ b/support/nfs/exports.c
|
||
|
@@ -39,12 +39,6 @@ struct flav_info flav_map[] = {
|
||
|
{ "krb5", RPC_AUTH_GSS_KRB5 },
|
||
|
{ "krb5i", RPC_AUTH_GSS_KRB5I },
|
||
|
{ "krb5p", RPC_AUTH_GSS_KRB5P },
|
||
|
- { "lipkey", RPC_AUTH_GSS_LKEY },
|
||
|
- { "lipkey-i", RPC_AUTH_GSS_LKEYI },
|
||
|
- { "lipkey-p", RPC_AUTH_GSS_LKEYP },
|
||
|
- { "spkm3", RPC_AUTH_GSS_SPKM },
|
||
|
- { "spkm3i", RPC_AUTH_GSS_SPKMI },
|
||
|
- { "spkm3p", RPC_AUTH_GSS_SPKMP },
|
||
|
{ "unix", AUTH_UNIX },
|
||
|
{ "sys", AUTH_SYS },
|
||
|
{ "null", AUTH_NULL },
|
||
|
diff --git a/support/nfs/nfsctl.c b/support/nfs/nfsctl.c
|
||
|
index 89fa1a4..fec775f 100644
|
||
|
--- a/support/nfs/nfsctl.c
|
||
|
+++ b/support/nfs/nfsctl.c
|
||
|
@@ -11,16 +11,22 @@
|
||
|
#endif
|
||
|
|
||
|
#include <unistd.h>
|
||
|
+#include <errno.h>
|
||
|
#include <asm/unistd.h>
|
||
|
#include "nfslib.h"
|
||
|
|
||
|
/* compatibility hack... */
|
||
|
-#ifndef __NR_nfsctl
|
||
|
+#if !defined(__NR_nfsctl) && defined(__NR_nfsservctl)
|
||
|
#define __NR_nfsctl __NR_nfsservctl
|
||
|
#endif
|
||
|
|
||
|
int
|
||
|
nfsctl (int cmd, struct nfsctl_arg * argp, union nfsctl_res * resp)
|
||
|
{
|
||
|
+#ifdef __NR_nfsctl
|
||
|
return syscall (__NR_nfsctl, cmd, argp, resp);
|
||
|
+#else
|
||
|
+ errno = ENOSYS;
|
||
|
+ return -1;
|
||
|
+#endif
|
||
|
}
|
||
|
diff --git a/tools/rpcdebug/rpcdebug.c b/tools/rpcdebug/rpcdebug.c
|
||
|
index 275a491..444616d 100644
|
||
|
--- a/tools/rpcdebug/rpcdebug.c
|
||
|
+++ b/tools/rpcdebug/rpcdebug.c
|
||
|
@@ -167,6 +167,9 @@ static struct flagmap {
|
||
|
FLAG(NFS, CALLBACK),
|
||
|
FLAG(NFS, CLIENT),
|
||
|
FLAG(NFS, MOUNT),
|
||
|
+ FLAG(NFS, FSCACHE),
|
||
|
+ FLAG(NFS, PNFS),
|
||
|
+ FLAG(NFS, PNFS_LD),
|
||
|
FLAG(NFS, ALL),
|
||
|
|
||
|
/* nfsd */
|
||
|
diff --git a/tools/rpcgen/Makefile.am b/tools/rpcgen/Makefile.am
|
||
|
index 51a2bfa..8a9ec89 100644
|
||
|
--- a/tools/rpcgen/Makefile.am
|
||
|
+++ b/tools/rpcgen/Makefile.am
|
||
|
@@ -12,6 +12,7 @@ rpcgen_SOURCES = rpc_clntout.c rpc_cout.c rpc_hout.c rpc_main.c \
|
||
|
rpcgen_CFLAGS=$(CFLAGS_FOR_BUILD)
|
||
|
rpcgen_CPPLAGS=$(CPPFLAGS_FOR_BUILD)
|
||
|
rpcgen_LDFLAGS=$(LDFLAGS_FOR_BUILD)
|
||
|
+rpcgen_LDADD=$(LIBTIRPC)
|
||
|
|
||
|
MAINTAINERCLEANFILES = Makefile.in
|
||
|
|
||
|
diff --git a/utils/Makefile.am b/utils/Makefile.am
|
||
|
index d074b85..09045dd 100644
|
||
|
--- a/utils/Makefile.am
|
||
|
+++ b/utils/Makefile.am
|
||
|
@@ -21,6 +21,10 @@ if CONFIG_MOUNT
|
||
|
OPTDIRS += mount
|
||
|
endif
|
||
|
|
||
|
+if CONFIG_NFSDCLD
|
||
|
+OPTDIRS += nfsdcld
|
||
|
+endif
|
||
|
+
|
||
|
SUBDIRS = \
|
||
|
exportfs \
|
||
|
mountd \
|
||
|
@@ -28,6 +32,7 @@ SUBDIRS = \
|
||
|
nfsstat \
|
||
|
showmount \
|
||
|
statd \
|
||
|
+ osd_login \
|
||
|
$(OPTDIRS)
|
||
|
|
||
|
MAINTAINERCLEANFILES = Makefile.in
|
||
|
diff --git a/utils/blkmapd/device-process.c b/utils/blkmapd/device-process.c
|
||
|
index 27ff374..652a7a8 100644
|
||
|
--- a/utils/blkmapd/device-process.c
|
||
|
+++ b/utils/blkmapd/device-process.c
|
||
|
@@ -296,7 +296,7 @@ decode_blk_volume(uint32_t **pp, uint32_t *end, struct bl_volume *vols, int voln
|
||
|
off_t stripe_unit = vol->param.bv_stripe_unit;
|
||
|
/* Check limitations imposed by device-mapper */
|
||
|
if ((stripe_unit & (stripe_unit - 1)) != 0
|
||
|
- || stripe_unit < (off_t) (PAGE_SIZE >> 9))
|
||
|
+ || stripe_unit < (off_t) (sysconf(_SC_PAGE_SIZE) >> 9))
|
||
|
return -EIO;
|
||
|
BLK_READBUF(p, end, 4);
|
||
|
READ32(vol->bv_vol_n);
|
||
|
diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c
|
||
|
index 7432a65..a3323d7 100644
|
||
|
--- a/utils/exportfs/exportfs.c
|
||
|
+++ b/utils/exportfs/exportfs.c
|
||
|
@@ -16,6 +16,7 @@
|
||
|
#include <sys/stat.h>
|
||
|
#include <sys/vfs.h>
|
||
|
#include <sys/stat.h>
|
||
|
+#include <sys/file.h>
|
||
|
#include <unistd.h>
|
||
|
#include <stdbool.h>
|
||
|
#include <stdlib.h>
|
||
|
@@ -43,6 +44,41 @@ static void usage(const char *progname);
|
||
|
static void validate_export(nfs_export *exp);
|
||
|
static int matchhostname(const char *hostname1, const char *hostname2);
|
||
|
static void export_d_read(const char *dname);
|
||
|
+static void grab_lockfile(void);
|
||
|
+static void release_lockfile(void);
|
||
|
+
|
||
|
+static const char *lockfile = EXP_LOCKFILE;
|
||
|
+static int _lockfd = -1;
|
||
|
+
|
||
|
+/*
|
||
|
+ * If we aren't careful, changes made by exportfs can be lost
|
||
|
+ * when multiple exports process run at once:
|
||
|
+ *
|
||
|
+ * exportfs process 1 exportfs process 2
|
||
|
+ * ------------------------------------------
|
||
|
+ * reads etab version A reads etab version A
|
||
|
+ * adds new export B adds new export C
|
||
|
+ * writes A+B writes A+C
|
||
|
+ *
|
||
|
+ * The locking in support/export/xtab.c will prevent mountd from
|
||
|
+ * seeing a partially written version of etab, and will prevent
|
||
|
+ * the two writers above from writing simultaneously and
|
||
|
+ * corrupting etab, but to prevent problems like the above we
|
||
|
+ * need these additional lockfile() routines.
|
||
|
+ */
|
||
|
+static void
|
||
|
+grab_lockfile()
|
||
|
+{
|
||
|
+ _lockfd = open(lockfile, O_CREAT|O_RDWR, 0666);
|
||
|
+ if (_lockfd != -1)
|
||
|
+ lockf(_lockfd, F_LOCK, 0);
|
||
|
+}
|
||
|
+static void
|
||
|
+release_lockfile()
|
||
|
+{
|
||
|
+ if (_lockfd != -1)
|
||
|
+ lockf(_lockfd, F_ULOCK, 0);
|
||
|
+}
|
||
|
|
||
|
int
|
||
|
main(int argc, char **argv)
|
||
|
@@ -129,6 +165,13 @@ main(int argc, char **argv)
|
||
|
return 0;
|
||
|
}
|
||
|
}
|
||
|
+
|
||
|
+ /*
|
||
|
+ * Serialize things as best we can
|
||
|
+ */
|
||
|
+ grab_lockfile();
|
||
|
+ atexit(release_lockfile);
|
||
|
+
|
||
|
if (f_export && ! f_ignore) {
|
||
|
export_read(_PATH_EXPORTS);
|
||
|
export_d_read(_PATH_EXPORTS_D);
|
||
|
diff --git a/utils/exportfs/exportfs.man b/utils/exportfs/exportfs.man
|
||
|
index 364f247..8853486 100644
|
||
|
--- a/utils/exportfs/exportfs.man
|
||
|
+++ b/utils/exportfs/exportfs.man
|
||
|
@@ -177,7 +177,7 @@ In this way
|
||
|
.B exportfs
|
||
|
can be used to modify the export options of an already exported directory.
|
||
|
.SS Unexporting Directories
|
||
|
-The third synopsis shows how to unexported a currently exported directory.
|
||
|
+The third synopsis shows how to unexport a currently exported directory.
|
||
|
When using
|
||
|
.BR "exportfs -ua" ,
|
||
|
all entries listed in
|
||
|
diff --git a/utils/exportfs/exports.man b/utils/exportfs/exports.man
|
||
|
index 54adfeb..bc1de73 100644
|
||
|
--- a/utils/exportfs/exports.man
|
||
|
+++ b/utils/exportfs/exports.man
|
||
|
@@ -293,24 +293,6 @@ be explicitly requested with either of the synonymous
|
||
|
.IR auth_nlm ,
|
||
|
or
|
||
|
.IR secure_locks .
|
||
|
-.TP
|
||
|
-.IR no_acl
|
||
|
-On some specially patched kernels, and when exporting filesystems that
|
||
|
-support ACLs, this option tells
|
||
|
-.B nfsd
|
||
|
-not to reveal ACLs to clients, so
|
||
|
-they will see only a subset of actual permissions on the given file
|
||
|
-system. This option is safe for filesystems used by NFSv2 clients and
|
||
|
-old NFSv3 clients that perform access decisions locally. Current
|
||
|
-NFSv3 clients use the ACCESS RPC to perform all access decisions on
|
||
|
-the server. Note that the
|
||
|
-.I no_acl
|
||
|
-option only has effect on kernels specially patched to support it, and
|
||
|
-when exporting filesystems with ACL support. The default is to export
|
||
|
-with ACL support (i.e. by default,
|
||
|
-.I no_acl
|
||
|
-is off).
|
||
|
-
|
||
|
.\".TP
|
||
|
.\".I noaccess
|
||
|
.\"This makes everything below the directory inaccessible for the named
|
||
|
diff --git a/utils/exportfs/nfsd.man b/utils/exportfs/nfsd.man
|
||
|
index 7365a1b..47b73be 100644
|
||
|
--- a/utils/exportfs/nfsd.man
|
||
|
+++ b/utils/exportfs/nfsd.man
|
||
|
@@ -12,7 +12,7 @@ nfsd \- special filesystem for controlling Linux NFS server
|
||
|
.SH DESCRIPTION
|
||
|
The
|
||
|
.B nfsd
|
||
|
-filesytem is a special filesystem which provides access to the Linux
|
||
|
+filesystem is a special filesystem which provides access to the Linux
|
||
|
NFS server. The filesystem consists of a single directory which
|
||
|
contains a number of files. These files are actually gateways into
|
||
|
the NFS server. Writing to them can affect the server. Reading from
|
||
|
@@ -86,7 +86,7 @@ should be followed by a newline, with white-space separating the
|
||
|
fields, and octal quoting of special characters.
|
||
|
|
||
|
On writing this, the program will be able to read back a filehandle
|
||
|
-for that path as exported to the given client. The filehandles length
|
||
|
+for that path as exported to the given client. The filehandle's length
|
||
|
will be at most the number of bytes given.
|
||
|
|
||
|
The filehandle will be represented in hex with a leading '\ex'.
|
||
|
@@ -165,7 +165,7 @@ file. The user-space program might then write
|
||
|
.ti +5
|
||
|
nfsd 127.0.0.1 1057206953 localhost
|
||
|
.br
|
||
|
-to indicate that 127.0.0.1 should map to localhost, atleast for now.
|
||
|
+to indicate that 127.0.0.1 should map to localhost, at least for now.
|
||
|
|
||
|
If the program uses select(2) or poll(2) to discover if it can read
|
||
|
from the
|
||
|
diff --git a/utils/gssd/Makefile.am b/utils/gssd/Makefile.am
|
||
|
index d7888ad..2365704 100644
|
||
|
--- a/utils/gssd/Makefile.am
|
||
|
+++ b/utils/gssd/Makefile.am
|
||
|
@@ -17,7 +17,6 @@ COMMON_SRCS = \
|
||
|
context_mit.c \
|
||
|
context_heimdal.c \
|
||
|
context_lucid.c \
|
||
|
- context_spkm3.c \
|
||
|
gss_util.c \
|
||
|
gss_oids.c \
|
||
|
err_util.c \
|
||
|
@@ -40,7 +39,7 @@ gssd_SOURCES = \
|
||
|
|
||
|
gssd_LDADD = ../../support/nfs/libnfs.a \
|
||
|
$(RPCSECGSS_LIBS) $(GSSGLUE_LIBS) $(KRBLIBS)
|
||
|
-gssd_LDFLAGS = $(KRBLDFLAGS)
|
||
|
+gssd_LDFLAGS = $(KRBLDFLAGS) $(LIBTIRPC)
|
||
|
|
||
|
gssd_CFLAGS = $(AM_CFLAGS) $(CFLAGS) \
|
||
|
$(RPCSECGSS_CFLAGS) $(GSSGLUE_CFLAGS) $(KRBCFLAGS)
|
||
|
@@ -58,8 +57,8 @@ svcgssd_SOURCES = \
|
||
|
|
||
|
svcgssd_LDADD = \
|
||
|
../../support/nfs/libnfs.a \
|
||
|
- $(RPCSECGSS_LIBS) $(GSSGLUE_LIBS) -lnfsidmap \
|
||
|
- $(KRBLIBS)
|
||
|
+ $(RPCSECGSS_LIBS) $(GSSGLUE_LIBS) $(LIBNFSIDMAP) \
|
||
|
+ $(KRBLIBS) $(LIBTIRPC)
|
||
|
|
||
|
svcgssd_LDFLAGS = $(KRBLDFLAGS)
|
||
|
|
||
|
diff --git a/utils/gssd/context.c b/utils/gssd/context.c
|
||
|
index 1e50bbf..fee7da2 100644
|
||
|
--- a/utils/gssd/context.c
|
||
|
+++ b/utils/gssd/context.c
|
||
|
@@ -51,10 +51,6 @@ serialize_context_for_kernel(gss_ctx_id_t ctx,
|
||
|
{
|
||
|
if (g_OID_equal(&krb5oid, mech))
|
||
|
return serialize_krb5_ctx(ctx, buf, endtime);
|
||
|
-#ifdef HAVE_SPKM3_H
|
||
|
- else if (g_OID_equal(&spkm3oid, mech))
|
||
|
- return serialize_spkm3_ctx(ctx, buf, endtime);
|
||
|
-#endif
|
||
|
else {
|
||
|
printerr(0, "ERROR: attempting to serialize context with "
|
||
|
"unknown/unsupported mechanism oid\n");
|
||
|
diff --git a/utils/gssd/context.h b/utils/gssd/context.h
|
||
|
index c9cb0bd..0e437f4 100644
|
||
|
--- a/utils/gssd/context.h
|
||
|
+++ b/utils/gssd/context.h
|
||
|
@@ -43,8 +43,6 @@
|
||
|
|
||
|
int serialize_context_for_kernel(gss_ctx_id_t ctx, gss_buffer_desc *buf,
|
||
|
gss_OID mech, int32_t *endtime);
|
||
|
-int serialize_spkm3_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf,
|
||
|
- int32_t *endtime);
|
||
|
int serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf,
|
||
|
int32_t *endtime);
|
||
|
|
||
|
diff --git a/utils/gssd/context_lucid.c b/utils/gssd/context_lucid.c
|
||
|
index 3e695ab..64146d7 100644
|
||
|
--- a/utils/gssd/context_lucid.c
|
||
|
+++ b/utils/gssd/context_lucid.c
|
||
|
@@ -80,6 +80,7 @@ prepare_krb5_rfc1964_buffer(gss_krb5_lucid_context_v1_t *lctx,
|
||
|
uint32_t i;
|
||
|
char *skd, *dkd;
|
||
|
gss_buffer_desc fakeoid;
|
||
|
+ int err;
|
||
|
|
||
|
/*
|
||
|
* The new Kerberos interface to get the gss context
|
||
|
@@ -138,11 +139,10 @@ prepare_krb5_rfc1964_buffer(gss_krb5_lucid_context_v1_t *lctx,
|
||
|
dkd = (char *) enc_key.data;
|
||
|
for (i = 0; i < enc_key.length; i++)
|
||
|
dkd[i] = skd[i] ^ 0xf0;
|
||
|
- if (write_lucid_keyblock(&p, end, &enc_key)) {
|
||
|
- free(enc_key.data);
|
||
|
- goto out_err;
|
||
|
- }
|
||
|
+ err = write_lucid_keyblock(&p, end, &enc_key);
|
||
|
free(enc_key.data);
|
||
|
+ if (err)
|
||
|
+ goto out_err;
|
||
|
|
||
|
if (write_lucid_keyblock(&p, end, &lctx->rfc1964_kd.ctx_key))
|
||
|
goto out_err;
|
||
|
@@ -153,7 +153,6 @@ out_err:
|
||
|
printerr(0, "ERROR: failed serializing krb5 context for kernel\n");
|
||
|
if (buf->value) free(buf->value);
|
||
|
buf->length = 0;
|
||
|
- if (enc_key.data) free(enc_key.data);
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
diff --git a/utils/gssd/context_spkm3.c b/utils/gssd/context_spkm3.c
|
||
|
deleted file mode 100644
|
||
|
index b927475..0000000
|
||
|
--- a/utils/gssd/context_spkm3.c
|
||
|
+++ /dev/null
|
||
|
@@ -1,184 +0,0 @@
|
||
|
-/*
|
||
|
- Copyright (c) 2004 The Regents of the University of Michigan.
|
||
|
- 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.
|
||
|
-*/
|
||
|
-
|
||
|
-#ifdef HAVE_CONFIG_H
|
||
|
-#include <config.h>
|
||
|
-#endif /* HAVE_CONFIG_H */
|
||
|
-
|
||
|
-#include <stdio.h>
|
||
|
-#include <syslog.h>
|
||
|
-#include <string.h>
|
||
|
-#include <gssapi/gssapi.h>
|
||
|
-#include <rpc/rpc.h>
|
||
|
-#include <rpc/auth_gss.h>
|
||
|
-#include "gss_util.h"
|
||
|
-#include "gss_oids.h"
|
||
|
-#include "err_util.h"
|
||
|
-#include "context.h"
|
||
|
-
|
||
|
-#ifdef HAVE_SPKM3_H
|
||
|
-
|
||
|
-#include <spkm3.h>
|
||
|
-
|
||
|
-/*
|
||
|
- * Function: prepare_spkm3_ctx_buffer()
|
||
|
- *
|
||
|
- * Prepare spkm3 lucid context for the kernel
|
||
|
- *
|
||
|
- * buf->length should be:
|
||
|
- *
|
||
|
- * version 4
|
||
|
- * ctx_id 4 + 12
|
||
|
- * qop 4
|
||
|
- * mech_used 4 + 7
|
||
|
- * ret_fl 4
|
||
|
- * req_fl 4
|
||
|
- * share 4 + key_len
|
||
|
- * conf_alg 4 + oid_len
|
||
|
- * d_conf_key 4 + key_len
|
||
|
- * intg_alg 4 + oid_len
|
||
|
- * d_intg_key 4 + key_len
|
||
|
- * kyestb 4 + oid_len
|
||
|
- * owl alg 4 + oid_len
|
||
|
-*/
|
||
|
-static int
|
||
|
-prepare_spkm3_ctx_buffer(gss_spkm3_lucid_ctx_t *lctx, gss_buffer_desc *buf)
|
||
|
-{
|
||
|
- char *p, *end;
|
||
|
- unsigned int buf_size = 0;
|
||
|
-
|
||
|
- buf_size = sizeof(lctx->version) +
|
||
|
- lctx->ctx_id.length + sizeof(lctx->ctx_id.length) +
|
||
|
- sizeof(lctx->endtime) +
|
||
|
- sizeof(lctx->mech_used.length) + lctx->mech_used.length +
|
||
|
- sizeof(lctx->ret_flags) +
|
||
|
- sizeof(lctx->conf_alg.length) + lctx->conf_alg.length +
|
||
|
- sizeof(lctx->derived_conf_key.length) +
|
||
|
- lctx->derived_conf_key.length +
|
||
|
- sizeof(lctx->intg_alg.length) + lctx->intg_alg.length +
|
||
|
- sizeof(lctx->derived_integ_key.length) +
|
||
|
- lctx->derived_integ_key.length;
|
||
|
-
|
||
|
- if (!(buf->value = calloc(1, buf_size)))
|
||
|
- goto out_err;
|
||
|
- p = buf->value;
|
||
|
- end = buf->value + buf_size;
|
||
|
-
|
||
|
- if (WRITE_BYTES(&p, end, lctx->version))
|
||
|
- goto out_err;
|
||
|
- printerr(2, "DEBUG: exporting version = %d\n", lctx->version);
|
||
|
-
|
||
|
- if (write_buffer(&p, end, &lctx->ctx_id))
|
||
|
- goto out_err;
|
||
|
- printerr(2, "DEBUG: exporting ctx_id(%d)\n", lctx->ctx_id.length);
|
||
|
-
|
||
|
- if (WRITE_BYTES(&p, end, lctx->endtime))
|
||
|
- goto out_err;
|
||
|
- printerr(2, "DEBUG: exporting endtime = %d\n", lctx->endtime);
|
||
|
-
|
||
|
- if (write_buffer(&p, end, &lctx->mech_used))
|
||
|
- goto out_err;
|
||
|
- printerr(2, "DEBUG: exporting mech oid (%d)\n", lctx->mech_used.length);
|
||
|
-
|
||
|
- if (WRITE_BYTES(&p, end, lctx->ret_flags))
|
||
|
- goto out_err;
|
||
|
- printerr(2, "DEBUG: exporting ret_flags = %d\n", lctx->ret_flags);
|
||
|
-
|
||
|
- if (write_buffer(&p, end, &lctx->conf_alg))
|
||
|
- goto out_err;
|
||
|
- printerr(2, "DEBUG: exporting conf_alg oid (%d)\n", lctx->conf_alg.length);
|
||
|
-
|
||
|
- if (write_buffer(&p, end, &lctx->derived_conf_key))
|
||
|
- goto out_err;
|
||
|
- printerr(2, "DEBUG: exporting conf key (%d)\n", lctx->derived_conf_key.length);
|
||
|
-
|
||
|
- if (write_buffer(&p, end, &lctx->intg_alg))
|
||
|
- goto out_err;
|
||
|
- printerr(2, "DEBUG: exporting intg_alg oid (%d)\n", lctx->intg_alg.length);
|
||
|
-
|
||
|
- if (write_buffer(&p, end, &lctx->derived_integ_key))
|
||
|
- goto out_err;
|
||
|
- printerr(2, "DEBUG: exporting intg key (%d)\n", lctx->derived_integ_key.length);
|
||
|
-
|
||
|
- buf->length = p - (char *)buf->value;
|
||
|
- return 0;
|
||
|
-out_err:
|
||
|
- printerr(0, "ERROR: failed serializing spkm3 context for kernel\n");
|
||
|
- if (buf->value) free(buf->value);
|
||
|
- buf->length = 0;
|
||
|
-
|
||
|
- return -1;
|
||
|
-}
|
||
|
-
|
||
|
-/* ANDROS: need to determine which fields of the spkm3_gss_ctx_id_desc_t
|
||
|
- * are needed in the kernel for get_mic, validate, wrap, unwrap, and destroy
|
||
|
- * and only export those fields to the kernel.
|
||
|
- */
|
||
|
-int
|
||
|
-serialize_spkm3_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime)
|
||
|
-{
|
||
|
- OM_uint32 vers, ret, maj_stat, min_stat;
|
||
|
- void *ret_ctx = 0;
|
||
|
- gss_spkm3_lucid_ctx_t *lctx;
|
||
|
-
|
||
|
- printerr(1, "serialize_spkm3_ctx called\n");
|
||
|
-
|
||
|
- printerr(2, "DEBUG: serialize_spkm3_ctx: lucid version!\n");
|
||
|
- maj_stat = gss_export_lucid_sec_context(&min_stat, &ctx, 1, &ret_ctx);
|
||
|
- if (maj_stat != GSS_S_COMPLETE)
|
||
|
- goto out_err;
|
||
|
-
|
||
|
- lctx = (gss_spkm3_lucid_ctx_t *)ret_ctx;
|
||
|
-
|
||
|
- vers = lctx->version;
|
||
|
- if (vers != 1) {
|
||
|
- printerr(0, "ERROR: unsupported spkm3 context version %d\n",
|
||
|
- vers);
|
||
|
- goto out_err;
|
||
|
- }
|
||
|
- ret = prepare_spkm3_ctx_buffer(lctx, buf);
|
||
|
-
|
||
|
- if (endtime)
|
||
|
- *endtime = lctx->endtime;
|
||
|
-
|
||
|
- maj_stat = gss_free_lucid_sec_context(&min_stat, ctx, ret_ctx);
|
||
|
-
|
||
|
- if (maj_stat != GSS_S_COMPLETE)
|
||
|
- printerr(0, "WARN: failed to free lucid sec context\n");
|
||
|
- if (ret)
|
||
|
- goto out_err;
|
||
|
- printerr(2, "DEBUG: serialize_spkm3_ctx: success\n");
|
||
|
- return 0;
|
||
|
-
|
||
|
-out_err:
|
||
|
- printerr(2, "DEBUG: serialize_spkm3_ctx: failed\n");
|
||
|
- return -1;
|
||
|
-}
|
||
|
-#endif /* HAVE_SPKM3_H */
|
||
|
diff --git a/utils/gssd/gss_oids.c b/utils/gssd/gss_oids.c
|
||
|
index a59c4a6..4362de2 100644
|
||
|
--- a/utils/gssd/gss_oids.c
|
||
|
+++ b/utils/gssd/gss_oids.c
|
||
|
@@ -38,6 +38,3 @@
|
||
|
/* from kerberos source, gssapi_krb5.c */
|
||
|
gss_OID_desc krb5oid =
|
||
|
{9, "\052\206\110\206\367\022\001\002\002"};
|
||
|
-
|
||
|
-gss_OID_desc spkm3oid =
|
||
|
- {7, "\053\006\001\005\005\001\003"};
|
||
|
diff --git a/utils/gssd/gss_oids.h b/utils/gssd/gss_oids.h
|
||
|
index 8b0a352..fde8532 100644
|
||
|
--- a/utils/gssd/gss_oids.h
|
||
|
+++ b/utils/gssd/gss_oids.h
|
||
|
@@ -34,7 +34,6 @@
|
||
|
#include <sys/types.h>
|
||
|
|
||
|
extern gss_OID_desc krb5oid;
|
||
|
-extern gss_OID_desc spkm3oid;
|
||
|
|
||
|
#ifndef g_OID_equal
|
||
|
#define g_OID_equal(o1,o2) \
|
||
|
diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c
|
||
|
index ccadb07..7825255 100644
|
||
|
--- a/utils/gssd/gssd.c
|
||
|
+++ b/utils/gssd/gssd.c
|
||
|
@@ -57,7 +57,7 @@
|
||
|
|
||
|
char pipefs_dir[PATH_MAX] = GSSD_PIPEFS_DIR;
|
||
|
char keytabfile[PATH_MAX] = GSSD_DEFAULT_KEYTAB_FILE;
|
||
|
-char ccachedir[PATH_MAX] = GSSD_DEFAULT_CRED_DIR;
|
||
|
+char ccachedir[PATH_MAX] = GSSD_DEFAULT_CRED_DIR ":" GSSD_USER_CRED_DIR;
|
||
|
char *ccachesearch[GSSD_MAX_CCACHE_SEARCH + 1];
|
||
|
int use_memcache = 0;
|
||
|
int root_uses_machine_creds = 1;
|
||
|
@@ -85,7 +85,7 @@ sig_hup(int signal)
|
||
|
static void
|
||
|
usage(char *progname)
|
||
|
{
|
||
|
- fprintf(stderr, "usage: %s [-f] [-M] [-n] [-v] [-r] [-p pipefsdir] [-k keytab] [-d ccachedir] [-t timeout] [-R preferred realm]\n",
|
||
|
+ fprintf(stderr, "usage: %s [-f] [-l] [-M] [-n] [-v] [-r] [-p pipefsdir] [-k keytab] [-d ccachedir] [-t timeout] [-R preferred realm]\n",
|
||
|
progname);
|
||
|
exit(1);
|
||
|
}
|
||
|
@@ -102,7 +102,7 @@ main(int argc, char *argv[])
|
||
|
char *progname;
|
||
|
|
||
|
memset(ccachesearch, 0, sizeof(ccachesearch));
|
||
|
- while ((opt = getopt(argc, argv, "fvrmnMp:k:d:t:R:")) != -1) {
|
||
|
+ while ((opt = getopt(argc, argv, "fvrlmnMp:k:d:t:R")) != -1) {
|
||
|
switch (opt) {
|
||
|
case 'f':
|
||
|
fg = 1;
|
||
|
@@ -143,6 +143,13 @@ main(int argc, char *argv[])
|
||
|
case 'R':
|
||
|
preferred_realm = strdup(optarg);
|
||
|
break;
|
||
|
+ case 'l':
|
||
|
+#ifdef HAVE_SET_ALLOWABLE_ENCTYPES
|
||
|
+ limit_to_legacy_enctypes = 1;
|
||
|
+#else
|
||
|
+ errx(1, "Setting encryption type not support by Kerberos libraries.");
|
||
|
+#endif
|
||
|
+ break;
|
||
|
default:
|
||
|
usage(argv[0]);
|
||
|
break;
|
||
|
diff --git a/utils/gssd/gssd.h b/utils/gssd/gssd.h
|
||
|
index b1b5793..28a8206 100644
|
||
|
--- a/utils/gssd/gssd.h
|
||
|
+++ b/utils/gssd/gssd.h
|
||
|
@@ -45,6 +45,7 @@
|
||
|
#define DNOTIFY_SIGNAL (SIGRTMIN + 3)
|
||
|
|
||
|
#define GSSD_DEFAULT_CRED_DIR "/tmp"
|
||
|
+#define GSSD_USER_CRED_DIR "/run/user"
|
||
|
#define GSSD_DEFAULT_CRED_PREFIX "krb5cc_"
|
||
|
#define GSSD_DEFAULT_MACHINE_CRED_SUFFIX "machine"
|
||
|
#define GSSD_DEFAULT_KEYTAB_FILE "/etc/krb5.keytab"
|
||
|
@@ -55,7 +56,7 @@
|
||
|
/*
|
||
|
* The gss mechanisms that we can handle
|
||
|
*/
|
||
|
-enum {AUTHTYPE_KRB5, AUTHTYPE_SPKM3, AUTHTYPE_LIPKEY};
|
||
|
+enum {AUTHTYPE_KRB5, AUTHTYPE_LIPKEY};
|
||
|
|
||
|
|
||
|
|
||
|
@@ -80,8 +81,6 @@ struct clnt_info {
|
||
|
char *protocol;
|
||
|
int krb5_fd;
|
||
|
int krb5_poll_index;
|
||
|
- int spkm3_fd;
|
||
|
- int spkm3_poll_index;
|
||
|
int gssd_fd;
|
||
|
int gssd_poll_index;
|
||
|
struct sockaddr_storage addr;
|
||
|
@@ -98,7 +97,6 @@ struct topdirs_info {
|
||
|
void init_client_list(void);
|
||
|
int update_client_list(void);
|
||
|
void handle_krb5_upcall(struct clnt_info *clp);
|
||
|
-void handle_spkm3_upcall(struct clnt_info *clp);
|
||
|
void handle_gssd_upcall(struct clnt_info *clp);
|
||
|
void gssd_run(void);
|
||
|
|
||
|
diff --git a/utils/gssd/gssd.man b/utils/gssd/gssd.man
|
||
|
index 073379d..d8138fa 100644
|
||
|
--- a/utils/gssd/gssd.man
|
||
|
+++ b/utils/gssd/gssd.man
|
||
|
@@ -6,7 +6,7 @@
|
||
|
.SH NAME
|
||
|
rpc.gssd \- rpcsec_gss daemon
|
||
|
.SH SYNOPSIS
|
||
|
-.B "rpc.gssd [-f] [-n] [-k keytab] [-p pipefsdir] [-v] [-r] [-d ccachedir]"
|
||
|
+.B "rpc.gssd [-f] [-n] [-k keytab] [-l] [-p pipefsdir] [-v] [-r] [-d ccachedir]"
|
||
|
.SH DESCRIPTION
|
||
|
The rpcsec_gss protocol gives a means of using the gss-api generic security
|
||
|
api to provide security for protocols using rpc (in particular, nfs). Before
|
||
|
@@ -70,6 +70,30 @@ for "machine credentials" is now:
|
||
|
If this search order does not use the correct key then provide a
|
||
|
keytab file that contains only correct keys.
|
||
|
.TP
|
||
|
+.B -l
|
||
|
+Tells
|
||
|
+.B rpc.gssd
|
||
|
+to limit session keys to Single DES even if the kernel supports stronger
|
||
|
+encryption types. Service ticket encryption is still governed by what
|
||
|
+the KDC believes the target server supports. This way the client can
|
||
|
+access a server that has strong keys in its keytab for ticket decryption
|
||
|
+but whose kernel only supports Single DES.
|
||
|
+.IP
|
||
|
+The alternative is to put only Single DES keys in the server's keytab
|
||
|
+and limit encryption types for its principal to Single DES on the KDC
|
||
|
+which will cause service tickets for this server to be encrypted using
|
||
|
+only Single DES and (as a side-effect) contain only Single DES session
|
||
|
+keys.
|
||
|
+.IP
|
||
|
+This legacy behaviour is only required for older servers
|
||
|
+(pre nfs-utils-1.2.4). If the server has a recent kernel, Kerberos
|
||
|
+implementation and nfs-utils it will work just fine with stronger
|
||
|
+encryption.
|
||
|
+.IP
|
||
|
+.B Note:
|
||
|
+This option is only available with Kerberos libraries that
|
||
|
+support setable encryption types.
|
||
|
+.TP
|
||
|
.B -p path
|
||
|
Tells
|
||
|
.B rpc.gssd
|
||
|
diff --git a/utils/gssd/gssd_main_loop.c b/utils/gssd/gssd_main_loop.c
|
||
|
index b06c223..cec09ea 100644
|
||
|
--- a/utils/gssd/gssd_main_loop.c
|
||
|
+++ b/utils/gssd/gssd_main_loop.c
|
||
|
@@ -98,17 +98,6 @@ scan_poll_results(int ret)
|
||
|
if (!ret)
|
||
|
break;
|
||
|
}
|
||
|
- i = clp->spkm3_poll_index;
|
||
|
- if (i >= 0 && pollarray[i].revents) {
|
||
|
- if (pollarray[i].revents & POLLHUP)
|
||
|
- dir_changed = 1;
|
||
|
- if (pollarray[i].revents & POLLIN)
|
||
|
- handle_spkm3_upcall(clp);
|
||
|
- pollarray[clp->spkm3_poll_index].revents = 0;
|
||
|
- ret--;
|
||
|
- if (!ret)
|
||
|
- break;
|
||
|
- }
|
||
|
}
|
||
|
};
|
||
|
|
||
|
diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
|
||
|
index 41328c9..aa39435 100644
|
||
|
--- a/utils/gssd/gssd_proc.c
|
||
|
+++ b/utils/gssd/gssd_proc.c
|
||
|
@@ -299,15 +299,11 @@ destroy_client(struct clnt_info *clp)
|
||
|
if (clp->krb5_poll_index != -1)
|
||
|
memset(&pollarray[clp->krb5_poll_index], 0,
|
||
|
sizeof(struct pollfd));
|
||
|
- if (clp->spkm3_poll_index != -1)
|
||
|
- memset(&pollarray[clp->spkm3_poll_index], 0,
|
||
|
- sizeof(struct pollfd));
|
||
|
if (clp->gssd_poll_index != -1)
|
||
|
memset(&pollarray[clp->gssd_poll_index], 0,
|
||
|
sizeof(struct pollfd));
|
||
|
if (clp->dir_fd != -1) close(clp->dir_fd);
|
||
|
if (clp->krb5_fd != -1) close(clp->krb5_fd);
|
||
|
- if (clp->spkm3_fd != -1) close(clp->spkm3_fd);
|
||
|
if (clp->gssd_fd != -1) close(clp->gssd_fd);
|
||
|
free(clp->dirname);
|
||
|
free(clp->servicename);
|
||
|
@@ -327,10 +323,8 @@ insert_new_clnt(void)
|
||
|
goto out;
|
||
|
}
|
||
|
clp->krb5_poll_index = -1;
|
||
|
- clp->spkm3_poll_index = -1;
|
||
|
clp->gssd_poll_index = -1;
|
||
|
clp->krb5_fd = -1;
|
||
|
- clp->spkm3_fd = -1;
|
||
|
clp->gssd_fd = -1;
|
||
|
clp->dir_fd = -1;
|
||
|
|
||
|
@@ -355,30 +349,22 @@ process_clnt_dir_files(struct clnt_info * clp)
|
||
|
snprintf(name, sizeof(name), "%s/krb5", clp->dirname);
|
||
|
clp->krb5_fd = open(name, O_RDWR);
|
||
|
}
|
||
|
- if (clp->spkm3_fd == -1) {
|
||
|
- snprintf(name, sizeof(name), "%s/spkm3", clp->dirname);
|
||
|
- clp->spkm3_fd = open(name, O_RDWR);
|
||
|
- }
|
||
|
|
||
|
/* If we opened a gss-specific pipe, let's try opening
|
||
|
* the new upcall pipe again. If we succeed, close
|
||
|
* gss-specific pipe(s).
|
||
|
*/
|
||
|
- if (clp->krb5_fd != -1 || clp->spkm3_fd != -1) {
|
||
|
+ if (clp->krb5_fd != -1) {
|
||
|
clp->gssd_fd = open(gname, O_RDWR);
|
||
|
if (clp->gssd_fd != -1) {
|
||
|
if (clp->krb5_fd != -1)
|
||
|
close(clp->krb5_fd);
|
||
|
clp->krb5_fd = -1;
|
||
|
- if (clp->spkm3_fd != -1)
|
||
|
- close(clp->spkm3_fd);
|
||
|
- clp->spkm3_fd = -1;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
- if ((clp->krb5_fd == -1) && (clp->spkm3_fd == -1) &&
|
||
|
- (clp->gssd_fd == -1))
|
||
|
+ if ((clp->krb5_fd == -1) && (clp->gssd_fd == -1))
|
||
|
return -1;
|
||
|
snprintf(info_file_name, sizeof(info_file_name), "%s/info",
|
||
|
clp->dirname);
|
||
|
@@ -431,15 +417,6 @@ insert_clnt_poll(struct clnt_info *clp)
|
||
|
pollarray[clp->krb5_poll_index].events |= POLLIN;
|
||
|
}
|
||
|
|
||
|
- if ((clp->spkm3_fd != -1) && (clp->spkm3_poll_index == -1)) {
|
||
|
- if (get_poll_index(&clp->spkm3_poll_index)) {
|
||
|
- printerr(0, "ERROR: Too many spkm3 clients\n");
|
||
|
- return -1;
|
||
|
- }
|
||
|
- pollarray[clp->spkm3_poll_index].fd = clp->spkm3_fd;
|
||
|
- pollarray[clp->spkm3_poll_index].events |= POLLIN;
|
||
|
- }
|
||
|
-
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
@@ -839,13 +816,6 @@ int create_auth_rpc_client(struct clnt_info *clp,
|
||
|
sec.mech = (gss_OID)&krb5oid;
|
||
|
sec.req_flags = GSS_C_MUTUAL_FLAG;
|
||
|
}
|
||
|
- else if (authtype == AUTHTYPE_SPKM3) {
|
||
|
- sec.mech = (gss_OID)&spkm3oid;
|
||
|
- /* XXX sec.req_flags = GSS_C_ANON_FLAG;
|
||
|
- * Need a way to switch....
|
||
|
- */
|
||
|
- sec.req_flags = GSS_C_MUTUAL_FLAG;
|
||
|
- }
|
||
|
else {
|
||
|
printerr(0, "ERROR: Invalid authentication type (%d) "
|
||
|
"in create_auth_rpc_client\n", authtype);
|
||
|
@@ -919,9 +889,8 @@ int create_auth_rpc_client(struct clnt_info *clp,
|
||
|
auth = authgss_create_default(rpc_clnt, clp->servicename, &sec);
|
||
|
if (!auth) {
|
||
|
/* Our caller should print appropriate message */
|
||
|
- printerr(2, "WARNING: Failed to create %s context for "
|
||
|
+ printerr(2, "WARNING: Failed to create krb5 context for "
|
||
|
"user with uid %d for server %s\n",
|
||
|
- (authtype == AUTHTYPE_KRB5 ? "krb5":"spkm3"),
|
||
|
uid, clp->servername);
|
||
|
goto out_fail;
|
||
|
}
|
||
|
@@ -949,6 +918,23 @@ int create_auth_rpc_client(struct clnt_info *clp,
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
+static char *
|
||
|
+user_cachedir(char *dirname, uid_t uid)
|
||
|
+{
|
||
|
+ struct passwd *pw;
|
||
|
+ char *ptr;
|
||
|
+
|
||
|
+ if ((pw = getpwuid(uid)) == NULL) {
|
||
|
+ printerr(0, "user_cachedir: Failed to find '%d' uid"
|
||
|
+ " for cache directory\n");
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+ ptr = malloc(strlen(dirname)+strlen(pw->pw_name)+2);
|
||
|
+ if (ptr)
|
||
|
+ sprintf(ptr, "%s/%s", dirname, pw->pw_name);
|
||
|
+
|
||
|
+ return ptr;
|
||
|
+}
|
||
|
/*
|
||
|
* this code uses the userland rpcsec gss library to create a krb5
|
||
|
* context on behalf of the kernel
|
||
|
@@ -963,7 +949,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
|
||
|
gss_buffer_desc token;
|
||
|
char **credlist = NULL;
|
||
|
char **ccname;
|
||
|
- char **dirname;
|
||
|
+ char **dirname, *dir, *userdir;
|
||
|
int create_resp = -1;
|
||
|
int err, downcall_err = -EACCES;
|
||
|
|
||
|
@@ -1006,7 +992,22 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
|
||
|
service == NULL)) {
|
||
|
/* Tell krb5 gss which credentials cache to use */
|
||
|
for (dirname = ccachesearch; *dirname != NULL; dirname++) {
|
||
|
- err = gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname);
|
||
|
+ /* See if the user name is needed */
|
||
|
+ if (strncmp(*dirname, GSSD_USER_CRED_DIR,
|
||
|
+ strlen(GSSD_USER_CRED_DIR)) == 0) {
|
||
|
+ userdir = user_cachedir(*dirname, uid);
|
||
|
+ if (userdir == NULL)
|
||
|
+ continue;
|
||
|
+ dir = userdir;
|
||
|
+ } else
|
||
|
+ dir = *dirname;
|
||
|
+
|
||
|
+ err = gssd_setup_krb5_user_gss_ccache(uid, clp->servername, dir);
|
||
|
+
|
||
|
+ if (userdir) {
|
||
|
+ free(userdir);
|
||
|
+ userdir = NULL;
|
||
|
+ }
|
||
|
if (err == -EKEYEXPIRED)
|
||
|
downcall_err = -EKEYEXPIRED;
|
||
|
else if (!err)
|
||
|
@@ -1103,59 +1104,6 @@ out_return_error:
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
-/*
|
||
|
- * this code uses the userland rpcsec gss library to create an spkm3
|
||
|
- * context on behalf of the kernel
|
||
|
- */
|
||
|
-static void
|
||
|
-process_spkm3_upcall(struct clnt_info *clp, uid_t uid, int fd)
|
||
|
-{
|
||
|
- CLIENT *rpc_clnt = NULL;
|
||
|
- AUTH *auth = NULL;
|
||
|
- struct authgss_private_data pd;
|
||
|
- gss_buffer_desc token;
|
||
|
-
|
||
|
- printerr(2, "handling spkm3 upcall (%s)\n", clp->dirname);
|
||
|
-
|
||
|
- token.length = 0;
|
||
|
- token.value = NULL;
|
||
|
-
|
||
|
- if (create_auth_rpc_client(clp, &rpc_clnt, &auth, uid, AUTHTYPE_SPKM3)) {
|
||
|
- printerr(0, "WARNING: Failed to create spkm3 context for "
|
||
|
- "user with uid %d\n", uid);
|
||
|
- goto out_return_error;
|
||
|
- }
|
||
|
-
|
||
|
- if (!authgss_get_private_data(auth, &pd)) {
|
||
|
- printerr(0, "WARNING: Failed to obtain authentication "
|
||
|
- "data for user with uid %d for server %s\n",
|
||
|
- uid, clp->servername);
|
||
|
- goto out_return_error;
|
||
|
- }
|
||
|
-
|
||
|
- if (serialize_context_for_kernel(pd.pd_ctx, &token, &spkm3oid, NULL)) {
|
||
|
- printerr(0, "WARNING: Failed to serialize spkm3 context for "
|
||
|
- "user with uid %d for server\n",
|
||
|
- uid, clp->servername);
|
||
|
- goto out_return_error;
|
||
|
- }
|
||
|
-
|
||
|
- do_downcall(fd, uid, &pd, &token);
|
||
|
-
|
||
|
-out:
|
||
|
- if (token.value)
|
||
|
- free(token.value);
|
||
|
- if (auth)
|
||
|
- AUTH_DESTROY(auth);
|
||
|
- if (rpc_clnt)
|
||
|
- clnt_destroy(rpc_clnt);
|
||
|
- return;
|
||
|
-
|
||
|
-out_return_error:
|
||
|
- do_error_downcall(fd, uid, -1);
|
||
|
- goto out;
|
||
|
-}
|
||
|
-
|
||
|
void
|
||
|
handle_krb5_upcall(struct clnt_info *clp)
|
||
|
{
|
||
|
@@ -1171,20 +1119,6 @@ handle_krb5_upcall(struct clnt_info *clp)
|
||
|
}
|
||
|
|
||
|
void
|
||
|
-handle_spkm3_upcall(struct clnt_info *clp)
|
||
|
-{
|
||
|
- uid_t uid;
|
||
|
-
|
||
|
- if (read(clp->spkm3_fd, &uid, sizeof(uid)) < (ssize_t)sizeof(uid)) {
|
||
|
- printerr(0, "WARNING: failed reading uid from spkm3 "
|
||
|
- "upcall pipe: %s\n", strerror(errno));
|
||
|
- return;
|
||
|
- }
|
||
|
-
|
||
|
- return process_spkm3_upcall(clp, uid, clp->spkm3_fd);
|
||
|
-}
|
||
|
-
|
||
|
-void
|
||
|
handle_gssd_upcall(struct clnt_info *clp)
|
||
|
{
|
||
|
uid_t uid;
|
||
|
@@ -1292,8 +1226,6 @@ handle_gssd_upcall(struct clnt_info *clp)
|
||
|
|
||
|
if (strcmp(mech, "krb5") == 0)
|
||
|
process_krb5_upcall(clp, uid, clp->gssd_fd, target, service);
|
||
|
- else if (strcmp(mech, "spkm3") == 0)
|
||
|
- process_spkm3_upcall(clp, uid, clp->gssd_fd);
|
||
|
else
|
||
|
printerr(0, "WARNING: handle_gssd_upcall: "
|
||
|
"received unknown gss mech '%s'\n", mech);
|
||
|
diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c
|
||
|
index 4b13fa1..887d118 100644
|
||
|
--- a/utils/gssd/krb5_util.c
|
||
|
+++ b/utils/gssd/krb5_util.c
|
||
|
@@ -129,6 +129,10 @@
|
||
|
/* Global list of principals/cache file names for machine credentials */
|
||
|
struct gssd_k5_kt_princ *gssd_k5_kt_princ_list = NULL;
|
||
|
|
||
|
+#ifdef HAVE_SET_ALLOWABLE_ENCTYPES
|
||
|
+int limit_to_legacy_enctypes = 0;
|
||
|
+#endif
|
||
|
+
|
||
|
/*==========================*/
|
||
|
/*=== Internal routines ===*/
|
||
|
/*==========================*/
|
||
|
@@ -1342,7 +1346,7 @@ limit_krb5_enctypes(struct rpc_gss_sec *sec)
|
||
|
* If we failed for any reason to produce global
|
||
|
* list of supported enctypes, use local default here.
|
||
|
*/
|
||
|
- if (krb5_enctypes == NULL)
|
||
|
+ if (krb5_enctypes == NULL || limit_to_legacy_enctypes)
|
||
|
maj_stat = gss_set_allowable_enctypes(&min_stat, credh,
|
||
|
&krb5oid, num_enctypes, enctypes);
|
||
|
else
|
||
|
diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h
|
||
|
index b42b91e..cd6e107 100644
|
||
|
--- a/utils/gssd/krb5_util.h
|
||
|
+++ b/utils/gssd/krb5_util.h
|
||
|
@@ -36,6 +36,7 @@ char *gssd_k5_err_msg(krb5_context context, krb5_error_code code);
|
||
|
void gssd_k5_get_default_realm(char **def_realm);
|
||
|
|
||
|
#ifdef HAVE_SET_ALLOWABLE_ENCTYPES
|
||
|
+extern int limit_to_legacy_enctypes;
|
||
|
int limit_krb5_enctypes(struct rpc_gss_sec *sec);
|
||
|
#endif
|
||
|
|
||
|
diff --git a/utils/gssd/svcgssd_mech2file.c b/utils/gssd/svcgssd_mech2file.c
|
||
|
index 65de8d0..ecd908b 100644
|
||
|
--- a/utils/gssd/svcgssd_mech2file.c
|
||
|
+++ b/utils/gssd/svcgssd_mech2file.c
|
||
|
@@ -53,8 +53,6 @@ struct mech2file {
|
||
|
|
||
|
struct mech2file m2f[] = {
|
||
|
{{9, "\052\206\110\206\367\022\001\002\002"}, "krb5"},
|
||
|
- {{7, "\053\006\001\005\005\001\003"}, "spkm3"},
|
||
|
- {{7, "\053\006\001\005\005\001\009"}, "lipkey"},
|
||
|
{{0,0},""},
|
||
|
};
|
||
|
|
||
|
diff --git a/utils/gssd/svcgssd_proc.c b/utils/gssd/svcgssd_proc.c
|
||
|
index c714d99..0d4f78d 100644
|
||
|
--- a/utils/gssd/svcgssd_proc.c
|
||
|
+++ b/utils/gssd/svcgssd_proc.c
|
||
|
@@ -369,12 +369,8 @@ get_hostbased_client_name(gss_name_t client_name, gss_OID mech,
|
||
|
if (g_OID_equal(&krb5oid, mech)) {
|
||
|
if (get_krb5_hostbased_name(&name, &cname) == 0)
|
||
|
*hostbased_name = cname;
|
||
|
- }
|
||
|
-
|
||
|
- /* No support for SPKM3, just print a warning (for now) */
|
||
|
- if (g_OID_equal(&spkm3oid, mech)) {
|
||
|
- printerr(1, "WARNING: get_hostbased_client_name: "
|
||
|
- "no hostbased_name support for SPKM3\n");
|
||
|
+ } else {
|
||
|
+ printerr(1, "WARNING: unknown/unsupport mech OID\n");
|
||
|
}
|
||
|
|
||
|
res = 0;
|
||
|
diff --git a/utils/idmapd/Makefile.am b/utils/idmapd/Makefile.am
|
||
|
index 4328e41..58b33ec 100644
|
||
|
--- a/utils/idmapd/Makefile.am
|
||
|
+++ b/utils/idmapd/Makefile.am
|
||
|
@@ -16,7 +16,7 @@ idmapd_SOURCES = \
|
||
|
nfs_idmap.h \
|
||
|
queue.h
|
||
|
|
||
|
-idmapd_LDADD = -levent -lnfsidmap ../../support/nfs/libnfs.a
|
||
|
+idmapd_LDADD = $(LIBEVENT) $(LIBNFSIDMAP) ../../support/nfs/libnfs.a
|
||
|
|
||
|
MAINTAINERCLEANFILES = Makefile.in
|
||
|
|
||
|
diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c
|
||
|
index 19d9114..e80efb4 100644
|
||
|
--- a/utils/idmapd/idmapd.c
|
||
|
+++ b/utils/idmapd/idmapd.c
|
||
|
@@ -778,8 +778,8 @@ nfsopen(struct idmap_client *ic)
|
||
|
} else {
|
||
|
event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfscb, ic);
|
||
|
event_add(&ic->ic_event, NULL);
|
||
|
- fcntl(ic->ic_dirfd, F_SETSIG, 0);
|
||
|
fcntl(ic->ic_dirfd, F_NOTIFY, 0);
|
||
|
+ fcntl(ic->ic_dirfd, F_SETSIG, 0);
|
||
|
if (verbose > 0)
|
||
|
xlog_warn("Opened %s", ic->ic_path);
|
||
|
}
|
||
|
diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am
|
||
|
index 7bc3e2b..7627854 100644
|
||
|
--- a/utils/mount/Makefile.am
|
||
|
+++ b/utils/mount/Makefile.am
|
||
|
@@ -24,7 +24,8 @@ EXTRA_DIST += nfsmount.conf
|
||
|
endif
|
||
|
|
||
|
mount_nfs_LDADD = ../../support/nfs/libnfs.a \
|
||
|
- ../../support/export/libexport.a
|
||
|
+ ../../support/export/libexport.a \
|
||
|
+ $(LIBTIRPC)
|
||
|
|
||
|
mount_nfs_SOURCES = $(mount_common)
|
||
|
|
||
|
diff --git a/utils/mount/mount_libmount.c b/utils/mount/mount_libmount.c
|
||
|
index e450d79..e8f17a9 100644
|
||
|
--- a/utils/mount/mount_libmount.c
|
||
|
+++ b/utils/mount/mount_libmount.c
|
||
|
@@ -346,6 +346,21 @@ static int mount_main(struct libmnt_context *cxt, int argc, char **argv)
|
||
|
|
||
|
if (chk_mountpoint(mount_point))
|
||
|
goto err;
|
||
|
+
|
||
|
+ /*
|
||
|
+ * The libmount strictly uses only options from fstab if running in
|
||
|
+ * restricted mode (suid, non-root user). This is done in
|
||
|
+ * mnt_context_prepare_mount() by default.
|
||
|
+ *
|
||
|
+ * We have to read fstab before nfsmount.conf, otherwise the options
|
||
|
+ * from nfsmount.conf will be ignored (overwrited).
|
||
|
+ */
|
||
|
+ rc = mnt_context_apply_fstab(cxt);
|
||
|
+ if (rc) {
|
||
|
+ nfs_error(_("%s: failed to apply fstab options\n"), progname);
|
||
|
+ goto err;
|
||
|
+ }
|
||
|
+
|
||
|
/*
|
||
|
* Concatenate mount options from the configuration file
|
||
|
*/
|
||
|
diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man
|
||
|
index ce40933..0d20cf0 100644
|
||
|
--- a/utils/mount/nfs.man
|
||
|
+++ b/utils/mount/nfs.man
|
||
|
@@ -372,14 +372,8 @@ Valid security flavors are
|
||
|
.BR sys ,
|
||
|
.BR krb5 ,
|
||
|
.BR krb5i ,
|
||
|
-.BR krb5p ,
|
||
|
-.BR lkey ,
|
||
|
-.BR lkeyi ,
|
||
|
-.BR lkeyp ,
|
||
|
-.BR spkm ,
|
||
|
-.BR spkmi ,
|
||
|
and
|
||
|
-.BR spkmp .
|
||
|
+.BR krb5p ,
|
||
|
Refer to the SECURITY CONSIDERATIONS section for details.
|
||
|
.TP 1.5i
|
||
|
.BR sharecache " / " nosharecache
|
||
|
@@ -1416,7 +1410,7 @@ security flavor encrypts every RPC request
|
||
|
to prevent data exposure during network transit; however,
|
||
|
expect some performance impact
|
||
|
when using integrity checking or encryption.
|
||
|
-Similar support for other forms of cryptographic security (such as lipkey and SPKM3)
|
||
|
+Similar support for other forms of cryptographic security
|
||
|
is also available.
|
||
|
.P
|
||
|
The NFS version 4 protocol allows
|
||
|
@@ -1561,10 +1555,10 @@ To ensure that the saved mount options are not erased during a remount,
|
||
|
specify either the local mount directory, or the server hostname and
|
||
|
export pathname, but not both, during a remount. For example,
|
||
|
.P
|
||
|
-.NF
|
||
|
-.TA 2.5i
|
||
|
+.nf
|
||
|
+.ta 8n
|
||
|
mount -o remount,ro /mnt
|
||
|
-.FI
|
||
|
+.fi
|
||
|
.P
|
||
|
merges the mount option
|
||
|
.B ro
|
||
|
diff --git a/utils/mount/nfs_mount.h b/utils/mount/nfs_mount.h
|
||
|
index 2becfb1..ec30c9b 100644
|
||
|
--- a/utils/mount/nfs_mount.h
|
||
|
+++ b/utils/mount/nfs_mount.h
|
||
|
@@ -75,9 +75,6 @@ struct nfs_mount_data {
|
||
|
#define AUTH_GSS_LKEY 390006
|
||
|
#define AUTH_GSS_LKEYI 390007
|
||
|
#define AUTH_GSS_LKEYP 390008
|
||
|
-#define AUTH_GSS_SPKM 390009
|
||
|
-#define AUTH_GSS_SPKMI 390010
|
||
|
-#define AUTH_GSS_SPKMP 390011
|
||
|
#endif
|
||
|
|
||
|
int nfsmount(const char *, const char *, int , char **, int, int);
|
||
|
diff --git a/utils/mount/nfsmount.c b/utils/mount/nfsmount.c
|
||
|
index 1298fe4..930622d 100644
|
||
|
--- a/utils/mount/nfsmount.c
|
||
|
+++ b/utils/mount/nfsmount.c
|
||
|
@@ -294,18 +294,6 @@ parse_options(char *old_opts, struct nfs_mount_data *data,
|
||
|
data->pseudoflavor = AUTH_GSS_KRB5I;
|
||
|
else if (!strcmp(secflavor, "krb5p"))
|
||
|
data->pseudoflavor = AUTH_GSS_KRB5P;
|
||
|
- else if (!strcmp(secflavor, "lipkey"))
|
||
|
- data->pseudoflavor = AUTH_GSS_LKEY;
|
||
|
- else if (!strcmp(secflavor, "lipkey-i"))
|
||
|
- data->pseudoflavor = AUTH_GSS_LKEYI;
|
||
|
- else if (!strcmp(secflavor, "lipkey-p"))
|
||
|
- data->pseudoflavor = AUTH_GSS_LKEYP;
|
||
|
- else if (!strcmp(secflavor, "spkm3"))
|
||
|
- data->pseudoflavor = AUTH_GSS_SPKM;
|
||
|
- else if (!strcmp(secflavor, "spkm3i"))
|
||
|
- data->pseudoflavor = AUTH_GSS_SPKMI;
|
||
|
- else if (!strcmp(secflavor, "spkm3p"))
|
||
|
- data->pseudoflavor = AUTH_GSS_SPKMP;
|
||
|
else if (sloppy)
|
||
|
continue;
|
||
|
else {
|
||
|
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
|
||
|
index 314a806..e09aa7c 100644
|
||
|
--- a/utils/mount/stropts.c
|
||
|
+++ b/utils/mount/stropts.c
|
||
|
@@ -540,6 +540,8 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options)
|
||
|
errno = EOPNOTSUPP;
|
||
|
else if (rpc_createerr.cf_stat == RPC_AUTHERROR)
|
||
|
errno = EACCES;
|
||
|
+ else if (rpc_createerr.cf_stat == RPC_TIMEDOUT)
|
||
|
+ errno = ETIMEDOUT;
|
||
|
else if (rpc_createerr.cf_error.re_errno != 0)
|
||
|
errno = rpc_createerr.cf_error.re_errno;
|
||
|
return 0;
|
||
|
@@ -665,9 +667,10 @@ static int nfs_try_mount_v3v2(struct nfsmount_info *mi)
|
||
|
case EHOSTUNREACH:
|
||
|
continue;
|
||
|
default:
|
||
|
- break;
|
||
|
+ goto out;
|
||
|
}
|
||
|
}
|
||
|
+out:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
@@ -751,9 +754,10 @@ static int nfs_try_mount_v4(struct nfsmount_info *mi)
|
||
|
case EHOSTUNREACH:
|
||
|
continue;
|
||
|
default:
|
||
|
- break;
|
||
|
+ goto out;
|
||
|
}
|
||
|
}
|
||
|
+out:
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
@@ -907,7 +911,8 @@ static int nfsmount_parent(struct nfsmount_info *mi)
|
||
|
if (nfs_try_mount(mi))
|
||
|
return EX_SUCCESS;
|
||
|
|
||
|
- if (nfs_is_permanent_error(errno)) {
|
||
|
+ /* retry background mounts when the server is not up */
|
||
|
+ if (nfs_is_permanent_error(errno) && errno != EOPNOTSUPP) {
|
||
|
mount_error(mi->spec, mi->node, errno);
|
||
|
return EX_FAIL;
|
||
|
}
|
||
|
@@ -942,7 +947,8 @@ static int nfsmount_child(struct nfsmount_info *mi)
|
||
|
if (nfs_try_mount(mi))
|
||
|
return EX_SUCCESS;
|
||
|
|
||
|
- if (nfs_is_permanent_error(errno))
|
||
|
+ /* retry background mounts when the server is not up */
|
||
|
+ if (nfs_is_permanent_error(errno) && errno != EOPNOTSUPP)
|
||
|
break;
|
||
|
|
||
|
if (time(NULL) > timeout)
|
||
|
diff --git a/utils/mountd/Makefile.am b/utils/mountd/Makefile.am
|
||
|
index eba81fc..7db968b 100644
|
||
|
--- a/utils/mountd/Makefile.am
|
||
|
+++ b/utils/mountd/Makefile.am
|
||
|
@@ -12,7 +12,7 @@ mountd_SOURCES = mountd.c mount_dispatch.c auth.c rmtab.c cache.c \
|
||
|
mountd_LDADD = ../../support/export/libexport.a \
|
||
|
../../support/nfs/libnfs.a \
|
||
|
../../support/misc/libmisc.a \
|
||
|
- $(LIBBSD) $(LIBWRAP) $(LIBNSL) $(LIBBLKID)
|
||
|
+ $(LIBBSD) $(LIBWRAP) $(LIBNSL) $(LIBBLKID) $(LIBDL) $(LIBTIRPC)
|
||
|
mountd_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) \
|
||
|
-I$(top_builddir)/support/include \
|
||
|
-I$(top_srcdir)/support/export
|
||
|
diff --git a/utils/mountd/auth.c b/utils/mountd/auth.c
|
||
|
index ccc849a..508040a 100644
|
||
|
--- a/utils/mountd/auth.c
|
||
|
+++ b/utils/mountd/auth.c
|
||
|
@@ -112,15 +112,23 @@ auth_reload()
|
||
|
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 buf[INET6_ADDRSTRLEN];
|
||
|
char *n;
|
||
|
|
||
|
if (use_ipaddr)
|
||
|
- return strdup(host_ntop(caller, buf, sizeof(buf)));
|
||
|
+ return get_client_ipaddr_name(caller);
|
||
|
n = client_compose(ai);
|
||
|
*error = unknown_host;
|
||
|
if (!n)
|
||
|
@@ -131,6 +139,23 @@ get_client_hostname(const struct sockaddr *caller, struct addrinfo *ai,
|
||
|
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,
|
||
|
@@ -155,9 +180,10 @@ auth_authenticate_newcache(const struct sockaddr *caller,
|
||
|
for (exp = exportlist[i].p_head; exp; exp = exp->m_next) {
|
||
|
if (strcmp(path, exp->m_export.e_path))
|
||
|
continue;
|
||
|
- if (!use_ipaddr && !client_member(my_client.m_hostname, exp->m_client->m_hostname))
|
||
|
+ if (!client_matches(exp, my_client.m_hostname, ai))
|
||
|
continue;
|
||
|
- if (use_ipaddr && !client_check(exp->m_client, ai))
|
||
|
+ if (exp->m_export.e_flags & NFSEXP_V4ROOT)
|
||
|
+ /* not acceptable for v[23] export */
|
||
|
continue;
|
||
|
break;
|
||
|
}
|
||
|
@@ -187,10 +213,6 @@ auth_authenticate_internal(const struct sockaddr *caller, const char *path,
|
||
|
return NULL;
|
||
|
}
|
||
|
}
|
||
|
- if (exp->m_export.e_flags & NFSEXP_V4ROOT) {
|
||
|
- *error = no_entry;
|
||
|
- return NULL;
|
||
|
- }
|
||
|
if (!(exp->m_export.e_flags & NFSEXP_INSECURE_PORT) &&
|
||
|
nfs_get_port(caller) >= IPPORT_RESERVED) {
|
||
|
*error = illegal_port;
|
||
|
diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c
|
||
|
index d2ae456..7d80432 100644
|
||
|
--- a/utils/mountd/cache.c
|
||
|
+++ b/utils/mountd/cache.c
|
||
|
@@ -84,7 +84,6 @@ static void auth_unix_ip(FILE *f)
|
||
|
char ipaddr[INET6_ADDRSTRLEN];
|
||
|
char *client = NULL;
|
||
|
struct addrinfo *tmp = NULL;
|
||
|
- struct addrinfo *ai = NULL;
|
||
|
if (readline(fileno(f), &lbuf, &lbuflen) != 1)
|
||
|
return;
|
||
|
|
||
|
@@ -107,12 +106,16 @@ static void auth_unix_ip(FILE *f)
|
||
|
|
||
|
/* addr is a valid, interesting address, find the domain name... */
|
||
|
if (!use_ipaddr) {
|
||
|
+ struct addrinfo *ai = NULL;
|
||
|
+
|
||
|
ai = client_resolve(tmp->ai_addr);
|
||
|
+ if (ai == NULL)
|
||
|
+ goto out;
|
||
|
client = client_compose(ai);
|
||
|
freeaddrinfo(ai);
|
||
|
+ if (!client)
|
||
|
+ goto out;
|
||
|
}
|
||
|
- freeaddrinfo(tmp);
|
||
|
-
|
||
|
qword_print(f, "nfsd");
|
||
|
qword_print(f, ipaddr);
|
||
|
qword_printuint(f, time(0) + DEFAULT_TTL);
|
||
|
@@ -124,6 +127,9 @@ static void auth_unix_ip(FILE *f)
|
||
|
xlog(D_CALL, "auth_unix_ip: client %p '%s'", client, client?client: "DEFAULT");
|
||
|
|
||
|
free(client);
|
||
|
+out:
|
||
|
+ freeaddrinfo(tmp);
|
||
|
+
|
||
|
}
|
||
|
|
||
|
static void auth_unix_gid(FILE *f)
|
||
|
@@ -495,6 +501,21 @@ static bool match_fsid(struct parsed_fsid *parsed, nfs_export *exp, char *path)
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
+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);
|
||
|
+ freeaddrinfo(tmp);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
static void nfsd_fh(FILE *f)
|
||
|
{
|
||
|
/* request are:
|
||
|
@@ -538,6 +559,12 @@ static void nfsd_fh(FILE *f)
|
||
|
|
||
|
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;
|
||
|
@@ -568,7 +595,8 @@ static void nfsd_fh(FILE *f)
|
||
|
next_exp = exp->m_next;
|
||
|
}
|
||
|
|
||
|
- if (!use_ipaddr && !client_member(dom, exp->m_client->m_hostname))
|
||
|
+ 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]?
|
||
|
@@ -578,29 +606,29 @@ static void nfsd_fh(FILE *f)
|
||
|
|
||
|
if (!match_fsid(&parsed, exp, path))
|
||
|
continue;
|
||
|
- if (use_ipaddr) {
|
||
|
- if (ai == NULL) {
|
||
|
- struct addrinfo *tmp;
|
||
|
- tmp = host_pton(dom);
|
||
|
- if (tmp == NULL)
|
||
|
- goto out;
|
||
|
- ai = client_resolve(tmp->ai_addr);
|
||
|
- freeaddrinfo(tmp);
|
||
|
- }
|
||
|
- if (!client_check(exp->m_client, ai))
|
||
|
- 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)
|
||
|
+ } 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;
|
||
|
+ }
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
@@ -742,14 +770,6 @@ static int path_matches(nfs_export *exp, char *path)
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
-client_matches(nfs_export *exp, char *dom, struct addrinfo *ai)
|
||
|
-{
|
||
|
- if (use_ipaddr)
|
||
|
- return client_check(exp->m_client, ai);
|
||
|
- return client_member(dom, exp->m_client->m_hostname);
|
||
|
-}
|
||
|
-
|
||
|
-static int
|
||
|
export_matches(nfs_export *exp, char *dom, char *path, struct addrinfo *ai)
|
||
|
{
|
||
|
return path_matches(exp, path) && client_matches(exp, dom, ai);
|
||
|
@@ -772,10 +792,14 @@ lookup_export(char *dom, char *path, struct addrinfo *ai)
|
||
|
found_type = i;
|
||
|
continue;
|
||
|
}
|
||
|
-
|
||
|
- /* Always prefer non-V4ROOT mounts */
|
||
|
- if (found->m_export.e_flags & NFSEXP_V4ROOT)
|
||
|
+ /* 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) ||
|
||
|
@@ -802,6 +826,229 @@ lookup_export(char *dom, char *path, struct addrinfo *ai)
|
||
|
return found;
|
||
|
}
|
||
|
|
||
|
+#ifdef HAVE_NFS_PLUGIN_H
|
||
|
+#include <dlfcn.h>
|
||
|
+#include <nfs-plugin.h>
|
||
|
+
|
||
|
+/*
|
||
|
+ * Walk through a set of FS locations and build a set of export options.
|
||
|
+ * Returns true if all went to plan; otherwise, false.
|
||
|
+ */
|
||
|
+static _Bool
|
||
|
+locations_to_options(struct jp_ops *ops, nfs_fsloc_set_t locations,
|
||
|
+ char *options, size_t remaining, int *ttl)
|
||
|
+{
|
||
|
+ char *server, *last_path, *rootpath, *ptr;
|
||
|
+ _Bool seen = false;
|
||
|
+
|
||
|
+ last_path = NULL;
|
||
|
+ rootpath = NULL;
|
||
|
+ server = NULL;
|
||
|
+ ptr = options;
|
||
|
+ *ttl = 0;
|
||
|
+
|
||
|
+ for (;;) {
|
||
|
+ enum jp_status status;
|
||
|
+ int len;
|
||
|
+
|
||
|
+ status = ops->jp_get_next_location(locations, &server,
|
||
|
+ &rootpath, ttl);
|
||
|
+ if (status == JP_EMPTY)
|
||
|
+ break;
|
||
|
+ if (status != JP_OK) {
|
||
|
+ xlog(D_GENERAL, "%s: failed to parse location: %s",
|
||
|
+ __func__, ops->jp_error(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: options buffer overflow", __func__);
|
||
|
+ goto out_false;
|
||
|
+ }
|
||
|
+ remaining -= (size_t)len;
|
||
|
+ ptr += len;
|
||
|
+ } else {
|
||
|
+ if (last_path == NULL)
|
||
|
+ len = snprintf(ptr, remaining, "refer=%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: options 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: options='%s', ttl=%d",
|
||
|
+ __func__, options, *ttl);
|
||
|
+ return seen;
|
||
|
+
|
||
|
+out_false:
|
||
|
+ free(rootpath);
|
||
|
+ free(server);
|
||
|
+ return false;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Walk through the set of FS locations and build an exportent.
|
||
|
+ * Returns pointer to an exportent if "junction" refers to a junction.
|
||
|
+ *
|
||
|
+ * Returned exportent points to static memory.
|
||
|
+ */
|
||
|
+static struct exportent *do_locations_to_export(struct jp_ops *ops,
|
||
|
+ nfs_fsloc_set_t locations, const char *junction,
|
||
|
+ char *options, size_t options_len)
|
||
|
+{
|
||
|
+ struct exportent *exp;
|
||
|
+ int ttl;
|
||
|
+
|
||
|
+ if (!locations_to_options(ops, locations, options, options_len, &ttl))
|
||
|
+ return NULL;
|
||
|
+
|
||
|
+ exp = mkexportent("*", (char *)junction, options);
|
||
|
+ if (exp == NULL) {
|
||
|
+ xlog(L_ERROR, "%s: Failed to construct exportent", __func__);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ exp->e_uuid = NULL;
|
||
|
+ exp->e_ttl = ttl;
|
||
|
+ return exp;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Convert set of FS locations to an exportent. Returns pointer to
|
||
|
+ * an exportent if "junction" refers to a junction.
|
||
|
+ *
|
||
|
+ * Returned exportent points to static memory.
|
||
|
+ */
|
||
|
+static struct exportent *locations_to_export(struct jp_ops *ops,
|
||
|
+ nfs_fsloc_set_t locations, const char *junction)
|
||
|
+{
|
||
|
+ struct exportent *exp;
|
||
|
+ char *options;
|
||
|
+
|
||
|
+ options = malloc(BUFSIZ);
|
||
|
+ if (options == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: failed to allocate options buffer",
|
||
|
+ __func__);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+ options[0] = '\0';
|
||
|
+
|
||
|
+ exp = do_locations_to_export(ops, locations, junction,
|
||
|
+ options, BUFSIZ);
|
||
|
+
|
||
|
+ free(options);
|
||
|
+ return exp;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Retrieve locations information in "junction" and dump it to the
|
||
|
+ * kernel. Returns pointer to an exportent if "junction" refers
|
||
|
+ * to a junction.
|
||
|
+ *
|
||
|
+ * Returned exportent points to static memory.
|
||
|
+ */
|
||
|
+static struct exportent *invoke_junction_ops(void *handle,
|
||
|
+ const char *junction)
|
||
|
+{
|
||
|
+ nfs_fsloc_set_t locations;
|
||
|
+ struct exportent *exp;
|
||
|
+ enum jp_status status;
|
||
|
+ struct jp_ops *ops;
|
||
|
+ char *error;
|
||
|
+
|
||
|
+ ops = (struct jp_ops *)dlsym(handle, "nfs_junction_ops");
|
||
|
+ error = dlerror();
|
||
|
+ if (error != NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: dlsym(jp_junction_ops): %s",
|
||
|
+ __func__, error);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+ if (ops->jp_api_version != JP_API_VERSION) {
|
||
|
+ xlog(D_GENERAL, "%s: unrecognized junction API version: %u",
|
||
|
+ __func__, ops->jp_api_version);
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ status = ops->jp_init(false);
|
||
|
+ if (status != JP_OK) {
|
||
|
+ xlog(D_GENERAL, "%s: failed to resolve %s: %s",
|
||
|
+ __func__, junction, ops->jp_error(status));
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ status = ops->jp_get_locations(junction, &locations);
|
||
|
+ if (status != JP_OK) {
|
||
|
+ xlog(D_GENERAL, "%s: failed to resolve %s: %s",
|
||
|
+ __func__, junction, ops->jp_error(status));
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+
|
||
|
+ exp = locations_to_export(ops, locations, junction);
|
||
|
+
|
||
|
+ ops->jp_put_locations(locations);
|
||
|
+ ops->jp_done();
|
||
|
+ return exp;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Load the junction plug-in, then try to resolve "pathname".
|
||
|
+ * Returns pointer to an initialized exportent if "junction"
|
||
|
+ * refers to a junction, or NULL if not.
|
||
|
+ *
|
||
|
+ * Returned exportent points to static memory.
|
||
|
+ */
|
||
|
+static struct exportent *lookup_junction(const char *pathname)
|
||
|
+{
|
||
|
+ struct exportent *exp;
|
||
|
+ void *handle;
|
||
|
+
|
||
|
+ handle = dlopen("libnfsjunct.so", RTLD_NOW);
|
||
|
+ if (handle == NULL) {
|
||
|
+ xlog(D_GENERAL, "%s: dlopen: %s", __func__, dlerror());
|
||
|
+ return NULL;
|
||
|
+ }
|
||
|
+ (void)dlerror(); /* Clear any error */
|
||
|
+
|
||
|
+ exp = invoke_junction_ops(handle, pathname);
|
||
|
+
|
||
|
+ /* We could leave it loaded to make junction resolution
|
||
|
+ * faster next time. However, if we want to replace the
|
||
|
+ * library, that would require restarting mountd. */
|
||
|
+ (void)dlclose(handle);
|
||
|
+ return exp;
|
||
|
+}
|
||
|
+#else /* !HAVE_NFS_PLUGIN_H */
|
||
|
+static inline struct exportent *lookup_junction(const char *UNUSED(pathname))
|
||
|
+{
|
||
|
+ return NULL;
|
||
|
+}
|
||
|
+#endif /* !HAVE_NFS_PLUGIN_H */
|
||
|
+
|
||
|
static void nfsd_export(FILE *f)
|
||
|
{
|
||
|
/* requests are:
|
||
|
@@ -834,13 +1081,9 @@ static void nfsd_export(FILE *f)
|
||
|
|
||
|
auth_reload();
|
||
|
|
||
|
- if (use_ipaddr) {
|
||
|
- struct addrinfo *tmp;
|
||
|
- tmp = host_pton(dom);
|
||
|
- if (tmp == NULL)
|
||
|
- goto out;
|
||
|
- ai = client_resolve(tmp->ai_addr);
|
||
|
- freeaddrinfo(tmp);
|
||
|
+ if (is_ipaddr_client(dom)) {
|
||
|
+ ai = lookup_client_addr(dom);
|
||
|
+ if (!ai)
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
@@ -854,7 +1097,7 @@ static void nfsd_export(FILE *f)
|
||
|
dump_to_cache(f, dom, path, NULL);
|
||
|
}
|
||
|
} else {
|
||
|
- dump_to_cache(f, dom, path, NULL);
|
||
|
+ dump_to_cache(f, dom, path, lookup_junction(path));
|
||
|
}
|
||
|
out:
|
||
|
xlog(D_CALL, "nfsd_export: found %p path %s", found, path ? path : NULL);
|
||
|
diff --git a/utils/mountd/fsloc.c b/utils/mountd/fsloc.c
|
||
|
index e2add2d..bc737d1 100644
|
||
|
--- a/utils/mountd/fsloc.c
|
||
|
+++ b/utils/mountd/fsloc.c
|
||
|
@@ -40,12 +40,12 @@ static void replicas_print(struct servers *sp)
|
||
|
{
|
||
|
int i;
|
||
|
if (!sp) {
|
||
|
- xlog(L_NOTICE, "NULL replicas pointer\n");
|
||
|
+ xlog(L_NOTICE, "NULL replicas pointer");
|
||
|
return;
|
||
|
}
|
||
|
- xlog(L_NOTICE, "replicas listsize=%i\n", sp->h_num);
|
||
|
+ xlog(L_NOTICE, "replicas listsize=%i", sp->h_num);
|
||
|
for (i=0; i<sp->h_num; i++) {
|
||
|
- xlog(L_NOTICE, " %s:%s\n",
|
||
|
+ xlog(L_NOTICE, " %s:%s",
|
||
|
sp->h_mp[i]->h_host, sp->h_mp[i]->h_path);
|
||
|
}
|
||
|
}
|
||
|
@@ -120,23 +120,37 @@ static struct servers *parse_list(char **list)
|
||
|
*/
|
||
|
static struct servers *method_list(char *data)
|
||
|
{
|
||
|
- char *copy, *ptr=data;
|
||
|
+ char *copy, *ptr=data, *p;
|
||
|
char **list;
|
||
|
int i, listsize;
|
||
|
struct servers *rv=NULL;
|
||
|
+ bool v6esc = false;
|
||
|
|
||
|
- xlog(L_NOTICE, "method_list(%s)\n", data);
|
||
|
+ xlog(L_NOTICE, "method_list(%s)", data);
|
||
|
for (ptr--, listsize=1; ptr; ptr=index(ptr, ':'), listsize++)
|
||
|
ptr++;
|
||
|
list = malloc(listsize * sizeof(char *));
|
||
|
copy = strdup(data);
|
||
|
if (copy)
|
||
|
- xlog(L_NOTICE, "converted to %s\n", copy);
|
||
|
+ xlog(L_NOTICE, "converted to %s", copy);
|
||
|
if (list && copy) {
|
||
|
ptr = copy;
|
||
|
- for (i=0; i<listsize; i++) {
|
||
|
- list[i] = strsep(&ptr, ":");
|
||
|
+ 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);
|
||
|
diff --git a/utils/mountd/mountd.h b/utils/mountd/mountd.h
|
||
|
index 4c184d2..6d358a7 100644
|
||
|
--- a/utils/mountd/mountd.h
|
||
|
+++ b/utils/mountd/mountd.h
|
||
|
@@ -56,4 +56,13 @@ struct nfs_fh_len *
|
||
|
cache_get_filehandle(nfs_export *exp, int len, char *p);
|
||
|
int cache_export(nfs_export *exp, char *path);
|
||
|
|
||
|
+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 /* MOUNTD_H */
|
||
|
diff --git a/utils/mountd/v4root.c b/utils/mountd/v4root.c
|
||
|
index c33a5a9..708eb61 100644
|
||
|
--- a/utils/mountd/v4root.c
|
||
|
+++ b/utils/mountd/v4root.c
|
||
|
@@ -46,6 +46,7 @@ static nfs_export pseudo_root = {
|
||
|
.e_nsqgids = 0,
|
||
|
.e_fsid = 0,
|
||
|
.e_mountpoint = NULL,
|
||
|
+ .e_ttl = DEFAULT_TTL,
|
||
|
},
|
||
|
.m_exported = 0,
|
||
|
.m_xtabent = 1,
|
||
|
@@ -83,7 +84,7 @@ v4root_create(char *path, nfs_export *export)
|
||
|
struct exportent *curexp = &export->m_export;
|
||
|
|
||
|
dupexportent(&eep, &pseudo_root.m_export);
|
||
|
- eep.e_hostname = strdup(curexp->e_hostname);
|
||
|
+ eep.e_hostname = curexp->e_hostname;
|
||
|
strncpy(eep.e_path, path, sizeof(eep.e_path));
|
||
|
if (strcmp(path, "/") != 0)
|
||
|
eep.e_flags &= ~NFSEXP_FSID;
|
||
|
@@ -149,13 +150,13 @@ static int v4root_add_parents(nfs_export *exp)
|
||
|
"pseudo export for '%s'", exp->m_export.e_path);
|
||
|
return -ENOMEM;
|
||
|
}
|
||
|
- for (ptr = path + 1; ptr; ptr = strchr(ptr, '/')) {
|
||
|
+ for (ptr = path; ptr; ptr = strchr(ptr, '/')) {
|
||
|
int ret;
|
||
|
char saved;
|
||
|
|
||
|
saved = *ptr;
|
||
|
*ptr = '\0';
|
||
|
- ret = pseudofs_update(hostname, path, exp);
|
||
|
+ ret = pseudofs_update(hostname, *path ? path : "/", exp);
|
||
|
if (ret)
|
||
|
return ret;
|
||
|
*ptr = saved;
|
||
|
@@ -192,6 +193,13 @@ v4root_set()
|
||
|
*/
|
||
|
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/utils/nfsd/Makefile.am b/utils/nfsd/Makefile.am
|
||
|
index c4c6fb0..1536065 100644
|
||
|
--- a/utils/nfsd/Makefile.am
|
||
|
+++ b/utils/nfsd/Makefile.am
|
||
|
@@ -8,7 +8,7 @@ KPREFIX = @kprefix@
|
||
|
sbin_PROGRAMS = nfsd
|
||
|
|
||
|
nfsd_SOURCES = nfsd.c nfssvc.c
|
||
|
-nfsd_LDADD = ../../support/nfs/libnfs.a
|
||
|
+nfsd_LDADD = ../../support/nfs/libnfs.a $(LIBTIRPC)
|
||
|
|
||
|
MAINTAINERCLEANFILES = Makefile.in
|
||
|
|
||
|
diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c
|
||
|
index 8bc5d3a..2a3f5cc 100644
|
||
|
--- a/utils/nfsd/nfsd.c
|
||
|
+++ b/utils/nfsd/nfsd.c
|
||
|
@@ -27,6 +27,10 @@
|
||
|
#include "nfssvc.h"
|
||
|
#include "xlog.h"
|
||
|
|
||
|
+#ifndef NFSD_NPROC
|
||
|
+#define NFSD_NPROC 8
|
||
|
+#endif
|
||
|
+
|
||
|
static void usage(const char *);
|
||
|
|
||
|
static struct option longopts[] =
|
||
|
@@ -90,7 +94,7 @@ nfsd_enable_protos(unsigned int *proto4, unsigned int *proto6)
|
||
|
int
|
||
|
main(int argc, char **argv)
|
||
|
{
|
||
|
- int count = 1, c, error = 0, portnum = 0, fd, found_one;
|
||
|
+ int count = NFSD_NPROC, c, error = 0, portnum = 0, fd, found_one;
|
||
|
char *p, *progname, *port;
|
||
|
char *haddr = NULL;
|
||
|
int socket_up = 0;
|
||
|
diff --git a/utils/nfsd/nfsd.man b/utils/nfsd/nfsd.man
|
||
|
index d8988d2..1cf9296 100644
|
||
|
--- a/utils/nfsd/nfsd.man
|
||
|
+++ b/utils/nfsd/nfsd.man
|
||
|
@@ -38,7 +38,7 @@ request on all known network addresses. This may change in future
|
||
|
releases of the Linux Kernel.
|
||
|
.TP
|
||
|
.B \-p " or " \-\-port port
|
||
|
-specify a diferent port to listen on for NFS requests. By default,
|
||
|
+specify a different port to listen on for NFS requests. By default,
|
||
|
.B rpc.nfsd
|
||
|
will listen on port 2049.
|
||
|
.TP
|
||
|
diff --git a/utils/nfsdcld/Makefile.am b/utils/nfsdcld/Makefile.am
|
||
|
new file mode 100644
|
||
|
index 0000000..f320dff
|
||
|
--- /dev/null
|
||
|
+++ b/utils/nfsdcld/Makefile.am
|
||
|
@@ -0,0 +1,14 @@
|
||
|
+## Process this file with automake to produce Makefile.in
|
||
|
+
|
||
|
+man8_MANS = nfsdcld.man
|
||
|
+EXTRA_DIST = $(man8_MANS)
|
||
|
+
|
||
|
+AM_CFLAGS += -D_LARGEFILE64_SOURCE
|
||
|
+sbin_PROGRAMS = nfsdcld
|
||
|
+
|
||
|
+nfsdcld_SOURCES = nfsdcld.c sqlite.c
|
||
|
+
|
||
|
+nfsdcld_LDADD = ../../support/nfs/libnfs.a $(LIBEVENT) $(LIBSQLITE)
|
||
|
+
|
||
|
+MAINTAINERCLEANFILES = Makefile.in
|
||
|
+
|
||
|
diff --git a/utils/nfsdcld/nfsdcld.c b/utils/nfsdcld/nfsdcld.c
|
||
|
new file mode 100644
|
||
|
index 0000000..2f0b004
|
||
|
--- /dev/null
|
||
|
+++ b/utils/nfsdcld/nfsdcld.c
|
||
|
@@ -0,0 +1,527 @@
|
||
|
+/*
|
||
|
+ * nfsdcld.c -- NFSv4 client name tracking daemon
|
||
|
+ *
|
||
|
+ * Copyright (C) 2011 Red Hat, 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., 51 Franklin Street, Fifth Floor,
|
||
|
+ * Boston, MA 02110-1301, USA.
|
||
|
+ */
|
||
|
+
|
||
|
+#ifdef HAVE_CONFIG_H
|
||
|
+#include "config.h"
|
||
|
+#endif /* HAVE_CONFIG_H */
|
||
|
+
|
||
|
+#include <errno.h>
|
||
|
+#include <event.h>
|
||
|
+#include <stdbool.h>
|
||
|
+#include <getopt.h>
|
||
|
+#include <string.h>
|
||
|
+#include <sys/stat.h>
|
||
|
+#include <sys/types.h>
|
||
|
+#include <fcntl.h>
|
||
|
+#include <unistd.h>
|
||
|
+#include <libgen.h>
|
||
|
+#include <sys/inotify.h>
|
||
|
+
|
||
|
+#include "xlog.h"
|
||
|
+#include "nfslib.h"
|
||
|
+#include "cld.h"
|
||
|
+#include "sqlite.h"
|
||
|
+
|
||
|
+#ifndef PIPEFS_DIR
|
||
|
+#define PIPEFS_DIR NFS_STATEDIR "/rpc_pipefs"
|
||
|
+#endif
|
||
|
+
|
||
|
+#define DEFAULT_CLD_PATH PIPEFS_DIR "/nfsd/cld"
|
||
|
+
|
||
|
+#define UPCALL_VERSION 1
|
||
|
+
|
||
|
+/* private data structures */
|
||
|
+struct cld_client {
|
||
|
+ int cl_fd;
|
||
|
+ struct event cl_event;
|
||
|
+ struct cld_msg cl_msg;
|
||
|
+};
|
||
|
+
|
||
|
+/* global variables */
|
||
|
+static char *pipepath = DEFAULT_CLD_PATH;
|
||
|
+static int inotify_fd = -1;
|
||
|
+static struct event pipedir_event;
|
||
|
+
|
||
|
+static struct option longopts[] =
|
||
|
+{
|
||
|
+ { "help", 0, NULL, 'h' },
|
||
|
+ { "foreground", 0, NULL, 'F' },
|
||
|
+ { "debug", 0, NULL, 'd' },
|
||
|
+ { "pipe", 1, NULL, 'p' },
|
||
|
+ { "storagedir", 1, NULL, 's' },
|
||
|
+ { NULL, 0, 0, 0 },
|
||
|
+};
|
||
|
+
|
||
|
+/* forward declarations */
|
||
|
+static void cldcb(int UNUSED(fd), short which, void *data);
|
||
|
+
|
||
|
+static void
|
||
|
+usage(char *progname)
|
||
|
+{
|
||
|
+ printf("%s [ -hFd ] [ -p pipe ] [ -s dir ]\n", progname);
|
||
|
+}
|
||
|
+
|
||
|
+#define INOTIFY_EVENT_MAX (sizeof(struct inotify_event) + NAME_MAX)
|
||
|
+
|
||
|
+static int
|
||
|
+cld_pipe_open(struct cld_client *clnt)
|
||
|
+{
|
||
|
+ int fd;
|
||
|
+
|
||
|
+ xlog(D_GENERAL, "%s: opening upcall pipe %s", __func__, pipepath);
|
||
|
+ fd = open(pipepath, O_RDWR, 0);
|
||
|
+ if (fd < 0) {
|
||
|
+ xlog(L_ERROR, "%s: open of %s failed: %m", __func__, pipepath);
|
||
|
+ return -errno;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (clnt->cl_event.ev_flags & EVLIST_INIT)
|
||
|
+ event_del(&clnt->cl_event);
|
||
|
+ if (clnt->cl_fd >= 0)
|
||
|
+ close(clnt->cl_fd);
|
||
|
+
|
||
|
+ clnt->cl_fd = fd;
|
||
|
+ event_set(&clnt->cl_event, clnt->cl_fd, EV_READ, cldcb, clnt);
|
||
|
+ /* event_add is done by the caller */
|
||
|
+ return 0;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+cld_inotify_cb(int UNUSED(fd), short which, void *data)
|
||
|
+{
|
||
|
+ int ret;
|
||
|
+ size_t elen;
|
||
|
+ ssize_t rret;
|
||
|
+ char evbuf[INOTIFY_EVENT_MAX];
|
||
|
+ char *dirc = NULL, *pname;
|
||
|
+ struct inotify_event *event = (struct inotify_event *)evbuf;
|
||
|
+ struct cld_client *clnt = data;
|
||
|
+
|
||
|
+ if (which != EV_READ)
|
||
|
+ return;
|
||
|
+
|
||
|
+ xlog(D_GENERAL, "%s: called for EV_READ", __func__);
|
||
|
+
|
||
|
+ dirc = strndup(pipepath, PATH_MAX);
|
||
|
+ if (!dirc) {
|
||
|
+ xlog(L_ERROR, "%s: unable to allocate memory", __func__);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ rret = read(inotify_fd, evbuf, INOTIFY_EVENT_MAX);
|
||
|
+ if (rret < 0) {
|
||
|
+ xlog(L_ERROR, "%s: read from inotify fd failed: %m", __func__);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* check to see if we have a filename in the evbuf */
|
||
|
+ if (!event->len) {
|
||
|
+ xlog(D_GENERAL, "%s: no filename in inotify event", __func__);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ pname = basename(dirc);
|
||
|
+ elen = strnlen(event->name, event->len);
|
||
|
+
|
||
|
+ /* does the filename match our pipe? */
|
||
|
+ if (strlen(pname) != elen || memcmp(pname, event->name, elen)) {
|
||
|
+ xlog(D_GENERAL, "%s: wrong filename (%s)", __func__,
|
||
|
+ event->name);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = cld_pipe_open(clnt);
|
||
|
+ switch (ret) {
|
||
|
+ case 0:
|
||
|
+ /* readd the event for the cl_event pipe */
|
||
|
+ event_add(&clnt->cl_event, NULL);
|
||
|
+ break;
|
||
|
+ case -ENOENT:
|
||
|
+ /* pipe must have disappeared, wait for it to come back */
|
||
|
+ goto out;
|
||
|
+ default:
|
||
|
+ /* anything else is fatal */
|
||
|
+ xlog(L_FATAL, "%s: unable to open new pipe (%d). Aborting.",
|
||
|
+ ret, __func__);
|
||
|
+ exit(ret);
|
||
|
+ }
|
||
|
+
|
||
|
+out:
|
||
|
+ event_add(&pipedir_event, NULL);
|
||
|
+ free(dirc);
|
||
|
+}
|
||
|
+
|
||
|
+static int
|
||
|
+cld_inotify_setup(void)
|
||
|
+{
|
||
|
+ int ret;
|
||
|
+ char *dirc, *dname;
|
||
|
+
|
||
|
+ dirc = strndup(pipepath, PATH_MAX);
|
||
|
+ if (!dirc) {
|
||
|
+ xlog_err("%s: unable to allocate memory", __func__);
|
||
|
+ ret = -ENOMEM;
|
||
|
+ goto out_free;
|
||
|
+ }
|
||
|
+
|
||
|
+ dname = dirname(dirc);
|
||
|
+
|
||
|
+ inotify_fd = inotify_init();
|
||
|
+ if (inotify_fd < 0) {
|
||
|
+ xlog_err("%s: inotify_init failed: %m", __func__);
|
||
|
+ ret = -errno;
|
||
|
+ goto out_free;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = inotify_add_watch(inotify_fd, dname, IN_CREATE);
|
||
|
+ if (ret < 0) {
|
||
|
+ xlog_err("%s: inotify_add_watch failed: %m", __func__);
|
||
|
+ ret = -errno;
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+
|
||
|
+out_free:
|
||
|
+ free(dirc);
|
||
|
+ return 0;
|
||
|
+out_err:
|
||
|
+ close(inotify_fd);
|
||
|
+ goto out_free;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Set an inotify watch on the directory that should contain the pipe, and then
|
||
|
+ * try to open it. If it fails with anything but -ENOENT, return the error
|
||
|
+ * immediately.
|
||
|
+ *
|
||
|
+ * If it succeeds, then set up the pipe event handler. At that point, set up
|
||
|
+ * the inotify event handler and go ahead and return success.
|
||
|
+ */
|
||
|
+static int
|
||
|
+cld_pipe_init(struct cld_client *clnt)
|
||
|
+{
|
||
|
+ int ret;
|
||
|
+
|
||
|
+ xlog(D_GENERAL, "%s: init pipe handlers", __func__);
|
||
|
+
|
||
|
+ ret = cld_inotify_setup();
|
||
|
+ if (ret != 0)
|
||
|
+ goto out;
|
||
|
+
|
||
|
+ clnt->cl_fd = -1;
|
||
|
+ ret = cld_pipe_open(clnt);
|
||
|
+ switch (ret) {
|
||
|
+ case 0:
|
||
|
+ /* add the event and we're good to go */
|
||
|
+ event_add(&clnt->cl_event, NULL);
|
||
|
+ break;
|
||
|
+ case -ENOENT:
|
||
|
+ /* ignore this error -- cld_inotify_cb will handle it */
|
||
|
+ ret = 0;
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ /* anything else is fatal */
|
||
|
+ close(inotify_fd);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* set event for inotify read */
|
||
|
+ event_set(&pipedir_event, inotify_fd, EV_READ, cld_inotify_cb, clnt);
|
||
|
+ event_add(&pipedir_event, NULL);
|
||
|
+out:
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+cld_not_implemented(struct cld_client *clnt)
|
||
|
+{
|
||
|
+ int ret;
|
||
|
+ ssize_t bsize, wsize;
|
||
|
+ struct cld_msg *cmsg = &clnt->cl_msg;
|
||
|
+
|
||
|
+ xlog(D_GENERAL, "%s: downcalling with not implemented error", __func__);
|
||
|
+
|
||
|
+ /* set up reply */
|
||
|
+ cmsg->cm_status = -EOPNOTSUPP;
|
||
|
+
|
||
|
+ bsize = sizeof(*cmsg);
|
||
|
+
|
||
|
+ wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize);
|
||
|
+ if (wsize != bsize)
|
||
|
+ xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m",
|
||
|
+ __func__, wsize);
|
||
|
+
|
||
|
+ /* reopen pipe, just to be sure */
|
||
|
+ ret = cld_pipe_open(clnt);
|
||
|
+ if (ret) {
|
||
|
+ xlog(L_FATAL, "%s: unable to reopen pipe: %d", __func__, ret);
|
||
|
+ exit(ret);
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+cld_create(struct cld_client *clnt)
|
||
|
+{
|
||
|
+ int ret;
|
||
|
+ ssize_t bsize, wsize;
|
||
|
+ struct cld_msg *cmsg = &clnt->cl_msg;
|
||
|
+
|
||
|
+ xlog(D_GENERAL, "%s: create client record.", __func__);
|
||
|
+
|
||
|
+ ret = sqlite_insert_client(cmsg->cm_u.cm_name.cn_id,
|
||
|
+ cmsg->cm_u.cm_name.cn_len);
|
||
|
+
|
||
|
+ cmsg->cm_status = ret ? -EREMOTEIO : ret;
|
||
|
+
|
||
|
+ bsize = sizeof(*cmsg);
|
||
|
+
|
||
|
+ xlog(D_GENERAL, "Doing downcall with status %d", cmsg->cm_status);
|
||
|
+ wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize);
|
||
|
+ if (wsize != bsize) {
|
||
|
+ xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m",
|
||
|
+ __func__, wsize);
|
||
|
+ ret = cld_pipe_open(clnt);
|
||
|
+ if (ret) {
|
||
|
+ xlog(L_FATAL, "%s: unable to reopen pipe: %d",
|
||
|
+ __func__, ret);
|
||
|
+ exit(ret);
|
||
|
+ }
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+cld_remove(struct cld_client *clnt)
|
||
|
+{
|
||
|
+ int ret;
|
||
|
+ ssize_t bsize, wsize;
|
||
|
+ struct cld_msg *cmsg = &clnt->cl_msg;
|
||
|
+
|
||
|
+ xlog(D_GENERAL, "%s: remove client record.", __func__);
|
||
|
+
|
||
|
+ ret = sqlite_remove_client(cmsg->cm_u.cm_name.cn_id,
|
||
|
+ cmsg->cm_u.cm_name.cn_len);
|
||
|
+
|
||
|
+ cmsg->cm_status = ret ? -EREMOTEIO : ret;
|
||
|
+
|
||
|
+ bsize = sizeof(*cmsg);
|
||
|
+
|
||
|
+ xlog(D_GENERAL, "%s: downcall with status %d", __func__,
|
||
|
+ cmsg->cm_status);
|
||
|
+ wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize);
|
||
|
+ if (wsize != bsize) {
|
||
|
+ xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m",
|
||
|
+ __func__, wsize);
|
||
|
+ ret = cld_pipe_open(clnt);
|
||
|
+ if (ret) {
|
||
|
+ xlog(L_FATAL, "%s: unable to reopen pipe: %d",
|
||
|
+ __func__, ret);
|
||
|
+ exit(ret);
|
||
|
+ }
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+cld_check(struct cld_client *clnt)
|
||
|
+{
|
||
|
+ int ret;
|
||
|
+ ssize_t bsize, wsize;
|
||
|
+ struct cld_msg *cmsg = &clnt->cl_msg;
|
||
|
+
|
||
|
+ xlog(D_GENERAL, "%s: check client record", __func__);
|
||
|
+
|
||
|
+ ret = sqlite_check_client(cmsg->cm_u.cm_name.cn_id,
|
||
|
+ cmsg->cm_u.cm_name.cn_len);
|
||
|
+
|
||
|
+ /* set up reply */
|
||
|
+ cmsg->cm_status = ret ? -EACCES : ret;
|
||
|
+
|
||
|
+ bsize = sizeof(*cmsg);
|
||
|
+
|
||
|
+ xlog(D_GENERAL, "%s: downcall with status %d", __func__,
|
||
|
+ cmsg->cm_status);
|
||
|
+ wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize);
|
||
|
+ if (wsize != bsize) {
|
||
|
+ xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m",
|
||
|
+ __func__, wsize);
|
||
|
+ ret = cld_pipe_open(clnt);
|
||
|
+ if (ret) {
|
||
|
+ xlog(L_FATAL, "%s: unable to reopen pipe: %d",
|
||
|
+ __func__, ret);
|
||
|
+ exit(ret);
|
||
|
+ }
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+cld_gracedone(struct cld_client *clnt)
|
||
|
+{
|
||
|
+ int ret;
|
||
|
+ ssize_t bsize, wsize;
|
||
|
+ struct cld_msg *cmsg = &clnt->cl_msg;
|
||
|
+
|
||
|
+ xlog(D_GENERAL, "%s: grace done. cm_gracetime=%ld", __func__,
|
||
|
+ cmsg->cm_u.cm_gracetime);
|
||
|
+
|
||
|
+ ret = sqlite_remove_unreclaimed(cmsg->cm_u.cm_gracetime);
|
||
|
+
|
||
|
+ /* set up reply: downcall with 0 status */
|
||
|
+ cmsg->cm_status = ret ? -EREMOTEIO : ret;
|
||
|
+
|
||
|
+ bsize = sizeof(*cmsg);
|
||
|
+
|
||
|
+ xlog(D_GENERAL, "Doing downcall with status %d", cmsg->cm_status);
|
||
|
+ wsize = atomicio((void *)write, clnt->cl_fd, cmsg, bsize);
|
||
|
+ if (wsize != bsize) {
|
||
|
+ xlog(L_ERROR, "%s: problem writing to cld pipe (%ld): %m",
|
||
|
+ __func__, wsize);
|
||
|
+ ret = cld_pipe_open(clnt);
|
||
|
+ if (ret) {
|
||
|
+ xlog(L_FATAL, "%s: unable to reopen pipe: %d",
|
||
|
+ __func__, ret);
|
||
|
+ exit(ret);
|
||
|
+ }
|
||
|
+ }
|
||
|
+}
|
||
|
+
|
||
|
+static void
|
||
|
+cldcb(int UNUSED(fd), short which, void *data)
|
||
|
+{
|
||
|
+ ssize_t len;
|
||
|
+ struct cld_client *clnt = data;
|
||
|
+ struct cld_msg *cmsg = &clnt->cl_msg;
|
||
|
+
|
||
|
+ if (which != EV_READ)
|
||
|
+ goto out;
|
||
|
+
|
||
|
+ len = atomicio(read, clnt->cl_fd, cmsg, sizeof(*cmsg));
|
||
|
+ if (len <= 0) {
|
||
|
+ xlog(L_ERROR, "%s: pipe read failed: %m", __func__);
|
||
|
+ cld_pipe_open(clnt);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (cmsg->cm_vers != UPCALL_VERSION) {
|
||
|
+ xlog(L_ERROR, "%s: unsupported upcall version: %hu",
|
||
|
+ cmsg->cm_vers);
|
||
|
+ cld_pipe_open(clnt);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ switch(cmsg->cm_cmd) {
|
||
|
+ case Cld_Create:
|
||
|
+ cld_create(clnt);
|
||
|
+ break;
|
||
|
+ case Cld_Remove:
|
||
|
+ cld_remove(clnt);
|
||
|
+ break;
|
||
|
+ case Cld_Check:
|
||
|
+ cld_check(clnt);
|
||
|
+ break;
|
||
|
+ case Cld_GraceDone:
|
||
|
+ cld_gracedone(clnt);
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ xlog(L_WARNING, "%s: command %u is not yet implemented",
|
||
|
+ __func__, cmsg->cm_cmd);
|
||
|
+ cld_not_implemented(clnt);
|
||
|
+ }
|
||
|
+out:
|
||
|
+ event_add(&clnt->cl_event, NULL);
|
||
|
+}
|
||
|
+
|
||
|
+int
|
||
|
+main(int argc, char **argv)
|
||
|
+{
|
||
|
+ char arg;
|
||
|
+ int rc = 0;
|
||
|
+ bool foreground = false;
|
||
|
+ char *progname;
|
||
|
+ char *storagedir = NULL;
|
||
|
+ struct cld_client clnt;
|
||
|
+
|
||
|
+ memset(&clnt, 0, sizeof(clnt));
|
||
|
+
|
||
|
+ progname = strdup(basename(argv[0]));
|
||
|
+ if (!progname) {
|
||
|
+ fprintf(stderr, "%s: unable to allocate memory.\n", argv[0]);
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ event_init();
|
||
|
+ xlog_syslog(0);
|
||
|
+ xlog_stderr(1);
|
||
|
+
|
||
|
+ /* process command-line options */
|
||
|
+ while ((arg = getopt_long(argc, argv, "hdFp:s:", longopts,
|
||
|
+ NULL)) != EOF) {
|
||
|
+ switch (arg) {
|
||
|
+ case 'd':
|
||
|
+ xlog_config(D_ALL, 1);
|
||
|
+ break;
|
||
|
+ case 'F':
|
||
|
+ foreground = true;
|
||
|
+ break;
|
||
|
+ case 'p':
|
||
|
+ pipepath = optarg;
|
||
|
+ break;
|
||
|
+ case 's':
|
||
|
+ storagedir = optarg;
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ usage(progname);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+
|
||
|
+ xlog_open(progname);
|
||
|
+ if (!foreground) {
|
||
|
+ xlog_syslog(1);
|
||
|
+ xlog_stderr(0);
|
||
|
+ rc = daemon(0, 0);
|
||
|
+ if (rc) {
|
||
|
+ xlog(L_ERROR, "Unable to daemonize: %m");
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ /* set up storage db */
|
||
|
+ rc = sqlite_maindb_init(storagedir);
|
||
|
+ if (rc) {
|
||
|
+ xlog(L_ERROR, "Failed to open main database: %d", rc);
|
||
|
+ goto out;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* set up event handler */
|
||
|
+ rc = cld_pipe_init(&clnt);
|
||
|
+ if (rc)
|
||
|
+ goto out;
|
||
|
+
|
||
|
+ xlog(D_GENERAL, "%s: Starting event dispatch handler.", __func__);
|
||
|
+ rc = event_dispatch();
|
||
|
+ if (rc < 0)
|
||
|
+ xlog(L_ERROR, "%s: event_dispatch failed: %m", __func__);
|
||
|
+
|
||
|
+ close(clnt.cl_fd);
|
||
|
+ close(inotify_fd);
|
||
|
+out:
|
||
|
+ free(progname);
|
||
|
+ return rc;
|
||
|
+}
|
||
|
diff --git a/utils/nfsdcld/nfsdcld.man b/utils/nfsdcld/nfsdcld.man
|
||
|
new file mode 100644
|
||
|
index 0000000..bad5f34
|
||
|
--- /dev/null
|
||
|
+++ b/utils/nfsdcld/nfsdcld.man
|
||
|
@@ -0,0 +1,180 @@
|
||
|
+.\" Automatically generated by Pod::Man 2.22 (Pod::Simple 3.13)
|
||
|
+.\"
|
||
|
+.\" Standard preamble:
|
||
|
+.\" ========================================================================
|
||
|
+.de Sp \" Vertical space (when we can't use .PP)
|
||
|
+.if t .sp .5v
|
||
|
+.if n .sp
|
||
|
+..
|
||
|
+.de Vb \" Begin verbatim text
|
||
|
+.ft CW
|
||
|
+.nf
|
||
|
+.ne \\$1
|
||
|
+..
|
||
|
+.de Ve \" End verbatim text
|
||
|
+.ft R
|
||
|
+.fi
|
||
|
+..
|
||
|
+.\" Set up some character translations and predefined strings. \*(-- will
|
||
|
+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
|
||
|
+.\" double quote, and \*(R" will give a right double quote. \*(C+ will
|
||
|
+.\" give a nicer C++. Capital omega is used to do unbreakable dashes and
|
||
|
+.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff,
|
||
|
+.\" nothing in troff, for use with C<>.
|
||
|
+.tr \(*W-
|
||
|
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
|
||
|
+.ie n \{\
|
||
|
+. ds -- \(*W-
|
||
|
+. ds PI pi
|
||
|
+. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
|
||
|
+. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch
|
||
|
+. ds L" ""
|
||
|
+. ds R" ""
|
||
|
+. ds C` ""
|
||
|
+. ds C' ""
|
||
|
+'br\}
|
||
|
+.el\{\
|
||
|
+. ds -- \|\(em\|
|
||
|
+. ds PI \(*p
|
||
|
+. ds L" ``
|
||
|
+. ds R" ''
|
||
|
+'br\}
|
||
|
+.\"
|
||
|
+.\" Escape single quotes in literal strings from groff's Unicode transform.
|
||
|
+.ie \n(.g .ds Aq \(aq
|
||
|
+.el .ds Aq '
|
||
|
+.\"
|
||
|
+.\" If the F register is turned on, we'll generate index entries on stderr for
|
||
|
+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
|
||
|
+.\" entries marked with X<> in POD. Of course, you'll have to process the
|
||
|
+.\" output yourself in some meaningful fashion.
|
||
|
+.ie \nF \{\
|
||
|
+. de IX
|
||
|
+. tm Index:\\$1\t\\n%\t"\\$2"
|
||
|
+..
|
||
|
+. nr % 0
|
||
|
+. rr F
|
||
|
+.\}
|
||
|
+.el \{\
|
||
|
+. de IX
|
||
|
+..
|
||
|
+.\}
|
||
|
+.\"
|
||
|
+.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
|
||
|
+.\" Fear. Run. Save yourself. No user-serviceable parts.
|
||
|
+. \" fudge factors for nroff and troff
|
||
|
+.if n \{\
|
||
|
+. ds #H 0
|
||
|
+. ds #V .8m
|
||
|
+. ds #F .3m
|
||
|
+. ds #[ \f1
|
||
|
+. ds #] \fP
|
||
|
+.\}
|
||
|
+.if t \{\
|
||
|
+. ds #H ((1u-(\\\\n(.fu%2u))*.13m)
|
||
|
+. ds #V .6m
|
||
|
+. ds #F 0
|
||
|
+. ds #[ \&
|
||
|
+. ds #] \&
|
||
|
+.\}
|
||
|
+. \" simple accents for nroff and troff
|
||
|
+.if n \{\
|
||
|
+. ds ' \&
|
||
|
+. ds ` \&
|
||
|
+. ds ^ \&
|
||
|
+. ds , \&
|
||
|
+. ds ~ ~
|
||
|
+. ds /
|
||
|
+.\}
|
||
|
+.if t \{\
|
||
|
+. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
|
||
|
+. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
|
||
|
+. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
|
||
|
+. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
|
||
|
+. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
|
||
|
+. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
|
||
|
+.\}
|
||
|
+. \" troff and (daisy-wheel) nroff accents
|
||
|
+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
|
||
|
+.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
|
||
|
+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
|
||
|
+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
|
||
|
+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
|
||
|
+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
|
||
|
+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
|
||
|
+.ds ae a\h'-(\w'a'u*4/10)'e
|
||
|
+.ds Ae A\h'-(\w'A'u*4/10)'E
|
||
|
+. \" corrections for vroff
|
||
|
+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
|
||
|
+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
|
||
|
+. \" for low resolution devices (crt and lpr)
|
||
|
+.if \n(.H>23 .if \n(.V>19 \
|
||
|
+\{\
|
||
|
+. ds : e
|
||
|
+. ds 8 ss
|
||
|
+. ds o a
|
||
|
+. ds d- d\h'-1'\(ga
|
||
|
+. ds D- D\h'-1'\(hy
|
||
|
+. ds th \o'bp'
|
||
|
+. ds Th \o'LP'
|
||
|
+. ds ae ae
|
||
|
+. ds Ae AE
|
||
|
+.\}
|
||
|
+.rm #[ #] #H #V #F C
|
||
|
+.\" ========================================================================
|
||
|
+.\"
|
||
|
+.IX Title "NFSDCLD 8"
|
||
|
+.TH NFSDCLD 8 "2011-12-21" "" ""
|
||
|
+.\" For nroff, turn off justification. Always turn off hyphenation; it makes
|
||
|
+.\" way too many mistakes in technical documents.
|
||
|
+.if n .ad l
|
||
|
+.nh
|
||
|
+.SH "NAME"
|
||
|
+nfsdcld \- NFSv4 Client Tracking Daemon
|
||
|
+.SH "SYNOPSIS"
|
||
|
+.IX Header "SYNOPSIS"
|
||
|
+nfsdcld [\-d] [\-F] [\-p path] [\-s stable storage dir]
|
||
|
+.SH "DESCRIPTION"
|
||
|
+.IX Header "DESCRIPTION"
|
||
|
+nfsdcld is the NFSv4 client tracking daemon. It is not necessary to run
|
||
|
+this daemon on machines that are not acting as NFSv4 servers.
|
||
|
+.PP
|
||
|
+When a network partition is combined with a server reboot, there are
|
||
|
+edge conditions that can cause the server to grant lock reclaims when
|
||
|
+other clients have taken conflicting locks in the interim. A more detailed
|
||
|
+explanation of this issue is described in \s-1RFC\s0 3530, section 8.6.3.
|
||
|
+.PP
|
||
|
+In order to prevent these problems, the server must track a small amount
|
||
|
+of per-client information on stable storage. This daemon provides the
|
||
|
+userspace piece of that functionality.
|
||
|
+.SH "OPTIONS"
|
||
|
+.IX Header "OPTIONS"
|
||
|
+.IP "\fB\-d\fR, \fB\-\-debug\fR" 4
|
||
|
+.IX Item "-d, --debug"
|
||
|
+Enable debug level logging.
|
||
|
+.IP "\fB\-F\fR, \fB\-\-foreground\fR" 4
|
||
|
+.IX Item "-F, --foreground"
|
||
|
+Runs the daemon in the foreground and prints all output to stderr
|
||
|
+.IP "\fB\-p\fR \fIpipe\fR, \fB\-\-pipe\fR=\fIpipe\fR" 4
|
||
|
+.IX Item "-p pipe, --pipe=pipe"
|
||
|
+Location of the \*(L"cld\*(R" upcall pipe. The default value is
|
||
|
+\&\fI/var/lib/nfs/rpc_pipefs/nfsd/cld\fR. If the pipe does not exist when the
|
||
|
+daemon starts then it will wait for it to be created.
|
||
|
+.IP "\fB\-s\fR \fIstoragedir\fR, \fB\-\-storagedir\fR=\fIstorage_dir\fR" 4
|
||
|
+.IX Item "-s storagedir, --storagedir=storage_dir"
|
||
|
+Directory where stable storage information should be kept. The default
|
||
|
+value is \fI/var/lib/nfs/nfsdcld\fR.
|
||
|
+.SH "NOTES"
|
||
|
+.IX Header "NOTES"
|
||
|
+The Linux kernel NFSv4 server has historically tracked this information
|
||
|
+on stable storage by manipulating information on the filesystem
|
||
|
+directly, in the directory to which \fI/proc/fs/nfsd/nfsv4recoverydir\fR
|
||
|
+points.
|
||
|
+.PP
|
||
|
+This daemon requires a kernel that supports the nfsdcld upcall. If the
|
||
|
+kernel does not support the new upcall, or is using the legacy client
|
||
|
+name tracking code then it will not create the pipe that nfsdcld uses to
|
||
|
+talk to the kernel.
|
||
|
+.SH "AUTHORS"
|
||
|
+.IX Header "AUTHORS"
|
||
|
+The nfsdcld daemon was developed by Jeff Layton <jlayton@redhat.com>.
|
||
|
diff --git a/utils/nfsdcld/sqlite.c b/utils/nfsdcld/sqlite.c
|
||
|
new file mode 100644
|
||
|
index 0000000..9e35774
|
||
|
--- /dev/null
|
||
|
+++ b/utils/nfsdcld/sqlite.c
|
||
|
@@ -0,0 +1,390 @@
|
||
|
+/*
|
||
|
+ * Copyright (C) 2011 Red Hat, 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., 51 Franklin Street, Fifth Floor,
|
||
|
+ * Boston, MA 02110-1301, USA.
|
||
|
+ */
|
||
|
+
|
||
|
+/*
|
||
|
+ * Explanation:
|
||
|
+ *
|
||
|
+ * This file contains the code to manage the sqlite backend database for the
|
||
|
+ * clstated upcall daemon.
|
||
|
+ *
|
||
|
+ * The main database is called main.sqlite and contains the following tables:
|
||
|
+ *
|
||
|
+ * parameters: simple key/value pairs for storing database info
|
||
|
+ *
|
||
|
+ * clients: one column containing a BLOB with the as sent by the client
|
||
|
+ * and a timestamp (in epoch seconds) of when the record was
|
||
|
+ * established
|
||
|
+ *
|
||
|
+ * FIXME: should we also record the fsid being accessed?
|
||
|
+ */
|
||
|
+
|
||
|
+#ifdef HAVE_CONFIG_H
|
||
|
+#include "config.h"
|
||
|
+#endif /* HAVE_CONFIG_H */
|
||
|
+
|
||
|
+#include <dirent.h>
|
||
|
+#include <errno.h>
|
||
|
+#include <event.h>
|
||
|
+#include <stdbool.h>
|
||
|
+#include <string.h>
|
||
|
+#include <sys/stat.h>
|
||
|
+#include <sys/types.h>
|
||
|
+#include <fcntl.h>
|
||
|
+#include <unistd.h>
|
||
|
+#include <sqlite3.h>
|
||
|
+#include <linux/limits.h>
|
||
|
+
|
||
|
+#include "xlog.h"
|
||
|
+
|
||
|
+#define CLD_SQLITE_SCHEMA_VERSION 1
|
||
|
+
|
||
|
+#ifndef CLD_SQLITE_TOPDIR
|
||
|
+#define CLD_SQLITE_TOPDIR NFS_STATEDIR "/nfsdcld"
|
||
|
+#endif
|
||
|
+
|
||
|
+/* in milliseconds */
|
||
|
+#define CLD_SQLITE_BUSY_TIMEOUT 10000
|
||
|
+
|
||
|
+/* private data structures */
|
||
|
+
|
||
|
+/* global variables */
|
||
|
+
|
||
|
+/* top level DB directory */
|
||
|
+static char *sqlite_topdir;
|
||
|
+
|
||
|
+/* reusable pathname and sql command buffer */
|
||
|
+static char buf[PATH_MAX];
|
||
|
+
|
||
|
+/* global database handle */
|
||
|
+static sqlite3 *dbh;
|
||
|
+
|
||
|
+/* forward declarations */
|
||
|
+
|
||
|
+/* make a directory, ignoring EEXIST errors unless it's not a directory */
|
||
|
+static int
|
||
|
+mkdir_if_not_exist(char *dirname)
|
||
|
+{
|
||
|
+ int ret;
|
||
|
+ struct stat statbuf;
|
||
|
+
|
||
|
+ ret = mkdir(dirname, S_IRWXU);
|
||
|
+ if (ret && errno != EEXIST)
|
||
|
+ return -errno;
|
||
|
+
|
||
|
+ ret = stat(dirname, &statbuf);
|
||
|
+ if (ret)
|
||
|
+ return -errno;
|
||
|
+
|
||
|
+ if (!S_ISDIR(statbuf.st_mode))
|
||
|
+ ret = -ENOTDIR;
|
||
|
+
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Open the "main" database, and attempt to initialize it by creating the
|
||
|
+ * parameters table and inserting the schema version into it. Ignore any errors
|
||
|
+ * from that, and then attempt to select the version out of it again. If the
|
||
|
+ * version appears wrong, then assume that the DB is corrupt or has been
|
||
|
+ * upgraded, and return an error. If all of that works, then attempt to create
|
||
|
+ * the "clients" table.
|
||
|
+ */
|
||
|
+int
|
||
|
+sqlite_maindb_init(char *topdir)
|
||
|
+{
|
||
|
+ int ret;
|
||
|
+ char *err = NULL;
|
||
|
+ sqlite3_stmt *stmt = NULL;
|
||
|
+
|
||
|
+ sqlite_topdir = topdir ? topdir : CLD_SQLITE_TOPDIR;
|
||
|
+
|
||
|
+ ret = mkdir_if_not_exist(sqlite_topdir);
|
||
|
+ if (ret)
|
||
|
+ return ret;
|
||
|
+
|
||
|
+ ret = snprintf(buf, PATH_MAX - 1, "%s/main.sqlite", sqlite_topdir);
|
||
|
+ if (ret < 0)
|
||
|
+ return ret;
|
||
|
+
|
||
|
+ buf[PATH_MAX - 1] = '\0';
|
||
|
+
|
||
|
+ ret = sqlite3_open(buf, &dbh);
|
||
|
+ if (ret != SQLITE_OK) {
|
||
|
+ xlog(L_ERROR, "Unable to open main database: %d", ret);
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sqlite3_busy_timeout(dbh, CLD_SQLITE_BUSY_TIMEOUT);
|
||
|
+ if (ret != SQLITE_OK) {
|
||
|
+ xlog(L_ERROR, "Unable to set sqlite busy timeout: %d", ret);
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* Try to create table */
|
||
|
+ ret = sqlite3_exec(dbh, "CREATE TABLE IF NOT EXISTS parameters "
|
||
|
+ "(key TEXT PRIMARY KEY, value TEXT);",
|
||
|
+ NULL, NULL, &err);
|
||
|
+ if (ret != SQLITE_OK) {
|
||
|
+ xlog(L_ERROR, "Unable to create parameter table: %d", ret);
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* insert version into table -- ignore error if it fails */
|
||
|
+ ret = snprintf(buf, sizeof(buf),
|
||
|
+ "INSERT OR IGNORE INTO parameters values (\"version\", "
|
||
|
+ "\"%d\");", CLD_SQLITE_SCHEMA_VERSION);
|
||
|
+ if (ret < 0) {
|
||
|
+ goto out_err;
|
||
|
+ } else if ((size_t)ret >= sizeof(buf)) {
|
||
|
+ ret = -EINVAL;
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sqlite3_exec(dbh, (const char *)buf, NULL, NULL, &err);
|
||
|
+ if (ret != SQLITE_OK) {
|
||
|
+ xlog(L_ERROR, "Unable to insert into parameter table: %d",
|
||
|
+ ret);
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sqlite3_prepare_v2(dbh,
|
||
|
+ "SELECT value FROM parameters WHERE key == \"version\";",
|
||
|
+ -1, &stmt, NULL);
|
||
|
+ if (ret != SQLITE_OK) {
|
||
|
+ xlog(L_ERROR, "Unable to prepare select statement: %d", ret);
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* check schema version */
|
||
|
+ ret = sqlite3_step(stmt);
|
||
|
+ if (ret != SQLITE_ROW) {
|
||
|
+ xlog(L_ERROR, "Select statement execution failed: %s",
|
||
|
+ sqlite3_errmsg(dbh));
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* process SELECT result */
|
||
|
+ ret = sqlite3_column_int(stmt, 0);
|
||
|
+ if (ret != CLD_SQLITE_SCHEMA_VERSION) {
|
||
|
+ xlog(L_ERROR, "Unsupported database schema version! "
|
||
|
+ "Expected %d, got %d.",
|
||
|
+ CLD_SQLITE_SCHEMA_VERSION, ret);
|
||
|
+ ret = -EINVAL;
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+
|
||
|
+ /* now create the "clients" table */
|
||
|
+ ret = sqlite3_exec(dbh, "CREATE TABLE IF NOT EXISTS clients "
|
||
|
+ "(id BLOB PRIMARY KEY, time INTEGER);",
|
||
|
+ NULL, NULL, &err);
|
||
|
+ if (ret != SQLITE_OK) {
|
||
|
+ xlog(L_ERROR, "Unable to create clients table: %s", err);
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+
|
||
|
+ sqlite3_free(err);
|
||
|
+ sqlite3_finalize(stmt);
|
||
|
+ return 0;
|
||
|
+
|
||
|
+out_err:
|
||
|
+ if (err) {
|
||
|
+ xlog(L_ERROR, "sqlite error: %s", err);
|
||
|
+ sqlite3_free(err);
|
||
|
+ }
|
||
|
+ sqlite3_finalize(stmt);
|
||
|
+ sqlite3_close(dbh);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Create a client record
|
||
|
+ *
|
||
|
+ * Returns a non-zero sqlite error code, or SQLITE_OK (aka 0)
|
||
|
+ */
|
||
|
+int
|
||
|
+sqlite_insert_client(const unsigned char *clname, const size_t namelen)
|
||
|
+{
|
||
|
+ int ret;
|
||
|
+ sqlite3_stmt *stmt = NULL;
|
||
|
+
|
||
|
+ ret = sqlite3_prepare_v2(dbh, "INSERT OR REPLACE INTO clients VALUES "
|
||
|
+ "(?, strftime('%s', 'now'));", -1,
|
||
|
+ &stmt, NULL);
|
||
|
+ if (ret != SQLITE_OK) {
|
||
|
+ xlog(L_ERROR, "%s: insert statement prepare failed: %s",
|
||
|
+ __func__, sqlite3_errmsg(dbh));
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sqlite3_bind_blob(stmt, 1, (const void *)clname, namelen,
|
||
|
+ SQLITE_STATIC);
|
||
|
+ if (ret != SQLITE_OK) {
|
||
|
+ xlog(L_ERROR, "%s: bind blob failed: %s", __func__,
|
||
|
+ sqlite3_errmsg(dbh));
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sqlite3_step(stmt);
|
||
|
+ if (ret == SQLITE_DONE)
|
||
|
+ ret = SQLITE_OK;
|
||
|
+ else
|
||
|
+ xlog(L_ERROR, "%s: unexpected return code from insert: %s",
|
||
|
+ __func__, sqlite3_errmsg(dbh));
|
||
|
+
|
||
|
+out_err:
|
||
|
+ xlog(D_GENERAL, "%s: returning %d", __func__, ret);
|
||
|
+ sqlite3_finalize(stmt);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+/* Remove a client record */
|
||
|
+int
|
||
|
+sqlite_remove_client(const unsigned char *clname, const size_t namelen)
|
||
|
+{
|
||
|
+ int ret;
|
||
|
+ sqlite3_stmt *stmt = NULL;
|
||
|
+
|
||
|
+ ret = sqlite3_prepare_v2(dbh, "DELETE FROM clients WHERE id==?", -1,
|
||
|
+ &stmt, NULL);
|
||
|
+ if (ret != SQLITE_OK) {
|
||
|
+ xlog(L_ERROR, "%s: statement prepare failed: %s",
|
||
|
+ __func__, sqlite3_errmsg(dbh));
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sqlite3_bind_blob(stmt, 1, (const void *)clname, namelen,
|
||
|
+ SQLITE_STATIC);
|
||
|
+ if (ret != SQLITE_OK) {
|
||
|
+ xlog(L_ERROR, "%s: bind blob failed: %s", __func__,
|
||
|
+ sqlite3_errmsg(dbh));
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sqlite3_step(stmt);
|
||
|
+ if (ret == SQLITE_DONE)
|
||
|
+ ret = SQLITE_OK;
|
||
|
+ else
|
||
|
+ xlog(L_ERROR, "%s: unexpected return code from delete: %d",
|
||
|
+ __func__, ret);
|
||
|
+
|
||
|
+out_err:
|
||
|
+ xlog(D_GENERAL, "%s: returning %d", __func__, ret);
|
||
|
+ sqlite3_finalize(stmt);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * Is the given clname in the clients table? If so, then update its timestamp
|
||
|
+ * and return success. If the record isn't present, or the update fails, then
|
||
|
+ * return an error.
|
||
|
+ */
|
||
|
+int
|
||
|
+sqlite_check_client(const unsigned char *clname, const size_t namelen)
|
||
|
+{
|
||
|
+ int ret;
|
||
|
+ sqlite3_stmt *stmt = NULL;
|
||
|
+
|
||
|
+ ret = sqlite3_prepare_v2(dbh, "SELECT count(*) FROM clients WHERE "
|
||
|
+ "id==?", -1, &stmt, NULL);
|
||
|
+ if (ret != SQLITE_OK) {
|
||
|
+ xlog(L_ERROR, "%s: unable to prepare update statement: %s",
|
||
|
+ __func__, sqlite3_errmsg(dbh));
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sqlite3_bind_blob(stmt, 1, (const void *)clname, namelen,
|
||
|
+ SQLITE_STATIC);
|
||
|
+ if (ret != SQLITE_OK) {
|
||
|
+ xlog(L_ERROR, "%s: bind blob failed: %s",
|
||
|
+ __func__, sqlite3_errmsg(dbh));
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sqlite3_step(stmt);
|
||
|
+ if (ret != SQLITE_ROW) {
|
||
|
+ xlog(L_ERROR, "%s: unexpected return code from select: %d",
|
||
|
+ __func__, ret);
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sqlite3_column_int(stmt, 0);
|
||
|
+ xlog(D_GENERAL, "%s: select returned %d rows", ret);
|
||
|
+ if (ret != 1) {
|
||
|
+ ret = -EACCES;
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+
|
||
|
+ sqlite3_finalize(stmt);
|
||
|
+ stmt = NULL;
|
||
|
+ ret = sqlite3_prepare_v2(dbh, "UPDATE OR FAIL clients SET "
|
||
|
+ "time=strftime('%s', 'now') WHERE id==?",
|
||
|
+ -1, &stmt, NULL);
|
||
|
+ if (ret != SQLITE_OK) {
|
||
|
+ xlog(L_ERROR, "%s: unable to prepare update statement: %s",
|
||
|
+ __func__, sqlite3_errmsg(dbh));
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sqlite3_bind_blob(stmt, 1, (const void *)clname, namelen,
|
||
|
+ SQLITE_STATIC);
|
||
|
+ if (ret != SQLITE_OK) {
|
||
|
+ xlog(L_ERROR, "%s: bind blob failed: %s",
|
||
|
+ __func__, sqlite3_errmsg(dbh));
|
||
|
+ goto out_err;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sqlite3_step(stmt);
|
||
|
+ if (ret == SQLITE_DONE)
|
||
|
+ ret = SQLITE_OK;
|
||
|
+ else
|
||
|
+ xlog(L_ERROR, "%s: unexpected return code from update: %s",
|
||
|
+ __func__, sqlite3_errmsg(dbh));
|
||
|
+
|
||
|
+out_err:
|
||
|
+ xlog(D_GENERAL, "%s: returning %d", __func__, ret);
|
||
|
+ sqlite3_finalize(stmt);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
+
|
||
|
+/*
|
||
|
+ * remove any client records that were not reclaimed since grace_start.
|
||
|
+ */
|
||
|
+int
|
||
|
+sqlite_remove_unreclaimed(time_t grace_start)
|
||
|
+{
|
||
|
+ int ret;
|
||
|
+ char *err = NULL;
|
||
|
+
|
||
|
+ ret = snprintf(buf, sizeof(buf), "DELETE FROM clients WHERE time < %ld",
|
||
|
+ grace_start);
|
||
|
+ if (ret < 0) {
|
||
|
+ return ret;
|
||
|
+ } else if ((size_t)ret >= sizeof(buf)) {
|
||
|
+ ret = -EINVAL;
|
||
|
+ return ret;
|
||
|
+ }
|
||
|
+
|
||
|
+ ret = sqlite3_exec(dbh, buf, NULL, NULL, &err);
|
||
|
+ if (ret != SQLITE_OK)
|
||
|
+ xlog(L_ERROR, "%s: delete failed: %s", __func__, err);
|
||
|
+
|
||
|
+ xlog(D_GENERAL, "%s: returning %d", __func__, ret);
|
||
|
+ sqlite3_free(err);
|
||
|
+ return ret;
|
||
|
+}
|
||
|
diff --git a/utils/nfsdcld/sqlite.h b/utils/nfsdcld/sqlite.h
|
||
|
new file mode 100644
|
||
|
index 0000000..c85e7d6
|
||
|
--- /dev/null
|
||
|
+++ b/utils/nfsdcld/sqlite.h
|
||
|
@@ -0,0 +1,29 @@
|
||
|
+/*
|
||
|
+ * Copyright (C) 2011 Red Hat, 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., 51 Franklin Street, Fifth Floor,
|
||
|
+ * Boston, MA 02110-1301, USA.
|
||
|
+ */
|
||
|
+
|
||
|
+#ifndef _SQLITE_H_
|
||
|
+#define _SQLITE_H_
|
||
|
+
|
||
|
+int sqlite_maindb_init(char *topdir);
|
||
|
+int sqlite_insert_client(const unsigned char *clname, const size_t namelen);
|
||
|
+int sqlite_remove_client(const unsigned char *clname, const size_t namelen);
|
||
|
+int sqlite_check_client(const unsigned char *clname, const size_t namelen);
|
||
|
+int sqlite_remove_unreclaimed(const time_t grace_start);
|
||
|
+
|
||
|
+#endif /* _SQLITE_H */
|
||
|
diff --git a/utils/nfsidmap/Makefile.am b/utils/nfsidmap/Makefile.am
|
||
|
index f837b91..c0675c4 100644
|
||
|
--- a/utils/nfsidmap/Makefile.am
|
||
|
+++ b/utils/nfsidmap/Makefile.am
|
||
|
@@ -4,6 +4,6 @@ man8_MANS = nfsidmap.man
|
||
|
|
||
|
sbin_PROGRAMS = nfsidmap
|
||
|
nfsidmap_SOURCES = nfsidmap.c
|
||
|
-nfsidmap_LDADD = -lnfsidmap -lkeyutils
|
||
|
+nfsidmap_LDADD = $(LIBNFSIDMAP) -lkeyutils ../../support/nfs/libnfs.a
|
||
|
|
||
|
MAINTAINERCLEANFILES = Makefile.in
|
||
|
diff --git a/utils/nfsidmap/nfsidmap.c b/utils/nfsidmap/nfsidmap.c
|
||
|
index 2d87381..cf11551 100644
|
||
|
--- a/utils/nfsidmap/nfsidmap.c
|
||
|
+++ b/utils/nfsidmap/nfsidmap.c
|
||
|
@@ -3,21 +3,33 @@
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
+#include <errno.h>
|
||
|
|
||
|
#include <pwd.h>
|
||
|
#include <grp.h>
|
||
|
#include <keyutils.h>
|
||
|
#include <nfsidmap.h>
|
||
|
|
||
|
-#include <syslog.h>
|
||
|
+#include <unistd.h>
|
||
|
+#include "xlog.h"
|
||
|
|
||
|
-/* gcc nfsidmap.c -o nfsidmap -l nfsidmap -l keyutils */
|
||
|
+int verbose = 0;
|
||
|
+char *usage="Usage: %s [-v] [-c || [-u|-g|-r key] || [-t timeout] key desc]";
|
||
|
|
||
|
#define MAX_ID_LEN 11
|
||
|
#define IDMAP_NAMESZ 128
|
||
|
#define USER 1
|
||
|
#define GROUP 0
|
||
|
|
||
|
+#define PROCKEYS "/proc/keys"
|
||
|
+#ifndef DEFAULT_KEYRING
|
||
|
+#define DEFAULT_KEYRING "id_resolver"
|
||
|
+#endif
|
||
|
+
|
||
|
+static int keyring_clear(char *keyring);
|
||
|
+
|
||
|
+#define UIDKEYS 0x1
|
||
|
+#define GIDKEYS 0x2
|
||
|
|
||
|
/*
|
||
|
* Find either a user or group id based on the name@domain string
|
||
|
@@ -36,9 +48,31 @@ int id_lookup(char *name_at_domain, key_serial_t key, int type)
|
||
|
rc = nfs4_group_owner_to_gid(name_at_domain, &gid);
|
||
|
sprintf(id, "%u", gid);
|
||
|
}
|
||
|
+ if (rc < 0)
|
||
|
+ xlog_err("id_lookup: %s: failed: %m",
|
||
|
+ (type == USER ? "nfs4_owner_to_uid" : "nfs4_group_owner_to_gid"));
|
||
|
|
||
|
- if (rc == 0)
|
||
|
+ if (rc == 0) {
|
||
|
rc = keyctl_instantiate(key, id, strlen(id) + 1, 0);
|
||
|
+ if (rc < 0) {
|
||
|
+ switch(rc) {
|
||
|
+ case -EDQUOT:
|
||
|
+ case -ENFILE:
|
||
|
+ case -ENOMEM:
|
||
|
+ /*
|
||
|
+ * The keyring is full. Clear the keyring and try again
|
||
|
+ */
|
||
|
+ rc = keyring_clear(DEFAULT_KEYRING);
|
||
|
+ if (rc == 0)
|
||
|
+ rc = keyctl_instantiate(key, id, strlen(id) + 1, 0);
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ if (rc < 0)
|
||
|
+ xlog_err("id_lookup: keyctl_instantiate failed: %m");
|
||
|
+ }
|
||
|
|
||
|
return rc;
|
||
|
}
|
||
|
@@ -57,6 +91,7 @@ int name_lookup(char *id, key_serial_t key, int type)
|
||
|
rc = nfs4_get_default_domain(NULL, domain, NFS4_MAX_DOMAIN_LEN);
|
||
|
if (rc != 0) {
|
||
|
rc = -1;
|
||
|
+ xlog_err("name_lookup: nfs4_get_default_domain failed: %m");
|
||
|
goto out;
|
||
|
}
|
||
|
|
||
|
@@ -67,39 +102,206 @@ int name_lookup(char *id, key_serial_t key, int type)
|
||
|
gid = atoi(id);
|
||
|
rc = nfs4_gid_to_name(gid, domain, name, IDMAP_NAMESZ);
|
||
|
}
|
||
|
+ if (rc < 0)
|
||
|
+ xlog_err("name_lookup: %s: failed: %m",
|
||
|
+ (type == USER ? "nfs4_uid_to_name" : "nfs4_gid_to_name"));
|
||
|
|
||
|
- if (rc == 0)
|
||
|
+ if (rc == 0) {
|
||
|
rc = keyctl_instantiate(key, &name, strlen(name), 0);
|
||
|
-
|
||
|
+ if (rc < 0)
|
||
|
+ xlog_err("name_lookup: keyctl_instantiate failed: %m");
|
||
|
+ }
|
||
|
out:
|
||
|
return rc;
|
||
|
}
|
||
|
+/*
|
||
|
+ * Clear all the keys on the given keyring
|
||
|
+ */
|
||
|
+static int keyring_clear(char *keyring)
|
||
|
+{
|
||
|
+ FILE *fp;
|
||
|
+ char buf[BUFSIZ];
|
||
|
+ key_serial_t key;
|
||
|
+
|
||
|
+ if (keyring == NULL)
|
||
|
+ keyring = DEFAULT_KEYRING;
|
||
|
+
|
||
|
+ if ((fp = fopen(PROCKEYS, "r")) == NULL) {
|
||
|
+ xlog_err("fopen(%s) failed: %m", PROCKEYS);
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ while(fgets(buf, BUFSIZ, fp) != NULL) {
|
||
|
+ if (strstr(buf, "keyring") == NULL)
|
||
|
+ continue;
|
||
|
+ if (strstr(buf, keyring) == NULL)
|
||
|
+ continue;
|
||
|
+ if (verbose) {
|
||
|
+ *(strchr(buf, '\n')) = '\0';
|
||
|
+ xlog_warn("clearing '%s'", buf);
|
||
|
+ }
|
||
|
+ /*
|
||
|
+ * The key is the first arugment in the string
|
||
|
+ */
|
||
|
+ *(strchr(buf, ' ')) = '\0';
|
||
|
+ sscanf(buf, "%x", &key);
|
||
|
+ if (keyctl_clear(key) < 0) {
|
||
|
+ xlog_err("keyctl_clear(0x%x) failed: %m", key);
|
||
|
+ fclose(fp);
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+ fclose(fp);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+ xlog_err("'%s' keyring was not found.", keyring);
|
||
|
+ fclose(fp);
|
||
|
+ return 1;
|
||
|
+}
|
||
|
+/*
|
||
|
+ * Revoke a key
|
||
|
+ */
|
||
|
+static int key_revoke(char *keystr, int keymask)
|
||
|
+{
|
||
|
+ FILE *fp;
|
||
|
+ char buf[BUFSIZ], *ptr;
|
||
|
+ key_serial_t key;
|
||
|
+ int mask;
|
||
|
+
|
||
|
+ xlog_syslog(0);
|
||
|
+
|
||
|
+ if ((fp = fopen(PROCKEYS, "r")) == NULL) {
|
||
|
+ xlog_err("fopen(%s) failed: %m", PROCKEYS);
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ while(fgets(buf, BUFSIZ, fp) != NULL) {
|
||
|
+ if (strstr(buf, "keyring") != NULL)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ mask = 0;
|
||
|
+ if ((ptr = strstr(buf, "uid:")) != NULL)
|
||
|
+ mask = UIDKEYS;
|
||
|
+ else if ((ptr = strstr(buf, "gid:")) != NULL)
|
||
|
+ mask = GIDKEYS;
|
||
|
+ else
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if ((keymask & mask) == 0)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (strncmp(ptr+4, keystr, strlen(keystr)) != 0)
|
||
|
+ continue;
|
||
|
+
|
||
|
+ if (verbose) {
|
||
|
+ *(strchr(buf, '\n')) = '\0';
|
||
|
+ xlog_warn("revoking '%s'", buf);
|
||
|
+ }
|
||
|
+ /*
|
||
|
+ * The key is the first arugment in the string
|
||
|
+ */
|
||
|
+ *(strchr(buf, ' ')) = '\0';
|
||
|
+ sscanf(buf, "%x", &key);
|
||
|
+
|
||
|
+ if (keyctl_revoke(key) < 0) {
|
||
|
+ xlog_err("keyctl_revoke(0x%x) failed: %m", key);
|
||
|
+ fclose(fp);
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ keymask &= ~mask;
|
||
|
+ if (keymask == 0) {
|
||
|
+ fclose(fp);
|
||
|
+ return 0;
|
||
|
+ }
|
||
|
+ }
|
||
|
+ xlog_err("'%s' key was not found.", keystr);
|
||
|
+ fclose(fp);
|
||
|
+ return 1;
|
||
|
+}
|
||
|
|
||
|
int main(int argc, char **argv)
|
||
|
{
|
||
|
char *arg;
|
||
|
char *value;
|
||
|
char *type;
|
||
|
- int rc = 1;
|
||
|
+ int rc = 1, opt;
|
||
|
int timeout = 600;
|
||
|
key_serial_t key;
|
||
|
+ char *progname, *keystr = NULL;
|
||
|
+ int clearing = 0, keymask = 0;
|
||
|
+
|
||
|
+ /* Set the basename */
|
||
|
+ if ((progname = strrchr(argv[0], '/')) != NULL)
|
||
|
+ progname++;
|
||
|
+ else
|
||
|
+ progname = argv[0];
|
||
|
|
||
|
- if (argc < 3)
|
||
|
+ xlog_open(progname);
|
||
|
+
|
||
|
+ while ((opt = getopt(argc, argv, "u:g:r:ct:v")) != -1) {
|
||
|
+ switch (opt) {
|
||
|
+ case 'u':
|
||
|
+ keymask = UIDKEYS;
|
||
|
+ keystr = strdup(optarg);
|
||
|
+ break;
|
||
|
+ case 'g':
|
||
|
+ keymask = GIDKEYS;
|
||
|
+ keystr = strdup(optarg);
|
||
|
+ break;
|
||
|
+ case 'r':
|
||
|
+ keymask = GIDKEYS|UIDKEYS;
|
||
|
+ keystr = strdup(optarg);
|
||
|
+ break;
|
||
|
+ case 'c':
|
||
|
+ clearing++;
|
||
|
+ break;
|
||
|
+ case 'v':
|
||
|
+ verbose++;
|
||
|
+ break;
|
||
|
+ case 't':
|
||
|
+ timeout = atoi(optarg);
|
||
|
+ break;
|
||
|
+ default:
|
||
|
+ xlog_warn(usage, progname);
|
||
|
+ break;
|
||
|
+ }
|
||
|
+ }
|
||
|
+
|
||
|
+ if (keystr) {
|
||
|
+ rc = key_revoke(keystr, keymask);
|
||
|
+ return rc;
|
||
|
+ }
|
||
|
+ if (clearing) {
|
||
|
+ xlog_syslog(0);
|
||
|
+ rc = keyring_clear(DEFAULT_KEYRING);
|
||
|
+ return rc;
|
||
|
+ }
|
||
|
+
|
||
|
+ xlog_stderr(0);
|
||
|
+ if ((argc - optind) != 2) {
|
||
|
+ xlog_err("Bad arg count. Check /etc/request-key.conf");
|
||
|
+ xlog_warn(usage, progname);
|
||
|
return 1;
|
||
|
+ }
|
||
|
+
|
||
|
+ if (verbose)
|
||
|
+ nfs4_set_debug(verbose, NULL);
|
||
|
+
|
||
|
+ key = strtol(argv[optind++], NULL, 10);
|
||
|
|
||
|
- arg = malloc(sizeof(char) * strlen(argv[2]) + 1);
|
||
|
- strcpy(arg, argv[2]);
|
||
|
+ arg = strdup(argv[optind]);
|
||
|
+ if (arg == NULL) {
|
||
|
+ xlog_err("strdup failed: %m");
|
||
|
+ return 1;
|
||
|
+ }
|
||
|
type = strtok(arg, ":");
|
||
|
value = strtok(NULL, ":");
|
||
|
|
||
|
- if (argc == 4) {
|
||
|
- timeout = atoi(argv[3]);
|
||
|
- if (timeout < 0)
|
||
|
- timeout = 0;
|
||
|
+ if (verbose) {
|
||
|
+ xlog_warn("key: 0x%lx type: %s value: %s timeout %ld",
|
||
|
+ key, type, value, timeout);
|
||
|
}
|
||
|
|
||
|
- key = strtol(argv[1], NULL, 10);
|
||
|
-
|
||
|
if (strcmp(type, "uid") == 0)
|
||
|
rc = id_lookup(value, key, USER);
|
||
|
else if (strcmp(type, "gid") == 0)
|
||
|
@@ -109,7 +311,7 @@ int main(int argc, char **argv)
|
||
|
else if (strcmp(type, "group") == 0)
|
||
|
rc = name_lookup(value, key, GROUP);
|
||
|
|
||
|
- /* Set timeout to 5 (600 seconds) minutes */
|
||
|
+ /* Set timeout to 10 (600 seconds) minutes */
|
||
|
if (rc == 0)
|
||
|
keyctl_set_timeout(key, timeout);
|
||
|
|
||
|
diff --git a/utils/nfsidmap/nfsidmap.man b/utils/nfsidmap/nfsidmap.man
|
||
|
index 2381908..3a3a523 100644
|
||
|
--- a/utils/nfsidmap/nfsidmap.man
|
||
|
+++ b/utils/nfsidmap/nfsidmap.man
|
||
|
@@ -5,6 +5,12 @@
|
||
|
.TH nfsidmap 5 "1 October 2010"
|
||
|
.SH NAME
|
||
|
nfsidmap \- The NFS idmapper upcall program
|
||
|
+.SH SYNOPSIS
|
||
|
+.B "nfsidmap [-v] [-t timeout] key desc"
|
||
|
+.br
|
||
|
+.B "nfsidmap [-v] [-c]"
|
||
|
+.br
|
||
|
+.B "nfsidmap [-v] [-u|-g|-r user]"
|
||
|
.SH DESCRIPTION
|
||
|
The file
|
||
|
.I /usr/sbin/nfsidmap
|
||
|
@@ -12,11 +18,36 @@ is used by the NFS idmapper to translate user and group ids into names, and to
|
||
|
translate user and group names into ids. Idmapper uses request-key to perform
|
||
|
the upcall and cache the result.
|
||
|
.I /usr/sbin/nfsidmap
|
||
|
-should only be called by request-key, and will perform the translation and
|
||
|
+is called by /sbin/request-key, and will perform the translation and
|
||
|
initialize a key with the resulting information.
|
||
|
.PP
|
||
|
-NFS_USE_NEW_IDMAPPER must be selected when configuring the kernel to use this
|
||
|
-feature.
|
||
|
+.I nfsidmap
|
||
|
+can also used to clear the keyring of all the keys or
|
||
|
+revoke one particular key.
|
||
|
+This is useful when the id mappings have failed to due
|
||
|
+to a lookup error resulting in all the cached uids/gids to be set
|
||
|
+to the user id nobody.
|
||
|
+.SH OPTIONS
|
||
|
+.TP
|
||
|
+.B -c
|
||
|
+Clear the keyring of all the keys.
|
||
|
+.TP
|
||
|
+.B -g user
|
||
|
+Revoke the gid key of the given user.
|
||
|
+.TP
|
||
|
+.B -r user
|
||
|
+Revoke both the uid and gid key of the given user.
|
||
|
+.TP
|
||
|
+.B -t timeout
|
||
|
+Set the expiration timer, in seconds, on the key.
|
||
|
+The default is 600 seconds (10 mins).
|
||
|
+.TP
|
||
|
+.B -u user
|
||
|
+Revoke the uid key of the given user.
|
||
|
+.TP
|
||
|
+.B -v
|
||
|
+Increases the verbosity of the output to syslog
|
||
|
+(can be specified multiple times).
|
||
|
.SH CONFIGURING
|
||
|
The file
|
||
|
.I /etc/request-key.conf
|
||
|
@@ -25,11 +56,13 @@ will need to be modified so
|
||
|
can properly direct the upcall. The following line should be added before a call
|
||
|
to keyctl negate:
|
||
|
.PP
|
||
|
-create id_resolver * * /usr/sbin/nfsidmap %k %d 600
|
||
|
+create id_resolver * * /usr/sbin/nfsidmap -t 600 %k %d
|
||
|
.PP
|
||
|
This will direct all id_resolver requests to the program
|
||
|
-.I /usr/sbin/nfsidmap
|
||
|
-The last parameter, 600, defines how many seconds into the future the key will
|
||
|
+.I /usr/sbin/nfsidmap.
|
||
|
+The
|
||
|
+.B -t 600
|
||
|
+defines how many seconds into the future the key will
|
||
|
expire. This is an optional parameter for
|
||
|
.I /usr/sbin/nfsidmap
|
||
|
and will default to 600 seconds when not specified.
|
||
|
@@ -48,9 +81,9 @@ You can choose to handle any of these individually, rather than using the
|
||
|
generic upcall program. If you would like to use your own program for a uid
|
||
|
lookup then you would edit your request-key.conf so it looks similar to this:
|
||
|
.PP
|
||
|
-create id_resolver uid:* * /some/other/program %k %d 600
|
||
|
+create id_resolver uid:* * /some/other/program %k %d
|
||
|
.br
|
||
|
-create id_resolver * * /usr/sbin/nfsidmap %k %d 600
|
||
|
+create id_resolver * * /usr/sbin/nfsidmap %k %d
|
||
|
.PP
|
||
|
Notice that the new line was added above the line for the generic program.
|
||
|
request-key will find the first matching line and run the corresponding program.
|
||
|
diff --git a/utils/osd_login/Makefile.am b/utils/osd_login/Makefile.am
|
||
|
new file mode 100644
|
||
|
index 0000000..adc493a
|
||
|
--- /dev/null
|
||
|
+++ b/utils/osd_login/Makefile.am
|
||
|
@@ -0,0 +1,12 @@
|
||
|
+## Process this file with automake to produce Makefile.in
|
||
|
+
|
||
|
+OSD_LOGIN_FILES= osd_login
|
||
|
+
|
||
|
+EXTRA_DIST= $(OSD_LOGIN_FILES)
|
||
|
+
|
||
|
+all-local: $(OSD_LOGIN_FILES)
|
||
|
+
|
||
|
+install-data-hook:
|
||
|
+ $(INSTALL) --mode 755 osd_login $(DESTDIR)/sbin/osd_login
|
||
|
+
|
||
|
+MAINTAINERCLEANFILES = Makefile.in
|
||
|
diff --git a/utils/osd_login/osd_login b/utils/osd_login/osd_login
|
||
|
new file mode 100644
|
||
|
index 0000000..08cd2d2
|
||
|
--- /dev/null
|
||
|
+++ b/utils/osd_login/osd_login
|
||
|
@@ -0,0 +1,118 @@
|
||
|
+#!/bin/bash
|
||
|
+#
|
||
|
+# osd_login : This script is part of the autologin feature
|
||
|
+# mandated by the pnfs-objects standard.
|
||
|
+# It is called from objlayoutdriver.ko in the kernel.
|
||
|
+
|
||
|
+# Copyright (C) 2012, Sachin Bhamare <sbhamare@panasas.com>
|
||
|
+# Copyright (C) 2012, Boaz Harrosh <bharrosh@panasas.com>
|
||
|
+#
|
||
|
+# This program is free software; you can redistribute it and/or modify
|
||
|
+# it under the terms of the GNU General Public License version 2 as
|
||
|
+# published by the Free Software Foundation.
|
||
|
+#
|
||
|
+# 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 02110-1301 USA
|
||
|
+
|
||
|
+umask 022
|
||
|
+
|
||
|
+PATH="/sbin:/usr/sbin:/bin:/usr/bin"
|
||
|
+
|
||
|
+iscsiadm=/sbin/iscsiadm
|
||
|
+
|
||
|
+PARENT_PID=$BASHPID
|
||
|
+WATCHDOG_TIMEOUT=15
|
||
|
+
|
||
|
+protocol=""
|
||
|
+portal=""
|
||
|
+uri=""
|
||
|
+osdname=""
|
||
|
+systemid=""
|
||
|
+
|
||
|
+usage()
|
||
|
+{
|
||
|
+ echo "Usage: $0 -u <URI> -o <OSDNAME> -s <SYSTEMID>"
|
||
|
+ echo "Options:"
|
||
|
+ echo "-u target uri e.g. iscsi://<ip>:<port>"
|
||
|
+ echo "-o osdname of the target OSD"
|
||
|
+ echo "-s systemid of the target OSD"
|
||
|
+}
|
||
|
+
|
||
|
+parse_cmdline()
|
||
|
+{
|
||
|
+ argc=$#
|
||
|
+ if [ $# -lt 3 ]; then
|
||
|
+ usage
|
||
|
+ exit 1
|
||
|
+ fi
|
||
|
+
|
||
|
+ # parse the input arguments
|
||
|
+ while getopts "u:o:s:" options; do
|
||
|
+ case $options in
|
||
|
+ u ) uri=$OPTARG;;
|
||
|
+ o ) osdname=$OPTARG;;
|
||
|
+ s ) systemid=$OPTARG;;
|
||
|
+ \? ) usage
|
||
|
+ exit 1;;
|
||
|
+ * ) usage
|
||
|
+ exit 1;;
|
||
|
+ esac
|
||
|
+ done
|
||
|
+
|
||
|
+ echo "-u : $uri"
|
||
|
+ echo "-o : $osdname"
|
||
|
+ echo "-s : $systemid"
|
||
|
+
|
||
|
+ protocol=`echo $uri | awk -F ':' '{print $1}'`
|
||
|
+ portal=`echo $uri | awk -F '//' '{print $2}'`
|
||
|
+}
|
||
|
+
|
||
|
+watchdog()
|
||
|
+{
|
||
|
+ timeout=$1
|
||
|
+ portal=$2
|
||
|
+
|
||
|
+ sleep $timeout
|
||
|
+ if kill -9 $PARENT_PID; then
|
||
|
+ echo "watchdog : Timed out (>$timeout seconds) while login into $portal" | logger -t "osd_login"
|
||
|
+ fi
|
||
|
+ echo "watchdog: exiting .."
|
||
|
+ exit 2
|
||
|
+}
|
||
|
+
|
||
|
+login_iscsi_osd()
|
||
|
+{
|
||
|
+ echo "login into: $1"
|
||
|
+ if ! $iscsiadm -m discovery -o nonpersistent -t sendtargets -p $1 --login; then
|
||
|
+ echo "$iscsiadm -m discovery -t sendtargets -p $1 --login returned error $? !"
|
||
|
+ sleep 1;
|
||
|
+ fi
|
||
|
+}
|
||
|
+
|
||
|
+echo "============= osd_login ========="
|
||
|
+echo "progname : $0"
|
||
|
+parse_cmdline "$@"
|
||
|
+echo "protocol: $protocol"
|
||
|
+echo "portal: $portal"
|
||
|
+
|
||
|
+watchdog $WATCHDOG_TIMEOUT $portal &
|
||
|
+watchdog_pid=$!
|
||
|
+
|
||
|
+case $protocol in
|
||
|
+iscsi)
|
||
|
+ login_iscsi_osd $portal |& logger -t "osd_login"
|
||
|
+ ;;
|
||
|
+*)
|
||
|
+ echo "Error: protocol $protocol not supported !" | logger -t "osd_login"
|
||
|
+ ;;
|
||
|
+esac
|
||
|
+
|
||
|
+kill -9 $watchdog_pid
|
||
|
+exit 0
|
||
|
diff --git a/utils/showmount/Makefile.am b/utils/showmount/Makefile.am
|
||
|
index 077b2c7..4ba5ead 100644
|
||
|
--- a/utils/showmount/Makefile.am
|
||
|
+++ b/utils/showmount/Makefile.am
|
||
|
@@ -7,7 +7,8 @@ sbin_PROGRAMS = showmount
|
||
|
showmount_SOURCES = showmount.c
|
||
|
showmount_LDADD = ../../support/export/libexport.a \
|
||
|
../../support/nfs/libnfs.a \
|
||
|
- ../../support/misc/libmisc.a
|
||
|
+ ../../support/misc/libmisc.a \
|
||
|
+ $(LIBTIRPC)
|
||
|
showmount_CPPFLAGS = $(AM_CPPFLAGS) $(CPPFLAGS) \
|
||
|
-I$(top_builddir)/support/export
|
||
|
|
||
|
diff --git a/utils/statd/Makefile.am b/utils/statd/Makefile.am
|
||
|
index 1744791..dc2bfc4 100644
|
||
|
--- a/utils/statd/Makefile.am
|
||
|
+++ b/utils/statd/Makefile.am
|
||
|
@@ -15,10 +15,10 @@ BUILT_SOURCES = $(GENFILES)
|
||
|
statd_LDADD = ../../support/nsm/libnsm.a \
|
||
|
../../support/nfs/libnfs.a \
|
||
|
../../support/misc/libmisc.a \
|
||
|
- $(LIBWRAP) $(LIBNSL) $(LIBCAP)
|
||
|
+ $(LIBWRAP) $(LIBNSL) $(LIBCAP) $(LIBTIRPC)
|
||
|
sm_notify_LDADD = ../../support/nsm/libnsm.a \
|
||
|
../../support/nfs/libnfs.a \
|
||
|
- $(LIBNSL) $(LIBCAP)
|
||
|
+ $(LIBNSL) $(LIBCAP) $(LIBTIRPC)
|
||
|
|
||
|
EXTRA_DIST = sim_sm_inter.x $(man8_MANS) COPYRIGHT simulate.c
|
||
|
|