]> git.decadent.org.uk Git - nfs-utils.git/commitdiff
Imported upstream 1.2.8
authorLuk Claes <luk@debian.org>
Fri, 10 May 2013 08:01:25 +0000 (10:01 +0200)
committerLuk Claes <luk@debian.org>
Fri, 10 May 2013 08:01:25 +0000 (10:01 +0200)
76 files changed:
.gitignore
ChangeLog [deleted file]
README
aclocal/kerberos5.m4
aclocal/libcap.m4
aclocal/librpcsecgss.m4
aclocal/libsqlite3.m4
aclocal/libtirpc.m4
aclocal/rpcsec_vers.m4
configure.ac
support/export/export.c
support/export/rmtab.c
support/export/xtab.c
support/include/exportfs.h
support/include/nfs/debug.h
support/include/nfs/nfs.h
support/include/nfslib.h
support/include/sockaddr.h
support/nfs/cacheio.c
support/nfs/exports.c
support/nsm/file.c
tests/nsm_client/Makefile.am
tools/nfs-iostat/nfs-iostat.py
tools/rpcdebug/Makefile.am
tools/rpcdebug/rpcdebug.c
utils/Makefile.am
utils/blkmapd/device-discovery.c
utils/blkmapd/device-process.c
utils/exportfs/exportfs.c
utils/gssd/Makefile.am
utils/gssd/context.c
utils/gssd/context.h
utils/gssd/context_heimdal.c
utils/gssd/context_lucid.c
utils/gssd/context_mit.c
utils/gssd/gss_util.c
utils/gssd/gss_util.h
utils/gssd/gssd.c
utils/gssd/gssd.h
utils/gssd/gssd.man
utils/gssd/gssd_main_loop.c
utils/gssd/gssd_proc.c
utils/gssd/krb5_util.c
utils/gssd/krb5_util.h
utils/gssd/svcgssd.c
utils/gssd/svcgssd_krb5.c
utils/gssd/svcgssd_proc.c
utils/idmapd/idmapd.c
utils/mount/Makefile.am
utils/mount/error.c
utils/mount/mount_libmount.c
utils/mount/network.c
utils/mount/nfs.man
utils/mount/nfsmount.conf.man
utils/mount/stropts.c
utils/mountd/auth.c
utils/mountd/cache.c
utils/mountd/mountd.c
utils/mountd/v4root.c
utils/nfsd/nfsd.c
utils/nfsd/nfsd.man
utils/nfsdcld/Makefile.am [deleted file]
utils/nfsdcld/nfsdcld.c [deleted file]
utils/nfsdcld/nfsdcld.man [deleted file]
utils/nfsdcld/sqlite.c [deleted file]
utils/nfsdcld/sqlite.h [deleted file]
utils/nfsdcltrack/Makefile.am [new file with mode: 0644]
utils/nfsdcltrack/nfsdcltrack.c [new file with mode: 0644]
utils/nfsdcltrack/nfsdcltrack.man [new file with mode: 0644]
utils/nfsdcltrack/sqlite.c [new file with mode: 0644]
utils/nfsdcltrack/sqlite.h [new file with mode: 0644]
utils/nfsidmap/nfsidmap.c
utils/osd_login/Makefile.am
utils/statd/rmtcall.c
utils/statd/sm-notify.c
utils/statd/statd.c

index 96f9750de089facd31cc2679fc056c3ab87fa5f4..51646375c31d0989f935b0cc627b7969a43c66c8 100644 (file)
@@ -3,7 +3,6 @@ aclocal.m4
 autom4te.cache
 compile
 config.guess
-config.log
 config.sub
 configure
 depcomp
@@ -20,6 +19,8 @@ aclocal/ltversion.m4
 aclocal/lt~obsolete.m4
 # files generated by configure
 confdefs.h
+config.cache
+config.log
 config.status
 conftest
 conftest.c
@@ -34,6 +35,7 @@ support/include/stamp-h1
 *.o
 .libs
 lib*.a
+test-driver
 tools/rpcgen/rpcgen
 tools/rpcdebug/rpcdebug
 utils/blkmapd/blkmapd
@@ -49,7 +51,7 @@ utils/rquotad/rquotad
 utils/rquotad/rquota.h
 utils/rquotad/rquota_xdr.c
 utils/showmount/showmount
-utils/nfsdcld/nfsdcld
+utils/nfsdcltrack/nfsdcltrack
 utils/statd/statd
 tools/locktest/testlk
 tools/getiversion/getiversion
diff --git a/ChangeLog b/ChangeLog
deleted file mode 100644 (file)
index 062ed67..0000000
--- a/ChangeLog
+++ /dev/null
@@ -1,1527 +0,0 @@
-commit 684cf4a5e0e84a1367690d7ecf4882cbdf4f3228
-Author: Prem Karat <prem.karat@linux.vnet.ibm.com>
-Date:   Thu Jun 30 07:29:20 2011 -0400
-
-    mount.nfs: Fix for the bug in v1.2.4 that breaks mount.nfs
-    
-    commit 30ebf047 failed to include these changes that breaks mount.nfs.
-    mount.nfs will continue to work fine with these changes
-    
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 057d2add27d1e05fed3ae7206ee043b6c1fda45a
-Author: NeilBrown <neilb@suse.de>
-Date:   Tue Jun 28 13:24:33 2011 -0400
-
-    Do not compile unnecessary files when the libmount code is enable
-    
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 30ebf04700654deddbf5f57d95e84ec69cea8610
-Author: Prem Karat <prem.karat@linux.vnet.ibm.com>
-Date:   Tue Jun 28 11:53:40 2011 -0400
-
-    mount.nfs: Don't hard code source and destination
-    
-    Currently souce and destination parameters should be passed as first and
-    second paramter while using mount.nfs. This patch allows them to be passed
-    anywhere while mounting.
-    
-    Current functionality is
-       mount.nfs source destn -o <options>
-    This patch will allow to do this
-       mount.nfs -o <options> source destn
-               or
-       mount.nfs -o <options> source -o <options> destn
-    
-    Signed-off-by: Prem Karat <prem.karat@linux.vnet.ibm.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit b3e190c4adfc9ec47567c968bd000d282d07b05e
-Author: NeilBrown <neilb@suse.de>
-Date:   Tue Jun 28 11:36:31 2011 -0400
-
-    mount: improve signal management when locking mtab
-    
-    As mount.nfs can run setuid it must be careful about how the user can
-    interact with in.  In particular it needs to ensure it does not
-    respond badly to any signals that the user might be able to generate.
-    
-    This is particularly an issue while updating /etc/mtab (when that is
-    not linked to /proc/mounts).  If the user can generate a signal which
-    kills mount.nfs while /etc/mtab is locked, then it will leave the file
-    locked, and could possibly corrupt mtab (particularly if 'ulimit 1'
-    was previously issued).
-    
-    Currently lock_mtab does set some handlers for signals, but not
-    enough.  It arranges for every signal up to (but not including)
-    SIGCHLD to cause mount.nfs to unlock mdadm promptly exit ... even if
-    the default behaviour would be to ignore the signal.  SIGALRM is
-    handled specially, and signals after SIGCHLD are left with their
-    default behaviour.  This includes for example SIGXFSZ which can be
-    generated by the user running "ulimit 1".
-    
-    So: change this so that some signals are left unchanged, SIGALRM is
-    handled as required, and all signals that the user can generate are
-    explicitly ignored.
-    
-    The remainder still cause mount.nfs to print a message, unlock mtab, and
-    exit.
-    
-    Signed-off-by: NeilBrown <neilb@suse.de>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit a99b7846e2abec5e26ab6b764b921d79559e0a0f
-Author: J. Bruce Fields <bfields@redhat.com>
-Date:   Mon Jun 27 12:31:07 2011 -0400
-
-    mountd: move fsidtype-specific code to helpers
-    
-    Now we can move these big switch statements into helper functions.
-    
-    Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit e6559fd0b7b63f5d152d33d598dc74d78df30ecb
-Author: J. Bruce Fields <bfields@redhat.com>
-Date:   Mon Jun 27 12:30:36 2011 -0400
-
-    mountd: gather fsid information into one struct
-    
-    A large part of nfsd_fh() is concerned with extracting
-    fsid-type-specific information from the fsid, then matching that
-    information with information from the export list and the filesystem.
-    
-    Moving all that information into one struct will allow some further
-    simplifications.
-    
-    Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 13a0a61d037f2cc09e7997a96ce5822b9317883b
-Author: J. Bruce Fields <bfields@redhat.com>
-Date:   Mon Jun 27 12:29:51 2011 -0400
-
-    mountd: prefer explicit subexports over crossmnt parents
-    
-    If a parent is exported with crossmnt, and if a child is also explicitly
-    exported, then both exports could potentially produce matches in this
-    loop; that isn't a bug.
-    
-    Instead of warning and ignoring the second match we find, we should
-    instead prefer whichever export is deeper in the tree, so that
-    children's options can override those of their parents.
-    
-    Reported-by: Olga Kornievskaia <aglo@citi.umich.edu>
-    Signed-off-by: J. Bruce Fields <bfields@redhat.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit f8d26c1db9a260597828685c7f62e1b29e78285f
-Author: Jeff Layton <jlayton@redhat.com>
-Date:   Wed Jun 22 15:52:55 2011 -0400
-
-    manpage: add section on character class matches to exports(5)
-    
-    Signed-off-by: Jeff Layton <jlayton@redhat.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit cb6676aea5bcfcbeaf868e53177eff51f4efe9a8
-Author: James Pearson <james-p@moving-picture.com>
-Date:   Wed Jun 22 15:51:47 2011 -0400
-
-    nfs-utils: remove possibly false statement from exports.man
-    
-    A very minor change suggested by J. Bruce Fields <bfields@fieldses.org>
-    to remove the statement that exporting to a single host or IP address is
-    the "most common format" - as it probably isn't.
-    
-    Signed-off-by: James Pearson <james-p@moving-picture.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 7d71ff8e3825a7f8c2d5c9b5b9344e95e7aa1392
-Author: Jeff Layton <jlayton@redhat.com>
-Date:   Wed Jun 22 15:51:02 2011 -0400
-
-    manpage: add info about IPv6 configuration to exports(5)
-    
-    The parts of the exports(5) manpage that discuss IP addressing neglect
-    IPv6 configuration. Update to include info on how to export to IPv6
-    subnets and addresses, and add a line demonstrating that to the EXAMPLE
-    section.
-    
-    Signed-off-by: Jeff Layton <jlayton@redhat.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 545ea1098089d6396d5a70111ec231c4de967faa
-Author: Benny Halevy <benny@tonian.com>
-Date:   Wed Jun 22 15:44:17 2011 -0400
-
-    nfsstat: reorder nfs4 stats for 2.6.39
-    
-    Signed-off-by: Benny Halevy <benny@tonian.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit c7ce7a4674ad446bee4dd3baf90155ce6b216816
-Author: Mi Jinlong <mijinlong@cn.fujitsu.com>
-Date:   Wed Jun 22 15:41:27 2011 -0400
-
-    libexport.a: fix using bad index for loop at cltsetup()
-    
-    In cltsetup(), when checking the address, use clp's naddr for index,
-    instead of  cltarg's naddr, which it's always zero there.
-    
-    Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit b50ad13298b3e9519a9bdecb8c146c9ecf39cef8
-Author: Jeff Layton <jlayton@redhat.com>
-Date:   Wed Jun 22 14:51:38 2011 -0400
-
-    nfs: fix host_reliable_addrinfo
-    
-    According to Neil Brown:
-    
-        The point of the word 'reliable' is to check that the name we get
-        really does belong to the host in question - ie that both the
-        forward and reverse maps agree.
-    
-        But the new code doesn't do that check at all.  Rather it simply
-        maps the address to a name, then discards the address and maps the
-        name back to a list of addresses and uses that list of addresses as
-        "where the request came from" for permission checking.
-    
-    This bug is exploitable via the following scenario and could allow an
-    attacker access to data that they shouldn't be able to access.
-    
-        Suppose you export a filesystem to some subnet or FQDN and also to a
-        wildcard or netgroup, and I know the details of this (maybe
-        showmount -e tells me) Suppose further that I can get IP packets to
-        your server..
-    
-        Then I create a reverse mapping for my ipaddress to a domain that I
-        own, say "black.hat.org", and a forward mapping from that domain to
-        my IP address, and one of your IP addresses.
-    
-        Then I try to mount your filesystem.  The IP address gets correctly
-        mapped to "black.hat.org" and then mapped to both my IP address and
-        your IP address.
-    
-        Then you search through all of your exports and find that one of the
-        addresses: yours - is allowed to access the filesystem.
-    
-        So you create an export based on the addrinfo you have which allows
-        my IP address the same access as your IP address.
-    
-    Fix this by instead using the forward lookup of the hostname just to
-    verify that the original address is in the list. Then do a numeric
-    lookup using the address and stick the hostname in the ai_canonname.
-    
-    Reviewed-by: NeilBrown <neilb@suse.de>
-    Signed-off-by: Jeff Layton <jlayton@redhat.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 7235a2164aabfd8dba1f7e1577047bda45053db0
-Author: James Pearson <james-p@moving-picture.com>
-Date:   Tue Jun 7 16:25:13 2011 -0400
-
-    exports: Clearly Defining Exports Priorities
-    
-    Added some verbiage to the exports(5) man page
-    that clearly explains the precedence around
-    how exports will work with regard to netgroups.
-    
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit a36f2437caffb23c68fdc0900544d59198bd52b6
-Author: Neil Brown <neilb@suse.de>
-Date:   Tue Jun 7 13:18:55 2011 -0400
-
-    Document "-n" for svcgssd
-    
-    The svcgssd man page doesn't mention the "-n" flag.
-    
-    Signed-off-by: NeilBrown <neilb@suse.de>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 40aed2c3fb5164195a9975ae7f15ebd4b992839d
-Author: Pavel Shilovsky <piastry@etersoft.ru>
-Date:   Tue Jun 7 13:18:13 2011 -0400
-
-    mountd: Fix missing varialble assignment in auth_unix_gid
-    
-    When we get into auth_unix_gid at the second time, groups_len
-    is not 0 and ngroups variable leave as 0. Then we use ngroups
-    in getgrouplist that fails in this case. This patch fixes it.
-    
-    Signed-off-by: Pavel Shilovsky <piastry@etersoft.ru>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 8935933dedcd820c2fb3dddff8b79fd5841dc217
-Author: Benny Halevy <bhalevy@panasas.com>
-Date:   Mon May 23 08:37:17 2011 -0400
-
-    nfsstat: reorder nfs4 stats for 2.6.38 and up
-    
-    match order in 2.6.38, 2.6.39 (-rc3) and development tree
-    while at it, get rid of obsolete ds_write and ds_commit
-    
-    Signed-off-by: Benny Halevy <bhalevy@panasas.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 27dcd8a775024160e741cce53e4a402eaac3501d
-Author: NeilBrown <neilb@suse.de>
-Date:   Mon May 23 08:23:51 2011 -0400
-
-    supress socket error when address family is not supported
-    
-    From: Suresh Jayaraman <sjayaraman@suse.de>
-    
-    It was observed that when ipv6 module was not loaded and cannot be auto-loaded,
-    when starting NFS server, the following error occurs:
-       "rpc.nfsd: unable to create inet6 TCP socket: errno 97 (Address
-       family not supported by protocol)"
-    
-    This is obviously a true message, but does not represent an "error" when ipv6
-    is not enabled.  Rather, it is an expected condition.  As such, it can be
-    confusing / misleading / distracting to display it in this scenario.
-    
-    This patch instead of throwing error when a socket call fails with
-    EAFNOSUPPORT, makes it as a NOTICE.
-    
-    Signed-off-by: Suresh Jayaraman <sjayaraman@suse.de>
-    Signed-off-by: Neil Brown <neilb@suse.de>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 7a802337bfc92d0b30fe94dbd0fa231990a26161
-Author: NeilBrown <neilb@suse.de>
-Date:   Mon May 23 08:19:57 2011 -0400
-
-    Remove risk of nfs_addmntent corrupting mtab
-    
-    nfs_addmntent is used to append directly to /etc/mtab.
-    If the write partially fail, e.g. due to RLIMIT_FSIZE,
-    truncate back to original size and return an error.
-    
-    See also https://bugzilla.redhat.com/show_bug.cgi?id=697975
-    (CVE-2011-1749) CVE-2011-1749 nfs-utils: mount.nfs fails to anticipate RLIMIT_FSIZE
-    
-    Signed-off-by: NeilBrown <neilb@suse.de>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 56f537535190d034039570bafd9a0de71b79b8f1
-Author: Ben Myers <bpm@sgi.com>
-Date:   Mon May 23 08:07:00 2011 -0400
-
-    exportfs: getexportent interprets -test-client- as default options
-    
-    With commit 1374c3861abdc66f3a1410e26cc85f86760b51dd Neil added a
-    -test-client- export to test the exportability of filesystems when exportfs
-    is run.  When using the old cache controls (i.e. /proc/fs/nfsd is not
-    mounted) exportfs will read /proc/fs/nfs/exports to process existing
-    exports and find these test client entries.  The dash at the beginning of
-    -test-client- will be cause getexportent to look for default options in the
-    rest of the string, which test-client- will not match:
-    
-    exportfs: /proc/fs/nfs/exports:1: unknown keyword "test-client-(rw"
-    
-    This patch resolves that problem (as Steve suggested) by not processing any
-    default options if we are reading the list of existing exports from the
-    kernel.  Default options are converted to individual exports by exportfs so
-    the kernel won't have any regardless.
-    
-    Signed-off-by: Ben Myers <bpm@sgi.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit c8e802c036a3f0fcd4481dae8b3ec09fb71f4118
-Author: Jim Rees <rees@umich.edu>
-Date:   Wed May 18 12:42:02 2011 -0400
-
-    Removed compilation warnings from mountd/cache.c
-    
-    Commit 5604b35a6 introduced a number of missing initializer
-    warnings that were missed. This patch removes those warnings.
-    
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 68f7938c85258a8c54b13169dcdeae61cc1bf286
-Author: Steve Dickson <steved@redhat.com>
-Date:   Tue Apr 26 13:32:35 2011 -0400
-
-    nfsstat: Output headings mislabled
-    
-    The badclnt and badauth headers were reversed
-    when the server side rpc stats (-s -o rpc) were
-    displayed.
-    
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 2e4a7e9b50a641dc8640a5dd911ee4a2f0b2c073
-Author: Steve Dickson <steved@redhat.com>
-Date:   Tue Apr 19 12:31:30 2011 -0400
-
-    rpc.svcgssd: Segmentation fault on error
-    
-    Commit 544ed73d introduced a regression that caused
-    rpc.svcgssd to seg fault on "Wrong principal in request"
-    errors in gss_accept_sec_context()
-    
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 5604b35a61e22930873ffc4e9971002f578e7978
-Author: Sean Finney <sean.finney@sonyericsson.com>
-Date:   Tue Apr 19 11:04:35 2011 -0400
-
-    nfs-utils: Increase the stdio file buffer size for procfs files
-    
-    Previously, when writing to /proc/net/rpc/*/channel, if a cache line
-    were larger than the default buffer size (likely 1024 bytes), mountd
-    and svcgssd would split writes into a number of buffer-sized writes.
-    Each of these writes would get an EINVAL error back from the kernel
-    procfs handle (it expects line-oriented input and does not account for
-    multiple/split writes), and no cache update would occur.
-    
-    When such behavior occurs, NFS clients depending on mountd to finish
-    the cache operation would block/hang, or receive EPERM, depending on
-    the context of the operation.  This is likely to happen if a user is a
-    member of a large (~100-200) number of groups.
-    
-    Instead, every fopen() on the procfs files in question is followed by
-    a call to setvbuf(), using a per-file dedicated buffer of
-    RPC_CHAN_BUF_SIZE length.
-    
-    Really, mountd should not be using stdio-style buffered file operations
-    on files in /proc to begin with.  A better solution would be to use
-    internally managed buffers and calls to write() instead of these stdio
-    calls, but that would be a more extensive change; so this is proposed
-    as a quick and not-so-dirty fix in the meantime.
-    
-    Signed-off-by: Sean Finney <sean.finney@sonyericsson.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 9274e94db85bac04e170414cb8e0f4be271cde90
-Author: Sean Finney <sean.finney@sonyericsson.com>
-Date:   Tue Apr 19 11:05:47 2011 -0400
-
-    mountd: Use a dynamic buffer for storing lists of gid's
-    
-    Previously, in auth_unix_gid, group lists were stored in an array of
-    hard-coded length 100, and in the situation that the group lists for a
-    particular call were too large, the array was swapped with a dynamically
-    allocated/freed buffer.  For environments where users are commonly in
-    a large number of groups, this isn't an ideal approach.
-    
-    Instead, use malloc/realloc to grow the list on an as-needed basis.
-    
-    Signed-off-by: Sean Finney <sean.finney@sonyericsson.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit a99269230a0e77e7bed4fa31c9547f0d61c7f206
-Author: Karel Zak <kzak@redhat.com>
-Date:   Wed Apr 6 12:39:21 2011 -0400
-
-    mount: add --enable-libmount-mount
-    
-    This patch allows to link mount.nfs with libmount from util-linux >=
-    v2.19. The new libmount based code is enabled by CONFIG_LIBMOUNT and
-    is stored in mount_libmount.c. The old code is not affected by this
-    change.
-    
-    The libmount does not have officially stable API yet, so the
-    --enable-libmount-mount is marked as experimental in the configure
-    help output.
-    
-    The ./configure option is the same as we use in util-linux to enable
-    support for libmount in mount(8).
-    
-    The addr= (and some other options necessary for remount/umount) are
-    stored to /etc/mtab or to /dev/.mount/utab. The utab file is *private*
-    libmount file. It's possible that some mount options (for example
-    user=) will be moved to kernel, so the utab will not be necessary.
-    
-    About libmount:
-    
-      * supports systems without and with regular /etc/mtab
-      * does not store VFS and FS mount options in userspace
-      * manages user= option and evaluate permissions
-      * parses VFS mount options and generate MS_* flags
-      * parses /etc/{fstab,mtab}, /proc/mounts or /proc/self/mountinfo
-      * long-term goal is to use the same code in all mount.<type> helpers
-    
-    Note, use
-    
-       LIBMOUNT_DEBUG=0xffff mount.nfs foo:/path /path
-    
-    to debug the library.
-    
-    On systems with util-linux v2.19 the findmnt(8) command uses libmount
-    to list all/selected mount points:
-    
-       $ findmnt /path
-       $ findmnt --mtab /path
-    
-    the --mtab appends userspace mount options (e.g. user=) to the output.
-    
-    CC: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Karel Zak <kzak@redhat.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit c01e5ca6179b8f5b041605d9bbd75a0f76812d54
-Author: Karel Zak <kzak@redhat.com>
-Date:   Wed Apr 6 11:36:40 2011 -0400
-
-    mount: move generic functions to utils.c and network.c
-    
-    Move generic code that could be shared between standard mount.nfs and
-    libmount version to utils.c and network.c.
-    
-    CC: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Karel Zak <kzak@redhat.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit d6c1b35c6b40243bfd6fba2591c9f8f2653078c0
-Author: Kevin Coffman <kwc@citi.umich.edu>
-Date:   Wed Apr 6 11:25:03 2011 -0400
-
-    nfs-utils: Add support to svcgssd to limit the negotiated enctypes
-    
-    Recent versions of Kerberos libraries negotiate and use
-    an "acceptor subkey".  This negotiation does not consider
-    that a service may have limited the encryption keys in its
-    keytab.  A patch (http://src.mit.edu/fisheye/changelog/krb5/?cs=24603)
-    has been added to the MIT Kerberos code to allow an application
-    to indicate that it wants to limit the encryption types negotiated.
-    (This functionality has been available on the client/initiator
-    side for a while.  The new patch adds this support to the
-    server/acceptor side.)
-    
-    This patch adds support to read a recently added nfsd
-    proc file to determine the encryption types supported by
-    the kernel and calls the function to limit encryption
-    types negotiated for the acceptor subkey.
-    
-    Signed-off-by: Kevin Coffman <kwc@citi.umich.edu>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 73840ef610accf4cf667427bc64805377c0d8394
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Wed Apr 6 10:53:57 2011 -0400
-
-    exports: add a configurable time-to-live for the kernel    cache entries
-    
-    From: Trond Myklebust <Trond.Myklebust@netapp.com>
-    
-    The fedfs ldap server will specify a ttl for its entries.
-    
-    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-    
-    This is a refactoring change only.  There should be no change in
-    behavior.
-    
-    Original patch had updates to utils/mountd/junctions.c, which no
-    longer exists.  These are not included here.
-    
-    Create a macro for the default cache TTL, which is used in several
-    places besides the export cache.
-    
-    Make e_ttl unsigned.
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 38e4c685410885a6d464ddd44eff4fd5e7f8459f
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Wed Apr 6 10:49:52 2011 -0400
-
-    statd: Remove vestigial "-w" option from man page synopsis
-    
-    The synopsis of rpc.statd in its man page lists "-w" as a valid
-    option.  There is currently no support in the source code for a "-w"
-    option.
-    
-    BugLink: https://bugzilla.linux-nfs.org/show_bug.cgi?id=199
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit b57cd77c13831051ad974ae027d96cd88a8d0c59
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Wed Apr 6 10:48:38 2011 -0400
-
-    mount.nfs: Don't leak socket in nfs_ca_sockname()
-    
-    Ensure the test socket is always closed before nfs_ca_sockname()
-    returns.  Otherwise it's orphaned.
-    
-    BugLink: https://bugzilla.linux-nfs.org/show_bug.cgi?id=197
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 502eef09d8050ffb87d394397c2780e1ef042d68
-Author: Steve Dickson <steved@redhat.com>
-Date:   Wed Apr 6 10:46:06 2011 -0400
-
-    Removed a warning from v4root.c
-    
-    v4root.c:176:9: warning: variable 'ret' set but not used
-    
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit c2fa189a0467c25666f014cf9ff2576a9f54d682
-Author: Steve Dickson <steved@redhat.com>
-Date:   Wed Apr 6 10:39:10 2011 -0400
-
-    Removed a warning from exportfs.c
-    
-    exportfs.c:280:29: warning: 'exp' may be used uninitialized in this function
-    
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit b98ae9df8c4904289c9390288325058b24caa423
-Author: Steve Dickson <steved@redhat.com>
-Date:   Wed Apr 6 10:36:30 2011 -0400
-
-    Removed a warning from conffile.c
-    
-    conffile.c:258:19: warning: 'j' may be used uninitialized in this function
-    
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 012e1a4bf2a002e8cd4d5be3478bfa20a91cbfed
-Author: Masatake YAMATO <yamato@redhat.com>
-Date:   Mon Mar 7 08:36:19 2011 -0500
-
-    Update man pages for /etc/exports.d
-    
-    Man page updates for /etc/exports.d.
-    
-    Signed-off-by: Masatake YAMATO <yamato@redhat.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit c7427b57e2be8ef0d57ad0618d4590c062b130f5
-Author: Masatake YAMATO <yamato@redhat.com>
-Date:   Mon Mar 7 08:18:51 2011 -0500
-
-    Read /etc/exports.d/*.export as extra export files
-    
-    This patch adding a capability to read /etc/exports.d/*.exports as
-    extra export files to exportfs.
-    
-    If one wants to add or remove an export entry in a script, currently
-    one may have to use sed or something tool for adding or removing the
-    line for the entry in /etc/exports file.
-    
-    With the patch, adding and removing an entry from a script is much
-    easier.
-    cat<<EOF... or mv can be used for adding. rm can be used for removing.
-    
-    Signed-off-by: Masatake YAMATO <yamato@redhat.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit edb9b7f2ab9806afb9af31eabeb505fe454c51df
-Author: Steve Dickson <steved@redhat.com>
-Date:   Sat Mar 5 16:17:01 2011 -0500
-
-    Cleaned up a warning in rpcdispatch.c
-    
-    rpcdispatch.c:40:20: warning: comparison between signed and unsigned
-    integer expressions
-    
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 930323817b61877d61fb8ef57229013daa2e6091
-Author: Steve Dickson <steved@redhat.com>
-Date:   Sat Mar 5 16:13:01 2011 -0500
-
-    mount: Remove MOUNT_CONFIG warnings
-    
-    The following changes are needed to remove compile warnings when
-    MOUNT_CONFIG is not defined
-    
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 3ef3dc8f1e87ba7a6eaa3c2a6965aff6c80ba414
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Thu Mar 3 17:26:33 2011 -0500
-
-    mount: Recognize zero as a valid value for the port= option
-    
-    While zero is not a valid IP port number, zero does represent a valid
-    value for "port=".  It means "query rpcbind to discover the actual
-    non-zero port number to use".  So the parsing functions that handle
-    "port=" should not flag zero as an invalid value.
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit b3a4dbfb61dad59829f5191d727267b2ea45937a
-Author: Mi Jinlong <mijinlong@cn.fujitsu.com>
-Date:   Wed Feb 9 11:29:42 2011 -0500
-
-    Gssd: modify wrong err message at handle_gssd_upcall
-    
-    Modify wrong err message at handle_gssd_upcall when
-    sscanf encryption types fail.
-    
-    Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 45e4597bd570ed40221f51887cde7d7f096f55e7
-Author: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
-Date:   Wed Feb 9 11:27:19 2011 -0500
-
-    Support AD style kerberos automatically in rpc.gss
-    
-    An Active Directory KDC will only grant a TGT for UPNs, getting
-    a TGT for SPNs is not possible:
-    
-    $ kinit -k host/ib5@ADS.ORCORP.CA
-    kinit: Client not found in Kerberos database while getting initial
-    credentials
-    
-    The correct thing to do for machine credentials is to get a TGT
-    for the computer UPN <HOSTNAME>$@REALM:
-    $ kinit -k IB5\$
-    $ klist
-    12/22/10 11:43:47  12/22/10 21:43:47  krbtgt/ADS.ORCORP.CA@ADS.ORCORP.CA
-    
-    Samba automatically creates /etc/krb5.keytab entry for the computer UPN,
-    this patch makes gssd_refresh_krb5_machine_credential prefer it above
-    the SPNs if it is present.
-    
-    The net result is that nfs client works automatically out of the box
-    if samba has been used to setup kerberos via 'net ads join' 'net ads
-    keytab create'
-    
-    Tested using Windows Server 2003 R2 as the AD server.
-    
-    Signed-off-by: Jason Gunthorpe <jgunthorpe@obsidianresearch.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 730f6986f86873513fa021a450eb55ccd0f2fbff
-Author: Steve Dickson <steved@redhat.com>
-Date:   Wed Jan 26 07:49:19 2011 -0500
-
-    Fixed segfault in rpc.mountd
-    
-    A unallocated piece of memory, instead of a NULL point, was being
-    used to initialize a ->next point in the mount link list which
-    caused a segfault after a few remote accesses via the showmount
-    command.
-    
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 544ed73d5ab27c1390833d5cf93b9585c151667d
-Author: Steve Dickson <steved@redhat.com>
-Date:   Fri Jan 14 10:12:28 2011 -0500
-
-    Improve debugging in svcgssd
-    
-    Added in gss_display_error() which translates the GSS error into the
-    actual GSS macro name. Currently only the translation of these errors
-    are logged. Since those translations are buried deep in the kerberos
-    library code, having the actual GSS macro name makes it easier to
-    follow the code.
-    
-    Moved the nfs4_init_name_mapping() call into main() so if debug is
-    enabled the DNS name and realms will be logged during start up.
-    
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 57be18b9ab08148a1cc9d5af588119885720be8b
-Author: Mi Jinlong <mijinlong@cn.fujitsu.com>
-Date:   Tue Jan 4 11:16:45 2011 -0500
-
-    libnsm.a: modify return value to false from 0 at nsm_drop_privileges()
-    
-    At nsm_drop_privileges(), for improving readability, unify
-    the return value.
-    
-    Signed-off-by: Mi Jinlong <mijinlong@cn.fujitsu.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 5c498280fd9353ded3ea169841079bdae23418e2
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Mon Dec 13 14:50:45 2010 -0500
-
-    libnsm.a: sm-notify sometimes ignores monitored hosts
-    
-    Monitored host information is stored in files under /var/lib/nfs.
-    When visiting entries in the monitored hosts directory, libnsm.a
-    examines the value of dirent.d_type to determine if an entry is a
-    regular file.
-    
-    According to readdir(3), the d_type field is not supported by all
-    file system types.  My root file system happens to be one where d_type
-    isn't supported.  Typical installations that use an ext-derived root
-    file system are not exposed to this issue, but those who use xfs, for
-    instance, are.
-    
-    On such file systems, not only are remote peers not notified of
-    reboots, but the NSM state number is never incremented.  A statd warm
-    restart would not re-monitor any hosts that were monitored before
-    the restart.
-    
-    When writing support/nsm/file.c, I copied the use of d_type from the
-    original statd code, so this has likely been an issue for some time.
-    
-    Replace the use of d_type in support/nsm/file.c with a call to
-    lstat(2).  It's extra code, but is guaranteed to work on all file
-    system types.
-    
-    Note there is a usage of d_type in gssd.  I'll let gssd and rpcpipefs
-    experts decide whether that's worth changing.
-    
-    Fix for:
-    
-      https://bugzilla.linux-nfs.org/show_bug.cgi?id=193
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 089df7c754d9ebab0a7b804f396626ac95fee2e6
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Mon Dec 13 14:47:42 2010 -0500
-
-    libnsm.a: Replace __attribute_noinline__
-    
-    Replace the __attribute_noinline__ form with
-    
-      __attribute__((__noinline__)).
-    
-    Even though the compiler didn't complain about __attribute_malloc__,
-    also replace those in order to maintain consistent style throughout the
-    source file.
-    
-    Fix for:
-    
-      https://bugzilla.linux-nfs.org/show_bug.cgi?id=194
-    
-    Reported-by: "Gabor Z. Papp" <gzp@papp.hu>
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 7869a76207d3f4b3bd4ab57b4a7a8807ac2ff0c6
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Mon Dec 13 14:36:15 2010 -0500
-
-    sm-notify: Make use of AI_NUMERICSERV conditional
-    
-    Gabor Papp reports nfs-utils-1.2.3 doesn't build on his system that
-    uses glibc-2.2.5:
-    
-    make[3]: Entering directory
-    `/home/gzp/src/nfs-utils-1.2.3/utils/statd'
-    gcc -DHAVE_CONFIG_H -I. -I../../support/include   -D_GNU_SOURCE -Wall
-       -Wextra -Wstrict-prototypes  -pipe -g -O2 -MT sm-notify.o -MD
-       -MP -MF .deps/sm-notify.Tpo -c -o sm-notify.o sm-notify.c
-       sm-notify.c: In function 'smn_bind_address':
-    sm-notify.c:247: error: 'AI_NUMERICSERV' undeclared (first use in this
-    function)
-    sm-notify.c:247: error: (Each undeclared identifier is reported only
-    once
-    sm-notify.c:247: error: for each function it appears in.)
-    make[3]: *** [sm-notify.o] Error 1
-    
-    According to the getaddrinfo(3) man page, AI_NUMERICSERV is available
-    only since glibc 2.3.4.  getaddrinfo(3) seems to convert strings
-    containing a number to the right port value without the use of
-    AI_NUMERICSERV, so I think we can survive on older glibc's without it.
-    It will allow admins to specify service names as well as port numbers
-    on those versions.
-    
-    There are uses of AI_NUMERICSERV in gssd and in nfs_svc_create().  The
-    one in nfs_svc_create() is behind HAVE_LIBTIRPC, and the other is a
-    issue only for those who want to deploy Kerberos -- likely in both
-    cases, a more modern glibc will be present.  I'm going to leave those
-    two.
-    
-    Fix for:
-    
-      https://bugzilla.linux-nfs.org/show_bug.cgi?id=195
-    
-    Reported-by: "Gabor Z. Papp" <gzp@papp.hu>
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit e8dbaddc8465dcd07b53f8e80a537703dd0248ca
-Author: Sid Moore <learnmost@gmail.com>
-Date:   Fri Dec 3 09:19:06 2010 -0500
-
-    rpc.mountd: Checking RPC Procedure ID before process it
-    
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 3c6973c595d62dc6452967d50ae8abe69f9f8bad
-Author: Mi Jinlong <mijinlong@cn.fujitsu.com>
-Date:   Mon Nov 29 10:59:10 2010 -0500
-
-    libnfs.a: fix a bug when parse section's arg
-    
-    When parsing section's arg at configure file, the pointer
-    should stop when fetch ']', and give the warning message.
-    
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 86f7be64cafd17d4a3f164603484eaedb4757431
-Author: Harshula Jayasuriya <harshula@redhat.com>
-Date:   Mon Nov 22 11:22:31 2010 -0500
-
-    nfs-utils: nfsstat: has_stats() does not function correctly for NFSv4 client stats
-    
-    The NFSv4 client procs/ops in "struct rpc_procinfo nfs4_procedures" is
-    used to generate the NFS client stats interface:
-    ------------------------------------------------------------
-    net 0 0 0 0
-    rpc 15 0 0
-    proc2 18 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
-    proc3 22 0 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 2 1 0
-    proc4 42 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 0 0
-    0 0 0
-    0 0 0 0 0 0 0
-    ------------------------------------------------------------
-    Note, for proc4, the number 42. That is the number of stats that follow
-    on the same line. Currently nfsstat's has_stats() relies on this number
-    to be equal to CLTPROC4_SZ. Unfortunately this is not the case. I have
-    changed has_stats() not to rely on these two values being equal. This
-    should also allow nfsstat to work with different kernel versions that
-    expose a different number of NFS client ops.
-    
-    * Fix has_stats()
-    * Stop print_clnt_list() printing server stats!
-    * Describe the option -3 and -4 completely in the nfsstat manpage.
-    
-    Signed-off-by: Harshula Jayasuriya <harshula@redhat.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 0868dcccb9a3bf3d022a32ff31311fe371484e77
-Author: Steve Dickson <steved@redhat.com>
-Date:   Sat Nov 20 15:01:21 2010 -0500
-
-    Enable nfsidmap to compile
-    
-    Only enable the compilation of nfsidmap when libnfsidmap support it.
-    
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 6f07548141e710767d425e119d9823691293771d
-Author: Bryan Schumaker <bjschuma@netapp.com>
-Date:   Fri Nov 19 12:01:10 2010 -0500
-
-    Add the new nfsidmap program
-    
-    This patch adds the nfsidmap program to nfs-utils.  This program is
-    called by the nfs idmapper through request-keys to map between
-    uid / user name and gid / group name.
-    
-    Signed-off-by: Bryan Schumaker <bjschuma@netapp.com>
-    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 409487978593de13ae36be0ee56d8111ad6b3319
-Author: Steve Dickson <steved@redhat.com>
-Date:   Mon Nov 22 11:33:37 2010 -0500
-
-    Removed a couple warnings from utils/mount/stropts.c
-    
-    stropts.c:740:6: warning: 'ret' may be used uninitialized in this function
-    stropts.c:653:6: warning: 'ret' may be used uninitialized in this function
-    
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit f4968a724c1d4162a8e2b9f6a19c460cc56c95f7
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Fri Oct 29 12:56:21 2010 -0400
-
-    nfs(5): Document remount behavior
-    
-    It appears that, for a long while, NFS "remount" mounts have
-    completely wiped the existing mount options in /etc/mtab for a given
-    mount point.  This is a problem for umount.nfs, since it reads its
-    options out of /etc/mtab to find out how to do the unmount.
-    
-    The mount(8) command provides the NFS mount subcommand with the mount
-    options to perform the remount.  There are four cases to consider:
-    
-      1. Both the device and mount directory are specified on the
-         command line, and the target mount point is in /etc/fstab
-    
-      2. Only one of the device and mount directory is specified on
-         the command line, and the target mount point is in
-         /etc/fstab
-    
-      3. Both the device and mount directory are specified on the
-         command line, and the target mount point is not in /etc/fstab
-    
-      4. Only one of the device and mount directory is specified on
-         the command line, and the target mount point is not in
-         /etc/fstab
-    
-    Currently only case 4 works correctly.  In that case, mount(8)
-    provides the correct set of mount options to the mount.nfs
-    subcommand and it can update /etc/mtab correctly.
-    
-    Cases 1 and 3 replace all mount options in /etc/mtab with the options
-    provided on the command line during a remount.  Case 2 replaces the
-    mount options in /etc/mtab with a mix of options from /etc/fstab and
-    /etc/mtab.
-    
-    Cases 1 and 3 are historical behavior.  Basically this is a formal
-    interface to allow administrators to replace the mount options in
-    /etc/mtab completely, instead of merging in new ones.  The present
-    patch documents that behavior in nfs(5), and provides best practice
-    for remounting NFS mount points.
-    
-    There are near-term plans to address case 2 by fixing mount(8)
-    (provided by utils-linux-ng in most distributions).
-    
-    This is a partial fix for:
-    
-      https://bugzilla.linux-nfs.org/show_bug.cgi?id=188
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 6d1a82b005994f759f2c847c0354413a24643da5
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Thu Oct 28 13:15:22 2010 -0400
-
-    nfs(5): Grammar and style fixes
-    
-    Clean up grammar and style issues introduced by recent updates.  Also,
-    I'm not certain inappropriate options are always ignored.
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit ab2cdb859f738a25e2567a2ec674cfa78a0a175d
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Thu Oct 28 13:13:19 2010 -0400
-
-    mount.nfs: mnt_freq and mnt_pass are always zero
-    
-    Clean up.
-    
-    No need to pass constant zeros to add_mtab() from its only call site.
-    Ensure that initialization of a struct mntent is consistent in both
-    places that it is done.
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit bc4a0c42570d5620cc1bb32428e16b9c9b5f3863
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Thu Oct 28 13:10:48 2010 -0400
-
-    mount.nfs: Fix memory leak in nfs_sys_mount()
-    
-    This appears to have been left behind by last year's adjustments to
-    how the extra_opts string is constructed.
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 1f237ac72e6f563908b350e11fd2bb866c003028
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Thu Oct 28 13:09:38 2010 -0400
-
-    mount: Fix compiler warning in nfs_parse_retry_option()
-    
-    stropts.c: In function nfs_parse_retry_option:
-    stropts.c:131: warning: conversion to unsigned int from long int may
-    alter its value
-    
-    Make it more clear what the second argument is for, and flag the
-    switch fallthrough case.
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 1ea2c3be33f2eb4630c5cdb78edf2bb670b294ab
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Thu Oct 28 12:12:12 2010 -0400
-
-    nfs-utils: Remove all uses of AI_ADDRCONFIG
-    
-    It was reported that, if only "lo" is up,
-    
-      mount.nfs 127.0.0.1:/export /mount
-    
-    fails with "Name or service not known".
-    
-    "man 3 getaddrinfo" says this:
-    
-      If hints.ai_flags includes the AI_ADDRCONFIG flag, then IPv4
-      addresses are returned in the list pointed to by res only if the
-      local system has at least one IPv4 address configured, and IPv6
-      addresses are only returned if the local system has at least
-      one IPv6 address configured.
-    
-    The man page oversimplifies here.  A review of glibc shows that
-    getaddrinfo(3) explicitly ignores loopback addresses when deciding
-    whether an IPv4 or IPv6 address is configured.
-    
-    This behavior around loopback is a problem not just for mount.nfs,
-    but also for RPC daemons that have to start up before a system's
-    networking is fully configured and started.  Given the history of
-    other problems with AI_ADDRCONFIG and the unpredictable behavior it
-    introduces, let's just remove it everywhere in nfs-utils.
-    
-    This fix addresses:
-    
-      https://bugzilla.linux-nfs.org/show_bug.cgi?id=191
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit f8e315543b7f1db7f37a4bfe8ede3020cef62868
-Author: Jeff Layton <jlayton@redhat.com>
-Date:   Thu Oct 28 09:18:33 2010 -0400
-
-    nfs-utils: fix default value for --enable-tirpc
-    
-    We need $enable_tirpc to be a tristate. 'yes' means that someone
-    explicitly requested building with tirpc. 'no' means that it was
-    explicitly disabled. Anything else means that no one specified a value.
-    
-    Fix it by setting the value to a blank string so that the default is
-    properly undefined.
-    
-    Reported-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Jeff Layton <jlayton@redhat.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit c62d756402509ca5d07c1fd4d2e5a9d78dc4171b
-Author: Steve Dickson <steved@redhat.com>
-Date:   Tue Oct 19 15:54:35 2010 -0400
-
-    Updated rpc.mountd man page
-    
-    Updated the rpc.mountd man page to no longer reference
-    v3 as the "newer" version and also mentioned v4 as
-    a supported version.
-    
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 79e9079e9af4e5c2aa1d77815df1147b26876eb8
-Author: Steve Dickson <steved@redhat.com>
-Date:   Tue Oct 19 15:54:04 2010 -0400
-
-    Cleared up the sync option in exportfs man page
-    
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 6f228ea26be06572de245aed5496aaa122cca5a8
-Author: Steve Dickson <steved@redhat.com>
-Date:   Fri Oct 15 17:20:28 2010 -0400
-
-    Removed duplicate entries in export man page
-    
-    The man page's paragraphs about "refer=" and "replicas="
-    each appear twice.
-    
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 849b7072a04975bb5da09245fbcacb0cb754a909
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Thu Oct 14 10:33:25 2010 -0400
-
-    mountd: Clear mountd registrations at start up
-    
-    Clear stale MNT registrations before mountd tries to create fresh
-    listeners, to ensure that mountd starts.  This is also what statd does.
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 93dcf64cc4a9e67f693aea35c8193428015f4a30
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Wed Oct 13 13:57:52 2010 -0400
-
-    behavior as file systems that use the monolithic /sbin/mount command.
-    See the MS_NOMTAB macro in utils-linux-ng/mount/mount.c.
-    
-    Note that mount(8) has MS_USERS and MS_USER in the "nomtab" category
-    as well, but mount.nfs needs to record those values so that unmounting
-    a user-mounted NFS file system can work.
-    
-    While we're here, fix some white space damage in fix_opts_string().
-    
-    This is a partial fix for:
-    
-      https://bugzilla.linux-nfs.org/show_bug.cgi?id=188
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit dc08c702a6c7f824f317af561f491635ee898a71
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Wed Oct 13 13:55:10 2010 -0400
-
-    umount.nfs: Distinguish between nfs4 and nfs mounts
-    
-    Neil Brown reports that umount.nfs is still confused by "-t nfs -o
-    vers=4" mounts.
-    
-    /etc/mtab can be confused.  /proc/mounts is authoritative on the
-    fstype of a mount.  Have umount.nfs consult it to determine which
-    mechanism to use for unmounting.  The code to read /proc/mounts was
-    lifted from the nfsstat command.
-    
-    The code introduced by this patch may look like belt-n-suspenders, but
-    we have two use cases to consider:
-    
-      1.  Old kernels don't support the "vers=4" mount option, so
-          umount.nfs must look for the "nfs4" fstype
-      2.  Upcoming kernels may eliminate support the "nfs4" fstype, so
-          umount.nfs must look for the "vers=4" mount option
-    
-    Thus this logic checks for "nfs4" first then looks for the NFS version
-    setting.
-    
-    Note that we could handle unmounting entirely in the kernel, but that
-    won't help older kernels that have this issue.
-    
-    See:
-      https://bugzilla.linux-nfs.org/show_bug.cgi?id=189
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 17962b82afb68ca8e6b0d3f432d36c6c7c4980ea
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Wed Oct 13 13:01:51 2010 -0400
-
-    mount.nfs: mountproto does not support RDMA
-    
-    Clean up.  Our client does not support the MNT protocol on RDMA.
-    
-    nfs_mount_protocol() isn't invoked for RDMA mounts (they are shunted
-    off before nfs_options2pmap() is invoked).  But in case it ever is,
-    it should return the expected response.
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 73c61fa5cd114fa6eae0e095724ed63aa66a4a6b
-Author: NeilBrown <neilb@suse.de>
-Date:   Wed Oct 13 12:08:41 2010 -0400
-
-    gcc complained:
-    
-    client.c: In function 'init_netmask6':
-    client.c:181:1: warning: no return statement in function returning
-    non-void
-    
-    and Suse' build system complained
-    
-    I: Program returns random data in a function
-    E: nfs-utils no-return-in-nonvoid-function client.c:181
-    
-    when I built without --enable-ipv6
-    
-    Reviewed-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: NeilBrown <neilb@suse.de>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 7e90281b88c05b01c61152b54a0cf2faec45b09c
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Wed Oct 13 12:02:32 2010 -0400
-
-    mount.nfs: Eliminate compiler warnings in utils/mount/network.c
-    
-    Clean up.
-    
-    network.c: In function get_socket:
-    network.c:431: warning: dereferencing type-punned pointer might break
-        strict-aliasing rules
-    
-    network.c: In function probe_bothports:
-    network.c:759: warning: dereferencing type-punned pointer might break
-        strict-aliasing rules
-    network.c:762: warning: dereferencing type-punned pointer might break
-        strict-aliasing rules
-    
-    network.c: In function nfs_probe_statd:
-    network.c:775: warning: dereferencing type-punned pointer might break
-        strict-aliasing rules
-    
-    network.c: In function nfs_call_umount:
-    network.c:904: warning: dereferencing type-punned pointer might break
-        strict-aliasing rules
-    
-    network.c: In function nfs_ca_sockname:
-    network.c:1106: warning: dereferencing type-punned pointer might break
-        strict-aliasing rules
-    network.c:1112: warning: dereferencing type-punned pointer might break
-        strict-aliasing rules
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 57385cf87790c0cbdfddfccdde66bd2c8da45923
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Wed Oct 13 11:59:30 2010 -0400
-
-    mount.nfs: Eliminate compiler warning in utils/mount/parse_opt.c
-    
-    parse_opt.c: In function po_rightmost:
-    parse_opt.c:517: warning: conversion to int from unsigned int may
-        change the sign of the result
-    
-    "i" contains the function's result value, so it should be defined as
-    the same type as the function's return type.
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 1ee10ef034cbca86da4df271ac4097a948e7ab59
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Wed Oct 13 11:58:27 2010 -0400
-
-    mount.nfs: Eliminate compiler warning in utils/mount/nfsumount.c
-    
-    Clean up.
-    
-    nfsumount.c:374: warning: ISO C forbids omitting the middle term of
-       a ?: expression
-    
-    This is also probably harmless, but let's make the code unambiguous.
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit e9c97e4f7075e563d7a442ca8298ac56bafba0d5
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Wed Oct 13 11:56:58 2010 -0400
-
-    mount.nfs: Eliminate compiler warning in utils/mount/nfsumount.c
-    
-    Clean up.
-    
-    nfsumount.c:265: warning: no previous prototype for nfsumount
-    
-    It's also a good idea if the compiler can ensure that the prototype
-    in nfsmount.h matches the actual function defined in nfsumount.c.
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit e2b6d9cbaf20df26dd371a715fce3ae158f37126
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Wed Oct 13 11:54:49 2010 -0400
-
-    mount.nfs: Eliminate compiler warnings in utils/mount/mount.c
-    
-    Clean up.
-    
-    mount.c: In function parse_opt:
-    mount.c:354: warning: conversion to size_t from int may change the
-        sign of the result
-    mount.c:354: warning: conversion to int from size_t may change the
-        sign of the result
-    mount.c:359: warning: conversion to size_t from int may change the
-        sign of the result
-    mount.c:359: warning: conversion to int from size_t may change the
-        sign of the result
-    mount.c: In function parse_opts:
-    mount.c:374: warning: conversion to int from size_t may change the
-        sign of the result
-    mount.c:377: warning: conversion to size_t from int may change the
-        sign of the result
-    
-    Character string lengths are usually size_t anyway.  We can easily
-    avoid the implicit type cast here.
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 013e8ec9ffb9f28f97e58299719023faf846a029
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Wed Oct 13 11:53:44 2010 -0400
-
-    mount.nfs: Eliminate compiler warning in utils/mount/mount.c
-    
-    Clean up.
-    
-    mount.c: At top level:
-    mount.c:324: warning: no previous prototype for ?mount_usage?
-    
-    mount_usage() has no callers outside of utils/mount/mount.c and no
-    prototype is provided in a header file.  Make it static.
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 47480475c99335c1203e81662f815b62573c19e8
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Wed Oct 13 11:50:57 2010 -0400
-
-    mount.nfs: Eliminate compiler warnings in utils/mount/version.h
-    
-    Clean up.
-    
-    In file included from mount.c:50:
-    version.h: In function linux_version_code:
-    version.h:48: warning: conversion to unsigned int from int may
-        change the sign of the result
-    version.h:48: warning: conversion to unsigned int from int may
-        change the sign of the result
-    version.h:48: warning: conversion to unsigned int from int may
-        change the sign of the result
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 00885013dccbe00f5cc4e19223cf18e85a8e616a
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Wed Oct 13 11:44:23 2010 -0400
-
-    mount.nfs: Eliminate compiler warning in utils/mount/mount.c
-    
-    Clean up.
-    
-    In file included from mount.c:41:
-    mount_config.h:35: warning: no previous prototype for mount_config_opts
-    
-    Functions defined in include files are usually declared as "static
-    inline," eliminating the need for a forward declaration.
-    
-    While I was there, I also fixed the macro that prevents including
-    mount_config.h multiple times, and fixed some white space damage.
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit ffa577350b03ddd421d455a8cd4cff86e3718264
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Wed Oct 13 11:38:22 2010 -0400
-
-    mount.nfs: Eliminate compiler warnings
-    
-    Clean up.
-    
-    fstab.c: In function ?lock_mtab?:
-    fstab.c:385: warning: declaration of ?errsv? shadows a previous local
-    fstab.c:367: warning: shadowed declaration is here
-    fstab.c:407: warning: declaration of ?errsv? shadows a previous local
-    fstab.c:367: warning: shadowed declaration is here
-    fstab.c:417: warning: declaration of ?tries? shadows a previous local
-    fstab.c:325: warning: shadowed declaration is here
-    fstab.c:422: warning: declaration of ?errsv? shadows a previous local
-    fstab.c:367: warning: shadowed declaration is here
-    
-    These are probably harmless.  Reusing a variable name, however, is a
-    little confusing to follow when reading the code.
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 5fe118b838254023d83424c5010ae73a91ec267d
-Author: Trond Myklebust <Trond.Myklebust@netapp.com>
-Date:   Wed Oct 13 11:27:21 2010 -0400
-
-    export: Ensure that we free struct exportent->e_uuid
-    
-    Currently, the exportent->e_uuid is initialised in
-    support/nfs/exports.c:parseopts(), but it is never freed.
-    
-    Also ensure that exportent->e_uuid is duplicated correctly in
-    dupexportent().
-    
-    Adjusted to account for the new export_free() helper.
-    
-    Also, e_uuid points to memory that is always allocated with strdup(3),
-    not with xstrdup().  Thus it must be freed via free(3) and not via
-    xfree().
-    
-    Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 656028f9925f5817c5a37565d27159973db84ec3
-Author: Chuck Lever <chuck.lever@oracle.com>
-Date:   Wed Oct 13 11:22:07 2010 -0400
-
-    libnfs.a: Allow multiple RPC listeners to share    listener port number
-    
-    Normally, when "-p" is not specified on the mountd command line, the
-    TI-RPC library chooses random port numbers for each listener.  If a
-    port number _is_ specified on the command line, all the listeners
-    will get the same port number, so SO_REUSEADDR needs to be set on
-    each socket.
-    
-    Thus we can't let TI-RPC create the listener sockets for us in this
-    case; we must create them ourselves and then set SO_REUSEADDR (and
-    other socket options) by hand.
-    
-    Different versions of the same RPC program have to share the same
-    listener and SVCXPRT, so we have to cache xprts we create, and re-use
-    them when additional requests for registration come from the
-    application.
-    
-    Though it doesn't look like it, this fix was "copied" from the legacy
-    rpc_init() function.  It's more complicated for TI-RPC, of course,
-    since a TI-RPC application can set up listeners with a nearly
-    arbitrary number of address families and socket types, not just the
-    two listeners that legacy RPC applications can set up (one for AF_INET
-    UDP and one for AF_INET TCP).
-    
-    See:
-      https://bugzilla.linux-nfs.org/show_bug.cgi?id=190
-    
-    Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 1296be71ebae4c0d7da61cc1077d97562d3bc549
-Author: Steve Dickson <steved@redhat.com>
-Date:   Wed Oct 13 10:17:58 2010 -0400
-
-    nfs-utils: Fixed typo in NFS man page
-    
-    Chuck pointed out there was a grammar typo in addition to the spelling
-    typo.  Here is a revised version of the patch.
-    
-    Signed-off-by: Jim Rees <rees@umich.edu>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 9afbdbad4436df6f7a5a501c6e4db04c3a5bbb08
-Author: Steve Dickson <steved@redhat.com>
-Date:   Wed Oct 13 10:15:12 2010 -0400
-
-    Fix style nits in atomicio.c
-    
-    Signed-off-by: Jim Rees <rees@umich.edu>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit c117b7a1f29db65d139824ba5bab2a58bf5609e2
-Author: Steve Dickson <steved@redhat.com>
-Date:   Wed Oct 13 10:09:53 2010 -0400
-
-    nfs-utils: Move common code into support
-    
-    There are several source files and headers present in the ./utils/idmapd
-    directory which are also usable in a doimapd daemon. Because of this we
-    move that support into the support directory such that it can be shared by
-    both daemons.
-    
-    Signed-off-by: Jim Rees <rees@umich.edu>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 8c217b9623c8304608196aeb2f7360abfdf987c8
-Author: Suresh Jayaraman <sjayaraman@suse.de>
-Date:   Wed Sep 29 07:14:14 2010 -0400
-
-    The kernel 2.6.37 has a add new mount option: local_lock.
-    Document the new option in the nfs(5) man page.
-    
-    Signed-off-by: Suresh Jayaraman <sjayaraman@suse.de>
-    Signed-off-by: Steve Dickson <steved@redhat.com>
-
-commit 554df6bc8456c6971c1c597f70d3b9131e4e5e11
-Author: Steve Dickson <steved@redhat.com>
-Date:   Tue Sep 28 08:24:16 2010 -0400
-
-    Revert "nfs-iostat.py: don't wait for an extra interval when given a count"
-    
-    This reverts commit 837796686ad8f9178c7b6855ada728a53ae511e3.
diff --git a/README b/README
index 348f5d4aa62087e8d5093ff1fc0e1d3e333c049c..7034c0091d49bb50b7b59dd3e4e8add933c6dbe9 100644 (file)
--- a/README
+++ b/README
@@ -1,4 +1,4 @@
-This is version 1.1.0 of nfs-utils, the Linux NFS utility package.
+This is nfs-utils, the Linux NFS userland utility package.
 
 
 0. PROJECT RESOURCES
@@ -108,31 +108,12 @@ scripts can be written to work correctly.
        the lock.
        rpc.statd is only needed for NFSv2 and NFSv3 support.
 
-   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
+   E/ rpc.nfsd
        Starting nfsd will automatically start lockd.  The nfs server
        will now be fully active and respond to any requests from
        clients.
        
-   G/ sm-notify
+   F/ 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
index 7574e2d3b380b22b63908f8586d22e76a2a5bc5b..0bf35d3fddb57a0b977a87f90063cf4500ce377d 100644 (file)
@@ -32,6 +32,8 @@ AC_DEFUN([AC_KERBEROS_V5],[
     if test "$K5CONFIG" != ""; then
       KRBCFLAGS=`$K5CONFIG --cflags`
       KRBLIBS=`$K5CONFIG --libs`
+      GSSKRB_CFLAGS=`$K5CONFIG --cflags gssapi`
+      GSSKRB_LIBS=`$K5CONFIG --libs gssapi`
       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 \
@@ -92,6 +94,8 @@ AC_DEFUN([AC_KERBEROS_V5],[
     AC_DEFINE(HAVE_SET_ALLOWABLE_ENCTYPES, 1, [Define this if the Kerberos GSS library supports gss_krb5_set_allowable_enctypes]), ,$KRBLIBS)
   AC_CHECK_LIB($gssapi_lib, gss_krb5_ccache_name,
     AC_DEFINE(HAVE_GSS_KRB5_CCACHE_NAME, 1, [Define this if the Kerberos GSS library supports gss_krb5_ccache_name]), ,$KRBLIBS)
+  AC_CHECK_LIB($gssapi_lib, gss_krb5_free_lucid_sec_context,
+    AC_DEFINE(HAVE_GSS_KRB5_FREE_LUCID_SEC_CONTEXT, 1, [Define this if the Kerberos GSS library supports gss_krb5_free_lucid_sec_context]), ,$KRBLIBS)
 
   dnl Check for newer error message facility
   AC_CHECK_LIB($gssapi_lib, krb5_get_error_message,
@@ -111,5 +115,7 @@ AC_DEFUN([AC_KERBEROS_V5],[
   AC_SUBST([KRBCFLAGS])
   AC_SUBST([KRBLDFLAGS])
   AC_SUBST([K5VERS])
+  AC_SUBST([GSSKRB_CFLAGS])
+  AC_SUBST([GSSKRB_LIBS])
 
 ])
index 68a624c141725eaddcc6645d8d9bf65391281a7c..f8a0ed178cccbc0639b7ab02343d7054e4015faa 100644 (file)
@@ -3,7 +3,7 @@ dnl
 AC_DEFUN([AC_LIBCAP], [
 
   dnl look for prctl
-  AC_CHECK_FUNC([prctl], , )
+  AC_CHECK_FUNC([prctl], , AC_MSG_ERROR([prctl syscall is not available]))
 
   AC_ARG_ENABLE([caps],
     [AS_HELP_STRING([--disable-caps], [Disable capabilities support])])
index d1dd25e2f0f63ead394e47008c31c59ce6970cf9..e8331413870183e1540554f7feefbbf1ae035398 100644 (file)
@@ -14,6 +14,8 @@ AC_DEFUN([AC_LIBRPCSECGSS], [
                  [AC_DEFINE([HAVE_AUTHGSS_SET_DEBUG_LEVEL], 1,
                  [Define to 1 if you have the `authgss_set_debug_level' function.])])
 
+    AC_DEFINE([HAVE_AUTHGSS_FREE_PRIVATE_DATA], 1,
+             [Define to 1 if your rpcsec library provides authgss_free_private_data,])
   fi
 
 ])dnl
index 73d1e4627a01bf979add7a62ec1db3ae084768e5..8c38993cbba8c23a0c21c8d3a9cd0ad24093c833 100644 (file)
@@ -29,5 +29,4 @@ AC_DEFUN([AC_SQLITE3_VERS], [
     LIBS="$saved_LIBS"])
 
   AC_MSG_RESULT($libsqlite3_cv_is_recent)
-  AM_CONDITIONAL(CONFIG_SQLITE3, [test "$libsqlite3_cv_is_recent" = "yes"])
 ])dnl
index 19b8361794854d0b616db61891e68aa1074cc7d3..b8233640837676d5b09db16d9910e54e4e1ab6ee 100644 (file)
@@ -23,6 +23,13 @@ AC_DEFUN([AC_LIBTIRPC], [
                  fi])
   fi
 
+  if test "$enable_tirpc" != "no"; then
+
+    dnl Check if library contains authgss_free_private_data
+    AC_CHECK_LIB([tirpc], [authgss_free_private_data], [have_free_private_data=yes],
+                       [have_free_private_data=no])
+  fi
+
   if test "$enable_tirpc" != "no"; then
     dnl also must have the headers installed where we expect
     dnl look for headers; add -I compiler option if found
@@ -42,6 +49,10 @@ AC_DEFUN([AC_LIBTIRPC], [
     AC_DEFINE([HAVE_LIBTIRPC], 1,
               [Define to 1 if you have and wish to use libtirpc.])
     LIBTIRPC="-ltirpc"
+    if test "$have_free_private_data" = "yes"; then
+      AC_DEFINE([HAVE_AUTHGSS_FREE_PRIVATE_DATA], 1,
+             [Define to 1 if your rpcsec library provides authgss_free_private_data,])
+    fi
   else
     LIBTIRPC=""
   fi
index 8218372ceaeef3591a064c5bd906fffade0cd578..11d2f18cb241c51c31c5921a342e5ec935e7de84 100644 (file)
@@ -1,7 +1,12 @@
 dnl Checks librpcsec version
 AC_DEFUN([AC_RPCSEC_VERSION], [
 
-  PKG_CHECK_MODULES([GSSGLUE], [libgssglue >= 0.3])
+  AC_ARG_WITH([gssglue],
+       [AC_HELP_STRING([--with-gssglue], [Use libgssglue for GSS support])])
+  if test x"$with_gssglue" = x"yes"; then
+    PKG_CHECK_MODULES([GSSGLUE], [libgssglue >= 0.3])
+    AC_CHECK_LIB([gssglue], [gss_set_allowable_enctypes])
+  fi
 
   dnl TI-RPC replaces librpcsecgss
   if test "$enable_tirpc" = no; then
index 86e8308a4c097a9238b472bbfa9cd2f9cd102b9c..7a885be48af1067d58540ad83a5f5ea945c3535c 100644 (file)
@@ -1,6 +1,6 @@
 dnl Process this file with autoconf to produce a configure script.
 dnl
-AC_INIT([linux nfs-utils],[1.2.6],[linux-nfs@vger.kernel.org],[nfs-utils])
+AC_INIT([linux nfs-utils],[1.2.8],[linux-nfs@vger.kernel.org],[nfs-utils])
 AC_CANONICAL_BUILD([])
 AC_CANONICAL_HOST([])
 AC_CONFIG_MACRO_DIR(aclocal)
@@ -76,7 +76,8 @@ AC_ARG_ENABLE(nfsv41,
        enable_nfsv41=yes)
        if test "$enable_nfsv41" = yes; then
                if test "$enable_nfsv4" != yes; then
-                       AC_MSG_ERROR([NFS v4.1 is enabled but NFS v4 is not. Use --disable-nfsv41])
+                       AC_MSG_WARN([NFS v4 is not enabled. Disabling NFS v4.1])
+                       enable_nfsv41=no
                fi
                BLKMAPD=blkmapd
        else
@@ -185,11 +186,11 @@ 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")
+AC_ARG_ENABLE(nfsdcltrack,
+       [AC_HELP_STRING([--enable-nfsdcltrack],
+                       [enable NFSv4 clientid tracking programs @<:@default=yes@:>@])],
+       enable_nfsdctrack=$enableval,
+       enable_nfsdcltrack="yes")
 
 dnl Check for TI-RPC library and headers
 AC_LIBTIRPC
@@ -269,31 +270,33 @@ if test "$enable_nfsv4" = yes; then
   dnl Check for sqlite3
   AC_SQLITE3_VERS
 
-  if test "$enable_nfsdcld" = "yes"; then
+  if test "$enable_nfsdcltrack" = "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
+               AC_MSG_ERROR([Cannot find header needed for nfsdcltrack]))
+
+    case $libsqlite3_cv_is_recent in
+    yes) ;;
+    unknown)
+      dnl do not fail when cross-compiling
+      AC_MSG_WARN([assuming sqlite is at least v3.3]) ;;
+    *)
+      AC_MSG_ERROR([nfsdcltrack requires sqlite-devel]) ;;
+    esac
   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
+else
+  enable_nfsdcltrack="no"
 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]))
+  AC_CHECK_HEADER(sys/inotify.h, , AC_MSG_ERROR([Cannot find header file sys/inotify.h]))
 fi
 
 dnl enable nfsidmap when its support by libnfsidmap
+AM_CONDITIONAL(CONFIG_NFSDCLTRACK, [test "$enable_nfsdcltrack" = "yes" ])
 AM_CONDITIONAL(CONFIG_NFSIDMAP, [test "$ac_cv_header_keyutils_h$ac_cv_lib_nfsidmap_nfs4_owner_to_uid" = "yesyes"])
 
 
@@ -343,6 +346,20 @@ if test "$enable_gss" = yes; then
   dnl Invoked after AC_KERBEROS_V5; AC_LIBRPCSECGSS needs to have KRBLIBS set
   AC_LIBRPCSECGSS
 
+  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
+    if test x"$GSSGLUE_LIBS" != x""; then
+      GSSAPI_CFLAGS=$GSSGLUE_CFLAGS
+      GSSAPI_LIBS=$GSSGLUE_LIBS
+    else
+      GSSAPI_CFLAGS=$GSSKRB_CFLAGS
+      GSSAPI_LIBS=$GSSKRB_LIBS
+    fi
+    AC_SUBST([GSSAPI_CFLAGS])
+    AC_SUBST([GSSAPI_LIBS])
+  fi
 fi
 
 dnl Check for IPv6 support
@@ -356,7 +373,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 nfs-plugin.h])
+                 ifaddrs.h nfs-plugin.h libio.h])
 
 dnl *************************************************************
 dnl Checks for typedefs, structures, and compiler characteristics
@@ -394,7 +411,7 @@ AC_CHECK_FUNCS([alarm atexit dup2 fdatasync ftruncate getcwd \
                gethostbyaddr gethostbyname gethostname getmntent \
                getnameinfo getrpcbyname getifaddrs \
                gettimeofday hasmntopt inet_ntoa innetgr memset mkdir pathconf \
-               realpath rmdir select socket strcasecmp strchr strdup \
+               ppoll realpath rmdir select socket strcasecmp strchr strdup \
                strerror strrchr strtol strtoul sigprocmask])
 
 
@@ -478,7 +495,7 @@ AC_CONFIG_FILES([
        tools/nfs-iostat/Makefile
        utils/Makefile
        utils/blkmapd/Makefile
-       utils/nfsdcld/Makefile
+       utils/nfsdcltrack/Makefile
        utils/exportfs/Makefile
        utils/gssd/Makefile
        utils/idmapd/Makefile
index 4fda30a799169e232e42b56d63579e315748c3c9..6b1d0459b78806f959348d8cf0665f3f06311f0b 100644 (file)
@@ -31,16 +31,21 @@ static nfs_export *
                export_allowed_internal(const struct addrinfo *ai,
                                const char *path);
 
+void
+exportent_release(struct exportent *eep)
+{
+       xfree(eep->e_squids);
+       xfree(eep->e_sqgids);
+       free(eep->e_mountpoint);
+       free(eep->e_fslocdata);
+       free(eep->e_uuid);
+       xfree(eep->e_hostname);
+}
+
 static void
 export_free(nfs_export *exp)
 {
-       xfree(exp->m_export.e_squids);
-       xfree(exp->m_export.e_sqgids);
-       free(exp->m_export.e_mountpoint);
-       free(exp->m_export.e_fslocdata);
-       free(exp->m_export.e_uuid);
-
-       xfree(exp->m_export.e_hostname);
+       exportent_release(&exp->m_export);
        xfree(exp);
 }
 
@@ -357,7 +362,7 @@ strtoint(char *str)
 static int 
 export_hash(char *str)
 {
-       int num = strtoint(str);
+       unsigned int num = strtoint(str);
 
        return num % HASH_TABLE_SIZE;
 }
index 31c0f50419193e7426c7ccf7bb7eb67045a213a8..d16b3b33b692dd421814590c2dcaddeeab0dd957 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * support/export/rmntab.c
+ * support/export/rmtab.c
  *
- * Interface to the rmnt file.
+ * Interface to the rmtab file.
  *
  */
 
@@ -12,7 +12,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <errno.h>
-#include "xmalloc.h"
+
 #include "misc.h"
 #include "nfslib.h"
 #include "exportfs.h"
index 2a43193c35a15345c053b005e46cf45eadabfe1b..e953071ea901dfc0c9ff0c03946acf98471f11a1 100644 (file)
@@ -14,7 +14,7 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
-#include "xmalloc.h"
+
 #include "nfslib.h"
 #include "exportfs.h"
 #include "xio.h"
index 99916e515af13691cbada636b10664673b7600dd..1fbf7542e9b875b25e062ffb00e7731314e11f79 100644 (file)
@@ -141,6 +141,7 @@ nfs_export *                        export_find(const struct addrinfo *ai,
 nfs_export *                   export_allowed(const struct addrinfo *ai,
                                                const char *path);
 nfs_export *                   export_create(struct exportent *, int canonical);
+void                           exportent_release(struct exportent *);
 void                           export_freeall(void);
 int                            export_export(nfs_export *);
 int                            export_unexport(nfs_export *);
@@ -176,6 +177,7 @@ struct export_features {
 };
 
 struct export_features *get_export_features(void);
+void fix_pseudoflavor_flags(struct exportent *ep);
 
 /* Record export error.  */
 extern int export_errno;
index dbec5bab7a5562c24a2c9127de456ae18e339cf9..80a1b1ddffe0d66b211322079a3388a3385f3638 100644 (file)
@@ -79,6 +79,7 @@ enum {
 #define NFSDBG_FSCACHE         0x0800
 #define NFSDBG_PNFS                    0x1000
 #define NFSDBG_PNFS_LD         0x2000
+#define NFSDBG_STATE           0x4000
 #define NFSDBG_ALL             0xFFFF
 
 #endif /* _NFS_DEBUG_H */
index 320880ea7bc9c9f38d2f8a9dfa44ca744ed19c9d..174c2dde0fc09c7d74219fadf744cf3e046fd1e1 100644 (file)
@@ -52,6 +52,7 @@ struct nfs_fh_old {
 #define NFSCTL_UDPISSET(_cltbits)     ((_cltbits) & NFSCTL_UDPBIT) 
 #define NFSCTL_TCPISSET(_cltbits)     ((_cltbits) & NFSCTL_TCPBIT) 
 
+#define NFSCTL_VERSET(_cltbits, _v)   ((_cltbits) |= (1 << ((_v) - 1))) 
 #define NFSCTL_UDPSET(_cltbits)       ((_cltbits) |= NFSCTL_UDPBIT)
 #define NFSCTL_TCPSET(_cltbits)       ((_cltbits) |= NFSCTL_TCPBIT)
 
index 73f3c20cd6c9db64096cd9d53192cd799b9755a8..f210a068f2214682b1dfe28f02494166c7fed0ee 100644 (file)
@@ -164,6 +164,7 @@ void qword_adduint(char **bpp, int *lp, unsigned int n);
 void qword_addeol(char **bpp, int *lp);
 int qword_get_uint(char **bpp, unsigned int *anint);
 void qword_printuint(FILE *f, unsigned int num);
+void qword_printtimefrom(FILE *f, unsigned int num);
 
 void closeall(int min);
 
index 9af25439c7d59c60ec5fca8bcafad53be185a5ff..a1c30f9bea5da5746f80668c5463ba11fc2e7f6f 100644 (file)
 #ifndef NFS_UTILS_SOCKADDR_H
 #define NFS_UTILS_SOCKADDR_H
 
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_LIBIO_H
 #include <libio.h>
+#endif
 #include <stdbool.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
@@ -193,16 +199,14 @@ compare_sockaddr6(const struct sockaddr *sa1, const struct sockaddr *sa2)
 {
        const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1;
        const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2;
+       const struct in6_addr *saddr1 = &sin1->sin6_addr;
+       const struct in6_addr *saddr2 = &sin2->sin6_addr;
 
-       if ((IN6_IS_ADDR_LINKLOCAL((char *)&sin1->sin6_addr) &&
-            IN6_IS_ADDR_LINKLOCAL((char *)&sin2->sin6_addr)) ||
-           (IN6_IS_ADDR_SITELOCAL((char *)&sin1->sin6_addr) &&
-            IN6_IS_ADDR_SITELOCAL((char *)&sin2->sin6_addr)))
+       if (IN6_IS_ADDR_LINKLOCAL(saddr1) && IN6_IS_ADDR_LINKLOCAL(saddr2))
                if (sin1->sin6_scope_id != sin2->sin6_scope_id)
                        return false;
 
-       return IN6_ARE_ADDR_EQUAL((char *)&sin1->sin6_addr,
-                                       (char *)&sin2->sin6_addr);
+       return IN6_ARE_ADDR_EQUAL(saddr1, saddr2);
 }
 #else  /* !IPV6_SUPPORTED */
 static inline _Bool
index 9bad8e61f827e814592f539d51fc2784547b939a..61e07a8257c961a7815ac0ae3816352cf14cfba5 100644 (file)
@@ -153,15 +153,25 @@ void qword_printuint(FILE *f, unsigned int num)
        fprintf(f, "%u ", num);
 }
 
+void qword_printtimefrom(FILE *f, unsigned int num)
+{
+       fprintf(f, "%lu ", time(0) + num);
+}
+
 int qword_eol(FILE *f)
 {
        int err;
 
-       fprintf(f,"\n");
-       err = fflush(f);
-       if (err) {
-               xlog_warn("qword_eol: fflush failed: errno %d (%s)",
+       err = fprintf(f,"\n");
+       if (err < 0) {
+               xlog_warn("qword_eol: fprintf failed: errno %d (%s)",
                            errno, strerror(errno));
+       } else {
+               err = fflush(f);
+               if (err) {
+                       xlog_warn("qword_eol: fflush failed: errno %d (%s)",
+                                 errno, strerror(errno));
+               }
        }
        /*
         * We must send one line (and one line only) in a single write
index 84a2b08b1f3c69e1b9765e1e42a7aa90c9b3d082..dea040f1006eb830f13a031d1a55dce80555867d 100644 (file)
@@ -469,7 +469,7 @@ static void clearflags(int mask, unsigned int active, struct exportent *ep)
  * ensure that the export flags agree with the flags on each
  * pseudoflavor:
  */
-static void fix_pseudoflavor_flags(struct exportent *ep)
+void fix_pseudoflavor_flags(struct exportent *ep)
 {
        struct export_features *ef;
        struct sec_entry *p;
@@ -643,6 +643,8 @@ bad_option:
                        cp++;
        }
 
+       if (ep->e_secinfo[0].flav == NULL)
+               secinfo_addflavor(find_flavor("sys"), ep);
        fix_pseudoflavor_flags(ep);
        ep->e_squids = squids;
        ep->e_sqgids = sqgids;
index 5dd52c1e2640fb2effd07004c8902700811aa775..4711c2cd79134f7f1c036c5cda8298aeb53af9a6 100644 (file)
@@ -338,10 +338,10 @@ nsm_is_default_parentdir(void)
  *
  * Returns true if successful, or false if some error occurred.
  */
+#ifdef HAVE_SYS_CAPABILITY_H
 static _Bool
 nsm_clear_capabilities(void)
 {
-#ifdef HAVE_SYS_CAPABILITY_H
        cap_t caps;
 
        caps = cap_from_text("cap_net_bind_service=ep");
@@ -357,10 +357,60 @@ nsm_clear_capabilities(void)
        }
 
        (void)cap_free(caps);
-#endif
        return true;
 }
 
+#define CAP_BOUND_PROCFILE "/proc/sys/kernel/cap-bound"
+static _Bool
+prune_bounding_set(void)
+{
+#ifdef PR_CAPBSET_DROP
+       int ret;
+       unsigned long i;
+       struct stat st;
+
+       /*
+        * Prior to kernel 2.6.25, the capabilities bounding set was a global
+        * value. Check to see if /proc/sys/kernel/cap-bound exists and don't
+        * bother to clear the bounding set if it does.
+        */
+       ret = stat(CAP_BOUND_PROCFILE, &st);
+       if (!ret) {
+               xlog(L_WARNING, "%s exists. Not attempting to clear "
+                               "capabilities bounding set.",
+                               CAP_BOUND_PROCFILE);
+               return true;
+       } else if (errno != ENOENT) {
+               /* Warn, but attempt to clear the bounding set anyway. */
+               xlog(L_WARNING, "Unable to stat %s: %m", CAP_BOUND_PROCFILE);
+       }
+
+       /* prune the bounding set to nothing */
+       for (i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >=0 ; ++i) {
+               ret = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
+               if (ret) {
+                       xlog(L_ERROR, "Unable to prune capability %lu from "
+                                     "bounding set: %m", i);
+                       return false;
+               }
+       }
+#endif /* PR_CAPBSET_DROP */
+       return true;
+}
+#else /* !HAVE_SYS_CAPABILITY_H */
+static _Bool
+nsm_clear_capabilities(void)
+{
+       return true;
+}
+
+static _Bool
+prune_bounding_set(void)
+{
+       return true;
+}
+#endif /* HAVE_SYS_CAPABILITY_H */
+
 /**
  * nsm_drop_privileges - drop root privileges
  * @pidfd: file descriptor of a pid file
@@ -393,6 +443,9 @@ nsm_drop_privileges(const int pidfd)
                return false;
        }
 
+       if (!prune_bounding_set())
+               return false;
+
        if (st.st_uid == 0) {
                xlog_warn("Running as root.  "
                        "chown %s to choose different user", nsm_base_dirname);
index 4bf0a4566df7d324a60b34e7571448e588613edc..4c153460dfb47cb1dde42aeb747aeae0885b3a11 100644 (file)
@@ -13,7 +13,7 @@ nsm_client_SOURCES = $(GENFILES) nsm_client.c
 
 BUILT_SOURCES = $(GENFILES)
 nsm_client_LDADD = ../../support/nfs/libnfs.a \
-                  ../../support/nsm/libnsm.a $(LIBCAP)
+                  ../../support/nsm/libnsm.a $(LIBCAP) $(LIBTIRPC)
 
 if CONFIG_RPCGEN
 RPCGEN = $(top_builddir)/tools/rpcgen/rpcgen
index d9096321f59aae9eb131340cb8a5cff5b38d7ccd..dfbef87ed06c67b05d5e53fa14481c6f9d502a59 100644 (file)
@@ -3,6 +3,8 @@
 """Emulate iostat for NFS mount points using /proc/self/mountstats
 """
 
+from __future__ import print_function
+
 __copyright__ = """
 Copyright (C) 2005, Chuck Lever <cel@netapp.com>
 
@@ -201,9 +203,9 @@ class DeviceData:
         result = DeviceData()
 
         # copy self into result
-        for key, value in self.__nfs_data.iteritems():
+        for key, value in self.__nfs_data.items():
             result.__nfs_data[key] = value
-        for key, value in self.__rpc_data.iteritems():
+        for key, value in self.__rpc_data.items():
             result.__rpc_data[key] = value
 
         # compute the difference of each item in the list
@@ -233,9 +235,9 @@ class DeviceData:
             client_bytes_read = float(nfs_stats['serverreadbytes'] - nfs_stats['directreadbytes'])
             ratio = ((app_bytes_read - client_bytes_read) * 100) / app_bytes_read
 
-            print
-            print 'app bytes: %f  client bytes %f' % (app_bytes_read, client_bytes_read)
-            print 'Data cache hit ratio: %4.2f%%' % ratio
+            print()
+            print('app bytes: %f  client bytes %f' % (app_bytes_read, client_bytes_read))
+            print('Data cache hit ratio: %4.2f%%' % ratio)
 
     def __print_attr_cache_stats(self, sample_time):
         """Print attribute cache efficiency stats
@@ -255,13 +257,13 @@ class DeviceData:
             data_invalidates = float(nfs_stats['datainvalidates'])
             attr_invalidates = float(nfs_stats['attrinvalidates'])
 
-            print
-            print '%d inode revalidations, hitting in cache %4.2f%% of the time' % \
-                (revalidates, ratio)
-            print '%d open operations (mandatory GETATTR requests)' % opens
+            print()
+            print('%d inode revalidations, hitting in cache %4.2f%% of the time' % \
+                (revalidates, ratio))
+            print('%d open operations (mandatory GETATTR requests)' % opens)
             if getattr_ops != 0:
-                print '%4.2f%% of GETATTRs resulted in data cache invalidations' % \
-                   ((data_invalidates * 100) / getattr_ops)
+                print('%4.2f%% of GETATTRs resulted in data cache invalidations' % \
+                   ((data_invalidates * 100) / getattr_ops))
 
     def __print_dir_cache_stats(self, sample_time):
         """Print directory stats
@@ -277,13 +279,13 @@ class DeviceData:
         lookups = nfs_stats['vfslookup']
         getdents = nfs_stats['vfsreaddir']
 
-        print
-        print '%d open operations (pathname lookups)' % opens
-        print '%d dentry revalidates and %d vfs lookup requests' % \
-            (dentry_revals, lookups),
-        print 'resulted in %d LOOKUPs on the wire' % lookup_ops
-        print '%d vfs getdents calls resulted in %d READDIRs on the wire' % \
-            (getdents, readdir_ops)
+        print()
+        print('%d open operations (pathname lookups)' % opens)
+        print('%d dentry revalidates and %d vfs lookup requests' % \
+            (dentry_revals, lookups))
+        print('resulted in %d LOOKUPs on the wire' % lookup_ops)
+        print('%d vfs getdents calls resulted in %d READDIRs on the wire' % \
+            (getdents, readdir_ops))
 
     def __print_page_stats(self, sample_time):
         """Print page cache stats
@@ -297,33 +299,33 @@ class DeviceData:
         vfswritepages = nfs_stats['vfswritepages']
         pages_written = nfs_stats['writepages']
 
-        print
-        print '%d nfs_readpage() calls read %d pages' % \
-            (vfsreadpage, vfsreadpage)
-        print '%d nfs_readpages() calls read %d pages' % \
-            (vfsreadpages, pages_read - vfsreadpage),
+        print()
+        print('%d nfs_readpage() calls read %d pages' % \
+            (vfsreadpage, vfsreadpage))
+        print('%d nfs_readpages() calls read %d pages' % \
+            (vfsreadpages, pages_read - vfsreadpage))
         if vfsreadpages != 0:
-            print '(%.1f pages per call)' % \
-                (float(pages_read - vfsreadpage) / vfsreadpages)
+            print('(%.1f pages per call)' % \
+                (float(pages_read - vfsreadpage) / vfsreadpages))
         else:
-            print
-
-        print
-        print '%d nfs_updatepage() calls' % nfs_stats['vfsupdatepage']
-        print '%d nfs_writepage() calls wrote %d pages' % \
-            (vfswritepage, vfswritepage)
-        print '%d nfs_writepages() calls wrote %d pages' % \
-            (vfswritepages, pages_written - vfswritepage),
+            print()
+
+        print()
+        print('%d nfs_updatepage() calls' % nfs_stats['vfsupdatepage'])
+        print('%d nfs_writepage() calls wrote %d pages' % \
+            (vfswritepage, vfswritepage))
+        print('%d nfs_writepages() calls wrote %d pages' % \
+            (vfswritepages, pages_written - vfswritepage))
         if (vfswritepages) != 0:
-            print '(%.1f pages per call)' % \
-                (float(pages_written - vfswritepage) / vfswritepages)
+            print('(%.1f pages per call)' % \
+                (float(pages_written - vfswritepage) / vfswritepages))
         else:
-            print
+            print()
 
         congestionwaits = nfs_stats['congestionwait']
         if congestionwaits != 0:
-            print
-            print '%d congestion waits' % congestionwaits
+            print()
+            print('%d congestion waits' % congestionwaits)
 
     def __print_rpc_op_stats(self, op, sample_time):
         """Print generic stats for one RPC op
@@ -351,15 +353,15 @@ class DeviceData:
             exe_per_op = 0.0
 
         op += ':'
-        print '%s' % op.lower().ljust(15),
-        print '  ops/s\t\t   kB/s\t\t  kB/op\t\tretrans\t\tavg RTT (ms)\tavg exe (ms)'
+        print('%s' % op.lower().ljust(15))
+        print('  ops/s\t\t   kB/s\t\t  kB/op\t\tretrans\t\tavg RTT (ms)\tavg exe (ms)')
 
-        print '\t\t%7.3f' % (ops / sample_time),
-        print '\t%7.3f' % (kilobytes / sample_time),
-        print '\t%7.3f' % kb_per_op,
-        print ' %7d (%3.1f%%)' % (retrans, retrans_percent),
-        print '\t%7.3f' % rtt_per_op,
-        print '\t%7.3f' % exe_per_op
+        print('\t\t%7.3f' % (ops / sample_time))
+        print('\t%7.3f' % (kilobytes / sample_time))
+        print('\t%7.3f' % kb_per_op)
+        print(' %7d (%3.1f%%)' % (retrans, retrans_percent))
+        print('\t%7.3f' % rtt_per_op)
+        print('\t%7.3f' % exe_per_op)
 
     def ops(self, sample_time):
         sends = float(self.__rpc_data['rpcsends'])
@@ -384,14 +386,14 @@ class DeviceData:
         else:
             backlog = 0.0
 
-        print
-        print '%s mounted on %s:' % \
-            (self.__nfs_data['export'], self.__nfs_data['mountpoint'])
-        print
+        print()
+        print('%s mounted on %s:' % \
+            (self.__nfs_data['export'], self.__nfs_data['mountpoint']))
+        print()
 
-        print '   op/s\t\trpc bklog'
-        print '%7.2f' % (sends / sample_time), 
-        print '\t%7.2f' % backlog
+        print('   op/s\t\trpc bklog')
+        print('%7.2f' % (sends / sample_time))
+        print('\t%7.2f' % backlog)
 
         if which == 0:
             self.__print_rpc_op_stats('READ', sample_time)
@@ -424,7 +426,7 @@ def parse_stats_file(filename):
     ms_dict = dict()
     key = ''
 
-    f = file(filename)
+    f = open(filename)
     for line in f.readlines():
         words = line.split()
         if len(words) == 0:
@@ -494,7 +496,7 @@ def list_nfs_mounts(givenlist, mountstats):
             if stats.is_nfs_mountpoint():
                 list += [device]
     else:
-        for device, descr in mountstats.iteritems():
+        for device, descr in mountstats.items():
             stats = DeviceData()
             stats.parse_stats(descr)
             if stats.is_nfs_mountpoint():
@@ -527,7 +529,7 @@ client are listed.
         usage="usage: %prog [ <interval> [ <count> ] ] [ <options> ] [ <mount point> ]",
         description=mydescription,
         version='version %s' % Iostats_version)
-    parser.set_defaults(which=0, sort=False, list=sys.maxint)
+    parser.set_defaults(which=0, sort=False, list=sys.maxsize)
 
     statgroup = OptionGroup(parser, "Statistics Options",
                             'File I/O is displayed unless one of the following is specified:')
@@ -572,29 +574,29 @@ client are listed.
             try:
                 interval = int(arg)
             except:
-                print 'Illegal <interval> value %s' % arg
+                print('Illegal <interval> value %s' % arg)
                 return
             if interval > 0:
                 interval_seen = True
             else:
-                print 'Illegal <interval> value %s' % arg
+                print('Illegal <interval> value %s' % arg)
                 return
         elif not count_seen:
             try:
                 count = int(arg)
             except:
-                print 'Ilegal <count> value %s' % arg
+                print('Ilegal <count> value %s' % arg)
                 return
             if count > 0:
                 count_seen = True
             else:
-                print 'Illegal <count> value %s' % arg
+                print('Illegal <count> value %s' % arg)
                 return
 
     # make certain devices contains only NFS mount points
     devices = list_nfs_mounts(origdevices, mountstats)
     if len(devices) == 0:
-        print 'No NFS mount points were found'
+        print('No NFS mount points were found')
         return
 
 
@@ -616,7 +618,7 @@ client are listed.
             # we need to recheck the devices list when reparsing
             devices = list_nfs_mounts(origdevices,mountstats)
             if len(devices) == 0:
-                print 'No NFS mount points were found'
+                print('No NFS mount points were found')
                 return
             count -= 1
     else: 
@@ -630,7 +632,7 @@ client are listed.
             # we need to recheck the devices list when reparsing
             devices = list_nfs_mounts(origdevices,mountstats)
             if len(devices) == 0:
-                print 'No NFS mount points were found'
+                print('No NFS mount points were found')
                 return
 
 #
@@ -641,7 +643,7 @@ prog = os.path.basename(sys.argv[0])
 try:
     iostat_command(prog)
 except KeyboardInterrupt:
-    print 'Caught ^C... exiting'
+    print('Caught ^C... exiting')
     sys.exit(1)
 
 sys.exit(0)
index 39b70c909b556eed02f763f8164dff597a211214..b0a3e1f9fe1a87d5ec8154756cf1349d0617ce6a 100644 (file)
@@ -1,15 +1,9 @@
 ## Process this file with automake to produce Makefile.in
 
-CC=$(CC_FOR_BUILD)
-LIBTOOL = @LIBTOOL@ --tag=CC
-
 man8_MANS = rpcdebug.man
 EXTRA_DIST = $(man8_MANS)
 
 sbin_PROGRAMS = rpcdebug
 rpcdebug_SOURCES = rpcdebug.c
-rpcdebug_CFLAGS=$(CFLAGS_FOR_BUILD)
-rpcdebug_CPPFLAGS=$(CPPFLAGS_FOR_BUILD) -I$(top_srcdir)/support/include
-rpcdebug_LDFLAGS=$(LDFLAGS_FOR_BUILD)
 
 MAINTAINERCLEANFILES = Makefile.in
index 444616d4759ee57e68796acb92152b59cfb17130..d6e10d36d97bbadbbcfac6a08ca74947fee78feb 100644 (file)
@@ -170,6 +170,7 @@ static struct flagmap {
        FLAG(NFS,       FSCACHE),
        FLAG(NFS,       PNFS),
        FLAG(NFS,       PNFS_LD),
+       FLAG(NFS,       STATE),
        FLAG(NFS,       ALL),
 
        /* nfsd */
index 09045dd6a85c8d06bc92737cdcef9fc9f4bae479..b892dc86cbb251fbf1df19e9ecbe56c90ef7fa77 100644 (file)
@@ -21,8 +21,8 @@ if CONFIG_MOUNT
 OPTDIRS += mount
 endif
 
-if CONFIG_NFSDCLD
-OPTDIRS += nfsdcld
+if CONFIG_NFSDCLTRACK
+OPTDIRS += nfsdcltrack
 endif
 
 SUBDIRS = \
index c21de3e7d6903be3f1da76c94b4c4efe6b9c456d..df4627e0c4b4eb55fa5913050cc2d8763fc146a0 100644 (file)
 #include <sys/ioctl.h>
 #include <sys/mount.h>
 #include <sys/select.h>
+#include <sys/inotify.h>
 #include <linux/kdev_t.h>
 #include <scsi/scsi.h>
 #include <scsi/scsi_ioctl.h>
 #include <scsi/sg.h>
+#include <signal.h>
 
 #include <stdlib.h>
 #include <stdio.h>
 
 #include "device-discovery.h"
 
+#define EVENT_SIZE (sizeof(struct inotify_event))
+#define EVENT_BUFSIZE (1024 * EVENT_SIZE)
+
 #define BL_PIPE_FILE   "/var/lib/nfs/rpc_pipefs/nfs/blocklayout"
+#define NFSPIPE_DIR    "/var/lib/nfs/rpc_pipefs/nfs"
+#define RPCPIPE_DIR    "/var/lib/nfs/rpc_pipefs"
 #define PID_FILE       "/var/run/blkmapd.pid"
 
 struct bl_disk *visible_disk_list;
+int    bl_watch_fd, bl_pipe_fd, nfs_pipedir_wfd, rpc_pipedir_wfd;
+int    pidfd = -1;
 
 struct bl_disk_path *bl_get_path(const char *filepath,
                                 struct bl_disk_path *paths)
@@ -262,7 +271,7 @@ int bl_discover_devices(void)
  * return 1: request processed, and more requests waiting;
  * return < 0: error
  */
-int bl_disk_inquiry_process(int fd)
+static int bl_disk_inquiry_process(int fd)
 {
        int ret = 0;
        struct bl_pipemsg_hdr head;
@@ -338,23 +347,70 @@ int bl_disk_inquiry_process(int fd)
        return ret;
 }
 
-/* TODO: set bl_process_stop to 1 in command */
-unsigned int bl_process_stop;
+static void bl_watch_dir(const char* dir, int *wd)
+{
+       *wd = inotify_add_watch(bl_watch_fd, dir, IN_CREATE|IN_DELETE);
+       if (*wd < 0)
+               BL_LOG_ERR("failed to watch %s: %s\n", dir, strerror(errno));
+}
 
-int bl_run_disk_inquiry_process(int fd)
+static void bl_rpcpipe_cb(void)
 {
-       fd_set rset;
-       int ret;
+       int rc, curr_byte = 0;
+       char eventArr[EVENT_BUFSIZE];
+       struct inotify_event *event;
+
+       rc = read(bl_watch_fd, &eventArr, EVENT_BUFSIZE);
+       if (rc < 0)
+               BL_LOG_ERR("read event fail: %s", strerror(errno));
+
+       while (rc > curr_byte) {
+               event = (struct inotify_event *)&eventArr[curr_byte];
+               curr_byte += EVENT_SIZE + event->len;
+               if (event->wd == rpc_pipedir_wfd) {
+                       if (strncmp(event->name, "nfs", 3))
+                               continue;
+                       if (event->mask & IN_CREATE) {
+                               BL_LOG_WARNING("nfs pipe dir created\n");
+                               bl_watch_dir(NFSPIPE_DIR, &nfs_pipedir_wfd);
+                               bl_pipe_fd = open(BL_PIPE_FILE, O_RDWR);
+                       } else if (event->mask & IN_DELETE) {
+                               BL_LOG_WARNING("nfs pipe dir deleted\n");
+                               inotify_rm_watch(bl_watch_fd, nfs_pipedir_wfd);
+                               close(bl_pipe_fd);
+                               nfs_pipedir_wfd = -1;
+                               bl_pipe_fd = -1;
+                       }
+               } else if (event->wd == nfs_pipedir_wfd) {
+                       if (strncmp(event->name, "blocklayout", 11))
+                               continue;
+                       if (event->mask & IN_CREATE) {
+                               BL_LOG_WARNING("blocklayout pipe file created\n");
+                               bl_pipe_fd = open(BL_PIPE_FILE, O_RDWR);
+                               if (bl_pipe_fd < 0)
+                                       BL_LOG_ERR("open %s failed: %s\n",
+                                               event->name, strerror(errno));
+                       } else if (event->mask & IN_DELETE) {
+                               BL_LOG_WARNING("blocklayout pipe file deleted\n");
+                               close(bl_pipe_fd);
+                               bl_pipe_fd = -1;
+                       }
+               }
+       }
+}
 
-       bl_process_stop = 0;
+static int bl_event_helper(void)
+{
+       fd_set rset;
+       int ret = 0, maxfd;
 
        for (;;) {
-               if (bl_process_stop)
-                       return 1;
                FD_ZERO(&rset);
-               FD_SET(fd, &rset);
-               ret = 0;
-               switch (select(fd + 1, &rset, NULL, NULL, NULL)) {
+               FD_SET(bl_watch_fd, &rset);
+               if (bl_pipe_fd > 0)
+                       FD_SET(bl_pipe_fd, &rset);
+               maxfd = (bl_watch_fd>bl_pipe_fd)?bl_watch_fd:bl_pipe_fd;
+               switch (select(maxfd + 1, &rset, NULL, NULL, NULL)) {
                case -1:
                        if (errno == EINTR)
                                continue;
@@ -365,18 +421,32 @@ int bl_run_disk_inquiry_process(int fd)
                case 0:
                        goto out;
                default:
-                       if (FD_ISSET(fd, &rset))
-                               ret = bl_disk_inquiry_process(fd);
+                       if (FD_ISSET(bl_watch_fd, &rset))
+                               bl_rpcpipe_cb();
+                       else if (bl_pipe_fd > 0 && FD_ISSET(bl_pipe_fd, &rset))
+                               ret = bl_disk_inquiry_process(bl_pipe_fd);
+                       if (ret)
+                               goto out;
                }
        }
  out:
        return ret;
 }
 
+void sig_die(int signal)
+{
+       if (pidfd >= 0) {
+               close(pidfd);
+               unlink(PID_FILE);
+       }
+       BL_LOG_ERR("exit on signal(%d)\n", signal);
+       exit(1);
+}
+
 /* Daemon */
 int main(int argc, char **argv)
 {
-       int fd, pidfd = -1, opt, dflag = 0, fg = 0, ret = 1;
+       int opt, dflag = 0, fg = 0, ret = 1;
        struct stat statbuf;
        char pidbuf[64];
 
@@ -421,23 +491,33 @@ int main(int argc, char **argv)
                write(pidfd, pidbuf, strlen(pidbuf));
        }
 
+       signal(SIGINT, sig_die);
+       signal(SIGTERM, sig_die);
+       signal(SIGHUP, SIG_IGN);
+
        if (dflag) {
                bl_discover_devices();
                exit(0);
        }
 
-       /* open pipe file */
-       fd = open(BL_PIPE_FILE, O_RDWR);
-       if (fd < 0) {
-               BL_LOG_ERR("open pipe file %s error\n", BL_PIPE_FILE);
+       if ((bl_watch_fd = inotify_init()) < 0) {
+               BL_LOG_ERR("init inotify failed %s\n", strerror(errno));
                exit(1);
        }
 
+       /* open pipe file */
+       bl_watch_dir(RPCPIPE_DIR, &rpc_pipedir_wfd);
+       bl_watch_dir(NFSPIPE_DIR, &nfs_pipedir_wfd);
+
+       bl_pipe_fd = open(BL_PIPE_FILE, O_RDWR);
+       if (bl_pipe_fd < 0)
+               BL_LOG_ERR("open pipe file %s failed: %s\n", BL_PIPE_FILE, strerror(errno));
+
        while (1) {
                /* discover device when needed */
                bl_discover_devices();
 
-               ret = bl_run_disk_inquiry_process(fd);
+               ret = bl_event_helper();
                if (ret < 0) {
                        /* what should we do with process error? */
                        BL_LOG_ERR("inquiry process return %d\n", ret);
index 652a7a8363449682d27a283e4da3e17adbf418c4..5fe3dffe5788c336c9b8a61f67c532b743c4ec47 100644 (file)
 
 #include "device-discovery.h"
 
-static char *pretty_sig(char *sig, uint32_t siglen)
-{
-       static char rs[100];
-       uint64_t sigval;
-       unsigned int i;
-
-       if (siglen <= sizeof(sigval)) {
-               sigval = 0;
-               for (i = 0; i < siglen; i++)
-                       sigval |= ((unsigned char *)sig)[i] << (i * 8);
-               sprintf(rs, "0x%0llx", (unsigned long long) sigval);
-       } else {
-               if (siglen > sizeof rs - 4) {
-                       siglen = sizeof rs - 4;
-                       sprintf(&rs[siglen], "...");
-               } else
-                       rs[siglen] = '\0';
-               memcpy(rs, sig, siglen);
-       }
-       return rs;
-}
-
 uint32_t *blk_overflow(uint32_t * p, uint32_t * end, size_t nbytes)
 {
        uint32_t *q = p + ((nbytes + 3) >> 2);
@@ -109,9 +87,6 @@ static int decode_blk_signature(uint32_t **pp, uint32_t * end,
                 * for mapping, then thrown away.
                 */
                comp->bs_string = (char *)p;
-               BL_LOG_INFO("%s: si_comps[%d]: bs_length %d, bs_string %s\n",
-                           __func__, i, siglen,
-                           pretty_sig(comp->bs_string, siglen));
                p += ((siglen + 3) >> 2);
        }
        *pp = p;
@@ -152,10 +127,6 @@ read_cmp_blk_sig(struct bl_disk *disk, int fd, struct bl_sig_comp *comp)
        }
 
        ret = memcmp(sig, comp->bs_string, siglen);
-       if (!ret)
-               BL_LOG_INFO("%s: %s sig %s at %lld\n", __func__, dev_name,
-                           pretty_sig(sig, siglen),
-                           (long long)comp->bs_offset);
 
  out:
        if (sig)
index a3323d733efb01c05a48c9bed8ae37f6dc40385d..9f7954130ee2adf9579f933ec44134d25ed141da 100644 (file)
@@ -40,7 +40,7 @@ static void   unexportfs(char *arg, int verbose);
 static void    exports_update(int verbose);
 static void    dump(int verbose);
 static void    error(nfs_export *exp, int err);
-static void    usage(const char *progname);
+static void    usage(const char *progname, int n);
 static void    validate_export(nfs_export *exp);
 static int     matchhostname(const char *hostname1, const char *hostname2);
 static void    export_d_read(const char *dname);
@@ -105,11 +105,17 @@ main(int argc, char **argv)
 
        export_errno = 0;
 
-       while ((c = getopt(argc, argv, "aio:ruvf")) != EOF) {
+       while ((c = getopt(argc, argv, "afhio:ruv")) != EOF) {
                switch(c) {
                case 'a':
                        f_all = 1;
                        break;
+               case 'f':
+                       force_flush = 1;
+                       break;
+               case 'h':
+                       usage(progname, 0);
+                       break;
                case 'i':
                        f_ignore = 1;
                        break;
@@ -126,11 +132,8 @@ main(int argc, char **argv)
                case 'v':
                        f_verbose = 1;
                        break;
-               case 'f':
-                       force_flush = 1;
-                       break;
                default:
-                       usage(progname);
+                       usage(progname, 1);
                        break;
                }
        }
@@ -723,8 +726,8 @@ error(nfs_export *exp, int err)
 }
 
 static void
-usage(const char *progname)
+usage(const char *progname, int n)
 {
-       fprintf(stderr, "usage: %s [-aruv] [host:/path]\n", progname);
-       exit(1);
+       fprintf(stderr, "usage: %s [-afhioruv] [host:/path]\n", progname);
+       exit(n);
 }
index 2365704c5db9b15d17f42b75adcb17f07f7e216f..a300da2b042baf9b14b77899d6419461a2e615d5 100644 (file)
@@ -38,11 +38,11 @@ gssd_SOURCES = \
        write_bytes.h
 
 gssd_LDADD =   ../../support/nfs/libnfs.a \
-               $(RPCSECGSS_LIBS) $(GSSGLUE_LIBS) $(KRBLIBS)
+               $(RPCSECGSS_LIBS) $(KRBLIBS) $(GSSAPI_LIBS)
 gssd_LDFLAGS = $(KRBLDFLAGS) $(LIBTIRPC)
 
 gssd_CFLAGS = $(AM_CFLAGS) $(CFLAGS) \
-             $(RPCSECGSS_CFLAGS) $(GSSGLUE_CFLAGS) $(KRBCFLAGS)
+             $(RPCSECGSS_CFLAGS) $(KRBCFLAGS) $(GSSAPI_CFLAGS)
 
 svcgssd_SOURCES = \
        $(COMMON_SRCS) \
@@ -57,18 +57,18 @@ svcgssd_SOURCES = \
 
 svcgssd_LDADD = \
        ../../support/nfs/libnfs.a \
-       $(RPCSECGSS_LIBS) $(GSSGLUE_LIBS) $(LIBNFSIDMAP) \
-       $(KRBLIBS) $(LIBTIRPC)
+       $(RPCSECGSS_LIBS) $(LIBNFSIDMAP) \
+       $(KRBLIBS) $(GSSAPI_LIBS) $(LIBTIRPC)
 
 svcgssd_LDFLAGS = $(KRBLDFLAGS)
 
 svcgssd_CFLAGS = $(AM_CFLAGS) $(CFLAGS) \
-                $(RPCSECGSS_CFLAGS) $(GSSGLUE_CFLAGS) $(KRBCFLAGS)
+                $(RPCSECGSS_CFLAGS) $(KRBCFLAGS) $(GSSAPI_CFLAGS)
 
 gss_clnt_send_err_SOURCES = gss_clnt_send_err.c
 
 gss_clnt_send_err_CFLAGS = $(AM_CFLAGS) $(CFLAGS) \
-                $(RPCSECGSS_CFLAGS) $(GSSGLUE_CFLAGS) $(KRBCFLAGS)
+                $(RPCSECGSS_CFLAGS) $(KRBCFLAGS) $(GSSAPI_CFLAGS)
 
 MAINTAINERCLEANFILES = Makefile.in
 
index fee7da27906e94b990fb7c49d73bf4f27a7003ac..7757a7700d14dd7fbe07f9878d6d79f514467156 100644 (file)
@@ -44,7 +44,7 @@
 #include "context.h"
 
 int
-serialize_context_for_kernel(gss_ctx_id_t ctx,
+serialize_context_for_kernel(gss_ctx_id_t *ctx,
                             gss_buffer_desc *buf,
                             gss_OID mech,
                             int32_t *endtime)
index 0e437f4a34f0862b8f89bd0d6fe62c41a3a1c906..3b55c8e4239cd9e814c8d540f0b3f90ade560107 100644 (file)
@@ -41,9 +41,9 @@
 #define KRB5_CTX_FLAG_CFX               0x00000002
 #define KRB5_CTX_FLAG_ACCEPTOR_SUBKEY   0x00000004
 
-int serialize_context_for_kernel(gss_ctx_id_t ctx, gss_buffer_desc *buf,
+int serialize_context_for_kernel(gss_ctx_id_t *ctx, gss_buffer_desc *buf,
                                 gss_OID mech, int32_t *endtime);
-int serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf,
+int serialize_krb5_ctx(gss_ctx_id_t *ctx, gss_buffer_desc *buf,
                       int32_t *endtime);
 
 #endif /* _CONTEXT_H_ */
index 6f3b8fd03f37e12a048337eed1d0d80e3bdb3224..1e8738aba96b9ad9c8b7017366355cd3001389fb 100644 (file)
@@ -203,9 +203,9 @@ int write_heimdal_seq_key(char **p, char *end, gss_ctx_id_t ctx)
  */
 
 int
-serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime)
+serialize_krb5_ctx(gss_ctx_id_t *_ctx, gss_buffer_desc *buf, int32_t *endtime)
 {
-
+       gss_ctx_id_t ctx = *_ctx;
        char *p, *end;
        static int constant_one = 1;
        static int constant_zero = 0;
index 64146d7078c9f31a82b2c0435f9ca7a170c29874..badbe88d82ec5c8c957aa880758f9ac51381f5ee 100644 (file)
@@ -257,7 +257,7 @@ out_err:
 
 
 int
-serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime)
+serialize_krb5_ctx(gss_ctx_id_t *ctx, gss_buffer_desc *buf, int32_t *endtime)
 {
        OM_uint32 maj_stat, min_stat;
        void *return_ctx = 0;
@@ -266,7 +266,7 @@ serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime)
        int retcode = 0;
 
        printerr(2, "DEBUG: %s: lucid version!\n", __FUNCTION__);
-       maj_stat = gss_export_lucid_sec_context(&min_stat, &ctx,
+       maj_stat = gss_export_lucid_sec_context(&min_stat, ctx,
                                                1, &return_ctx);
        if (maj_stat != GSS_S_COMPLETE) {
                pgsserr("gss_export_lucid_sec_context",
index e6db9cbb77b858ba91f659b9a7f43ef312317a21..fad67569f47accdc6adc49bb0a59a025c5dd9973 100644 (file)
@@ -152,9 +152,9 @@ typedef struct gss_union_ctx_id_t {
 } gss_union_ctx_id_desc, *gss_union_ctx_id_t;
 
 int
-serialize_krb5_ctx(gss_ctx_id_t ctx, gss_buffer_desc *buf, int32_t *endtime)
+serialize_krb5_ctx(gss_ctx_id_t *ctx, gss_buffer_desc *buf, int32_t *endtime)
 {
-       krb5_gss_ctx_id_t kctx = ((gss_union_ctx_id_t)ctx)->internal_ctx_id;
+       krb5_gss_ctx_id_t kctx = ((gss_union_ctx_id_t)(*ctx))->internal_ctx_id;
        char *p, *end;
        static int constant_zero = 0;
        static int constant_one = 1;
index 0e327b04d87250f6a037670aee825fb8db6887d5..2e6d40f0e7e128c06f632b666f3c91844fa87ef5 100644 (file)
@@ -95,7 +95,7 @@
 /* Global gssd_credentials handle */
 gss_cred_id_t gssd_creds;
 
-gss_OID g_mechOid = GSS_C_NULL_OID;;
+gss_OID g_mechOid = GSS_C_NULL_OID;
 
 #if 0
 static void
index 67b3077a8d252d31346fce6fdbd795a0c0c28287..c81fc5a98d5fbe0864b1c1b172e3cd5c28ed6800 100644 (file)
@@ -42,4 +42,16 @@ void pgsserr(char *msg, u_int32_t maj_stat, u_int32_t min_stat,
        const gss_OID mech);
 int gssd_check_mechs(void);
 
+#ifndef HAVE_LIBGSSGLUE
+#include <gssapi/gssapi_krb5.h>
+#define gss_free_lucid_sec_context(min, ctx, ret) \
+               gss_krb5_free_lucid_sec_context(min, ret)
+
+#define gss_export_lucid_sec_context gss_krb5_export_lucid_sec_context
+#define gss_set_allowable_enctypes(min, cred, oid, num, types) \
+               gss_krb5_set_allowable_enctypes(min, cred, num, types)
+#endif
+
+extern int avoid_dns;
+
 #endif /* _GSS_UTIL_H_ */
index 782525566acc56ec46eeda628072b39d72de5655..8ee478bc0bccb0aedee7bd3557e0f194ad69ab30 100644 (file)
@@ -71,7 +71,7 @@ sig_die(int signal)
        if (root_uses_machine_creds)
                gssd_destroy_krb5_machine_creds();
        printerr(1, "exiting on signal %d\n", signal);
-       exit(1);
+       exit(0);
 }
 
 void
@@ -85,7 +85,7 @@ sig_hup(int signal)
 static void
 usage(char *progname)
 {
-       fprintf(stderr, "usage: %s [-f] [-l] [-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] [-D]\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, "fvrlmnMp:k:d:t:R")) != -1) {
+       while ((opt = getopt(argc, argv, "DfvrlmnMp:k:d:t:R:")) != -1) {
                switch (opt) {
                        case 'f':
                                fg = 1;
@@ -147,9 +147,12 @@ main(int argc, char *argv[])
 #ifdef HAVE_SET_ALLOWABLE_ENCTYPES
                                limit_to_legacy_enctypes = 1;
 #else 
-                               errx(1, "Setting encryption type not support by Kerberos libraries.");
+                               errx(1, "Encryption type limits not supported by Kerberos libraries.");
 #endif
                                break;
+                       case 'D':
+                               avoid_dns = 0;
+                               break;
                        default:
                                usage(argv[0]);
                                break;
index 28a8206d95210190368e79a6acee70e8aa5a45d3..86472a1239355d18f2ad2acd6583907a7c6b294a 100644 (file)
@@ -45,8 +45,8 @@
 #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_USER_CRED_DIR                     "/run/user/%U"
+#define GSSD_DEFAULT_CRED_PREFIX               "krb5cc"
 #define GSSD_DEFAULT_MACHINE_CRED_SUFFIX       "machine"
 #define GSSD_DEFAULT_KEYTAB_FILE               "/etc/krb5.keytab"
 #define GSSD_SERVICE_NAME                      "nfs"
@@ -81,8 +81,10 @@ struct clnt_info {
        char                    *protocol;
        int                     krb5_fd;
        int                     krb5_poll_index;
+       int                     krb5_close_me;
        int                     gssd_fd;
        int                     gssd_poll_index;
+       int                     gssd_close_me;
        struct sockaddr_storage addr;
 };
 
index d8138faf0e3f8ac4ce1f15c37c886bf2238bb060..1df75c57e1f6f09fb5a2891a4554751583b5cf1c 100644 (file)
 .\" rpc.gssd(8)
 .\"
 .\" Copyright (C) 2003 J. Bruce Fields <bfields@umich.edu>
-.TH rpc.gssd 8 "14 Mar 2007"
+.\"
+.TH rpc.gssd 8 "20 Feb 2013"
 .SH NAME
-rpc.gssd \- rpcsec_gss daemon
+rpc.gssd \- RPCSEC_GSS daemon
 .SH SYNOPSIS
-.B "rpc.gssd [-f] [-n] [-k keytab] [-l] [-p pipefsdir] [-v] [-r] [-d ccachedir]"
+.B rpc.gssd
+.RB [ \-DfMnlvr ]
+.RB [ \-k
+.IR keytab ]
+.RB [ \-p
+.IR pipefsdir ]
+.RB [ \-d
+.IR ccachedir ]
+.RB [ \-t
+.IR timeout ]
+.RB [ \-R
+.IR realm ]
+.SH INTRODUCTION
+The RPCSEC_GSS protocol, defined in RFC 5403, is used to provide
+strong security for RPC-based protocols such as NFS.
+.P
+Before exchanging RPC requests using RPCSEC_GSS, an RPC client must
+establish a GSS
+.IR "security context" .
+A security context is shared state on each
+end of a network transport that enables GSS-API security services.
+.P
+Security contexts are established using
+.IR "security credentials" .
+A credential grants temporary access to a secure network service,
+much as a railway ticket grants temporary access to use a rail service.
+.P
+A user typically obtains a credential by providing a password to the
+.BR kinit (1)
+command, or via a PAM library at login time.
+A credential acquired with a
+.I user principal
+is known as a
+.I user credential
+(see
+.BR kerberos (1)
+for more on principals).
+.P
+For certain operations, a credential is required
+which represents no user,
+is otherwise unprivileged,
+and is always available.
+This is referred to as a
+.IR "machine credential" .
+.P
+Machine credentials are typically established using a
+.IR "service principal" ,
+whose encrypted password, called its
+.IR key ,
+is stored in a file, called a
+.IR keytab ,
+to avoid requiring a user prompt.
+A machine credential effectively does not expire because the system
+can renew it as needed without user intervention.
+.P
+Once obtained, credentials are typically stored in local temporary files
+with well-known pathnames.
 .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
-exchanging any rpc requests using rpcsec_gss, the rpc client must first
-establish a security context.  The linux kernel's implementation of rpcsec_gss
-depends on the userspace daemon
+To establish GSS security contexts using these credential files,
+the Linux kernel RPC client depends on a userspace daemon called
+.BR rpc.gssd .
+The
+.B rpc.gssd
+daemon uses the rpc_pipefs filesystem to communicate with the kernel.
+.SS User Credentials
+When a user authenticates using a command such as
+.BR kinit (1),
+the resulting credential is stored in a file with a well-known name
+constructed using the user's UID.
+.P
+To interact with an NFS server
+on behalf of a particular Kerberos-authenticated user,
+the Linux kernel RPC client requests that
+.B rpc.gssd
+initialize a security context with the credential
+in that user's credential file.
+.P
+Typically, credential files are placed in
+.IR /tmp .
+However,
+.B rpc.gssd
+can search for credential files in more than one directory.
+See the description of the
+.B -d
+option for details.
+.SS Machine Credentials
+A user credential is established by a user and
+is then shared with the kernel and
+.BR rpc.gssd .
+A machine credential is established by
+.B rpc.gssd
+for the kernel when there is no user.
+Therefore
+.B rpc.gssd
+must already have the materials on hand to establish this credential
+without requiring user intervention.
+.P
+.B rpc.gssd
+searches the local system's keytab for a principal and key to use
+to establish the machine credential.
+By default,
+.B rpc.gssd
+assumes the file
+.I /etc/krb5.keytab
+contains principals and keys that can be used to obtain machine credentials.
+.P
+.B rpc.gssd
+searches in the following order for a principal to use.
+The first matching credential is used.
+For the search, <hostname> and <REALM> are replaced with the local
+system's hostname and Kerberos realm.
+.sp
+   <HOSTNAME>$@<REALM>
+.br
+   root/<hostname>@<REALM>
+.br
+   nfs/<hostname>@<REALM>
+.br
+   host/<hostname>@<REALM>
+.br
+   root/<anyname>@<REALM>
+.br
+   nfs/<anyname>@<REALM>
+.br
+   host/<anyname>@<REALM>
+.sp
+The <anyname> entries match on the service name and realm, but ignore the hostname.
+These can be used if a principal matching the local host's name is not found.
+.P
+Note that the first principal in the search order is a user principal
+that enables Kerberized NFS when the local system is joined
+to an Active Directory domain using Samba.
+A password for this principal must be provided in the local system's keytab.
+.P
+You can specify another keytab by using the
+.B -k
+option if
+.I /etc/krb5.keytab
+does not exist or does not provide one of these principals.
+.SS Credentials for UID 0
+UID 0 is a special case.
+By default
+.B rpc.gssd
+uses the system's machine credentials for UID 0 accesses
+that require GSS authentication.
+This limits the privileges of the root user
+when accessing network resources that require authentication.
+.P
+Specify the
+.B -n
+option when starting
+.B rpc.gssd
+if you'd like to force the root user to obtain a user credential
+rather than use the local system's machine credential.
+.P
+When
+.B -n
+is specified,
+the kernel continues to request a GSS context established
+with a machine credential for NFSv4 operations,
+such as SETCLIENTID or RENEW, that manage state.
+If
 .B rpc.gssd
-to establish security contexts.  The
+cannot obtain a machine credential (say, the local system has
+no keytab), NFSv4 operations that require machine credentials will fail.
+.SS Encryption types
+A realm administrator can choose to add keys encoded in a number of different
+encryption types to the local system's keytab.
+For instance, a host/ principal might have keys for the
+.BR aes256-cts-hmac-sha1-96 ,
+.BR aes128-cts-hmac-sha1-96 ,
+.BR des3-cbc-sha1 ", and"
+.BR arcfour-hmac " encryption types."
+This permits
 .B rpc.gssd
-daemon uses files in the rpc_pipefs filesystem to communicate with the kernel.
-
+to choose an appropriate encryption type that the target NFS server
+supports.
+.P
+These encryption types are stronger than legacy single-DES encryption types.
+To interoperate in environments where servers support
+only weak encryption types,
+you can restrict your client to use only single-DES encryption types
+by specifying the
+.B -l
+option when starting
+.BR rpc.gssd .
 .SH OPTIONS
 .TP
+.B -D
+DNS Reverse lookups are not used for determining the
+server names pass to GSSAPI. This option will reverses that and forces 
+the use of DNS Reverse resolution of the server's IP address to 
+retrieve the server name to use in GSAPI authentication.
+.TP
 .B -f
 Runs
 .B rpc.gssd
 in the foreground and sends output to stderr (as opposed to syslogd)
 .TP
 .B -n
-By default,
-.B rpc.gssd
-treats accesses by the user with UID 0 specially, and uses
-"machine credentials" for all accesses by that user which
-require Kerberos authentication.
-With the \-n option, "machine credentials" will not be used
-for accesses by UID 0.  Instead, credentials must be obtained
-manually like all other users.  Use of this option means that
-"root" must manually obtain Kerberos credentials before
-attempting to mount an nfs filesystem requiring Kerberos
-authentication.
+When specified, UID 0 is forced to obtain user credentials
+which are used instead of the local system's machine credentials.
 .TP
-.B -k keytab
+.BI "-k " keytab
 Tells
 .B rpc.gssd
 to use the keys found in
 .I keytab
-to obtain "machine credentials".
-The default value is "/etc/krb5.keytab".
-.IP
-Previous versions of
-.B rpc.gssd
-used only "nfs/*" keys found within the keytab.
-To be more consistent with other implementations, we now look for
-specific keytab entries.  The search order for keytabs to be used
-for "machine credentials" is now:
-.br
-  <HOSTNAME>$@<REALM>
-.br
-  root/<hostname>@<REALM>
-.br
-  nfs/<hostname>@<REALM>
-.br
-  host/<hostname>@<REALM>
-.br
-  root/<anyname>@<REALM>
-.br
-  nfs/<anyname>@<REALM>
-.br
-  host/<anyname>@<REALM>
-.IP
-If this search order does not use the correct key then provide a
-keytab file that contains only correct keys.
+to obtain machine credentials.
+The default value is
+.IR /etc/krb5.keytab .
 .TP
 .B -l
-Tells
+When specified, restricts
 .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.
+to sessions to weak encryption types such as
+.BR des-cbc-crc .
+This option is available only when the local system's Kerberos library
+supports settable encryption types.
 .TP
-.B -p path
+.BI "-p " path
 Tells
 .B rpc.gssd
 where to look for the rpc_pipefs filesystem.  The default value is
-"/var/lib/nfs/rpc_pipefs".
+.IR /var/lib/nfs/rpc_pipefs .
 .TP
-.B -d directory
-Tells
+.BI "-d " search-path
+This option specifies a colon separated list of directories that
+.B rpc.gssd
+searches for credential files.  The default value is
+.IR /tmp:/run/user/%U .
+The literal sequence "%U" can be specified to substitue the UID
+of the user for whom credentials are being searched.
+.TP
+.B -M
+By default, machine credentials are stored in files in the first
+directory in the credential directory search path (see the
+.B -d
+option).  When
+.B -M
+is set,
 .B rpc.gssd
-where to look for Kerberos credential files.  The default value is "/tmp".
-This can also be a colon separated list of directories to be searched
-for Kerberos credential files.  Note that if machine credentials are being
-stored in files, then the first directory on this list is where the
-machine credentials are stored.
+stores machine credentials in memory instead.
 .TP
 .B -v
 Increases the verbosity of the output (can be specified multiple times).
 .TP
 .B -r
-If the rpcsec_gss library supports setting debug level,
+If the RPCSEC_GSS library supports setting debug level,
 increases the verbosity of the output (can be specified multiple times).
 .TP
-.B -R realm
+.BI "-R " realm
 Kerberos tickets from this
 .I realm
 will be preferred when scanning available credentials cache files to be
 used to create a context.  By default, the default realm, as configured
 in the Kerberos configuration file, is preferred.
 .TP
-.B -t timeout
-Timeout, in seconds, for kernel gss contexts. This option allows you to force 
+.BI "-t " timeout
+Timeout, in seconds, for kernel GSS contexts. This option allows you to force 
 new kernel contexts to be negotiated after
 .I timeout
 seconds, which allows changing Kerberos tickets and identities frequently.
 The default is no explicit timeout, which means the kernel context will live
 the lifetime of the Kerberos service ticket used in its creation.
 .SH SEE ALSO
-.BR rpc.svcgssd(8)
+.BR rpc.svcgssd (8),
+.BR kerberos (1),
+.BR kinit (1),
+.BR krb5.conf (5)
 .SH AUTHORS
 .br
 Dug Song <dugsong@umich.edu>
index cec09ea5b218fa6d586f5d5798e0280d4dde4125..ccf7fe534009fad885ce404d82178ba2b6426b7c 100644 (file)
 #include "err_util.h"
 
 extern struct pollfd *pollarray;
-extern int pollsize;
+extern unsigned long pollsize;
 
 #define POLL_MILLISECS 500
 
 static volatile int dir_changed = 1;
 
-static void dir_notify_handler(int sig, siginfo_t *si, void *data)
+static void dir_notify_handler(__attribute__((unused))int sig)
 {
-       printerr(2, "dir_notify_handler: sig %d si %p data %p\n", sig, si, data);
-
        dir_changed = 1;
 }
 
@@ -78,8 +76,10 @@ scan_poll_results(int ret)
        {
                i = clp->gssd_poll_index;
                if (i >= 0 && pollarray[i].revents) {
-                       if (pollarray[i].revents & POLLHUP)
+                       if (pollarray[i].revents & POLLHUP) {
+                               clp->gssd_close_me = 1;
                                dir_changed = 1;
+                       }
                        if (pollarray[i].revents & POLLIN)
                                handle_gssd_upcall(clp);
                        pollarray[clp->gssd_poll_index].revents = 0;
@@ -89,8 +89,10 @@ scan_poll_results(int ret)
                }
                i = clp->krb5_poll_index;
                if (i >= 0 && pollarray[i].revents) {
-                       if (pollarray[i].revents & POLLHUP)
+                       if (pollarray[i].revents & POLLHUP) {
+                               clp->krb5_close_me = 1;
                                dir_changed = 1;
+                       }
                        if (pollarray[i].revents & POLLIN)
                                handle_krb5_upcall(clp);
                        pollarray[clp->krb5_poll_index].revents = 0;
@@ -99,7 +101,7 @@ scan_poll_results(int ret)
                                break;
                }
        }
-};
+}
 
 static int
 topdirs_add_entry(struct dirent *dent)
@@ -119,11 +121,13 @@ topdirs_add_entry(struct dirent *dent)
        }
        snprintf(tdi->dirname, PATH_MAX, "%s/%s", pipefs_dir, dent->d_name);
        tdi->fd = open(tdi->dirname, O_RDONLY);
-       if (tdi->fd != -1) {
-               fcntl(tdi->fd, F_SETSIG, DNOTIFY_SIGNAL);
-               fcntl(tdi->fd, F_NOTIFY,
-                     DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT);
+       if (tdi->fd == -1) {
+               printerr(0, "ERROR: failed to open %s\n", tdi->dirname);
+               free(tdi);
+               return -1;
        }
+       fcntl(tdi->fd, F_SETSIG, DNOTIFY_SIGNAL);
+       fcntl(tdi->fd, F_NOTIFY, DN_CREATE|DN_DELETE|DN_MODIFY|DN_MULTISHOT);
 
        TAILQ_INSERT_HEAD(&topdirs_list, tdi, list);
        return 0;
@@ -175,17 +179,52 @@ out_err:
        return -1;
 }
 
+#ifdef HAVE_PPOLL
+static void gssd_poll(struct pollfd *fds, unsigned long nfds)
+{
+       sigset_t emptyset;
+       int ret;
+
+       sigemptyset(&emptyset);
+       ret = ppoll(fds, nfds, NULL, &emptyset);
+       if (ret < 0) {
+               if (errno != EINTR)
+                       printerr(0, "WARNING: error return from poll\n");
+       } else if (ret == 0) {
+               printerr(0, "WARNING: unexpected timeout\n");
+       } else {
+               scan_poll_results(ret);
+       }
+}
+#else  /* !HAVE_PPOLL */
+static void gssd_poll(struct pollfd *fds, unsigned long nfds)
+{
+       int ret;
+
+       /* race condition here: dir_changed could be set before we
+        * enter the poll, and we'd never notice if it weren't for the
+        * timeout. */
+       ret = poll(fds, nfds, POLL_MILLISECS);
+       if (ret < 0) {
+               if (errno != EINTR)
+                       printerr(0, "WARNING: error return from poll\n");
+       } else if (ret == 0) {
+               /* timeout */
+       } else { /* ret > 0 */
+               scan_poll_results(ret);
+       }
+}
+#endif /* !HAVE_PPOLL */
+
 void
 gssd_run()
 {
-       int                     ret;
-       struct sigaction        dn_act;
+       struct sigaction        dn_act = {
+               .sa_handler = dir_notify_handler
+       };
        sigset_t                set;
 
-       /* Taken from linux/Documentation/dnotify.txt: */
-       dn_act.sa_sigaction = dir_notify_handler;
        sigemptyset(&dn_act.sa_mask);
-       dn_act.sa_flags = SA_SIGINFO;
        sigaction(DNOTIFY_SIGNAL, &dn_act, NULL);
 
        /* just in case the signal is blocked... */
@@ -207,19 +246,7 @@ gssd_run()
                                exit(1);
                        }
                }
-               /* race condition here: dir_changed could be set before we
-                * enter the poll, and we'd never notice if it weren't for the
-                * timeout. */
-               ret = poll(pollarray, pollsize, POLL_MILLISECS);
-               if (ret < 0) {
-                       if (errno != EINTR)
-                               printerr(0,
-                                        "WARNING: error return from poll\n");
-               } else if (ret == 0) {
-                       /* timeout */
-               } else { /* ret > 0 */
-                       scan_poll_results(ret);
-               }
+               gssd_poll(pollarray, pollsize);
        }
        topdirs_free_list();
 
index aa394359e27398fd3dfe25462ca2be177b7088d4..af1844c2d38490e1ccb5c21e2aa45cd34cca376e 100644 (file)
@@ -52,6 +52,7 @@
 #include <sys/socket.h>
 #include <arpa/inet.h>
 #include <sys/fsuid.h>
+#include <sys/resource.h>
 
 #include <stdio.h>
 #include <stdlib.h>
@@ -66,6 +67,7 @@
 #include <errno.h>
 #include <gssapi/gssapi.h>
 #include <netdb.h>
+#include <ctype.h>
 
 #include "gssd.h"
 #include "err_util.h"
 
 struct pollfd * pollarray;
 
-int pollsize;  /* the size of pollaray (in pollfd's) */
+unsigned long pollsize;  /* the size of pollaray (in pollfd's) */
+
+/* Avoid DNS reverse lookups on server names */
+int avoid_dns = 1;
 
 /*
  * convert a presentation address string to a sockaddr_storage struct. Returns
@@ -164,12 +169,31 @@ addrstr_to_sockaddr(struct sockaddr *sa, const char *node, const char *port)
  * convert a sockaddr to a hostname
  */
 static char *
-sockaddr_to_hostname(const struct sockaddr *sa, const char *addr)
+get_servername(const char *name, const struct sockaddr *sa, const char *addr)
 {
        socklen_t               addrlen;
        int                     err;
-       char                    *hostname;
+       char                    *hostname;
        char                    hbuf[NI_MAXHOST];
+       unsigned char           buf[sizeof(struct in6_addr)];
+       int                     servername = 0;
+
+       if (avoid_dns) {
+               /*
+                * Determine if this is a server name, or an IP address.
+                * If it is an IP address, do the DNS lookup otherwise
+                * skip the DNS lookup.
+                */
+               servername = 0;
+               if (strchr(name, '.') && inet_pton(AF_INET, name, buf) == 1)
+                       servername = 1; /* IPv4 */
+               else if (strchr(name, ':') && inet_pton(AF_INET6, name, buf) == 1)
+                       servername = 1; /* or IPv6 */
+
+               if (servername) {
+                       return strdup(name);
+               }
+       }
 
        switch (sa->sa_family) {
        case AF_INET:
@@ -207,7 +231,7 @@ read_service_info(char *info_file_name, char **servicename, char **servername,
                  struct sockaddr *addr) {
 #define INFOBUFLEN 256
        char            buf[INFOBUFLEN + 1];
-       static char     dummy[128];
+       static char     server[128];
        int             nbytes;
        static char     service[128];
        static char     address[128];
@@ -235,7 +259,7 @@ read_service_info(char *info_file_name, char **servicename, char **servername,
                   "service: %127s %15s version %15s\n"
                   "address: %127s\n"
                   "protocol: %15s\n",
-                  dummy,
+                  server,
                   service, program, version,
                   address,
                   protoname);
@@ -250,25 +274,14 @@ read_service_info(char *info_file_name, char **servicename, char **servername,
        if ((p = strstr(buf, "port")) != NULL)
                sscanf(p, "port: %127s\n", port);
 
-       /* check service, program, and version */
-       if (memcmp(service, "nfs", 3) != 0)
-               return -1;
+       /* get program, and version numbers */
        *prog = atoi(program + 1); /* skip open paren */
        *vers = atoi(version);
 
-       if (strlen(service) == 3 ) {
-               if ((*prog != 100003) || ((*vers != 2) && (*vers != 3) &&
-                   (*vers != 4)))
-                       goto fail;
-       } else if (memcmp(service, "nfs4_cb", 7) == 0) {
-               if (*vers != 1)
-                       goto fail;
-       }
-
        if (!addrstr_to_sockaddr(addr, address, port))
                goto fail;
 
-       *servername = sockaddr_to_hostname(addr, address);
+       *servername = get_servername(server, addr, address);
        if (*servername == NULL)
                goto fail;
 
@@ -340,6 +353,25 @@ process_clnt_dir_files(struct clnt_info * clp)
        char    gname[PATH_MAX];
        char    info_file_name[PATH_MAX];
 
+       if (clp->gssd_close_me) {
+               printerr(2, "Closing 'gssd' pipe for %s\n", clp->dirname);
+               close(clp->gssd_fd);
+               memset(&pollarray[clp->gssd_poll_index], 0,
+                       sizeof(struct pollfd));
+               clp->gssd_fd = -1;
+               clp->gssd_poll_index = -1;
+               clp->gssd_close_me = 0;
+       }
+       if (clp->krb5_close_me) {
+               printerr(2, "Closing 'krb5' pipe for %s\n", clp->dirname);
+               close(clp->krb5_fd);
+               memset(&pollarray[clp->krb5_poll_index], 0,
+                       sizeof(struct pollfd));
+               clp->krb5_fd = -1;
+               clp->krb5_poll_index = -1;
+               clp->krb5_close_me = 0;
+       }
+
        if (clp->gssd_fd == -1) {
                snprintf(gname, sizeof(gname), "%s/gssd", clp->dirname);
                clp->gssd_fd = open(gname, O_RDWR);
@@ -379,10 +411,10 @@ process_clnt_dir_files(struct clnt_info * clp)
 static int
 get_poll_index(int *ind)
 {
-       int i;
+       unsigned int i;
 
        *ind = -1;
-       for (i=0; i<FD_ALLOC_BLOCK; i++) {
+       for (i=0; i<pollsize; i++) {
                if (pollarray[i].events == 0) {
                        *ind = i;
                        break;
@@ -464,9 +496,13 @@ fail_keep_client:
 void
 init_client_list(void)
 {
+       struct rlimit rlim;
        TAILQ_INIT(&clnt_list);
        /* Eventually plan to grow/shrink poll array: */
        pollsize = FD_ALLOC_BLOCK;
+       if (getrlimit(RLIMIT_NOFILE, &rlim) == 0 &&
+           rlim.rlim_cur != RLIM_INFINITY)
+               pollsize = rlim.rlim_cur;
        pollarray = calloc(pollsize, sizeof(struct pollfd));
 }
 
@@ -548,9 +584,8 @@ process_pipedir(char *pipe_name)
 
        update_old_clients(namelist, j, pipe_name);
        for (i=0; i < j; i++) {
-               if (i < FD_ALLOC_BLOCK
-                               && !strncmp(namelist[i]->d_name, "clnt", 4)
-                               && !find_client(namelist[i]->d_name, pipe_name))
+               if (!strncmp(namelist[i]->d_name, "clnt", 4)
+                   && !find_client(namelist[i]->d_name, pipe_name))
                        process_clnt_dir(namelist[i]->d_name, pipe_name);
                free(namelist[i]);
        }
@@ -640,19 +675,22 @@ parse_enctypes(char *enctypes)
 
 static int
 do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
-           gss_buffer_desc *context_token)
+           gss_buffer_desc *context_token, OM_uint32 lifetime_rec)
 {
        char    *buf = NULL, *p = NULL, *end = NULL;
        unsigned int timeout = context_timeout;
        unsigned int buf_size = 0;
 
-       printerr(1, "doing downcall\n");
+       printerr(1, "doing downcall lifetime_rec %u\n", lifetime_rec);
        buf_size = sizeof(uid) + sizeof(timeout) + sizeof(pd->pd_seq_win) +
                sizeof(pd->pd_ctx_hndl.length) + pd->pd_ctx_hndl.length +
                sizeof(context_token->length) + context_token->length;
        p = buf = malloc(buf_size);
        end = buf + buf_size;
 
+       /* context_timeout set by -t option overrides context lifetime */
+       if (timeout == 0)
+               timeout = lifetime_rec;
        if (WRITE_BYTES(&p, end, uid)) goto out_err;
        if (WRITE_BYTES(&p, end, timeout)) goto out_err;
        if (WRITE_BYTES(&p, end, pd->pd_seq_win)) goto out_err;
@@ -693,7 +731,7 @@ out_err:
 
 /*
  * If the port isn't already set, do an rpcbind query to the remote server
- * using the program and version and get the port. 
+ * using the program and version and get the port.
  *
  * Newer kernels send the value of the port= mount option in the "info"
  * file for the upcall or '0' for NFSv2/3. For NFSv4 it sends the value
@@ -780,11 +818,13 @@ set_port:
  * Create an RPC connection and establish an authenticated
  * gss context with a server.
  */
-int create_auth_rpc_client(struct clnt_info *clp,
-                          CLIENT **clnt_return,
-                          AUTH **auth_return,
-                          uid_t uid,
-                          int authtype)
+static int
+create_auth_rpc_client(struct clnt_info *clp,
+                      CLIENT **clnt_return,
+                      AUTH **auth_return,
+                      uid_t uid,
+                      int authtype,
+                      gss_cred_id_t cred)
 {
        CLIENT                  *rpc_clnt = NULL;
        struct rpc_gss_sec      sec;
@@ -810,7 +850,7 @@ int create_auth_rpc_client(struct clnt_info *clp,
 
        sec.qop = GSS_C_QOP_DEFAULT;
        sec.svc = RPCSEC_GSS_SVC_NONE;
-       sec.cred = GSS_C_NO_CREDENTIAL;
+       sec.cred = cred;
        sec.req_flags = 0;
        if (authtype == AUTHTYPE_KRB5) {
                sec.mech = (gss_OID)&krb5oid;
@@ -918,23 +958,6 @@ 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
@@ -949,18 +972,14 @@ 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, *dir, *userdir;
+       char                    **dirname;
        int                     create_resp = -1;
        int                     err, downcall_err = -EACCES;
+       gss_cred_id_t           gss_cred;
+       OM_uint32               maj_stat, min_stat, lifetime_rec;
 
        printerr(1, "handling krb5 upcall (%s)\n", clp->dirname);
 
-       if (tgtname) {
-               if (clp->servicename) {
-                       free(clp->servicename);
-                       clp->servicename = strdup(tgtname);
-               }
-       }
        token.length = 0;
        token.value = NULL;
        memset(&pd, 0, sizeof(struct authgss_private_data));
@@ -991,30 +1010,20 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
        if (uid != 0 || (uid == 0 && root_uses_machine_creds == 0 &&
                                service == NULL)) {
                /* Tell krb5 gss which credentials cache to use */
-               for (dirname = ccachesearch; *dirname != NULL; 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;
-                       }
+               /* Try first to acquire credentials directly via GSSAPI */
+               err = gssd_acquire_user_cred(uid, &gss_cred);
+               if (!err)
+                       create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
+                                                            AUTHTYPE_KRB5, gss_cred);
+               /* if create_auth_rplc_client fails try the traditional method of
+                * trolling for credentials */
+               for (dirname = ccachesearch; create_resp != 0 && *dirname != NULL; dirname++) {
+                       err = gssd_setup_krb5_user_gss_ccache(uid, clp->servername, *dirname);
                        if (err == -EKEYEXPIRED)
                                downcall_err = -EKEYEXPIRED;
                        else if (!err)
                                create_resp = create_auth_rpc_client(clp, &rpc_clnt, &auth, uid,
-                                                            AUTHTYPE_KRB5);
-                       if (create_resp == 0)
-                               break;
+                                                            AUTHTYPE_KRB5, GSS_C_NO_CREDENTIAL);
                }
        }
        if (create_resp != 0) {
@@ -1024,7 +1033,8 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
                        int success = 0;
                        do {
                                gssd_refresh_krb5_machine_credential(clp->servername,
-                                                                    NULL, service);
+                                                                    NULL, service,
+                                                                    tgtname);
                                /*
                                 * Get a list of credential cache names and try each
                                 * of them until one works or we've tried them all
@@ -1033,22 +1043,23 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
                                        printerr(0, "ERROR: No credentials found "
                                                 "for connection to server %s\n",
                                                 clp->servername);
-                                               goto out_return_error;
+                                       goto out_return_error;
                                }
                                for (ccname = credlist; ccname && *ccname; ccname++) {
                                        gssd_setup_krb5_machine_gss_ccache(*ccname);
                                        if ((create_auth_rpc_client(clp, &rpc_clnt,
                                                                    &auth, uid,
-                                                                   AUTHTYPE_KRB5)) == 0) {
+                                                                   AUTHTYPE_KRB5,
+                                                                   GSS_C_NO_CREDENTIAL)) == 0) {
                                                /* Success! */
                                                success++;
                                                break;
-                                       } 
+                                       }
                                        printerr(2, "WARNING: Failed to create machine krb5 context "
                                                 "with credentials cache %s for server %s\n",
                                                 *ccname, clp->servername);
                                }
-                               gssd_free_krb5_machine_cred_list(credlist);                     
+                               gssd_free_krb5_machine_cred_list(credlist);
                                if (!success) {
                                        if(nocache == 0) {
                                                nocache++;
@@ -1077,20 +1088,29 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
                goto out_return_error;
        }
 
-       if (serialize_context_for_kernel(pd.pd_ctx, &token, &krb5oid, NULL)) {
+       /* Grab the context lifetime to pass to the kernel. lifetime_rec
+        * is set to zero on error */
+       maj_stat = gss_inquire_context(&min_stat, pd.pd_ctx, NULL, NULL,
+                                      &lifetime_rec, NULL, NULL, NULL, NULL);
+
+       if (maj_stat)
+               printerr(1, "WARNING: Failed to inquire context for lifetme "
+                           "maj_stat %u\n", maj_stat);
+
+       if (serialize_context_for_kernel(&pd.pd_ctx, &token, &krb5oid, NULL)) {
                printerr(0, "WARNING: Failed to serialize krb5 context for "
                            "user with uid %d for server %s\n",
                         uid, clp->servername);
                goto out_return_error;
        }
 
-       do_downcall(fd, uid, &pd, &token);
+       do_downcall(fd, uid, &pd, &token, lifetime_rec);
 
 out:
        if (token.value)
                free(token.value);
-#ifndef HAVE_LIBTIRPC
-       if (pd.pd_ctx_hndl.length != 0)
+#ifdef HAVE_AUTHGSS_FREE_PRIVATE_DATA
+       if (pd.pd_ctx_hndl.length != 0 || pd.pd_ctx != 0)
                authgss_free_private_data(&pd);
 #endif
        if (auth)
@@ -1115,7 +1135,7 @@ handle_krb5_upcall(struct clnt_info *clp)
                return;
        }
 
-       return process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL);
+       process_krb5_upcall(clp, uid, clp->krb5_fd, NULL, NULL);
 }
 
 void
@@ -1236,6 +1256,6 @@ out:
        free(enctypes);
        free(target);
        free(service);
-       return; 
+       return;
 }
 
index 887d118f3b19277196dcf75b5c532cb3c3376e92..6275dd8717c64c69939481444bc4b115a2a93a13 100644 (file)
@@ -139,7 +139,7 @@ int limit_to_legacy_enctypes = 0;
 
 static int select_krb5_ccache(const struct dirent *d);
 static int gssd_find_existing_krb5_ccache(uid_t uid, char *dirname,
-               struct dirent **d);
+               const char **cctype, struct dirent **d);
 static int gssd_get_single_krb5_cred(krb5_context context,
                krb5_keytab kt, struct gssd_k5_kt_princ *ple, int nocache);
 static int query_krb5_ccache(const char* cred_cache, char **ret_princname,
@@ -169,16 +169,17 @@ select_krb5_ccache(const struct dirent *d)
 
 /*
  * Look in directory "dirname" for files that look like they
- * are Kerberos Credential Cache files for a given UID.  Return
- * non-zero and the dirent pointer for the entry most likely to be
- * what we want. Otherwise, return zero and no dirent pointer.
- * The caller is responsible for freeing the dirent if one is returned.
+ * are Kerberos Credential Cache files for a given UID.
  *
- * Returns 0 if a valid-looking entry was found and a non-zero error
- * code otherwise.
+ * Returns 0 if a valid-looking entry is found.  "*cctype" is
+ * set to the name of the cache type.  A pointer to the dirent
+ * is planted in "*d".  Caller must free "*d" with free(3).
+ *
+ * Otherwise, a negative errno is returned.
  */
 static int
-gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d)
+gssd_find_existing_krb5_ccache(uid_t uid, char *dirname,
+                              const char **cctype, struct dirent **d)
 {
        struct dirent **namelist;
        int n;
@@ -192,6 +193,7 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d)
        int score, best_match_score = 0, err = -EACCES;
 
        memset(&best_match_stat, 0, sizeof(best_match_stat));
+       *cctype = NULL;
        *d = NULL;
        n = scandir(dirname, &namelist, select_krb5_ccache, 0);
        if (n < 0) {
@@ -203,41 +205,51 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d)
                for (i = 0; i < n; i++) {
                        snprintf(statname, sizeof(statname),
                                 "%s/%s", dirname, namelist[i]->d_name);
-                       printerr(3, "CC file '%s' being considered, "
+                       printerr(3, "CC '%s' being considered, "
                                 "with preferred realm '%s'\n",
                                 statname, preferred_realm ?
                                        preferred_realm : "<none selected>");
-                       snprintf(buf, sizeof(buf), "FILE:%s/%s", dirname, 
-                                       namelist[i]->d_name);
                        if (lstat(statname, &tmp_stat)) {
-                               printerr(0, "Error doing stat on file '%s'\n",
+                               printerr(0, "Error doing stat on '%s'\n",
                                         statname);
                                free(namelist[i]);
                                continue;
                        }
                        /* Only pick caches owned by the user (uid) */
                        if (tmp_stat.st_uid != uid) {
-                               printerr(3, "CC file '%s' owned by %u, not %u\n",
+                               printerr(3, "CC '%s' owned by %u, not %u\n",
                                         statname, tmp_stat.st_uid, uid);
                                free(namelist[i]);
                                continue;
                        }
-                       if (!S_ISREG(tmp_stat.st_mode)) {
-                               printerr(3, "CC file '%s' is not a regular file\n",
+                       if (!S_ISREG(tmp_stat.st_mode) &&
+                           !S_ISDIR(tmp_stat.st_mode)) {
+                               printerr(3, "CC '%s' is not a regular "
+                                        "file or directory\n",
                                         statname);
                                free(namelist[i]);
                                continue;
                        }
                        if (uid == 0 && !root_uses_machine_creds && 
                                strstr(namelist[i]->d_name, "_machine_")) {
-                               printerr(3, "CC file '%s' not available to root\n",
+                               printerr(3, "CC '%s' not available to root\n",
                                         statname);
                                free(namelist[i]);
                                continue;
                        }
+                       if (S_ISDIR(tmp_stat.st_mode)) {
+                               *cctype = "DIR";
+                       } else
+                       if (S_ISREG(tmp_stat.st_mode)) {
+                               *cctype = "FILE";
+                       } else {
+                               continue;
+                       }
+                       snprintf(buf, sizeof(buf), "%s:%s/%s", *cctype,
+                                dirname, namelist[i]->d_name);
                        if (!query_krb5_ccache(buf, &princname, &realm)) {
-                               printerr(3, "CC file '%s' is expired or corrupt\n",
-                                        statname);
+                               printerr(3, "CC '%s' is expired or corrupt\n",
+                                        buf);
                                free(namelist[i]);
                                err = -EKEYEXPIRED;
                                continue;
@@ -248,9 +260,9 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d)
                                        strcmp(realm, preferred_realm) == 0) 
                                score++;
 
-                       printerr(3, "CC file '%s'(%s@%s) passed all checks and"
+                       printerr(3, "CC '%s'(%s@%s) passed all checks and"
                                    " has mtime of %u\n",
-                                statname, princname, realm, 
+                                buf, princname, realm, 
                                 tmp_stat.st_mtime);
                        /*
                         * if more than one match is found, return the most
@@ -284,10 +296,11 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname, struct dirent **d)
                                else {
                                        free(namelist[i]);
                                }
-                               printerr(3, "CC file '%s/%s' is our "
+                               printerr(3, "CC '%s:%s/%s' is our "
                                            "current best match "
                                            "with mtime of %u\n",
-                                        dirname, best_match_dir->d_name,
+                                        cctype, dirname,
+                                        best_match_dir->d_name,
                                         best_match_stat.st_mtime);
                        }
                        free(princname);
@@ -337,6 +350,11 @@ gssd_get_single_krb5_cred(krb5_context context,
 
        memset(&my_creds, 0, sizeof(my_creds));
 
+       /*
+        * Workaround for clock skew among NFS server, NFS client and KDC
+        * 300 because clock skew must be within 300sec for kerberos
+        */
+       now += 300;
        if (ple->ccname && ple->endtime > now && !nocache) {
                printerr(2, "INFO: Credentials in CC '%s' are good until %d\n",
                         ple->ccname, ple->endtime);
@@ -761,12 +779,16 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt,
 }
 
 /*
- * Find a keytab entry to use for a given target hostname.
+ * Find a keytab entry to use for a given target realm.
  * Tries to find the most appropriate keytab to use given the
  * name of the host we are trying to connect with.
+ *
+ * Note: the tgtname contains a hostname in the realm that we
+ * are authenticating to. It may, or may not be the same as
+ * the server hostname.
  */
 static int
-find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname,
+find_keytab_entry(krb5_context context, krb5_keytab kt, const char *tgtname,
                  krb5_keytab_entry *kte, const char **svcnames)
 {
        krb5_error_code code;
@@ -782,14 +804,14 @@ find_keytab_entry(krb5_context context, krb5_keytab kt, const char *hostname,
 
 
        /* Get full target hostname */
-       retval = get_full_hostname(hostname, targethostname,
+       retval = get_full_hostname(tgtname, targethostname,
                                   sizeof(targethostname));
        if (retval)
                goto out;
 
        /* Get full local hostname */
-       retval = gethostname(myhostname, sizeof(myhostname));
-       if (retval) {
+       if (gethostname(myhostname, sizeof(myhostname)) == -1) {
+               retval = errno;
                k5err = gssd_k5_err_msg(context, retval);
                printerr(1, "%s while getting local hostname\n", k5err);
                goto out;
@@ -1020,29 +1042,52 @@ err_cache:
  * given only a UID.  We really need more information, but we
  * do the best we can.
  *
- * Returns 0 if a ccache was found, and a non-zero error code otherwise.
+ * Returns 0 if a ccache was found, or a negative errno otherwise.
  */
 int
-gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, char *dirname)
+gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, char *dirpattern)
 {
-       char                    buf[MAX_NETOBJ_SZ];
+       char                    buf[MAX_NETOBJ_SZ], dirname[PATH_MAX];
+       const char              *cctype;
        struct dirent           *d;
-       int                     err;
+       int                     err, i, j;
 
        printerr(2, "getting credentials for client with uid %u for "
                    "server %s\n", uid, servername);
-       memset(buf, 0, sizeof(buf));
-       err = gssd_find_existing_krb5_ccache(uid, dirname, &d);
+
+       for (i = 0, j = 0; dirpattern[i] != '\0'; i++) {
+               switch (dirpattern[i]) {
+               case '%':
+                       switch (dirpattern[i + 1]) {
+                       case '%':
+                               dirname[j++] = dirpattern[i];
+                               i++;
+                               break;
+                       case 'U':
+                               j += sprintf(dirname + j, "%lu",
+                                            (unsigned long) uid);
+                               i++;
+                               break;
+                       }
+                       break;
+               default:
+                       dirname[j++] = dirpattern[i];
+                       break;
+               }
+       }
+       dirname[j] = '\0';
+
+       err = gssd_find_existing_krb5_ccache(uid, dirname, &cctype, &d);
        if (err)
                return err;
 
-       snprintf(buf, sizeof(buf), "FILE:%s/%s", dirname, d->d_name);
+       snprintf(buf, sizeof(buf), "%s:%s/%s", cctype, dirname, d->d_name);
        free(d);
 
        printerr(2, "using %s as credentials cache for client with "
                    "uid %u for server %s\n", buf, uid, servername);
        gssd_set_krb5_ccache_name(buf);
-       return err;
+       return 0;
 }
 
 /*
@@ -1092,7 +1137,7 @@ gssd_get_krb5_machine_cred_list(char ***list)
                if (ple->ccname) {
                        /* Make sure cred is up-to-date before returning it */
                        retval = gssd_refresh_krb5_machine_credential(NULL, ple,
-                               NULL);
+                               NULL, NULL);
                        if (retval)
                                continue;
                        if (i + 1 > listsize) {
@@ -1172,9 +1217,9 @@ gssd_destroy_krb5_machine_creds(void)
                                    "cache '%s'\n", k5err, ple->ccname);
                }
        }
+       krb5_free_context(context);
   out:
        free(k5err);
-       krb5_free_context(context);
 }
 
 /*
@@ -1183,7 +1228,8 @@ gssd_destroy_krb5_machine_creds(void)
 int
 gssd_refresh_krb5_machine_credential(char *hostname,
                                     struct gssd_k5_kt_princ *ple, 
-                                        char *service)
+                                        char *service,
+                                        char *tgtname)
 {
        krb5_error_code code = 0;
        krb5_context context;
@@ -1216,19 +1262,22 @@ gssd_refresh_krb5_machine_credential(char *hostname,
                k5err = gssd_k5_err_msg(context, code);
                printerr(0, "ERROR: %s: %s while resolving keytab '%s'\n",
                         __func__, k5err, keytabfile);
-               goto out;
+               goto out_free_context;
        }
 
        if (ple == NULL) {
                krb5_keytab_entry kte;
 
-               code = find_keytab_entry(context, kt, hostname, &kte, svcnames);
+               if (tgtname == NULL)
+                       tgtname = hostname;
+
+               code = find_keytab_entry(context, kt, tgtname, &kte, svcnames);
                if (code) {
                        printerr(0, "ERROR: %s: no usable keytab entry found "
                                 "in keytab %s for connection with host %s\n",
                                 __FUNCTION__, keytabfile, hostname);
                        retval = code;
-                       goto out;
+                       goto out_free_kt;
                }
 
                ple = get_ple_by_princ(context, kte.principal);
@@ -1244,14 +1293,15 @@ gssd_refresh_krb5_machine_credential(char *hostname,
                                 __FUNCTION__, pname ? pname : "<unparsable>",
                                 hostname);
                        if (pname) k5_free_unparsed_name(context, pname);
-                       goto out;
+                       goto out_free_kt;
                }
        }
        retval = gssd_get_single_krb5_cred(context, kt, ple, 0);
-out:
-       if (kt)
-               krb5_kt_close(context, kt);
+out_free_kt:
+       krb5_kt_close(context, kt);
+out_free_context:
        krb5_free_context(context);
+out:
        free(k5err);
        return retval;
 }
@@ -1300,6 +1350,57 @@ gssd_k5_get_default_realm(char **def_realm)
        krb5_free_context(context);
 }
 
+static int
+gssd_acquire_krb5_cred(gss_name_t name, gss_cred_id_t *gss_cred)
+{
+       OM_uint32 maj_stat, min_stat;
+       gss_OID_set_desc desired_mechs = { 1, &krb5oid };
+
+       maj_stat = gss_acquire_cred(&min_stat, name, GSS_C_INDEFINITE,
+                                   &desired_mechs, GSS_C_INITIATE,
+                                   gss_cred, NULL, NULL);
+
+       if (maj_stat != GSS_S_COMPLETE) {
+               if (get_verbosity() > 0)
+                       pgsserr("gss_acquire_cred",
+                               maj_stat, min_stat, &krb5oid);
+               return -1;
+       }
+
+       return 0;
+}
+
+int
+gssd_acquire_user_cred(uid_t uid, gss_cred_id_t *gss_cred)
+{
+       OM_uint32 maj_stat, min_stat;
+       gss_buffer_desc name_buf;
+       gss_name_t name;
+       char buf[11];
+       int ret;
+
+       ret = snprintf(buf, 11, "%u", uid);
+       if (ret < 1 || ret > 10) {
+               return -1;
+       }
+       name_buf.value = buf;
+       name_buf.length = ret + 1;
+
+       maj_stat = gss_import_name(&min_stat, &name_buf,
+                                  GSS_C_NT_STRING_UID_NAME, &name);
+       if (maj_stat != GSS_S_COMPLETE) {
+               if (get_verbosity() > 0)
+                       pgsserr("gss_import_name",
+                               maj_stat, min_stat, &krb5oid);
+               return -1;
+       }
+
+       ret = gssd_acquire_krb5_cred(name, gss_cred);
+
+       maj_stat = gss_release_name(&min_stat, &name);
+       return ret;
+}
+
 #ifdef HAVE_SET_ALLOWABLE_ENCTYPES
 /*
  * this routine obtains a credentials handle via gss_acquire_cred()
@@ -1318,28 +1419,18 @@ int
 limit_krb5_enctypes(struct rpc_gss_sec *sec)
 {
        u_int maj_stat, min_stat;
-       gss_cred_id_t credh;
-       gss_OID_set_desc  desired_mechs;
        krb5_enctype enctypes[] = { ENCTYPE_DES_CBC_CRC,
                                    ENCTYPE_DES_CBC_MD5,
                                    ENCTYPE_DES_CBC_MD4 };
        int num_enctypes = sizeof(enctypes) / sizeof(enctypes[0]);
        extern int num_krb5_enctypes;
        extern krb5_enctype *krb5_enctypes;
+       int err = -1;
 
-       /* We only care about getting a krb5 cred */
-       desired_mechs.count = 1;
-       desired_mechs.elements = &krb5oid;
-
-       maj_stat = gss_acquire_cred(&min_stat, NULL, 0,
-                                   &desired_mechs, GSS_C_INITIATE,
-                                   &credh, NULL, NULL);
-
-       if (maj_stat != GSS_S_COMPLETE) {
-               if (get_verbosity() > 0)
-                       pgsserr("gss_acquire_cred",
-                               maj_stat, min_stat, &krb5oid);
-               return -1;
+       if (sec->cred == GSS_C_NO_CREDENTIAL) {
+               err = gssd_acquire_krb5_cred(GSS_C_NO_NAME, &sec->cred);
+               if (err)
+                       return -1;
        }
 
        /*
@@ -1347,19 +1438,17 @@ limit_krb5_enctypes(struct rpc_gss_sec *sec)
         * list of supported enctypes, use local default here.
         */
        if (krb5_enctypes == NULL || limit_to_legacy_enctypes)
-               maj_stat = gss_set_allowable_enctypes(&min_stat, credh,
+               maj_stat = gss_set_allowable_enctypes(&min_stat, sec->cred,
                                        &krb5oid, num_enctypes, enctypes);
        else
-               maj_stat = gss_set_allowable_enctypes(&min_stat, credh,
+               maj_stat = gss_set_allowable_enctypes(&min_stat, sec->cred,
                                        &krb5oid, num_krb5_enctypes, krb5_enctypes);
 
        if (maj_stat != GSS_S_COMPLETE) {
                pgsserr("gss_set_allowable_enctypes",
                        maj_stat, min_stat, &krb5oid);
-               gss_release_cred(&min_stat, &credh);
                return -1;
        }
-       sec->cred = credh;
 
        return 0;
 }
index cd6e107326923449375f0a93e81b0a5cf8d0a342..eed12944a73024c015d79f1c4aace2a9d31a1688 100644 (file)
@@ -31,10 +31,13 @@ void gssd_setup_krb5_machine_gss_ccache(char *servername);
 void gssd_destroy_krb5_machine_creds(void);
 int  gssd_refresh_krb5_machine_credential(char *hostname,
                                          struct gssd_k5_kt_princ *ple, 
-                                         char *service);
+                                         char *service,
+                                         char *tgtname);
 char *gssd_k5_err_msg(krb5_context context, krb5_error_code code);
 void gssd_k5_get_default_realm(char **def_realm);
 
+int gssd_acquire_user_cred(uid_t uid, gss_cred_id_t *gss_cred);
+
 #ifdef HAVE_SET_ALLOWABLE_ENCTYPES
 extern int limit_to_legacy_enctypes;
 int limit_krb5_enctypes(struct rpc_gss_sec *sec);
index 1afff9e5a4935c3a9be76b4ccaf2d02f3463e74c..8aee3b2e64a99d5c66f6f3674219410ad9157c10 100644 (file)
@@ -153,7 +153,7 @@ sig_die(int signal)
 {
        /* destroy krb5 machine creds */
        printerr(1, "exiting on signal %d\n", signal);
-       exit(1);
+       exit(0);
 }
 
 void
index 6c34faf4b5f8537fc8c5f04508adf979f2a7ae7e..1d44d3449c02cd71cfbe0d7be6f1f9991654a798 100644 (file)
@@ -38,6 +38,7 @@
 
 #include <stdio.h>
 #include <errno.h>
+#include <ctype.h>
 #include <gssapi/gssapi.h>
 #include <krb5.h>
 
@@ -98,6 +99,12 @@ parse_enctypes(char *enctypes)
        if (n == 0)
                return ENOENT;
 
+       /* Skip pass any non digits */
+       while (*enctypes && isdigit(*enctypes) == 0)
+               enctypes++;
+       if (*enctypes == '\0')
+               return EINVAL;
+
        /* Allocate space for enctypes array */
        if ((parsed_enctypes = (int *) calloc(n, sizeof(int))) == NULL) {
                return ENOMEM;
index 0d4f78d9668396aaebb05ab97804cfb1e8d5ed5a..3757d5191041b0341ea8ed11db6b26d3bea4f460 100644 (file)
@@ -484,7 +484,7 @@ handle_nullreq(FILE *f) {
 
        /* kernel needs ctx to calculate verifier on null response, so
         * must give it context before doing null call: */
-       if (serialize_context_for_kernel(ctx, &ctx_token, mech, &ctx_endtime)) {
+       if (serialize_context_for_kernel(&ctx, &ctx_token, mech, &ctx_endtime)) {
                printerr(0, "WARNING: handle_nullreq: "
                            "serialize_context_for_kernel failed\n");
                maj_stat = GSS_S_FAILURE;
index e80efb4549f1f3633c5469c039f4dd6004f23398..beba9c4517076e156ad697f6b66d362b8d444aae 100644 (file)
@@ -145,7 +145,6 @@ static void svrreopen(int, short, void *);
 static int  nfsopen(struct idmap_client *);
 static void nfscb(int, short, void *);
 static void nfsdcb(int, short, void *);
-static int  validateascii(char *, u_int32_t);
 static int  addfield(char **, ssize_t *, char *);
 static int  getfield(char **, char *, size_t);
 
@@ -425,7 +424,8 @@ dirscancb(int UNUSED(fd), short UNUSED(which), void *data)
                            pipefsdir, ents[i]->d_name);
 
                        if ((ic->ic_dirfd = open(path, O_RDONLY, 0)) == -1) {
-                               xlog_warn("dirscancb: open(%s): %s", path, strerror(errno));
+                               if (verbose > 0)
+                                       xlog_warn("dirscancb: open(%s): %s", path, strerror(errno));
                                free(ic);
                                goto out;
                        }
@@ -642,6 +642,8 @@ out:
 static void
 imconv(struct idmap_client *ic, struct idmap_msg *im)
 {
+       u_int32_t len;
+
        switch (im->im_conv) {
        case IDMAP_CONV_IDTONAME:
                idtonameres(im);
@@ -652,10 +654,10 @@ imconv(struct idmap_client *ic, struct idmap_msg *im)
                            im->im_id, im->im_name);
                break;
        case IDMAP_CONV_NAMETOID:
-               if (validateascii(im->im_name, sizeof(im->im_name)) == -1) {
-                       im->im_status |= IDMAP_STATUS_INVALIDMSG;
+               len = strnlen(im->im_name, IDMAP_NAMESZ - 1);
+               /* Check for NULL termination just to be careful */
+               if (im->im_name[len+1] != '\0')
                        return;
-               }
                nametoidres(im);
                if (verbose > 1)
                        xlog_warn("%s %s: (%s) name \"%s\" -> id \"%d\"",
@@ -854,25 +856,6 @@ nametoidres(struct idmap_msg *im)
        }
 }
 
-static int
-validateascii(char *string, u_int32_t len)
-{
-       u_int32_t i;
-
-       for (i = 0; i < len; i++) {
-               if (string[i] == '\0')
-                       break;
-
-               if (string[i] & 0x80)
-                       return (-1);
-       }
-
-       if ((i >= len) || string[i] != '\0')
-               return (-1);
-
-       return (i + 1);
-}
-
 static int
 addfield(char **bpp, ssize_t *bsizp, char *fld)
 {
index 7627854f311f377c9dab7120e503d6e145bcf380..5810936893985c6274f2e09fa1da0fc42de842ee 100644 (file)
@@ -1,7 +1,7 @@
 ## Process this file with automake to produce Makefile.in
 
 # These binaries go in /sbin (not /usr/sbin), and that cannot be
-# overriden at config time.
+# overridden at config time.
 sbindir = /sbin
 
 man8_MANS      = mount.nfs.man umount.nfs.man
index 83ad1d2f796a29551e5beb797966ff17e475c8e9..f8fc13fea3d794048e73cd05a2eaa9d2d0bd27c3 100644 (file)
@@ -225,7 +225,7 @@ void mount_error(const char *spec, const char *mount_point, int error)
        case ENOENT:
                if (spec)
                        nfs_error(_("%s: mounting %s failed, "
-                               "reason given by server:\n  %s"),
+                               "reason given by server: %s"),
                                progname, spec, strerror(error));
                else
                        nfs_error(_("%s: mount point %s does not exist"),
index e8f17a9c5910fcb2494d59639e760017b82da2a2..701d41e42e2e8725d1f8a2bb1c07d1d343a2a8a8 100644 (file)
@@ -140,14 +140,14 @@ static int try_mount(struct libmnt_context *cxt, int bg)
        return ret;
 }
 
-/* returns: error = -1, success = 0 , unknown = 1 */
+/* returns: error = -1, success = 1 , not vers4 == 0 */
 static int is_vers4(struct libmnt_context *cxt)
 {
        struct libmnt_fs *fs = mnt_context_get_fs(cxt);
        struct libmnt_table *tb = NULL;
        const char *src = mnt_context_get_source(cxt),
                   *tgt = mnt_context_get_target(cxt);
-       int rc = 1;
+       int rc = 0;
 
        if (!src || !tgt)
                return -1;
@@ -163,7 +163,7 @@ static int is_vers4(struct libmnt_context *cxt)
        if (fs) {
                const char *type = mnt_fs_get_fstype(fs);
                if (type && strcmp(type, "nfs4") == 0)
-                       rc = 0;
+                       rc = 1;
        }
        mnt_free_table(tb);
        return rc;
@@ -173,6 +173,7 @@ static int umount_main(struct libmnt_context *cxt, int argc, char **argv)
 {
        int rc, c;
        char *spec = NULL, *opts = NULL;
+       int ret = EX_FAIL;
 
        static const struct option longopts[] = {
                { "force", 0, 0, 'f' },
@@ -209,8 +210,6 @@ static int umount_main(struct libmnt_context *cxt, int argc, char **argv)
 
        if (mnt_context_set_target(cxt, spec))
                goto err;
-       if (mnt_context_set_fstype_pattern(cxt, "nfs,nfs4"))    /* restrict filesystems */
-               goto err;
 
        /* read mtab/fstab, evaluate permissions, etc. */
        rc = mnt_context_prepare_umount(cxt);
@@ -220,6 +219,14 @@ static int umount_main(struct libmnt_context *cxt, int argc, char **argv)
                goto err;
        }
 
+       if (mnt_context_get_fstype(cxt) &&
+           !mnt_match_fstype(mnt_context_get_fstype(cxt), "nfs,nfs4")) {
+
+               nfs_error(_("%s: %s: is not an NFS filesystem"), progname, spec);
+               ret = EX_USAGE;
+               goto err;
+       }
+
        opts = retrieve_mount_options(mnt_context_get_fs(cxt));
 
        if (!mnt_context_is_lazy(cxt)) {
@@ -244,6 +251,7 @@ static int umount_main(struct libmnt_context *cxt, int argc, char **argv)
                        nfs_umount23(spec, "tcp,v3");
        }
 
+       ret = EX_FILEIO;
        rc = mnt_context_do_umount(cxt);        /* call umount(2) syscall */
        mnt_context_finalize_mount(cxt);        /* mtab update */
 
@@ -252,12 +260,10 @@ static int umount_main(struct libmnt_context *cxt, int argc, char **argv)
                umount_error(rc, spec);
                goto err;
        }
-
-       free(opts);
-       return EX_SUCCESS;
+       ret = EX_SUCCESS;
 err:
        free(opts);
-       return EX_FAIL;
+       return ret;
 }
 
 static int mount_main(struct libmnt_context *cxt, int argc, char **argv)
index e7bd522ac8da7927a7cfde97e3fc968137d356ab..4be48cd6a5f0941d3cb1be2b0d40ce9d7ece6d31 100644 (file)
@@ -155,9 +155,8 @@ static const unsigned long probe_nfs2_only[] = {
        0,
 };
 
-static const unsigned long probe_nfs3_first[] = {
+static const unsigned long probe_nfs3_only[] = {
        3,
-       2,
        0,
 };
 
@@ -167,10 +166,8 @@ static const unsigned long probe_mnt1_first[] = {
        0,
 };
 
-static const unsigned long probe_mnt3_first[] = {
+static const unsigned long probe_mnt3_only[] = {
        3,
-       1,
-       2,
        0,
 };
 
@@ -626,7 +623,7 @@ static int nfs_probe_nfsport(const struct sockaddr *sap, const socklen_t salen,
                probe_proto = nfs_default_proto();
 
                return nfs_probe_port(sap, salen, pmap,
-                                       probe_nfs3_first, probe_proto);
+                                       probe_nfs3_only, probe_proto);
        } else
                return nfs_probe_port(sap, salen, pmap,
                                        probe_nfs2_only, probe_udp_only);
@@ -653,7 +650,7 @@ static int nfs_probe_mntport(const struct sockaddr *sap, const socklen_t salen,
 
        if (nfs_mount_data_version >= 4)
                return nfs_probe_port(sap, salen, pmap,
-                                       probe_mnt3_first, probe_udp_first);
+                                       probe_mnt3_only, probe_udp_first);
        else
                return nfs_probe_port(sap, salen, pmap,
                                        probe_mnt1_first, probe_udp_only);
@@ -717,7 +714,7 @@ int nfs_probe_bothports(const struct sockaddr *mnt_saddr,
        memcpy(&save_nfs, nfs_pmap, sizeof(save_nfs));
        memcpy(&save_mnt, mnt_pmap, sizeof(save_mnt));
        probe_vers = (nfs_mount_data_version >= 4) ?
-                       probe_mnt3_first : probe_mnt1_first;
+                       probe_mnt3_only : probe_mnt1_first;
 
        for (; *probe_vers; probe_vers++) {
                nfs_pmap->pm_vers = mntvers_to_nfs(*probe_vers);
index 87e27e1519615d3663172dc0b29d7aef33514695..a8ec46cb7509ba85c6d3359f3bc3eb27f7fc47d4 100644 (file)
@@ -1,5 +1,5 @@
 .\"@(#)nfs.5"
-.TH NFS 5 "2 November 2007"
+.TH NFS 5 "9 October 2012"
 .SH NAME
 nfs \- fstab format and options for the
 .B nfs
@@ -347,6 +347,13 @@ using an automounter (refer to
 .BR automount (8)
 for details).
 .TP 1.5i
+.BR rdirplus " / " nordirplus
+Selects whether to use NFS v3 or v4 READDIRPLUS requests.
+If this option is not specified, the NFS client uses READDIRPLUS requests
+on NFS v3 or v4 mounts to read small directories.
+Some applications perform better if the client uses only READDIR requests
+for all directories.
+.TP 1.5i
 .BI retry= n
 The number of minutes that the
 .BR mount (8)
@@ -359,21 +366,22 @@ If a value of zero is specified, the
 .BR mount (8)
 command exits immediately after the first failure.
 .TP 1.5i
-.BI sec= mode
-The RPCGSS security flavor to use for accessing files on this mount point.
-If the
-.B sec
-option is not specified, or if
-.B sec=sys
-is specified, the NFS client uses the AUTH_SYS security flavor
-for all NFS requests on this mount point.
-Valid security flavors are
+.BI sec= flavor
+The security flavor to use for accessing files on this mount point.
+If the server does not support this flavor, the mount operation fails.
+If
+.B sec=
+is not specified, the client attempts to find
+a security flavor that both the client and the server supports.
+Valid
+.I flavors
+are
 .BR none ,
 .BR sys ,
 .BR krb5 ,
 .BR krb5i ,
 and
-.BR krb5p ,
+.BR krb5p .
 Refer to the SECURITY CONSIDERATIONS section for details.
 .TP 1.5i
 .BR sharecache " / " nosharecache
@@ -460,29 +468,27 @@ by other clients, but can impact application and server performance.
 .IP
 The DATA AND METADATA COHERENCE section contains a
 detailed discussion of these trade-offs.
+.TP 1.5i
+.BR fsc " / " nofsc
+Enable/Disables the cache of (read-only) data pages to the local disk 
+using the FS-Cache facility. See cachefilesd(8) 
+and <kernel_soruce>/Documentation/filesystems/caching
+for detail on how to configure the FS-Cache facility.
+Default value is nofsc.
 .SS "Options for NFS versions 2 and 3 only"
 Use these options, along with the options in the above subsection,
 for NFS versions 2 and 3 only.
 .TP 1.5i
 .BI proto= netid
-The transport protocol name and protocol family the NFS client uses
-to transmit requests to the NFS server for this mount point.
-If an NFS server has both an IPv4 and an IPv6 address, using a specific
-netid will force the use of IPv4 or IPv6 networking to communicate
-with that server.
-.IP
-If support for TI-RPC is built into the
-.B mount.nfs
-command,
-.I netid
-is a valid netid listed in
-.IR /etc/netconfig .
-The value "rdma" may also be specified.
-If the
-.B mount.nfs
-command does not have TI-RPC support, then
+The
 .I netid
-is one of "tcp," "udp," or "rdma," and only IPv4 may be used.
+determines the transport that is used to communicate with the NFS
+server.  Available options are
+.BR udp ", " udp6 ", "tcp ", " tcp6 ", and " rdma .
+Those which end in
+.B 6
+use IPv6 addresses and are only available if support for TI-RPC is
+built in. Others use IPv4 addresses.
 .IP
 Each transport protocol uses different default
 .B retrans
@@ -562,19 +568,18 @@ This option can be used when mounting an NFS server
 through a firewall that blocks the rpcbind protocol.
 .TP 1.5i
 .BI mountproto= netid
-The transport protocol name and protocol family the NFS client uses
+The transport the NFS client uses
 to transmit requests to the NFS server's mountd service when performing
 this mount request, and when later unmounting this mount point.
 .IP
-If support for TI-RPC is built into the
+.I netid
+may be one of
+.BR udp ", and " tcp
+which use IPv4 address or, if TI-RPC is built into the
 .B mount.nfs
 command,
-.I netid
-is a valid netid listed in
-.IR /etc/netconfig .
-Otherwise,
-.I netid
-is one of "tcp" or "udp," and only IPv4 may be used.
+.BR udp6 ", and " tcp6
+which use IPv6 addresses.
 .IP
 This option can be used when mounting an NFS server
 through a firewall that blocks a particular transport.
@@ -711,13 +716,6 @@ Disabling the NFSACL sideband protocol may be necessary
 if the negotiation causes problems on the client or server.
 Refer to the SECURITY CONSIDERATIONS section for more details.
 .TP 1.5i
-.BR rdirplus " / " nordirplus
-Selects whether to use NFS version 3 READDIRPLUS requests.
-If this option is not specified, the NFS client uses READDIRPLUS requests
-on NFS version 3 mounts to read small directories.
-Some applications perform better if the client uses only READDIR requests
-for all directories.
-.TP 1.5i
 .BR local_lock= mechanism
 Specifies whether to use local locking for any or both of the flock and the
 POSIX locking mechanisms.
@@ -766,21 +764,14 @@ Use these options, along with the options in the first subsection above,
 for NFS version 4 and newer.
 .TP 1.5i
 .BI proto= netid
-The transport protocol name and protocol family the NFS client uses
-to transmit requests to the NFS server for this mount point.
-If an NFS server has both an IPv4 and an IPv6 address, using a specific
-netid will force the use of IPv4 or IPv6 networking to communicate
-with that server.
-.IP
-If support for TI-RPC is built into the
-.B mount.nfs
-command,
-.I netid
-is a valid netid listed in
-.IR /etc/netconfig .
-Otherwise,
+The
 .I netid
-is one of "tcp" or "udp," and only IPv4 may be used.
+determines the transport that is used to communicate with the NFS
+server.  Supported options are
+.BR tcp ", " tcp6 ", and " rdma .
+.B tcp6
+use IPv6 addresses and is only available if support for TI-RPC is
+built in. Both others use IPv4 addresses.
 .IP
 All NFS version 4 servers are required to support TCP,
 so if this mount option is not specified, the NFS version 4 client
@@ -844,6 +835,8 @@ The DATA AND METADATA COHERENCE section discusses
 the behavior of this option in more detail.
 .TP 1.5i
 .BI clientaddr= n.n.n.n
+.TP 1.5i
+.BI clientaddr= n:n: ... :n
 Specifies a single IPv4 address (in dotted-quad form),
 or a non-link-local IPv6 address,
 that the NFS client advertises to allow servers
@@ -1452,19 +1445,19 @@ These auxiliary protocols use no authentication.
 In addition to combining these sideband protocols with the main NFS protocol,
 NFS version 4 introduces more advanced forms of access control,
 authentication, and in-transit data protection.
-The NFS version 4 specification mandates NFSv4 ACLs,
-RPCGSS authentication, and RPCGSS security flavors
+The NFS version 4 specification mandates support for
+strong authentication and security flavors
 that provide per-RPC integrity checking and encryption.
 Because NFS version 4 combines the
 function of the sideband protocols into the main NFS protocol,
 the new security features apply to all NFS version 4 operations
 including mounting, file locking, and so on.
 RPCGSS authentication can also be used with NFS versions 2 and 3,
-but does not protect their sideband protocols.
+but it does not protect their sideband protocols.
 .P
 The
 .B sec
-mount option specifies the RPCGSS security mode
+mount option specifies the security flavor
 that is in effect on a given NFS mount point.
 Specifying
 .B sec=krb5
@@ -1495,13 +1488,14 @@ Similar support for other forms of cryptographic security
 is also available.
 .P
 The NFS version 4 protocol allows
-clients and servers to negotiate among multiple security flavors
-during mount processing.
-However, Linux does not yet implement such negotiation.
-The Linux client specifies a single security flavor at mount time
-which remains in effect for the lifetime of the mount.
-If the server does not support this flavor,
-the initial mount request is rejected by the server.
+a client to renegotiate the security flavor
+when the client crosses into a new filesystem on the server.
+The newly negotiated flavor effects only accesses of the new filesystem.
+.P
+Such negotiation typically occurs when a client crosses
+from a server's pseudo-fs
+into one of the server's exported physical filesystems,
+which often have more restrictive security settings than the pseudo-fs.
 .SS "Using non-privileged source ports"
 NFS clients usually communicate with NFS servers via network sockets.
 Each end of a socket is assigned a port value, which is simply a number
index 12a3fe796d19d1c86f4bd4e15b993673d34d5241..3aa345649b82837e720f2209716fbaed357dbae8 100644 (file)
@@ -1,5 +1,5 @@
 .\"@(#)nfsmount.conf.5"
-.TH NFSMOUNT.CONF 5 "9 Mar 2008"
+.TH NFSMOUNT.CONF 5 "9 October 2012"
 .SH NAME
 nfsmount.conf - Configuration file for NFS mounts
 .SH SYNOPSIS
@@ -18,6 +18,10 @@ to particular variables using the
 .BR = 
 operator, as in 
 .BR Proto=Tcp .
+The variables that can be assigned are exactly the set of NFS specific
+mount options listed in
+.BR nfs (5).
+.PP
 Sections are broken up into three basic categories:
 Global options, Server options and Mount Point options.
 .HP
@@ -54,7 +58,7 @@ are defined in the configuration file.
     Proto=Tcp
 .RS
 .HP
-The TCP protocol will be used on every NFS mount.
+The TCP/IPv4 protocol will be used on every NFS mount.
 .HP
 .RE
 [ Server \(lqnfsserver.foo.com\(rq ]
@@ -62,10 +66,13 @@ The TCP protocol will be used on every NFS mount.
     rsize=32k
 .br
     wsize=32k
+.br
+    proto=udp6
 .HP
 .RS
-A 33k (32768 bytes) block size will be used as the read and write
-size on all mounts to the 'nfsserver.foo.com' server.
+A 32k (32768 bytes) block size will be used as the read and write
+size on all mounts to the 'nfsserver.foo.com' server.  UDP/IPv6
+is the protocol to be used.
 .HP
 .RE
 .BR 
index e09aa7c3b470e5322e5b5ebf3115f73eeed947fd..1dc38ef27ba50a83e8f221e1d18fb0fcfb3ae3bf 100644 (file)
@@ -542,6 +542,8 @@ nfs_rewrite_pmap_mount_options(struct mount_options *options)
                        errno = EACCES;
                else if (rpc_createerr.cf_stat == RPC_TIMEDOUT)
                        errno = ETIMEDOUT;
+               else if (rpc_createerr.cf_stat == RPC_PROGVERSMISMATCH)
+                       errno = EPROTONOSUPPORT;
                else if (rpc_createerr.cf_error.re_errno != 0)
                        errno = rpc_createerr.cf_error.re_errno;
                return 0;
@@ -665,6 +667,8 @@ static int nfs_try_mount_v3v2(struct nfsmount_info *mi)
                case ECONNREFUSED:
                case EOPNOTSUPP:
                case EHOSTUNREACH:
+               case ETIMEDOUT:
+               case EACCES:
                        continue;
                default:
                        goto out;
@@ -679,6 +683,7 @@ static int nfs_do_mount_v4(struct nfsmount_info *mi,
 {
        struct mount_options *options = po_dup(mi->options);
        int result = 0;
+       char *extra_opts = NULL;
 
        if (!options) {
                errno = ENOMEM;
@@ -714,20 +719,26 @@ static int nfs_do_mount_v4(struct nfsmount_info *mi,
                goto out_fail;
        }
 
-       /*
-        * Update option string to be recorded in /etc/mtab.
-        */
-       if (po_join(options, mi->extra_opts) == PO_FAILED) {
+       if (po_join(options, &extra_opts) == PO_FAILED) {
                errno = ENOMEM;
                goto out_fail;
        }
 
        if (verbose)
                printf(_("%s: trying text-based options '%s'\n"),
-                       progname, *mi->extra_opts);
+                       progname, extra_opts);
 
        result = nfs_sys_mount(mi, options);
 
+       /*
+        * If success, update option string to be recorded in /etc/mtab.
+        */
+       if (result) {
+           free(*mi->extra_opts);
+           *mi->extra_opts = extra_opts;
+       } else
+           free(extra_opts);
+
 out_fail:
        po_destroy(options);
        return result;
@@ -752,6 +763,8 @@ static int nfs_try_mount_v4(struct nfsmount_info *mi)
                switch (errno) {
                case ECONNREFUSED:
                case EHOSTUNREACH:
+               case ETIMEDOUT:
+               case EACCES:
                        continue;
                default:
                        goto out;
index 508040ad610bd0fd7268de26114f47f08baeda84..330cab531ea5b7832c987b8824b3200f392650a7 100644 (file)
 #include <config.h>
 #endif
 
+#include <sys/types.h>
 #include <sys/stat.h>
 #include <netinet/in.h>
 #include <arpa/inet.h>
 #include <errno.h>
+#include <fcntl.h>
 #include <unistd.h>
 
 #include "sockaddr.h"
@@ -21,7 +23,6 @@
 #include "nfslib.h"
 #include "exportfs.h"
 #include "mountd.h"
-#include "xmalloc.h"
 #include "v4root.h"
 
 enum auth_error
index 7d804322a2dfce0a45256dcb44d05297dce7ed5e..737927c78e8549c83ccf358b0f1636f353d303b6 100644 (file)
@@ -29,7 +29,6 @@
 #include "nfslib.h"
 #include "exportfs.h"
 #include "mountd.h"
-#include "xmalloc.h"
 #include "fsloc.h"
 #include "pseudoflavors.h"
 
@@ -81,7 +80,7 @@ static void auth_unix_ip(FILE *f)
         */
        char *cp;
        char class[20];
-       char ipaddr[INET6_ADDRSTRLEN];
+       char ipaddr[INET6_ADDRSTRLEN + 1];
        char *client = NULL;
        struct addrinfo *tmp = NULL;
        if (readline(fileno(f), &lbuf, &lbuflen) != 1)
@@ -95,7 +94,7 @@ static void auth_unix_ip(FILE *f)
            strcmp(class, "nfsd") != 0)
                return;
 
-       if (qword_get(&cp, ipaddr, sizeof(ipaddr)) <= 0)
+       if (qword_get(&cp, ipaddr, sizeof(ipaddr) - 1) <= 0)
                return;
 
        tmp = host_pton(ipaddr);
@@ -109,25 +108,24 @@ static void auth_unix_ip(FILE *f)
                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;
+               if (ai) {
+                       client = client_compose(ai);
+                       freeaddrinfo(ai);
+               }
        }
        qword_print(f, "nfsd");
        qword_print(f, ipaddr);
-       qword_printuint(f, time(0) + DEFAULT_TTL);
-       if (use_ipaddr)
+       qword_printtimefrom(f, DEFAULT_TTL);
+       if (use_ipaddr) {
+               memmove(ipaddr + 1, ipaddr, strlen(ipaddr) + 1);
+               ipaddr[0] = '$';
                qword_print(f, ipaddr);
-       else if (client)
+       else if (client)
                qword_print(f, *client?client:"DEFAULT");
        qword_eol(f);
        xlog(D_CALL, "auth_unix_ip: client %p '%s'", client, client?client: "DEFAULT");
 
        free(client);
-out:
        freeaddrinfo(tmp);
 
 }
@@ -183,7 +181,7 @@ static void auth_unix_gid(FILE *f)
                }
        }
        qword_printuint(f, uid);
-       qword_printuint(f, time(0) + DEFAULT_TTL);
+       qword_printtimefrom(f, DEFAULT_TTL);
        if (rv >= 0) {
                qword_printuint(f, ngroups);
                for (i=0; i<ngroups; i++)
@@ -238,17 +236,17 @@ static const char *get_uuid_blkdev(char *path)
 #define get_uuid_blkdev(path) (NULL)
 #endif
 
-static int get_uuid(const char *val, int uuidlen, char *u)
+static int get_uuid(const char *val, size_t uuidlen, char *u)
 {
        /* extract hex digits from uuidstr and compose a uuid
         * of the given length (max 16), xoring bytes to make
         * a smaller uuid.
         */
-       int i = 0;
+       size_t i = 0;
        
        memset(u, 0, uuidlen);
        for ( ; *val ; val++) {
-               char c = *val;
+               int c = *val;
                if (!isxdigit(c))
                        continue;
                if (isalpha(c)) {
@@ -260,7 +258,7 @@ static int get_uuid(const char *val, int uuidlen, char *u)
                        c = c - '0' + 0;
                if ((i&1) == 0)
                        c <<= 4;
-               u[i/2] ^= c;
+               u[i/2] ^= (char)c;
                i++;
                if (i == uuidlen*2)
                        i = 0;
@@ -268,7 +266,7 @@ static int get_uuid(const char *val, int uuidlen, char *u)
        return 1;
 }
 
-static int uuid_by_path(char *path, int type, int uuidlen, char *uuid)
+static int uuid_by_path(char *path, int type, size_t uuidlen, char *uuid)
 {
        /* get a uuid for the filesystem found at 'path'.
         * There are several possible ways of generating the
@@ -329,7 +327,7 @@ static char *next_mnt(void **v, char *p)
 {
        FILE *f;
        struct mntent *me;
-       int l = strlen(p);
+       size_t l = strlen(p);
        if (*v == NULL) {
                f = setmntent("/etc/mtab", "r");
                *v = f;
@@ -347,15 +345,39 @@ static char *next_mnt(void **v, char *p)
        return me->mnt_dir;
 }
 
+static int is_subdirectory(char *child, char *parent)
+{
+       size_t l = strlen(parent);
+
+       if (strcmp(parent, "/") == 0)
+               return 1;
+
+       return strcmp(child, parent) == 0
+               || (strncmp(child, parent, l) == 0 && child[l] == '/');
+}
+
+static int path_matches(nfs_export *exp, char *path)
+{
+       if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT)
+               return is_subdirectory(path, exp->m_export.e_path);
+       return strcmp(path, exp->m_export.e_path) == 0;
+}
+
+static int
+export_matches(nfs_export *exp, char *dom, char *path, struct addrinfo *ai)
+{
+       return path_matches(exp, path) && client_matches(exp, dom, ai);
+}
+
 /* True iff e1 is a child of e2 and e2 has crossmnt set: */
 static bool subexport(struct exportent *e1, struct exportent *e2)
 {
        char *p1 = e1->e_path, *p2 = e2->e_path;
-       int l2 = strlen(p2);
+       size_t l2 = strlen(p2);
 
        return e2->e_flags & NFSEXP_CROSSMOUNT
-              && strncmp(p1, p2, l2) == 0
-              && p1[l2] == '/';
+               && strncmp(p1, p2, l2) == 0
+               && p1[l2] == '/';
 }
 
 struct parsed_fsid {
@@ -366,15 +388,17 @@ struct parsed_fsid {
        unsigned int minor;
        unsigned int major;
        unsigned int fsidnum;
-       int uuidlen;
+       size_t uuidlen;
        char *fhuuid;
 };
 
-int parse_fsid(int fsidtype, int fsidlen, char *fsid, struct parsed_fsid *parsed)
+static int parse_fsid(int fsidtype, int fsidlen, char *fsid,
+               struct parsed_fsid *parsed)
 {
        unsigned int dev;
        unsigned long long inode64;
 
+       memset(parsed, 0, sizeof(*parsed));
        parsed->fsidtype = fsidtype;
        switch(fsidtype) {
        case FSID_DEV: /* 4 bytes: 2 major, 2 minor, 4 inode */
@@ -501,7 +525,7 @@ static bool match_fsid(struct parsed_fsid *parsed, nfs_export *exp, char *path)
        return false;
 }
 
-struct addrinfo *lookup_client_addr(char *dom)
+static struct addrinfo *lookup_client_addr(char *dom)
 {
        struct addrinfo *ret;
        struct addrinfo *tmp;
@@ -713,6 +737,7 @@ static void write_secinfo(FILE *f, struct exportent *ep, int flag_mask)
                /* There was no sec= option */
                return;
        }
+       fix_pseudoflavor_flags(ep);
        qword_print(f, "secinfo");
        qword_printint(f, p - ep->e_secinfo);
        for (p = ep->e_secinfo; p->flav; p++) {
@@ -730,7 +755,7 @@ static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *ex
                int different_fs = strcmp(path, exp->e_path) != 0;
                int flag_mask = different_fs ? ~NFSEXP_FSID : ~0;
 
-               qword_printuint(f, time(0) + exp->e_ttl);
+               qword_printtimefrom(f, exp->e_ttl);
                qword_printint(f, exp->e_flags & flag_mask);
                qword_printint(f, exp->e_anonuid);
                qword_printint(f, exp->e_anongid);
@@ -750,31 +775,10 @@ static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *ex
                        qword_printhex(f, u, 16);
                }
        } else
-               qword_printuint(f, time(0) + DEFAULT_TTL);
+               qword_printtimefrom(f, DEFAULT_TTL);
        return qword_eol(f);
 }
 
-static int is_subdirectory(char *child, char *parent)
-{
-       int l = strlen(parent);
-
-       return strcmp(child, parent) == 0
-               || (strncmp(child, parent, l) == 0 && child[l] == '/');
-}
-
-static int path_matches(nfs_export *exp, char *path)
-{
-       if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT)
-               return is_subdirectory(path, exp->m_export.e_path);
-       return strcmp(path, exp->m_export.e_path) == 0;
-}
-
-static int
-export_matches(nfs_export *exp, char *dom, char *path, struct addrinfo *ai)
-{
-       return path_matches(exp, path) && client_matches(exp, dom, ai);
-}
-
 static nfs_export *
 lookup_export(char *dom, char *path, struct addrinfo *ai)
 {
@@ -828,15 +832,70 @@ lookup_export(char *dom, char *path, struct addrinfo *ai)
 
 #ifdef HAVE_NFS_PLUGIN_H
 #include <dlfcn.h>
+#include <link.h>
 #include <nfs-plugin.h>
 
 /*
- * Walk through a set of FS locations and build a set of export options.
+ * Find the export entry for the parent of "pathname".
+ * Caller must not free returned exportent.
+ */
+static struct exportent *lookup_parent_export(char *dom,
+               const char *pathname, struct addrinfo *ai)
+{
+       char *parent, *slash;
+       nfs_export *result;
+
+       parent = strdup(pathname);
+       if (parent == NULL) {
+               xlog(D_GENERAL, "%s: failed to allocate parent path buffer",
+                       __func__);
+               goto out_default;
+       }
+       xlog(D_CALL, "%s: pathname = '%s'", __func__, pathname);
+
+again:
+       /* shorten pathname by one component */
+       slash = strrchr(parent, '/');
+       if (slash == NULL) {
+               xlog(D_GENERAL, "%s: no slash found in pathname",
+                       __func__);
+               goto out_default;
+       }
+       *slash = '\0';
+
+       if (strlen(parent) == 0) {
+               result = lookup_export(dom, "/", ai);
+               if (result == NULL) {
+                       xlog(L_ERROR, "%s: no root export found.", __func__);
+                       goto out_default;
+               }
+               goto out;
+       }
+
+       result = lookup_export(dom, parent, ai);
+       if (result == NULL) {
+               xlog(D_GENERAL, "%s: lookup_export(%s) found nothing",
+                       __func__, parent);
+               goto again;
+       }
+
+out:
+       xlog(D_CALL, "%s: found export for %s", __func__, parent);
+       free(parent);
+       return &result->m_export;
+
+out_default:
+       free(parent);
+       return mkexportent("*", "/", "insecure");
+}
+
+/*
+ * Walk through a set of FS locations and build an e_fslocdata string.
  * Returns true if all went to plan; otherwise, false.
  */
-static _Bool
-locations_to_options(struct jp_ops *ops, nfs_fsloc_set_t locations,
-               char *options, size_t remaining, int *ttl)
+static bool locations_to_fslocdata(struct jp_ops *ops,
+               nfs_fsloc_set_t locations, char *fslocdata,
+               size_t remaining, int *ttl)
 {
        char *server, *last_path, *rootpath, *ptr;
        _Bool seen = false;
@@ -844,7 +903,7 @@ locations_to_options(struct jp_ops *ops, nfs_fsloc_set_t locations,
        last_path = NULL;
        rootpath = NULL;
        server = NULL;
-       ptr = options;
+       ptr = fslocdata;
        *ttl = 0;
 
        for (;;) {
@@ -870,14 +929,14 @@ locations_to_options(struct jp_ops *ops, nfs_fsloc_set_t locations,
                                goto out_false;
                        }
                        if ((size_t)len >= remaining) {
-                               xlog(D_GENERAL, "%s: options buffer overflow", __func__);
+                               xlog(D_GENERAL, "%s: fslocdata buffer overflow", __func__);
                                goto out_false;
                        }
                        remaining -= (size_t)len;
                        ptr += len;
                } else {
                        if (last_path == NULL)
-                               len = snprintf(ptr, remaining, "refer=%s@%s",
+                               len = snprintf(ptr, remaining, "%s@%s",
                                                        rootpath, server);
                        else
                                len = snprintf(ptr, remaining, ":%s@%s",
@@ -887,7 +946,7 @@ locations_to_options(struct jp_ops *ops, nfs_fsloc_set_t locations,
                                goto out_false;
                        }
                        if ((size_t)len >= remaining) {
-                               xlog(D_GENERAL, "%s: options buffer overflow",
+                               xlog(D_GENERAL, "%s: fslocdata buffer overflow",
                                        __func__);
                                goto out_false;
                        }
@@ -901,8 +960,8 @@ locations_to_options(struct jp_ops *ops, nfs_fsloc_set_t locations,
                free(server);
        }
 
-       xlog(D_CALL, "%s: options='%s', ttl=%d",
-               __func__, options, *ttl);
+       xlog(D_CALL, "%s: fslocdata='%s', ttl=%d",
+               __func__, fslocdata, *ttl);
        return seen;
 
 out_false:
@@ -912,71 +971,72 @@ out_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.
+ * Duplicate the junction's parent's export options and graft in
+ * the fslocdata we constructed from the locations list.
  */
-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)
+static struct exportent *create_junction_exportent(struct exportent *parent,
+               const char *junction, const char *fslocdata, int ttl)
 {
-       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;
+       static struct exportent *eep;
+
+       eep = (struct exportent *)malloc(sizeof(*eep));
+       if (eep == NULL)
+               goto out_nomem;
+
+       dupexportent(eep, parent);
+       strcpy(eep->e_path, junction);
+       eep->e_hostname = strdup(parent->e_hostname);
+       if (eep->e_hostname == NULL) {
+               free(eep);
+               goto out_nomem;
+       }
+       free(eep->e_uuid);
+       eep->e_uuid = NULL;
+       eep->e_ttl = (unsigned int)ttl;
+
+       free(eep->e_fslocdata);
+       eep->e_fslocdata = strdup(fslocdata);
+       if (eep->e_fslocdata == NULL) {
+               free(eep->e_hostname);
+               free(eep);
+               goto out_nomem;
        }
+       eep->e_fslocmethod = FSLOC_REFER;
+       return eep;
 
-       exp->e_uuid = NULL;
-       exp->e_ttl = ttl;
-       return exp;
+out_nomem:
+       xlog(L_ERROR, "%s: No memory", __func__);
+       return NULL;
 }
 
 /*
- * 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.
+ * Walk through the set of FS locations and build an exportent.
+ * Returns pointer to an exportent if "junction" refers to a junction.
  */
 static struct exportent *locations_to_export(struct jp_ops *ops,
-               nfs_fsloc_set_t locations, const char *junction)
+               nfs_fsloc_set_t locations, const char *junction,
+               struct exportent *parent)
 {
-       struct exportent *exp;
-       char *options;
+       static char fslocdata[BUFSIZ];
+       int ttl;
 
-       options = malloc(BUFSIZ);
-       if (options == NULL) {
-               xlog(D_GENERAL, "%s: failed to allocate options buffer",
-                       __func__);
+       fslocdata[0] = '\0';
+       if (!locations_to_fslocdata(ops, locations,
+                                       fslocdata, sizeof(fslocdata), &ttl))
                return NULL;
-       }
-       options[0] = '\0';
-
-       exp = do_locations_to_export(ops, locations, junction,
-                                               options, BUFSIZ);
-
-       free(options);
-       return exp;
+       return create_junction_exportent(parent, junction, fslocdata, ttl);
 }
 
 /*
  * 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)
+static struct exportent *invoke_junction_ops(void *handle, char *dom,
+               const char *junction, struct addrinfo *ai)
 {
+       struct exportent *parent, *exp = NULL;
        nfs_fsloc_set_t locations;
-       struct exportent *exp;
        enum jp_status status;
        struct jp_ops *ops;
        char *error;
@@ -1002,15 +1062,28 @@ static struct exportent *invoke_junction_ops(void *handle,
        }
 
        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;
+       switch (status) {
+       case JP_OK:
+               break;
+       case JP_NOTJUNCTION:
+               xlog(D_GENERAL, "%s: %s is not a junction",
+                       __func__, junction);
+               goto out;
+       default:
+               xlog(L_WARNING, "Dangling junction %s: %s",
+                       junction, ops->jp_error(status));
+               goto out;
        }
 
-       exp = locations_to_export(ops, locations, junction);
+       parent = lookup_parent_export(dom, junction, ai);
+       if (parent == NULL)
+               goto out;
+
+       exp = locations_to_export(ops, locations, junction, parent);
 
        ops->jp_put_locations(locations);
+
+out:
        ops->jp_done();
        return exp;
 }
@@ -1019,12 +1092,12 @@ static struct exportent *invoke_junction_ops(void *handle,
  * 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)
+static struct exportent *lookup_junction(char *dom, const char *pathname,
+               struct addrinfo *ai)
 {
        struct exportent *exp;
+       struct link_map *map;
        void *handle;
 
        handle = dlopen("libnfsjunct.so", RTLD_NOW);
@@ -1032,9 +1105,14 @@ static struct exportent *lookup_junction(const char *pathname)
                xlog(D_GENERAL, "%s: dlopen: %s", __func__, dlerror());
                return NULL;
        }
+
+       if (dlinfo(handle, RTLD_DI_LINKMAP, &map) == 0)
+               xlog(D_GENERAL, "%s: loaded plug-in %s",
+                       __func__, map->l_name);
+
        (void)dlerror();        /* Clear any error */
 
-       exp = invoke_junction_ops(handle, pathname);
+       exp = invoke_junction_ops(handle, dom, pathname, ai);
 
        /* We could leave it loaded to make junction resolution
         * faster next time.  However, if we want to replace the
@@ -1042,10 +1120,24 @@ static struct exportent *lookup_junction(const char *pathname)
        (void)dlclose(handle);
        return exp;
 }
+
+static void lookup_nonexport(FILE *f, char *dom, char *path,
+               struct addrinfo *ai)
+{
+       struct exportent *eep;
+
+       eep = lookup_junction(dom, path, ai);
+       dump_to_cache(f, dom, path, eep);
+       if (eep == NULL)
+               return;
+       exportent_release(eep);
+       free(eep);
+}
 #else  /* !HAVE_NFS_PLUGIN_H */
-static inline struct exportent *lookup_junction(const char *UNUSED(pathname))
+static void lookup_nonexport(FILE *f, char *dom, char *path,
+               struct addrinfo *UNUSED(ai))
 {
-       return NULL;
+       dump_to_cache(f, dom, path, NULL);
 }
 #endif /* !HAVE_NFS_PLUGIN_H */
 
@@ -1096,9 +1188,9 @@ static void nfsd_export(FILE *f)
                             " or fsid= required", path);
                        dump_to_cache(f, dom, path, NULL);
                }
-       } else {
-               dump_to_cache(f, dom, path, lookup_junction(path));
-       }
+       } else
+               lookup_nonexport(f, dom, path, ai);
+
  out:
        xlog(D_CALL, "nfsd_export: found %p path %s", found, path ? path : NULL);
        if (dom) free(dom);
@@ -1258,7 +1350,7 @@ int cache_export(nfs_export *exp, char *path)
        qword_print(f, "nfsd");
        qword_print(f,
                host_ntop(get_addrlist(exp->m_client, 0), buf, sizeof(buf)));
-       qword_printuint(f, time(0) + exp->m_export.e_ttl);
+       qword_printtimefrom(f, exp->m_export.e_ttl);
        qword_print(f, exp->m_client->m_hostname);
        err = qword_eol(f);
        
index bcf5080a7351b522c436abd24712ae7ff1b43f76..993b6e65e58f612ef90c718991cd450d66649e65 100644 (file)
@@ -196,7 +196,8 @@ killer (int sig)
                wait_for_workers();
        }
        cleanup_lockfiles();
-       xlog (L_FATAL, "Caught signal %d, un-registering and exiting.", sig);
+       xlog (L_NOTICE, "Caught signal %d, un-registering and exiting.", sig);
+       exit(0);
 }
 
 static void
index 708eb614b92cc88aee2fa752c7cf1abf0a998c3f..34d098ad28d18ee3441f2a068b6acdae8122ea5d 100644 (file)
@@ -55,13 +55,16 @@ static nfs_export pseudo_root = {
        .m_warned = 0,
 };
 
-void set_pseudofs_security(struct exportent *pseudo, struct exportent *source)
+static void
+set_pseudofs_security(struct exportent *pseudo, struct exportent *source)
 {
        struct sec_entry *se;
        int i;
 
        if (source->e_flags & NFSEXP_INSECURE_PORT)
                pseudo->e_flags |= NFSEXP_INSECURE_PORT;
+       if ((source->e_flags & NFSEXP_ROOTSQUASH) == 0)
+               pseudo->e_flags &= ~NFSEXP_ROOTSQUASH;
        for (se = source->e_secinfo; se->flav; se++) {
                struct sec_entry *new;
 
@@ -92,7 +95,8 @@ v4root_create(char *path, nfs_export *export)
        exp = export_create(&eep, 0);
        if (exp == NULL)
                return NULL;
-       xlog(D_CALL, "v4root_create: path '%s'", exp->m_export.e_path);
+       xlog(D_CALL, "v4root_create: path '%s' flags 0x%x", 
+               exp->m_export.e_path, exp->m_export.e_flags);
        return &exp->m_export;
 }
 
@@ -118,7 +122,8 @@ v4root_support(void)
        return 0;
 }
 
-int pseudofs_update(char *hostname, char *path, nfs_export *source)
+static int
+pseudofs_update(char *hostname, char *path, nfs_export *source)
 {
        nfs_export *exp;
 
index 2a3f5cca4ae736a41075b1ad0d1a597d3a823235..e87c0a95952d17e584476312ef250ba1519d3bca 100644 (file)
@@ -38,6 +38,7 @@ static struct option longopts[] =
        { "host", 1, 0, 'H' },
        { "help", 0, 0, 'h' },
        { "no-nfs-version", 1, 0, 'N' },
+       { "nfs-version", 1, 0, 'V' },
        { "no-tcp", 0, 0, 'T' },
        { "no-udp", 0, 0, 'U' },
        { "port", 1, 0, 'P' },
@@ -119,7 +120,7 @@ main(int argc, char **argv)
        xlog_syslog(0);
        xlog_stderr(1);
 
-       while ((c = getopt_long(argc, argv, "dH:hN:p:P:sTU", longopts, NULL)) != EOF) {
+       while ((c = getopt_long(argc, argv, "dH:hN:V:p:P:sTU", longopts, NULL)) != EOF) {
                switch(c) {
                case 'd':
                        xlog_config(D_ALL, 1);
@@ -175,6 +176,27 @@ main(int argc, char **argv)
                                exit(1);
                        }
                        break;
+               case 'V':
+                       switch((c = strtol(optarg, &p, 0))) {
+                       case 4:
+                               if (*p == '.') {
+                                       int i = atoi(p+1);
+                                       if (i != 1) {
+                                               fprintf(stderr, "%s: unsupported minor version\n", optarg);
+                                               exit(1);
+                                       }
+                                       minorvers41 = 1;
+                                       break;
+                               }
+                       case 3:
+                       case 2:
+                               NFSCTL_VERSET(versbits, c);
+                               break;
+                       default:
+                               fprintf(stderr, "%s: Unsupported version\n", optarg);
+                               exit(1);
+                       }
+                       break;
                case 's':
                        xlog_syslog(1);
                        xlog_stderr(0);
@@ -312,7 +334,7 @@ static void
 usage(const char *prog)
 {
        fprintf(stderr, "Usage:\n"
-               "%s [-d|--debug] [-H hostname] [-p|-P|--port port] [-N|--no-nfs-version version ] [-s|--syslog] [-T|--no-tcp] [-U|--no-udp] nrservs\n", 
+               "%s [-d|--debug] [-H hostname] [-p|-P|--port port] [-N|--no-nfs-version version] [-V|--nfs-version version] [-s|--syslog] [-T|--no-tcp] [-U|--no-udp] nrservs\n", 
                prog);
        exit(2);
 }
index 1cf92969a6dd86506d96d03a58d9926de53e2fbd..7de0867e39e8d72d747b311345d2f9ac1e042038 100644 (file)
@@ -47,7 +47,7 @@ This option can be used to request that
 .B rpc.nfsd
 does not offer certain versions of NFS. The current version of
 .B rpc.nfsd
-can support both NFS version 2,3 and the newer version 4.
+can support NFS versions 2,3,4 and the newer version 4.1.
 .TP
 .B \-s " or " \-\-syslog
 By default,
@@ -67,6 +67,13 @@ Disable
 .B rpc.nfsd
 from accepting UDP connections from clients.
 .TP
+.B \-V " or " \-\-nfs-version vers
+This option can be used to request that 
+.B rpc.nfsd
+offer certain versions of NFS. The current version of
+.B rpc.nfsd
+can support NFS versions 2,3,4 and the newer version 4.1.
+.TP
 .I nproc
 specify the number of NFS server threads. By default, just one
 thread is started. However, for optimum performance several threads
diff --git a/utils/nfsdcld/Makefile.am b/utils/nfsdcld/Makefile.am
deleted file mode 100644 (file)
index 073a71b..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-## 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) $(LIBCAP)
-
-MAINTAINERCLEANFILES = Makefile.in
-
diff --git a/utils/nfsdcld/nfsdcld.c b/utils/nfsdcld/nfsdcld.c
deleted file mode 100644 (file)
index e7af4e3..0000000
+++ /dev/null
@@ -1,607 +0,0 @@
-/*
- * 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>
-#ifdef HAVE_SYS_CAPABILITY_H
-#include <sys/prctl.h>
-#include <sys/capability.h>
-#endif
-
-#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"
-
-#ifndef CLD_DEFAULT_STORAGEDIR
-#define CLD_DEFAULT_STORAGEDIR NFS_STATEDIR "/nfsdcld"
-#endif
-
-#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);
-}
-
-static int
-cld_set_caps(void)
-{
-       int ret = 0;
-#ifdef HAVE_SYS_CAPABILITY_H
-       unsigned long i;
-       cap_t caps;
-
-       if (getuid() != 0) {
-               xlog(L_ERROR, "Not running as root. Daemon won't be able to "
-                             "open the pipe after dropping capabilities!");
-               return -EINVAL;
-       }
-
-       /* prune the bounding set to nothing */
-       for (i = 0; i <= CAP_LAST_CAP; ++i) {
-               ret = prctl(PR_CAPBSET_DROP, i);
-               if (ret) {
-                       xlog(L_ERROR, "Unable to prune capability %lu from "
-                                     "bounding set: %m", i);
-                       return -errno;
-               }
-       }
-
-       /* get a blank capset */
-       caps = cap_init();
-       if (caps == NULL) {
-               xlog(L_ERROR, "Unable to get blank capability set: %m");
-               return -errno;
-       }
-
-       /* reset the process capabilities */
-       if (cap_set_proc(caps) != 0) {
-               xlog(L_ERROR, "Unable to set process capabilities: %m");
-               ret = -errno;
-       }
-       cap_free(caps);
-#endif
-       return ret;
-}
-
-#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(D_GENERAL, "%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 = CLD_DEFAULT_STORAGEDIR;
-       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;
-               }
-       }
-
-       /* drop all capabilities */
-       rc = cld_set_caps();
-       if (rc)
-               goto out;
-
-       /*
-        * now see if the storagedir is writable by root w/o CAP_DAC_OVERRIDE.
-        * If it isn't then give the user a warning but proceed as if
-        * everything is OK. If the DB has already been created, then
-        * everything might still work. If it doesn't exist at all, then
-        * assume that the maindb init will be able to create it. Fail on
-        * anything else.
-        */
-       if (access(storagedir, W_OK) == -1) {
-               switch (errno) {
-               case EACCES:
-                       xlog(L_WARNING, "Storage directory %s is not writable. "
-                                       "Should be owned by root and writable "
-                                       "by owner!", storagedir);
-                       break;
-               case ENOENT:
-                       /* ignore and assume that we can create dir as root */
-                       break;
-               default:
-                       xlog(L_ERROR, "Unexpected error when checking access "
-                                     "on %s: %m", storagedir);
-                       rc = -errno;
-                       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
deleted file mode 100644 (file)
index 9ddaf64..0000000
+++ /dev/null
@@ -1,185 +0,0 @@
-.\" 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 \fIstorage_dir\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.
-.PP
-This daemon should be run as root, as the pipe that it uses to communicate
-with the kernel is only accessable by root. The daemon however does drop all
-superuser capabilities after starting. Because of this, the \fIstoragedir\fR
-should be owned by root, and be readable and writable by owner.
-.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
deleted file mode 100644 (file)
index bb2519d..0000000
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * 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
-
-/* 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;
-
-       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
deleted file mode 100644 (file)
index c85e7d6..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * 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/nfsdcltrack/Makefile.am b/utils/nfsdcltrack/Makefile.am
new file mode 100644 (file)
index 0000000..a860ffb
--- /dev/null
@@ -0,0 +1,13 @@
+## Process this file with automake to produce Makefile.in
+
+man8_MANS      = nfsdcltrack.man
+EXTRA_DIST     = $(man8_MANS)
+
+AM_CFLAGS      += -D_LARGEFILE64_SOURCE
+sbin_PROGRAMS  = nfsdcltrack
+
+nfsdcltrack_SOURCES = nfsdcltrack.c sqlite.c
+nfsdcltrack_LDADD = ../../support/nfs/libnfs.a $(LIBSQLITE) $(LIBCAP)
+
+MAINTAINERCLEANFILES = Makefile.in
+
diff --git a/utils/nfsdcltrack/nfsdcltrack.c b/utils/nfsdcltrack/nfsdcltrack.c
new file mode 100644 (file)
index 0000000..4334340
--- /dev/null
@@ -0,0 +1,532 @@
+/*
+ * nfsdcltrack.c -- NFSv4 client name tracking program
+ *
+ * Copyright (C) 2012 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 <stdio.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.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 <dirent.h>
+#ifdef HAVE_SYS_CAPABILITY_H
+#include <sys/prctl.h>
+#include <sys/capability.h>
+#endif
+
+#include "xlog.h"
+#include "sqlite.h"
+
+#ifndef CLD_DEFAULT_STORAGEDIR
+#define CLD_DEFAULT_STORAGEDIR NFS_STATEDIR "/nfsdcltrack"
+#endif
+
+/* defined by RFC 3530 */
+#define NFS4_OPAQUE_LIMIT      1024
+
+/* private data structures */
+struct cltrack_cmd {
+       char *name;
+       bool needs_arg;
+       int (*func)(const char *arg);
+};
+
+/* forward declarations */
+static int cltrack_init(const char *unused);
+static int cltrack_create(const char *id);
+static int cltrack_remove(const char *id);
+static int cltrack_check(const char *id);
+static int cltrack_gracedone(const char *gracetime);
+
+/* global variables */
+static struct option longopts[] =
+{
+       { "help", 0, NULL, 'h' },
+       { "debug", 0, NULL, 'd' },
+       { "foreground", 0, NULL, 'f' },
+       { "storagedir", 1, NULL, 's' },
+       { NULL, 0, 0, 0 },
+};
+
+static struct cltrack_cmd commands[] =
+{
+       { "init", false, cltrack_init },
+       { "create", true, cltrack_create },
+       { "remove", true, cltrack_remove },
+       { "check", true, cltrack_check },
+       { "gracedone", true, cltrack_gracedone },
+       { NULL, false, NULL },
+};
+
+static char *storagedir = CLD_DEFAULT_STORAGEDIR;
+
+/* common buffer for holding id4 blobs */
+static unsigned char blob[NFS4_OPAQUE_LIMIT];
+
+static void
+usage(char *progname)
+{
+       printf("%s [ -hfd ] [ -s dir ] < cmd > < arg >\n", progname);
+       printf("Where < cmd > is one of the following and takes the following < arg >:\n");
+       printf("    init\n");
+       printf("    create <nfs_client_id4>\n");
+       printf("    remove <nfs_client_id4>\n");
+       printf("    check  <nfs_client_id4>\n");
+       printf("    gracedone <epoch time>\n");
+}
+
+
+/**
+ * hex_to_bin - convert a hex digit to its real value
+ * @ch: ascii character represents hex digit
+ *
+ * hex_to_bin() converts one hex digit to its actual value or -1 in case of bad
+ * input.
+ *
+ * Note: borrowed from lib/hexdump.c in the Linux kernel sources.
+ */
+static int
+hex_to_bin(char ch)
+{
+       if ((ch >= '0') && (ch <= '9'))
+               return ch - '0';
+       ch = tolower(ch);
+       if ((ch >= 'a') && (ch <= 'f'))
+               return ch - 'a' + 10;
+       return -1;
+}
+
+/**
+ * hex_str_to_bin - convert a hexidecimal string into a binary blob
+ *
+ * @src: string of hex digit pairs
+ * @dst: destination buffer to hold binary data
+ * @dstsize: size of the destination buffer
+ *
+ * Walk a string of hex digit pairs and convert them into binary data. Returns
+ * the resulting length of the binary data or a negative error code. If the
+ * data will not fit in the buffer, it returns -ENOBUFS (but will likely have
+ * clobbered the dst buffer in the process of determining that). If there are
+ * non-hexidecimal characters in the src, or an odd number of them then it
+ * returns -EINVAL.
+ */
+static ssize_t
+hex_str_to_bin(const char *src, unsigned char *dst, ssize_t dstsize)
+{
+       unsigned char *tmpdst = dst;
+
+       while (*src) {
+               int hi, lo;
+
+               /* make sure we don't overrun the dst buffer */
+               if ((tmpdst - dst) >= dstsize)
+                       return -ENOBUFS;
+
+               hi = hex_to_bin(*src++);
+
+               /* did we get an odd number of characters? */
+               if (!*src)
+                       return -EINVAL;
+               lo = hex_to_bin(*src++);
+
+               /* one of the characters isn't a hex digit */
+               if (hi < 0 || lo < 0)
+                       return -EINVAL;
+
+               /* now place it in the dst buffer */
+               *tmpdst++ = (hi << 4) | lo;
+       }
+
+       return (ssize_t)(tmpdst - dst);
+}
+
+/*
+ * This program will almost always be run with root privileges since the
+ * kernel will call out to run it. Drop all capabilities prior to doing
+ * anything important to limit the exposure to potential compromise.
+ *
+ * FIXME: should we setuid to a different user early on instead?
+ */
+static int
+cltrack_set_caps(void)
+{
+       int ret = 0;
+#ifdef HAVE_SYS_CAPABILITY_H
+       unsigned long i;
+       cap_t caps;
+
+       /* prune the bounding set to nothing */
+       for (i = 0; prctl(PR_CAPBSET_READ, i, 0, 0, 0) >= 0 ; ++i) {
+               ret = prctl(PR_CAPBSET_DROP, i, 0, 0, 0);
+               if (ret) {
+                       xlog(L_ERROR, "Unable to prune capability %lu from "
+                                     "bounding set: %m", i);
+                       return -errno;
+               }
+       }
+
+       /* get a blank capset */
+       caps = cap_init();
+       if (caps == NULL) {
+               xlog(L_ERROR, "Unable to get blank capability set: %m");
+               return -errno;
+       }
+
+       /* reset the process capabilities */
+       if (cap_set_proc(caps) != 0) {
+               xlog(L_ERROR, "Unable to set process capabilities: %m");
+               ret = -errno;
+       }
+       cap_free(caps);
+#endif
+       return ret;
+}
+
+static int
+cltrack_init(const char __attribute__((unused)) *unused)
+{
+       int ret;
+
+       /*
+        * see if the storagedir is writable by root w/o CAP_DAC_OVERRIDE.
+        * If it isn't then give the user a warning but proceed as if
+        * everything is OK. If the DB has already been created, then
+        * everything might still work. If it doesn't exist at all, then
+        * assume that the maindb init will be able to create it. Fail on
+        * anything else.
+        */
+       if (access(storagedir, W_OK) == -1) {
+               switch (errno) {
+               case EACCES:
+                       xlog(L_WARNING, "Storage directory %s is not writable. "
+                                       "Should be owned by root and writable "
+                                       "by owner!", storagedir);
+                       break;
+               case ENOENT:
+                       /* ignore and assume that we can create dir as root */
+                       break;
+               default:
+                       xlog(L_ERROR, "Unexpected error when checking access "
+                                     "on %s: %m", storagedir);
+                       return -errno;
+               }
+       }
+
+       /* set up storage db */
+       ret = sqlite_maindb_init(storagedir);
+       if (ret) {
+               xlog(L_ERROR, "Failed to init database: %d", ret);
+               /*
+                * Convert any error here into -EACCES. It's not truly
+                * accurate in all cases, but it should cause the kernel to
+                * stop upcalling until the problem is resolved.
+                */
+               ret = -EACCES;
+       }
+       return ret;
+}
+
+static int
+cltrack_create(const char *id)
+{
+       int ret;
+       ssize_t len;
+
+       xlog(D_GENERAL, "%s: create client record.", __func__);
+
+       ret = sqlite_prepare_dbh(storagedir);
+       if (ret)
+               return ret;
+
+       len = hex_str_to_bin(id, blob, sizeof(blob));
+       if (len < 0)
+               return (int)len;
+
+       ret = sqlite_insert_client(blob, len);
+
+       return ret ? -EREMOTEIO : ret;
+}
+
+static int
+cltrack_remove(const char *id)
+{
+       int ret;
+       ssize_t len;
+
+       xlog(D_GENERAL, "%s: remove client record.", __func__);
+
+       ret = sqlite_prepare_dbh(storagedir);
+       if (ret)
+               return ret;
+
+       len = hex_str_to_bin(id, blob, sizeof(blob));
+       if (len < 0)
+               return (int)len;
+
+       ret = sqlite_remove_client(blob, len);
+
+       return ret ? -EREMOTEIO : ret;
+}
+
+static int
+cltrack_check_legacy(const unsigned char *blob, const ssize_t len)
+{
+       int ret;
+       struct stat st;
+       char *recdir = getenv("NFSDCLTRACK_LEGACY_RECDIR");
+
+       if (!recdir) {
+               xlog(D_GENERAL, "No NFSDCLTRACK_LEGACY_RECDIR env var");
+               return -EOPNOTSUPP;
+       }
+
+       /* fail recovery on any stat failure */
+       ret = stat(recdir, &st);
+       if (ret) {
+               xlog(D_GENERAL, "Unable to stat %s: %d", recdir, errno);
+               return -errno;
+       }
+
+       /* fail if it isn't a directory */
+       if (!S_ISDIR(st.st_mode)) {
+               xlog(D_GENERAL, "%s is not a directory: mode=0%o", recdir
+                               , st.st_mode);
+               return -ENOTDIR;
+       }
+
+       /* Dir exists, try to insert record into db */
+       ret = sqlite_insert_client(blob, len);
+       if (ret) {
+               xlog(D_GENERAL, "Failed to insert client: %d", ret);
+               return -EREMOTEIO;
+       }
+
+       /* remove the legacy recoverydir */
+       ret = rmdir(recdir);
+       if (ret) {
+               xlog(D_GENERAL, "Failed to rmdir %s: %d", recdir, errno);
+               return -errno;
+       }
+       return 0;
+}
+
+static int
+cltrack_check(const char *id)
+{
+       int ret;
+       ssize_t len;
+
+       xlog(D_GENERAL, "%s: check client record", __func__);
+
+       ret = sqlite_prepare_dbh(storagedir);
+       if (ret)
+               return ret;
+
+       len = hex_str_to_bin(id, blob, sizeof(blob));
+       if (len < 0)
+               return (int)len;
+
+       ret = sqlite_check_client(blob, len);
+       if (ret)
+               ret = cltrack_check_legacy(blob, len);
+
+       return ret ? -EPERM : ret;
+}
+
+/* Clean out the v4recoverydir -- best effort here */
+static void
+cltrack_legacy_gracedone(void)
+{
+       DIR *v4recovery;
+       struct dirent *entry;
+       char *dirname = getenv("NFSDCLTRACK_LEGACY_TOPDIR");
+
+       if (!dirname)
+               return;
+
+       v4recovery = opendir(dirname);
+       if (!v4recovery)
+               return;
+
+       while ((entry = readdir(v4recovery))) {
+               int len;
+
+               /* skip "." and ".." */
+               if (entry->d_name[0] == '.') {
+                       switch (entry->d_name[1]) {
+                       case '\0':
+                               continue;
+                       case '.':
+                               if (entry->d_name[2] == '\0')
+                                       continue;
+                       }
+               }
+
+               /* borrow the clientid blob for this */
+               len = snprintf((char *)blob, sizeof(blob), "%s/%s", dirname,
+                               entry->d_name);
+
+               /* if there's a problem, then skip this entry */
+               if (len < 0 || (size_t)len >= sizeof(blob)) {
+                       xlog(L_WARNING, "%s: unable to build filename for %s!",
+                               __func__, entry->d_name);
+                       continue;
+               }
+
+               len = rmdir((char *)blob);
+               if (len)
+                       xlog(L_WARNING, "%s: unable to rmdir %s: %d", __func__,
+                               (char *)blob, len);
+       }
+
+       closedir(v4recovery);
+}
+
+static int
+cltrack_gracedone(const char *timestr)
+{
+       int ret;
+       char *tail;
+       time_t gracetime;
+
+
+       ret = sqlite_prepare_dbh(storagedir);
+       if (ret)
+               return ret;
+
+       errno = 0;
+       gracetime = strtol(timestr, &tail, 0);
+
+       /* did the resulting value overflow? (Probably -ERANGE here) */
+       if (errno)
+               return -errno;
+
+       /* string wasn't fully converted */
+       if (*tail)
+               return -EINVAL;
+
+       xlog(D_GENERAL, "%s: grace done. gracetime=%ld", __func__, gracetime);
+
+       ret = sqlite_remove_unreclaimed(gracetime);
+
+       cltrack_legacy_gracedone();
+
+       return ret ? -EREMOTEIO : ret;
+}
+
+static struct cltrack_cmd *
+find_cmd(char *cmdname)
+{
+       struct cltrack_cmd *current = &commands[0];
+
+       while (current->name) {
+               if (!strcmp(cmdname, current->name))
+                       return current;
+               ++current;
+       }
+
+       xlog(L_ERROR, "%s: '%s' doesn't match any known command",
+                       __func__, cmdname);
+       return NULL;
+}
+
+int
+main(int argc, char **argv)
+{
+       char arg;
+       int rc = 0;
+       char *progname, *cmdarg = NULL;
+       struct cltrack_cmd *cmd;
+
+       progname = basename(argv[0]);
+
+       xlog_syslog(1);
+       xlog_stderr(0);
+
+       /* process command-line options */
+       while ((arg = getopt_long(argc, argv, "hdfs:", longopts,
+                                 NULL)) != EOF) {
+               switch (arg) {
+               case 'd':
+                       xlog_config(D_ALL, 1);
+               case 'f':
+                       xlog_syslog(0);
+                       xlog_stderr(1);
+                       break;
+               case 's':
+                       storagedir = optarg;
+                       break;
+               default:
+                       usage(progname);
+                       return 0;
+               }
+       }
+
+       xlog_open(progname);
+
+       /* we expect a command, at least */
+       if (optind >= argc) {
+               xlog(L_ERROR, "Missing command name\n");
+               rc = -EINVAL;
+               goto out;
+       }
+
+       /* drop all capabilities */
+       rc = cltrack_set_caps();
+       if (rc)
+               goto out;
+
+       cmd = find_cmd(argv[optind]);
+       if (!cmd) {
+               /*
+                * In the event that we get a command that we don't understand
+                * then return a distinct error. The kernel can use this to
+                * determine a new kernel/old userspace situation and cope
+                * with it.
+                */
+               rc = -ENOSYS;
+               goto out;
+       }
+
+       /* populate arg var if command needs it */
+       if (cmd->needs_arg) {
+               if (optind + 1 >= argc) {
+                       xlog(L_ERROR, "Command %s requires an argument\n",
+                               cmd->name);
+                       rc = -EINVAL;
+                       goto out;
+               }
+               cmdarg = argv[optind + 1];
+       }
+       rc = cmd->func(cmdarg);
+out:
+       return rc;
+}
diff --git a/utils/nfsdcltrack/nfsdcltrack.man b/utils/nfsdcltrack/nfsdcltrack.man
new file mode 100644 (file)
index 0000000..47007df
--- /dev/null
@@ -0,0 +1,211 @@
+.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16)
+.\"
+.\" 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 "NFSDCLTRACK 8"
+.TH NFSDCLTRACK 8 "2012-10-24" "" ""
+.\" 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"
+nfsdcltrack \- NFSv4 Client Tracking Callout Program
+.SH "SYNOPSIS"
+.IX Header "SYNOPSIS"
+nfsdcltrack [\-d] [\-f] [\-s stable storage dir] <command> <args...>
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+nfsdcltack is the NFSv4 client tracking callout program. It is not necessary
+to install 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 program provides the
+userspace piece of that functionality. When the kernel needs to manipulate
+the database that stores this info, it will execute this program to handle
+it.
+.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"
+Log to stderr instead of syslog.
+.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/nfsdcltrack\fR.
+.SH "COMMANDS"
+.IX Header "COMMANDS"
+nfsdcltrack requires a command for each invocation. Supported commands
+are:
+.IP "\fBinit\fR" 4
+.IX Item "init"
+Initialize the database. This command requires no argument.
+.IP "\fBcreate\fR" 4
+.IX Item "create"
+Create a new client record (or update the timestamp on an existing one). This command requires a hex-encoded nfs_client_id4 as an argument.
+.IP "\fBremove\fR" 4
+.IX Item "remove"
+Remove a client record from the database. This command requires a hex-encoded nfs_client_id4 as an argument.
+.IP "\fBcheck\fR" 4
+.IX Item "check"
+Check to see if a nfs_client_id4 is allowed to reclaim. This command requires a hex-encoded nfs_client_id4 as an argument.
+.IP "\fBgracedone\fR" 4
+.IX Item "gracedone"
+Remove any unreclaimed client records from the database. This command requires a epoch boot time as an argument.
+.SH "LEGACY TRANSITION MECHANISM"
+.IX Header "LEGACY TRANSITION MECHANISM"
+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. If the kernel passes the correct information, then nfsdcltrack
+can use it to allow a seamless transition from the old client tracking
+scheme to the new one.
+.PP
+On a \fBcheck\fR operation, if there is no record of the client in the
+database, nfsdcltrack will look to see if the \fB\s-1NFSDCLTRACK_LEGACY_RECDIR\s0\fR
+environment variable is set. If it is, then it will fetch that value and
+see if a directory exists by that name. If it does, then the check
+operation will succeed and the directory will be removed.
+.PP
+On a \fBgracedone\fR operation, nfsdcltrack will look to see if the
+\&\fB\s-1NFSDCLTRACK_LEGACY_TOPDIR\s0\fR environment variable is set. If it is, then
+it will attempt to clean out that directory prior to exiting.
+.PP
+Note that this transition is one-way. If the machine subsequently reboots
+back into an older kernel that does not support the nfsdcltrack upcall
+then the clients will not be able to recover their state.
+.SH "NOTES"
+.IX Header "NOTES"
+This program requires a kernel that supports the nfsdcltrack usermodehelper
+upcall. This support was first added to mainline kernels in 3.8.
+.SH "AUTHORS"
+.IX Header "AUTHORS"
+nfsdcltrack was developed by Jeff Layton <jlayton@redhat.com>.
diff --git a/utils/nfsdcltrack/sqlite.c b/utils/nfsdcltrack/sqlite.c
new file mode 100644 (file)
index 0000000..bac6789
--- /dev/null
@@ -0,0 +1,400 @@
+/*
+ * 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
+
+/* in milliseconds */
+#define CLD_SQLITE_BUSY_TIMEOUT 10000
+
+/* private data structures */
+
+/* global variables */
+
+/* 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(const 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 database and set up the database handle for it */
+int
+sqlite_prepare_dbh(const char *topdir)
+{
+       int ret;
+
+       /* Do nothing if the database handle is already set up */
+       if (dbh)
+               return 0;
+
+       ret = snprintf(buf, PATH_MAX - 1, "%s/main.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);
+               dbh = NULL;
+               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);
+               sqlite3_close(dbh);
+               dbh = NULL;
+       }
+
+       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(const char *topdir)
+{
+       int ret;
+       char *err = NULL;
+       sqlite3_stmt *stmt = NULL;
+
+       ret = mkdir_if_not_exist(topdir);
+       if (ret)
+               return ret;
+
+       ret = sqlite_prepare_dbh(topdir);
+       if (ret)
+               return ret;
+
+       /* 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", __func__, 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/nfsdcltrack/sqlite.h b/utils/nfsdcltrack/sqlite.h
new file mode 100644 (file)
index 0000000..ebf04c3
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ * 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_prepare_dbh(const char *topdir);
+int sqlite_maindb_init(const 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 */
index cf1155188851836fcd0ef38934afd9d9f8244cb9..e14543c85770d5dd9f167d55c4517486cde302ed 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <unistd.h>
 #include "xlog.h"
+#include "conffile.h"
 
 int verbose = 0;
 char *usage="Usage: %s [-v] [-c || [-u|-g|-r key] || [-t timeout] key desc]";
@@ -26,6 +27,10 @@ char *usage="Usage: %s [-v] [-c || [-u|-g|-r key] || [-t timeout] key desc]";
 #define DEFAULT_KEYRING "id_resolver"
 #endif
 
+#ifndef PATH_IDMAPDCONF
+#define PATH_IDMAPDCONF "/etc/idmapd.conf"
+#endif
+
 static int keyring_clear(char *keyring);
 
 #define UIDKEYS 0x1
@@ -267,6 +272,13 @@ int main(int argc, char **argv)
                }
        }
 
+       if (nfs4_init_name_mapping(PATH_IDMAPDCONF))  {
+               xlog_err("Unable to create name to user id mappings.");
+               return 1;
+       }
+       if (!verbose)
+               verbose = conf_get_num("General", "Verbosity", 0);
+
        if (keystr) {
                rc = key_revoke(keystr, keymask);
                return rc;              
index adc493a37710684f2328b75ac5366c96d0ac315e..20c2d8c9027ff0fe34ab6c5f4484d2264f5fc009 100644 (file)
@@ -1,12 +1,9 @@
 ## Process this file with automake to produce Makefile.in
 
-OSD_LOGIN_FILES= osd_login
+# These binaries go in /sbin (not /usr/sbin), and that cannot be
+# overridden at config time.
+sbindir = /sbin
 
-EXTRA_DIST= $(OSD_LOGIN_FILES)
-
-all-local: $(OSD_LOGIN_FILES)
-
-install-data-hook:
-       $(INSTALL) --mode 755 osd_login $(DESTDIR)/sbin/osd_login
+sbin_SCRIPTS = osd_login
 
 MAINTAINERCLEANFILES = Makefile.in
index 4ecb03c25fc9830e25917c8ff39f3ebfb744d579..fd576d9158b6fa54dd530147401056d9b6b4419d 100644 (file)
@@ -68,21 +68,19 @@ statd_get_socket(void)
 {
        struct sockaddr_in      sin;
        struct servent *se;
-       int loopcnt = 100;
+       const int loopcnt = 100;
+       int i, tmp_sockets[loopcnt];
 
        if (sockfd >= 0)
                return sockfd;
 
-       while (loopcnt-- > 0) {
-
-               if (sockfd >= 0) close(sockfd);
+       for (i = 0; i < loopcnt; ++i) {
 
                if ((sockfd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) {
                        xlog(L_ERROR, "%s: Can't create socket: %m", __func__);
-                       return -1;
+                       break;
                }
 
-
                memset(&sin, 0, sizeof(sin));
                sin.sin_family = AF_INET;
                sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
@@ -96,7 +94,16 @@ statd_get_socket(void)
                if (se == NULL)
                        break;
                /* rather not use that port, try again */
+
+               tmp_sockets[i] = sockfd;
        }
+
+       while (--i >= 0)
+               close(tmp_sockets[i]);
+
+       if (sockfd < 0)
+               return -1;
+
        FD_SET(sockfd, &SVC_FDSET);
        return sockfd;
 }
index a3290aa82a84cf5d517212a7c2fa90b2dbb9bc11..9dbe5d9083361f2422716b004d029ff19e222779 100644 (file)
@@ -349,7 +349,7 @@ smn_bind_address(const char *srcaddr, const char *srcport)
 {
        struct addrinfo *ai = NULL;
        struct addrinfo hint = {
-               .ai_flags       = AI_NUMERICSERV,
+               .ai_flags       = AI_NUMERICSERV | AI_V4MAPPED,
                .ai_family      = nsm_family,
                .ai_protocol    = (int)IPPROTO_UDP,
        };
index 01fdb41301889bf6f36d6d68d5cc4d6b51673b33..652546cb9b40e190b8f4a125a2f8068fa4868c14 100644 (file)
@@ -99,7 +99,8 @@ static void
 killer (int sig)
 {
        statd_unregister ();
-       xlog_err ("Caught signal %d, un-registering and exiting", sig);
+       xlog(D_GENERAL, "Caught signal %d, un-registering and exiting", sig);
+       exit(0);
 }
 
 static void