446b32aaf5
Signed-off-by: Steve Dickson <steved@redhat.com>
1576 lines
49 KiB
Diff
1576 lines
49 KiB
Diff
diff --git a/README b/README
|
|
index 61702f7..7034c00 100644
|
|
--- a/README
|
|
+++ b/README
|
|
@@ -1,4 +1,4 @@
|
|
-This is version 1.2.6 of nfs-utils, the Linux NFS utility package.
|
|
+This is nfs-utils, the Linux NFS userland utility package.
|
|
|
|
|
|
0. PROJECT RESOURCES
|
|
diff --git a/aclocal/librpcsecgss.m4 b/aclocal/librpcsecgss.m4
|
|
index d1dd25e..e833141 100644
|
|
--- a/aclocal/librpcsecgss.m4
|
|
+++ b/aclocal/librpcsecgss.m4
|
|
@@ -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
|
|
diff --git a/aclocal/libtirpc.m4 b/aclocal/libtirpc.m4
|
|
index 19b8361..b823364 100644
|
|
--- a/aclocal/libtirpc.m4
|
|
+++ b/aclocal/libtirpc.m4
|
|
@@ -24,6 +24,13 @@ AC_DEFUN([AC_LIBTIRPC], [
|
|
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
|
|
AC_CHECK_HEADERS([${tirpc_header_dir}/netconfig.h],
|
|
@@ -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
|
|
diff --git a/configure.ac b/configure.ac
|
|
index f461219..cc7f3b4 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -358,7 +358,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
|
|
diff --git a/support/export/rmtab.c b/support/export/rmtab.c
|
|
index 31c0f50..d16b3b3 100644
|
|
--- a/support/export/rmtab.c
|
|
+++ b/support/export/rmtab.c
|
|
@@ -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"
|
|
diff --git a/support/export/xtab.c b/support/export/xtab.c
|
|
index 2a43193..e953071 100644
|
|
--- a/support/export/xtab.c
|
|
+++ b/support/export/xtab.c
|
|
@@ -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"
|
|
diff --git a/support/include/sockaddr.h b/support/include/sockaddr.h
|
|
index 72766db..a1c30f9 100644
|
|
--- a/support/include/sockaddr.h
|
|
+++ b/support/include/sockaddr.h
|
|
@@ -20,7 +20,13 @@
|
|
#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>
|
|
diff --git a/support/nfs/cacheio.c b/support/nfs/cacheio.c
|
|
index e641c45..61e07a8 100644
|
|
--- a/support/nfs/cacheio.c
|
|
+++ b/support/nfs/cacheio.c
|
|
@@ -162,11 +162,16 @@ 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
|
|
diff --git a/support/nfs/exports.c b/support/nfs/exports.c
|
|
index 84a2b08..6c08a2b 100644
|
|
--- a/support/nfs/exports.c
|
|
+++ b/support/nfs/exports.c
|
|
@@ -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;
|
|
diff --git a/tools/nfs-iostat/nfs-iostat.py b/tools/nfs-iostat/nfs-iostat.py
|
|
index d909632..dfbef87 100644
|
|
--- a/tools/nfs-iostat/nfs-iostat.py
|
|
+++ b/tools/nfs-iostat/nfs-iostat.py
|
|
@@ -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)
|
|
diff --git a/tools/rpcdebug/Makefile.am b/tools/rpcdebug/Makefile.am
|
|
index 39b70c9..b0a3e1f 100644
|
|
--- a/tools/rpcdebug/Makefile.am
|
|
+++ b/tools/rpcdebug/Makefile.am
|
|
@@ -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
|
|
diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c
|
|
index a3292c9..0be2517 100644
|
|
--- a/utils/gssd/gssd.c
|
|
+++ b/utils/gssd/gssd.c
|
|
@@ -147,7 +147,7 @@ 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;
|
|
default:
|
|
diff --git a/utils/gssd/gssd.man b/utils/gssd/gssd.man
|
|
index c74b7e8..79d9bf9 100644
|
|
--- a/utils/gssd/gssd.man
|
|
+++ b/utils/gssd/gssd.man
|
|
@@ -2,22 +2,197 @@
|
|
.\" 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 [ \-fMnlvr ]
|
|
+.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
|
|
-to establish security contexts. The
|
|
+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
|
|
-daemon uses files in the rpc_pipefs filesystem to communicate with the kernel.
|
|
-
|
|
+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
|
|
+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
|
|
+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 -f
|
|
@@ -26,115 +201,76 @@ Runs
|
|
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:/run/user/%U".
|
|
-This can also be a colon separated list of directories to be searched for
|
|
-Kerberos credential files. The sequence "%U", if used, is replaced with
|
|
-the UID of the user for whom credentials are being searched.
|
|
-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>
|
|
diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
|
|
index ec251fa..698f86f 100644
|
|
--- a/utils/gssd/gssd_proc.c
|
|
+++ b/utils/gssd/gssd_proc.c
|
|
@@ -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>
|
|
@@ -168,7 +169,7 @@ sockaddr_to_hostname(const struct sockaddr *sa, const char *addr)
|
|
{
|
|
socklen_t addrlen;
|
|
int err;
|
|
- char *hostname;
|
|
+ char *hostname;
|
|
char hbuf[NI_MAXHOST];
|
|
|
|
switch (sa->sa_family) {
|
|
@@ -250,21 +251,10 @@ 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;
|
|
|
|
@@ -398,10 +388,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;
|
|
@@ -483,9 +473,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));
|
|
}
|
|
|
|
@@ -567,9 +561,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]);
|
|
}
|
|
@@ -715,7 +708,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
|
|
@@ -962,12 +955,6 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
|
|
|
|
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));
|
|
@@ -1016,7 +1003,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
|
|
@@ -1025,7 +1013,7 @@ 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);
|
|
@@ -1035,12 +1023,12 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
|
|
/* 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++;
|
|
@@ -1090,7 +1078,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname,
|
|
out:
|
|
if (token.value)
|
|
free(token.value);
|
|
-#ifndef HAVE_LIBTIRPC
|
|
+#ifdef HAVE_AUTHGSS_FREE_PRIVATE_DATA
|
|
if (pd.pd_ctx_hndl.length != 0)
|
|
authgss_free_private_data(&pd);
|
|
#endif
|
|
@@ -1237,6 +1225,6 @@ out:
|
|
free(enctypes);
|
|
free(target);
|
|
free(service);
|
|
- return;
|
|
+ return;
|
|
}
|
|
|
|
diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c
|
|
index 60ba594..20b55b3 100644
|
|
--- a/utils/gssd/krb5_util.c
|
|
+++ b/utils/gssd/krb5_util.c
|
|
@@ -169,13 +169,13 @@ 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,
|
|
@@ -350,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);
|
|
@@ -774,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;
|
|
@@ -795,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;
|
|
@@ -1033,7 +1042,7 @@ 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 *dirpattern)
|
|
@@ -1078,7 +1087,7 @@ gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, char *dirpattern)
|
|
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;
|
|
}
|
|
|
|
/*
|
|
@@ -1128,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) {
|
|
@@ -1208,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);
|
|
}
|
|
|
|
/*
|
|
@@ -1219,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;
|
|
@@ -1252,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);
|
|
@@ -1280,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;
|
|
}
|
|
diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h
|
|
index cd6e107..9f41625 100644
|
|
--- a/utils/gssd/krb5_util.h
|
|
+++ b/utils/gssd/krb5_util.h
|
|
@@ -31,7 +31,8 @@ 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);
|
|
|
|
diff --git a/utils/gssd/svcgssd_krb5.c b/utils/gssd/svcgssd_krb5.c
|
|
index 6c34faf..1d44d34 100644
|
|
--- a/utils/gssd/svcgssd_krb5.c
|
|
+++ b/utils/gssd/svcgssd_krb5.c
|
|
@@ -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;
|
|
diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c
|
|
index e80efb4..beba9c4 100644
|
|
--- a/utils/idmapd/idmapd.c
|
|
+++ b/utils/idmapd/idmapd.c
|
|
@@ -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\"",
|
|
@@ -855,25 +857,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)
|
|
{
|
|
char ch, *bp = *bpp;
|
|
diff --git a/utils/mount/error.c b/utils/mount/error.c
|
|
index 83ad1d2..f8fc13f 100644
|
|
--- a/utils/mount/error.c
|
|
+++ b/utils/mount/error.c
|
|
@@ -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"),
|
|
diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man
|
|
index c15de98..374ac06 100644
|
|
--- a/utils/mount/nfs.man
|
|
+++ b/utils/mount/nfs.man
|
|
@@ -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)
|
|
@@ -708,13 +715,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.
|
|
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
|
|
index 9b4197b..8ee3024 100644
|
|
--- a/utils/mount/stropts.c
|
|
+++ b/utils/mount/stropts.c
|
|
@@ -666,6 +666,7 @@ static int nfs_try_mount_v3v2(struct nfsmount_info *mi)
|
|
case EOPNOTSUPP:
|
|
case EHOSTUNREACH:
|
|
case ETIMEDOUT:
|
|
+ case EACCES:
|
|
continue;
|
|
default:
|
|
goto out;
|
|
@@ -761,6 +762,7 @@ static int nfs_try_mount_v4(struct nfsmount_info *mi)
|
|
case ECONNREFUSED:
|
|
case EHOSTUNREACH:
|
|
case ETIMEDOUT:
|
|
+ case EACCES:
|
|
continue;
|
|
default:
|
|
goto out;
|
|
diff --git a/utils/mountd/auth.c b/utils/mountd/auth.c
|
|
index 508040a..330cab5 100644
|
|
--- a/utils/mountd/auth.c
|
|
+++ b/utils/mountd/auth.c
|
|
@@ -10,10 +10,12 @@
|
|
#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
|
|
diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c
|
|
index e950ec6..978698d 100644
|
|
--- a/utils/mountd/cache.c
|
|
+++ b/utils/mountd/cache.c
|
|
@@ -29,7 +29,6 @@
|
|
#include "nfslib.h"
|
|
#include "exportfs.h"
|
|
#include "mountd.h"
|
|
-#include "xmalloc.h"
|
|
#include "fsloc.h"
|
|
#include "pseudoflavors.h"
|
|
|
|
@@ -109,12 +108,10 @@ 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);
|
|
@@ -127,7 +124,6 @@ static void auth_unix_ip(FILE *f)
|
|
xlog(D_CALL, "auth_unix_ip: client %p '%s'", client, client?client: "DEFAULT");
|
|
|
|
free(client);
|
|
-out:
|
|
freeaddrinfo(tmp);
|
|
|
|
}
|
|
@@ -347,6 +343,30 @@ 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)
|
|
{
|
|
@@ -354,8 +374,8 @@ static bool subexport(struct exportent *e1, struct exportent *e2)
|
|
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 {
|
|
@@ -756,27 +776,6 @@ static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *ex
|
|
return qword_eol(f);
|
|
}
|
|
|
|
-static int is_subdirectory(char *child, char *parent)
|
|
-{
|
|
- size_t 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)
|
|
{
|
|
@@ -830,6 +829,7 @@ lookup_export(char *dom, char *path, struct addrinfo *ai)
|
|
|
|
#ifdef HAVE_NFS_PLUGIN_H
|
|
#include <dlfcn.h>
|
|
+#include <link.h>
|
|
#include <nfs-plugin.h>
|
|
|
|
/*
|
|
@@ -1094,6 +1094,7 @@ 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);
|
|
@@ -1101,6 +1102,11 @@ static struct exportent *lookup_junction(char *dom, 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, dom, pathname, ai);
|
|
diff --git a/utils/mountd/v4root.c b/utils/mountd/v4root.c
|
|
index 726b50d..34d098a 100644
|
|
--- a/utils/mountd/v4root.c
|
|
+++ b/utils/mountd/v4root.c
|
|
@@ -55,7 +55,8 @@ 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;
|
|
@@ -121,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;
|
|
|
|
diff --git a/utils/nfsdcltrack/nfsdcltrack.c b/utils/nfsdcltrack/nfsdcltrack.c
|
|
index 9801b9c..4334340 100644
|
|
--- a/utils/nfsdcltrack/nfsdcltrack.c
|
|
+++ b/utils/nfsdcltrack/nfsdcltrack.c
|
|
@@ -379,6 +379,17 @@ cltrack_legacy_gracedone(void)
|
|
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);
|
|
diff --git a/utils/statd/rmtcall.c b/utils/statd/rmtcall.c
|
|
index 4ecb03c..fd576d9 100644
|
|
--- a/utils/statd/rmtcall.c
|
|
+++ b/utils/statd/rmtcall.c
|
|
@@ -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;
|
|
}
|