9e917f864c
The content of this branch was automatically imported from Fedora ELN with the following as its source: https://src.fedoraproject.org/rpms/nfs-utils#ae3700f20b5680274b29ff27c2f54879b44ab34b
3021 lines
83 KiB
Diff
3021 lines
83 KiB
Diff
diff --git a/aclocal/libevent.m4 b/aclocal/libevent.m4
|
|
index b5ac00f..e0b820b 100644
|
|
--- a/aclocal/libevent.m4
|
|
+++ b/aclocal/libevent.m4
|
|
@@ -1,12 +1,12 @@
|
|
dnl Checks for libevent
|
|
AC_DEFUN([AC_LIBEVENT], [
|
|
|
|
- dnl Check for libevent, but do not add -levent to LIBS
|
|
- AC_CHECK_LIB([event], [event_dispatch], [LIBEVENT=-levent],
|
|
+ dnl Check for libevent, but do not add -levent_core to LIBS
|
|
+ AC_CHECK_LIB([event_core], [event_base_dispatch], [LIBEVENT=-levent_core],
|
|
[AC_MSG_ERROR([libevent not found.])])
|
|
AC_SUBST(LIBEVENT)
|
|
|
|
- AC_CHECK_HEADERS([event.h], ,
|
|
+ AC_CHECK_HEADERS([event2/event.h], ,
|
|
[AC_MSG_ERROR([libevent headers not found.])])
|
|
|
|
])dnl
|
|
diff --git a/configure.ac b/configure.ac
|
|
index 942f3c0..dbb795f 100644
|
|
--- a/configure.ac
|
|
+++ b/configure.ac
|
|
@@ -638,13 +638,12 @@ my_am_cflags="\
|
|
-Werror=parentheses \
|
|
-Werror=aggregate-return \
|
|
-Werror=unused-result \
|
|
- -Wno-cast-function-type \
|
|
-fno-strict-aliasing \
|
|
"
|
|
|
|
AC_DEFUN([CHECK_CCSUPPORT], [
|
|
my_save_cflags="$CFLAGS"
|
|
- CFLAGS=$1
|
|
+ CFLAGS="-Werror $1"
|
|
AC_MSG_CHECKING([whether CC supports $1])
|
|
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([])],
|
|
[AC_MSG_RESULT([yes])]
|
|
@@ -658,9 +657,10 @@ CHECK_CCSUPPORT([-Werror=format-overflow=2], [flg1])
|
|
CHECK_CCSUPPORT([-Werror=int-conversion], [flg2])
|
|
CHECK_CCSUPPORT([-Werror=incompatible-pointer-types], [flg3])
|
|
CHECK_CCSUPPORT([-Werror=misleading-indentation], [flg4])
|
|
+CHECK_CCSUPPORT([-Wno-cast-function-type], [flg5])
|
|
AX_GCC_FUNC_ATTRIBUTE([format])
|
|
|
|
-AC_SUBST([AM_CFLAGS], ["$my_am_cflags $flg1 $flg2 $flg3 $flg4"])
|
|
+AC_SUBST([AM_CFLAGS], ["$my_am_cflags $flg1 $flg2 $flg3 $flg4 $flg5"])
|
|
|
|
# Make sure that $ACLOCAL_FLAGS are used during a rebuild
|
|
AC_SUBST([ACLOCAL_AMFLAGS], ["-I $ac_macro_dir \$(ACLOCAL_FLAGS)"])
|
|
diff --git a/support/include/xcommon.h b/support/include/xcommon.h
|
|
index 30b0403..efde83c 100644
|
|
--- a/support/include/xcommon.h
|
|
+++ b/support/include/xcommon.h
|
|
@@ -7,7 +7,7 @@
|
|
*/
|
|
|
|
#ifndef _XMALLOC_H
|
|
-#define _MALLOC_H
|
|
+#define _XMALLOC_H
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
diff --git a/support/nfs/exports.c b/support/nfs/exports.c
|
|
index 97eb318..037febd 100644
|
|
--- a/support/nfs/exports.c
|
|
+++ b/support/nfs/exports.c
|
|
@@ -838,6 +838,7 @@ struct export_features *get_export_features(void)
|
|
close(fd);
|
|
if (c == -1)
|
|
goto err;
|
|
+ buf[c] = 0;
|
|
c = sscanf(buf, "%x %x", &ef.flags, &ef.secinfo_flags);
|
|
if (c != 2)
|
|
goto err;
|
|
diff --git a/support/nfs/xlog.c b/support/nfs/xlog.c
|
|
index 687d862..86acd6a 100644
|
|
--- a/support/nfs/xlog.c
|
|
+++ b/support/nfs/xlog.c
|
|
@@ -156,13 +156,29 @@ xlog_enabled(int fac)
|
|
void
|
|
xlog_backend(int kind, const char *fmt, va_list args)
|
|
{
|
|
- va_list args2;
|
|
-
|
|
if (!(kind & (L_ALL)) && !(logging && (kind & logmask)))
|
|
return;
|
|
|
|
- if (log_stderr)
|
|
+ if (log_stderr) {
|
|
+ va_list args2;
|
|
+#ifdef VERBOSE_PRINTF
|
|
+ time_t now;
|
|
+ struct tm *tm;
|
|
+
|
|
+ time(&now);
|
|
+ tm = localtime(&now);
|
|
+ fprintf(stderr, "%s[%d] %04d-%02d-%02d %02d:%02d:%02d ",
|
|
+ log_name, log_pid,
|
|
+ tm->tm_year+1900, tm->tm_mon + 1, tm->tm_mday,
|
|
+ tm->tm_hour, tm->tm_min, tm->tm_sec);
|
|
+#else
|
|
+ fprintf(stderr, "%s: ", log_name);
|
|
+#endif
|
|
va_copy(args2, args);
|
|
+ vfprintf(stderr, fmt, args2);
|
|
+ fprintf(stderr, "\n");
|
|
+ va_end(args2);
|
|
+ }
|
|
|
|
if (log_syslog) {
|
|
switch (kind) {
|
|
@@ -185,25 +201,6 @@ xlog_backend(int kind, const char *fmt, va_list args)
|
|
}
|
|
}
|
|
|
|
- if (log_stderr) {
|
|
-#ifdef VERBOSE_PRINTF
|
|
- time_t now;
|
|
- struct tm *tm;
|
|
-
|
|
- time(&now);
|
|
- tm = localtime(&now);
|
|
- fprintf(stderr, "%s[%d] %04d-%02d-%02d %02d:%02d:%02d ",
|
|
- log_name, log_pid,
|
|
- tm->tm_year+1900, tm->tm_mon + 1, tm->tm_mday,
|
|
- tm->tm_hour, tm->tm_min, tm->tm_sec);
|
|
-#else
|
|
- fprintf(stderr, "%s: ", log_name);
|
|
-#endif
|
|
- vfprintf(stderr, fmt, args2);
|
|
- fprintf(stderr, "\n");
|
|
- va_end(args2);
|
|
- }
|
|
-
|
|
if (kind == L_FATAL)
|
|
exit(1);
|
|
}
|
|
diff --git a/support/nfsidmap/libnfsidmap.c b/support/nfsidmap/libnfsidmap.c
|
|
index bce448c..0a912e5 100644
|
|
--- a/support/nfsidmap/libnfsidmap.c
|
|
+++ b/support/nfsidmap/libnfsidmap.c
|
|
@@ -237,24 +237,40 @@ static int load_translation_plugin(char *method, struct mapping_plugin *plgn)
|
|
{
|
|
void *dl = NULL;
|
|
struct trans_func *trans = NULL;
|
|
- libnfsidmap_plugin_init_t init_func;
|
|
+ libnfsidmap_plugin_init_t init_func = NULL;
|
|
char plgname[128];
|
|
int ret = 0;
|
|
|
|
- snprintf(plgname, sizeof(plgname), "%s/%s.so", PATH_PLUGINS, method);
|
|
+ /* Look for library using search path first to allow overriding */
|
|
+ snprintf(plgname, sizeof(plgname), "%s.so", method);
|
|
|
|
dl = dlopen(plgname, RTLD_NOW | RTLD_LOCAL);
|
|
- if (dl == NULL) {
|
|
- IDMAP_LOG(1, ("libnfsidmap: Unable to load plugin: %s",
|
|
- dlerror()));
|
|
- return -1;
|
|
+ if (dl != NULL) {
|
|
+ /* Is it really one of our libraries */
|
|
+ init_func = (libnfsidmap_plugin_init_t) dlsym(dl, PLUGIN_INIT_FUNC);
|
|
+ if (init_func == NULL) {
|
|
+ dlclose(dl);
|
|
+ dl = NULL;
|
|
+ }
|
|
}
|
|
- init_func = (libnfsidmap_plugin_init_t) dlsym(dl, PLUGIN_INIT_FUNC);
|
|
- if (init_func == NULL) {
|
|
- IDMAP_LOG(1, ("libnfsidmap: Unable to get init function: %s",
|
|
- dlerror()));
|
|
- dlclose(dl);
|
|
- return -1;
|
|
+
|
|
+ if (dl == NULL) {
|
|
+ /* Fallback to hard-coded path */
|
|
+ snprintf(plgname, sizeof(plgname), "%s/%s.so", PATH_PLUGINS, method);
|
|
+
|
|
+ dl = dlopen(plgname, RTLD_NOW | RTLD_LOCAL);
|
|
+ if (dl == NULL) {
|
|
+ IDMAP_LOG(1, ("libnfsidmap: Unable to load plugin: %s: %s",
|
|
+ plgname, dlerror()));
|
|
+ return -1;
|
|
+ }
|
|
+ init_func = (libnfsidmap_plugin_init_t) dlsym(dl, PLUGIN_INIT_FUNC);
|
|
+ if (init_func == NULL) {
|
|
+ IDMAP_LOG(1, ("libnfsidmap: Unable to get init function: %s: %s",
|
|
+ plgname, dlerror()));
|
|
+ dlclose(dl);
|
|
+ return -1;
|
|
+ }
|
|
}
|
|
trans = init_func();
|
|
if (trans == NULL) {
|
|
@@ -496,6 +512,19 @@ out:
|
|
return ret ? -ENOENT: 0;
|
|
}
|
|
|
|
+void nfs4_term_name_mapping(void)
|
|
+{
|
|
+ if (nfs4_plugins)
|
|
+ unload_plugins(nfs4_plugins);
|
|
+ if (gss_plugins)
|
|
+ unload_plugins(gss_plugins);
|
|
+
|
|
+ nfs4_plugins = gss_plugins = NULL;
|
|
+
|
|
+ free_local_realms();
|
|
+ conf_cleanup();
|
|
+}
|
|
+
|
|
int
|
|
nfs4_get_default_domain(char *UNUSED(server), char *domain, size_t len)
|
|
{
|
|
diff --git a/support/nfsidmap/nfsidmap.h b/support/nfsidmap/nfsidmap.h
|
|
index 1063065..5a79568 100644
|
|
--- a/support/nfsidmap/nfsidmap.h
|
|
+++ b/support/nfsidmap/nfsidmap.h
|
|
@@ -50,6 +50,7 @@ typedef struct _extra_mapping_params {
|
|
typedef void (*nfs4_idmap_log_function_t)(const char *, ...);
|
|
|
|
int nfs4_init_name_mapping(char *conffile);
|
|
+void nfs4_term_name_mapping(void);
|
|
int nfs4_get_default_domain(char *server, char *domain, size_t len);
|
|
int nfs4_uid_to_name(uid_t uid, char *domain, char *name, size_t len);
|
|
int nfs4_gid_to_name(gid_t gid, char *domain, char *name, size_t len);
|
|
diff --git a/support/nfsidmap/nfsidmap_common.c b/support/nfsidmap/nfsidmap_common.c
|
|
index f89b82e..4d2cb14 100644
|
|
--- a/support/nfsidmap/nfsidmap_common.c
|
|
+++ b/support/nfsidmap/nfsidmap_common.c
|
|
@@ -34,12 +34,21 @@ static char * toupper_str(char *s)
|
|
return s;
|
|
}
|
|
|
|
+static struct conf_list *local_realms = NULL;
|
|
+
|
|
+void free_local_realms(void)
|
|
+{
|
|
+ if (local_realms) {
|
|
+ conf_free_list(local_realms);
|
|
+ local_realms = NULL;
|
|
+ }
|
|
+}
|
|
+
|
|
/* Get list of "local equivalent" realms. Meaning the list of realms
|
|
* where john@REALM.A is considered the same user as john@REALM.B
|
|
* If not specified, default to upper-case of local domain name */
|
|
struct conf_list *get_local_realms(void)
|
|
{
|
|
- static struct conf_list *local_realms = NULL;
|
|
if (local_realms) return local_realms;
|
|
|
|
local_realms = conf_get_list("General", "Local-Realms");
|
|
diff --git a/support/nfsidmap/nfsidmap_private.h b/support/nfsidmap/nfsidmap_private.h
|
|
index f1af55f..a5cb6dd 100644
|
|
--- a/support/nfsidmap/nfsidmap_private.h
|
|
+++ b/support/nfsidmap/nfsidmap_private.h
|
|
@@ -37,6 +37,7 @@
|
|
#include "conffile.h"
|
|
|
|
struct conf_list *get_local_realms(void);
|
|
+void free_local_realms(void);
|
|
int get_nostrip(void);
|
|
int get_reformat_group(void);
|
|
|
|
diff --git a/support/nfsidmap/nss.c b/support/nfsidmap/nss.c
|
|
index 9d46499..669760b 100644
|
|
--- a/support/nfsidmap/nss.c
|
|
+++ b/support/nfsidmap/nss.c
|
|
@@ -467,6 +467,17 @@ static int nss_plugin_init(void)
|
|
return 0;
|
|
}
|
|
|
|
+/*
|
|
+ * Called by dlclose(). See dlopen(3) man page
|
|
+ */
|
|
+__attribute__((destructor))
|
|
+static int nss_plugin_term(void)
|
|
+{
|
|
+ free_local_realms();
|
|
+ conf_cleanup();
|
|
+ return 0;
|
|
+}
|
|
+
|
|
|
|
struct trans_func nss_trans = {
|
|
.name = "nsswitch",
|
|
diff --git a/systemd/nfs-server.service b/systemd/nfs-server.service
|
|
index 24118d6..06c1adb 100644
|
|
--- a/systemd/nfs-server.service
|
|
+++ b/systemd/nfs-server.service
|
|
@@ -1,18 +1,18 @@
|
|
[Unit]
|
|
Description=NFS server and services
|
|
DefaultDependencies=no
|
|
-Requires= network.target proc-fs-nfsd.mount
|
|
-Requires= nfs-mountd.service
|
|
+Requires=network.target proc-fs-nfsd.mount
|
|
+Requires=nfs-mountd.service
|
|
Wants=rpcbind.socket network-online.target
|
|
Wants=rpc-statd.service nfs-idmapd.service
|
|
Wants=rpc-statd-notify.service
|
|
Wants=nfsdcld.service
|
|
|
|
-After= network-online.target local-fs.target
|
|
-After= proc-fs-nfsd.mount rpcbind.socket nfs-mountd.service
|
|
-After= nfs-idmapd.service rpc-statd.service
|
|
-After= nfsdcld.service
|
|
-Before= rpc-statd-notify.service
|
|
+After=network-online.target local-fs.target
|
|
+After=proc-fs-nfsd.mount rpcbind.socket nfs-mountd.service
|
|
+After=nfs-idmapd.service rpc-statd.service
|
|
+After=nfsdcld.service
|
|
+Before=rpc-statd-notify.service
|
|
|
|
# GSS services dependencies and ordering
|
|
Wants=auth-rpcgss-module.service
|
|
diff --git a/tools/mountstats/mountstats.py b/tools/mountstats/mountstats.py
|
|
index 014f38a..00adc96 100755
|
|
--- a/tools/mountstats/mountstats.py
|
|
+++ b/tools/mountstats/mountstats.py
|
|
@@ -1,4 +1,4 @@
|
|
-#!/usr/bin/python
|
|
+#!/usr/bin/python3
|
|
# -*- python-mode -*-
|
|
"""Parse /proc/self/mountstats and display it in human readable form
|
|
"""
|
|
@@ -560,7 +560,10 @@ class DeviceData:
|
|
# the reference to them. so we build new lists here
|
|
# for the result object.
|
|
for op in result.__rpc_data['ops']:
|
|
- result.__rpc_data[op] = list(map(difference, self.__rpc_data[op], old_stats.__rpc_data[op]))
|
|
+ try:
|
|
+ result.__rpc_data[op] = list(map(difference, self.__rpc_data[op], old_stats.__rpc_data[op]))
|
|
+ except KeyError:
|
|
+ continue
|
|
|
|
# update the remaining keys
|
|
if protocol == 'udp':
|
|
diff --git a/tools/nfs-iostat/nfs-iostat.py b/tools/nfs-iostat/nfs-iostat.py
|
|
index b7e98a2..4f5e8a6 100755
|
|
--- a/tools/nfs-iostat/nfs-iostat.py
|
|
+++ b/tools/nfs-iostat/nfs-iostat.py
|
|
@@ -1,4 +1,4 @@
|
|
-#!/usr/bin/python
|
|
+#!/usr/bin/python3
|
|
# -*- python-mode -*-
|
|
"""Emulate iostat for NFS mount points using /proc/self/mountstats
|
|
"""
|
|
@@ -213,8 +213,11 @@ class DeviceData:
|
|
# the reference to them. so we build new lists here
|
|
# for the result object.
|
|
for op in result.__rpc_data['ops']:
|
|
- result.__rpc_data[op] = list(map(
|
|
- difference, self.__rpc_data[op], old_stats.__rpc_data[op]))
|
|
+ try:
|
|
+ result.__rpc_data[op] = list(map(
|
|
+ difference, self.__rpc_data[op], old_stats.__rpc_data[op]))
|
|
+ except KeyError:
|
|
+ continue
|
|
|
|
# update the remaining keys we care about
|
|
result.__rpc_data['rpcsends'] -= old_stats.__rpc_data['rpcsends']
|
|
@@ -380,6 +383,8 @@ class DeviceData:
|
|
sends = float(self.__rpc_data['rpcsends'])
|
|
if sample_time == 0:
|
|
sample_time = float(self.__nfs_data['age'])
|
|
+ if sample_time == 0:
|
|
+ sample_time = 1;
|
|
return (sends / sample_time)
|
|
|
|
def display_iostats(self, sample_time, which):
|
|
diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c
|
|
index a04a789..cde5e51 100644
|
|
--- a/utils/exportfs/exportfs.c
|
|
+++ b/utils/exportfs/exportfs.c
|
|
@@ -85,8 +85,11 @@ grab_lockfile()
|
|
static void
|
|
release_lockfile()
|
|
{
|
|
- if (_lockfd != -1)
|
|
+ if (_lockfd != -1) {
|
|
lockf(_lockfd, F_ULOCK, 0);
|
|
+ close(_lockfd);
|
|
+ _lockfd = -1;
|
|
+ }
|
|
}
|
|
|
|
int
|
|
@@ -184,6 +187,7 @@ main(int argc, char **argv)
|
|
xtab_export_read();
|
|
dump(f_verbose, f_export_format);
|
|
free_state_path_names(&etab);
|
|
+ export_freeall();
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -225,6 +229,7 @@ main(int argc, char **argv)
|
|
xtab_export_write();
|
|
cache_flush(force_flush);
|
|
free_state_path_names(&etab);
|
|
+ export_freeall();
|
|
|
|
return export_errno;
|
|
}
|
|
diff --git a/utils/gssd/Makefile.am b/utils/gssd/Makefile.am
|
|
index 321046b..21d3bb8 100644
|
|
--- a/utils/gssd/Makefile.am
|
|
+++ b/utils/gssd/Makefile.am
|
|
@@ -67,7 +67,6 @@ gssd_CFLAGS = \
|
|
svcgssd_SOURCES = \
|
|
$(COMMON_SRCS) \
|
|
svcgssd.c \
|
|
- svcgssd_main_loop.c \
|
|
svcgssd_mech2file.c \
|
|
svcgssd_proc.c \
|
|
svcgssd_krb5.c \
|
|
@@ -78,6 +77,7 @@ svcgssd_SOURCES = \
|
|
svcgssd_LDADD = \
|
|
../../support/nfs/libnfs.la \
|
|
../../support/nfsidmap/libnfsidmap.la \
|
|
+ $(LIBEVENT) \
|
|
$(RPCSECGSS_LIBS) \
|
|
$(KRBLIBS) $(GSSAPI_LIBS) $(LIBTIRPC)
|
|
|
|
diff --git a/utils/gssd/gss_names.c b/utils/gssd/gss_names.c
|
|
index 2a7f3a1..982b96f 100644
|
|
--- a/utils/gssd/gss_names.c
|
|
+++ b/utils/gssd/gss_names.c
|
|
@@ -110,10 +110,12 @@ get_hostbased_client_name(gss_name_t client_name, gss_OID mech,
|
|
/* For Kerberos, transform the NT_KRB5_PRINCIPAL name to
|
|
* an NT_HOSTBASED_SERVICE name */
|
|
if (g_OID_equal(&krb5oid, mech)) {
|
|
- if (get_krb5_hostbased_name(&name, &cname) == 0)
|
|
- *hostbased_name = cname;
|
|
+ if (get_krb5_hostbased_name(&name, &cname) != 0)
|
|
+ goto out_rel_buf;
|
|
+ *hostbased_name = cname;
|
|
} else {
|
|
printerr(1, "WARNING: unknown/unsupport mech OID\n");
|
|
+ goto out_rel_buf;
|
|
}
|
|
|
|
res = 0;
|
|
diff --git a/utils/gssd/gss_util.c b/utils/gssd/gss_util.c
|
|
index 2e6d40f..a4b2777 100644
|
|
--- a/utils/gssd/gss_util.c
|
|
+++ b/utils/gssd/gss_util.c
|
|
@@ -339,3 +339,9 @@ out:
|
|
return retval;
|
|
}
|
|
|
|
+void
|
|
+gssd_cleanup(void)
|
|
+{
|
|
+ u_int32_t min_stat;
|
|
+ gss_release_cred(&min_stat, &gssd_creds);
|
|
+}
|
|
diff --git a/utils/gssd/gss_util.h b/utils/gssd/gss_util.h
|
|
index aa9f778..4da64e3 100644
|
|
--- a/utils/gssd/gss_util.h
|
|
+++ b/utils/gssd/gss_util.h
|
|
@@ -41,6 +41,7 @@ int gssd_acquire_cred(char *server_name, const gss_OID oid);
|
|
void pgsserr(char *msg, u_int32_t maj_stat, u_int32_t min_stat,
|
|
const gss_OID mech);
|
|
int gssd_check_mechs(void);
|
|
+void gssd_cleanup(void);
|
|
|
|
#ifndef HAVE_LIBGSSGLUE
|
|
#include <gssapi/gssapi_krb5.h>
|
|
diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c
|
|
index 588da0f..85bc4b0 100644
|
|
--- a/utils/gssd/gssd.c
|
|
+++ b/utils/gssd/gssd.c
|
|
@@ -64,7 +64,7 @@
|
|
#include <fcntl.h>
|
|
#include <dirent.h>
|
|
#include <netdb.h>
|
|
-#include <event.h>
|
|
+#include <event2/event.h>
|
|
|
|
#include "gssd.h"
|
|
#include "err_util.h"
|
|
@@ -77,7 +77,7 @@ static char *pipefs_path = GSSD_PIPEFS_DIR;
|
|
static DIR *pipefs_dir;
|
|
static int pipefs_fd;
|
|
static int inotify_fd;
|
|
-struct event inotify_ev;
|
|
+struct event *inotify_ev;
|
|
|
|
char *keytabfile = GSSD_DEFAULT_KEYTAB_FILE;
|
|
char **ccachesearch;
|
|
@@ -90,9 +90,9 @@ char *ccachedir = NULL;
|
|
/* Avoid DNS reverse lookups on server names */
|
|
static bool avoid_dns = true;
|
|
static bool use_gssproxy = false;
|
|
-int thread_started = false;
|
|
-pthread_mutex_t pmutex = PTHREAD_MUTEX_INITIALIZER;
|
|
-pthread_cond_t pcond = PTHREAD_COND_INITIALIZER;
|
|
+pthread_mutex_t clp_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
+static bool signal_received = false;
|
|
+static struct event_base *evbase = NULL;
|
|
|
|
TAILQ_HEAD(topdir_list_head, topdir) topdir_list;
|
|
|
|
@@ -359,20 +359,28 @@ out:
|
|
free(port);
|
|
}
|
|
|
|
+/* Actually frees clp and fields that might be used from other
|
|
+ * threads if was last reference.
|
|
+ */
|
|
static void
|
|
-gssd_destroy_client(struct clnt_info *clp)
|
|
+gssd_free_client(struct clnt_info *clp)
|
|
{
|
|
- if (clp->krb5_fd >= 0) {
|
|
+ int refcnt;
|
|
+
|
|
+ pthread_mutex_lock(&clp_lock);
|
|
+ refcnt = --clp->refcount;
|
|
+ pthread_mutex_unlock(&clp_lock);
|
|
+ if (refcnt > 0)
|
|
+ return;
|
|
+
|
|
+ printerr(3, "freeing client %s\n", clp->relpath);
|
|
+
|
|
+ if (clp->krb5_fd >= 0)
|
|
close(clp->krb5_fd);
|
|
- event_del(&clp->krb5_ev);
|
|
- }
|
|
|
|
- if (clp->gssd_fd >= 0) {
|
|
+ if (clp->gssd_fd >= 0)
|
|
close(clp->gssd_fd);
|
|
- event_del(&clp->gssd_ev);
|
|
- }
|
|
|
|
- inotify_rm_watch(inotify_fd, clp->wd);
|
|
free(clp->relpath);
|
|
free(clp->servicename);
|
|
free(clp->servername);
|
|
@@ -380,6 +388,30 @@ gssd_destroy_client(struct clnt_info *clp)
|
|
free(clp);
|
|
}
|
|
|
|
+/* Called when removing from clnt_list to tear down event handling.
|
|
+ * Will then free clp if was last reference.
|
|
+ */
|
|
+static void
|
|
+gssd_destroy_client(struct clnt_info *clp)
|
|
+{
|
|
+ printerr(3, "destroying client %s\n", clp->relpath);
|
|
+
|
|
+ if (clp->krb5_ev) {
|
|
+ event_del(clp->krb5_ev);
|
|
+ event_free(clp->krb5_ev);
|
|
+ clp->krb5_ev = NULL;
|
|
+ }
|
|
+
|
|
+ if (clp->gssd_ev) {
|
|
+ event_del(clp->gssd_ev);
|
|
+ event_free(clp->gssd_ev);
|
|
+ clp->gssd_ev = NULL;
|
|
+ }
|
|
+
|
|
+ inotify_rm_watch(inotify_fd, clp->wd);
|
|
+ gssd_free_client(clp);
|
|
+}
|
|
+
|
|
static void gssd_scan(void);
|
|
|
|
static int
|
|
@@ -416,11 +448,21 @@ static struct clnt_upcall_info *alloc_upcall_info(struct clnt_info *clp)
|
|
info = malloc(sizeof(struct clnt_upcall_info));
|
|
if (info == NULL)
|
|
return NULL;
|
|
+
|
|
+ pthread_mutex_lock(&clp_lock);
|
|
+ clp->refcount++;
|
|
+ pthread_mutex_unlock(&clp_lock);
|
|
info->clp = clp;
|
|
|
|
return info;
|
|
}
|
|
|
|
+void free_upcall_info(struct clnt_upcall_info *info)
|
|
+{
|
|
+ gssd_free_client(info->clp);
|
|
+ free(info);
|
|
+}
|
|
+
|
|
/* For each upcall read the upcall info into the buffer, then create a
|
|
* thread in a detached state so that resources are released back into
|
|
* the system without the need for a join.
|
|
@@ -438,13 +480,13 @@ gssd_clnt_gssd_cb(int UNUSED(fd), short UNUSED(which), void *data)
|
|
info->lbuflen = read(clp->gssd_fd, info->lbuf, sizeof(info->lbuf));
|
|
if (info->lbuflen <= 0 || info->lbuf[info->lbuflen-1] != '\n') {
|
|
printerr(0, "WARNING: %s: failed reading request\n", __func__);
|
|
- free(info);
|
|
+ free_upcall_info(info);
|
|
return;
|
|
}
|
|
info->lbuf[info->lbuflen-1] = 0;
|
|
|
|
if (start_upcall_thread(handle_gssd_upcall, info))
|
|
- free(info);
|
|
+ free_upcall_info(info);
|
|
}
|
|
|
|
static void
|
|
@@ -461,12 +503,12 @@ gssd_clnt_krb5_cb(int UNUSED(fd), short UNUSED(which), void *data)
|
|
sizeof(info->uid)) < (ssize_t)sizeof(info->uid)) {
|
|
printerr(0, "WARNING: %s: failed reading uid from krb5 "
|
|
"upcall pipe: %s\n", __func__, strerror(errno));
|
|
- free(info);
|
|
+ free_upcall_info(info);
|
|
return;
|
|
}
|
|
|
|
if (start_upcall_thread(handle_krb5_upcall, info))
|
|
- free(info);
|
|
+ free_upcall_info(info);
|
|
}
|
|
|
|
static struct clnt_info *
|
|
@@ -478,6 +520,8 @@ gssd_get_clnt(struct topdir *tdi, const char *name)
|
|
if (!strcmp(clp->name, name))
|
|
return clp;
|
|
|
|
+ printerr(3, "creating client %s/%s\n", tdi->name, name);
|
|
+
|
|
clp = calloc(1, sizeof(struct clnt_info));
|
|
if (!clp) {
|
|
printerr(0, "ERROR: can't malloc clnt_info: %s\n",
|
|
@@ -501,6 +545,7 @@ gssd_get_clnt(struct topdir *tdi, const char *name)
|
|
clp->name = clp->relpath + strlen(tdi->name) + 1;
|
|
clp->krb5_fd = -1;
|
|
clp->gssd_fd = -1;
|
|
+ clp->refcount = 1;
|
|
|
|
TAILQ_INSERT_HEAD(&tdi->clnt_list, clp, list);
|
|
return clp;
|
|
@@ -515,11 +560,8 @@ static int
|
|
gssd_scan_clnt(struct clnt_info *clp)
|
|
{
|
|
int clntfd;
|
|
- bool gssd_was_closed;
|
|
- bool krb5_was_closed;
|
|
|
|
- gssd_was_closed = clp->gssd_fd < 0 ? true : false;
|
|
- krb5_was_closed = clp->krb5_fd < 0 ? true : false;
|
|
+ printerr(3, "scanning client %s\n", clp->relpath);
|
|
|
|
clntfd = openat(pipefs_fd, clp->relpath, O_RDONLY);
|
|
if (clntfd < 0) {
|
|
@@ -535,16 +577,30 @@ gssd_scan_clnt(struct clnt_info *clp)
|
|
if (clp->gssd_fd == -1 && clp->krb5_fd == -1)
|
|
clp->krb5_fd = openat(clntfd, "krb5", O_RDWR | O_NONBLOCK);
|
|
|
|
- if (gssd_was_closed && clp->gssd_fd >= 0) {
|
|
- event_set(&clp->gssd_ev, clp->gssd_fd, EV_READ | EV_PERSIST,
|
|
- gssd_clnt_gssd_cb, clp);
|
|
- event_add(&clp->gssd_ev, NULL);
|
|
+ if (!clp->gssd_ev && clp->gssd_fd >= 0) {
|
|
+ clp->gssd_ev = event_new(evbase, clp->gssd_fd, EV_READ | EV_PERSIST,
|
|
+ gssd_clnt_gssd_cb, clp);
|
|
+ if (!clp->gssd_ev) {
|
|
+ printerr(0, "ERROR: %s: can't create gssd event for %s: %s\n",
|
|
+ __FUNCTION__, clp->relpath, strerror(errno));
|
|
+ close(clp->gssd_fd);
|
|
+ clp->gssd_fd = -1;
|
|
+ } else {
|
|
+ event_add(clp->gssd_ev, NULL);
|
|
+ }
|
|
}
|
|
|
|
- if (krb5_was_closed && clp->krb5_fd >= 0) {
|
|
- event_set(&clp->krb5_ev, clp->krb5_fd, EV_READ | EV_PERSIST,
|
|
- gssd_clnt_krb5_cb, clp);
|
|
- event_add(&clp->krb5_ev, NULL);
|
|
+ if (!clp->krb5_ev && clp->krb5_fd >= 0) {
|
|
+ clp->krb5_ev = event_new(evbase, clp->krb5_fd, EV_READ | EV_PERSIST,
|
|
+ gssd_clnt_krb5_cb, clp);
|
|
+ if (!clp->krb5_ev) {
|
|
+ printerr(0, "ERROR: %s: can't create krb5 event for %s: %s\n",
|
|
+ __FUNCTION__, clp->relpath, strerror(errno));
|
|
+ close(clp->krb5_fd);
|
|
+ clp->krb5_fd = -1;
|
|
+ } else {
|
|
+ event_add(clp->krb5_ev, NULL);
|
|
+ }
|
|
}
|
|
|
|
if (clp->krb5_fd == -1 && clp->gssd_fd == -1)
|
|
@@ -651,7 +707,7 @@ gssd_scan_topdir(const char *name)
|
|
if (clp->scanned)
|
|
continue;
|
|
|
|
- printerr(3, "destroying client %s\n", clp->relpath);
|
|
+ printerr(3, "orphaned client %s\n", clp->relpath);
|
|
saveprev = clp->list.tqe_prev;
|
|
TAILQ_REMOVE(&tdi->clnt_list, clp, list);
|
|
gssd_destroy_client(clp);
|
|
@@ -748,12 +804,16 @@ gssd_inotify_clnt(struct topdir *tdi, struct clnt_info *clp, const struct inotif
|
|
} else if (ev->mask & IN_DELETE) {
|
|
if (!strcmp(ev->name, "gssd") && clp->gssd_fd >= 0) {
|
|
close(clp->gssd_fd);
|
|
- event_del(&clp->gssd_ev);
|
|
+ event_del(clp->gssd_ev);
|
|
+ event_free(clp->gssd_ev);
|
|
+ clp->gssd_ev = NULL;
|
|
clp->gssd_fd = -1;
|
|
|
|
} else if (!strcmp(ev->name, "krb5") && clp->krb5_fd >= 0) {
|
|
close(clp->krb5_fd);
|
|
- event_del(&clp->krb5_ev);
|
|
+ event_del(clp->krb5_ev);
|
|
+ event_free(clp->krb5_ev);
|
|
+ clp->krb5_ev = NULL;
|
|
clp->krb5_fd = -1;
|
|
}
|
|
|
|
@@ -826,10 +886,15 @@ found:
|
|
static void
|
|
sig_die(int signal)
|
|
{
|
|
- if (root_uses_machine_creds)
|
|
- gssd_destroy_krb5_machine_creds();
|
|
+ if (signal_received) {
|
|
+ gssd_destroy_krb5_principals(root_uses_machine_creds);
|
|
+ printerr(1, "forced exiting on signal %d\n", signal);
|
|
+ exit(0);
|
|
+ }
|
|
+
|
|
+ signal_received = true;
|
|
printerr(1, "exiting on signal %d\n", signal);
|
|
- exit(0);
|
|
+ event_base_loopexit(evbase, NULL);
|
|
}
|
|
|
|
static void
|
|
@@ -886,9 +951,10 @@ main(int argc, char *argv[])
|
|
int rpc_verbosity = 0;
|
|
int opt;
|
|
int i;
|
|
+ int rc;
|
|
extern char *optarg;
|
|
char *progname;
|
|
- struct event sighup_ev;
|
|
+ struct event *sighup_ev;
|
|
|
|
read_gss_conf();
|
|
|
|
@@ -1027,7 +1093,11 @@ main(int argc, char *argv[])
|
|
if (gssd_check_mechs() != 0)
|
|
errx(1, "Problem with gssapi library");
|
|
|
|
- event_init();
|
|
+ evbase = event_base_new();
|
|
+ if (!evbase) {
|
|
+ printerr(0, "ERROR: failed to create event base: %s\n", strerror(errno));
|
|
+ exit(EXIT_FAILURE);
|
|
+ }
|
|
|
|
pipefs_dir = opendir(pipefs_path);
|
|
if (!pipefs_dir) {
|
|
@@ -1049,18 +1119,51 @@ main(int argc, char *argv[])
|
|
|
|
signal(SIGINT, sig_die);
|
|
signal(SIGTERM, sig_die);
|
|
- signal_set(&sighup_ev, SIGHUP, gssd_scan_cb, NULL);
|
|
- signal_add(&sighup_ev, NULL);
|
|
- event_set(&inotify_ev, inotify_fd, EV_READ | EV_PERSIST, gssd_inotify_cb, NULL);
|
|
- event_add(&inotify_ev, NULL);
|
|
+ sighup_ev = evsignal_new(evbase, SIGHUP, gssd_scan_cb, NULL);
|
|
+ if (!sighup_ev) {
|
|
+ printerr(0, "ERROR: failed to create SIGHUP event: %s\n", strerror(errno));
|
|
+ exit(EXIT_FAILURE);
|
|
+ }
|
|
+ evsignal_add(sighup_ev, NULL);
|
|
+ inotify_ev = event_new(evbase, inotify_fd, EV_READ | EV_PERSIST,
|
|
+ gssd_inotify_cb, NULL);
|
|
+ if (!inotify_ev) {
|
|
+ printerr(0, "ERROR: failed to create inotify event: %s\n", strerror(errno));
|
|
+ exit(EXIT_FAILURE);
|
|
+ }
|
|
+ event_add(inotify_ev, NULL);
|
|
|
|
TAILQ_INIT(&topdir_list);
|
|
gssd_scan();
|
|
daemon_ready();
|
|
|
|
- event_dispatch();
|
|
+ rc = event_base_dispatch(evbase);
|
|
|
|
- printerr(0, "ERROR: event_dispatch() returned!\n");
|
|
- return EXIT_FAILURE;
|
|
-}
|
|
+ printerr(0, "event_dispatch() returned %i!\n", rc);
|
|
+
|
|
+ gssd_destroy_krb5_principals(root_uses_machine_creds);
|
|
+
|
|
+ while (!TAILQ_EMPTY(&topdir_list)) {
|
|
+ struct topdir *tdi = TAILQ_FIRST(&topdir_list);
|
|
+ TAILQ_REMOVE(&topdir_list, tdi, list);
|
|
+ while (!TAILQ_EMPTY(&tdi->clnt_list)) {
|
|
+ struct clnt_info *clp = TAILQ_FIRST(&tdi->clnt_list);
|
|
+ TAILQ_REMOVE(&tdi->clnt_list, clp, list);
|
|
+ gssd_destroy_client(clp);
|
|
+ }
|
|
+ free(tdi);
|
|
+ }
|
|
+
|
|
+ event_free(inotify_ev);
|
|
+ event_free(sighup_ev);
|
|
+ event_base_free(evbase);
|
|
|
|
+ close(inotify_fd);
|
|
+ close(pipefs_fd);
|
|
+ closedir(pipefs_dir);
|
|
+
|
|
+ free(preferred_realm);
|
|
+ free(ccachesearch);
|
|
+
|
|
+ return rc < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
|
|
+}
|
|
diff --git a/utils/gssd/gssd.h b/utils/gssd/gssd.h
|
|
index f4f5975..1e8c58d 100644
|
|
--- a/utils/gssd/gssd.h
|
|
+++ b/utils/gssd/gssd.h
|
|
@@ -62,13 +62,10 @@ extern int root_uses_machine_creds;
|
|
extern unsigned int context_timeout;
|
|
extern unsigned int rpc_timeout;
|
|
extern char *preferred_realm;
|
|
-extern pthread_mutex_t ple_lock;
|
|
-extern pthread_cond_t pcond;
|
|
-extern pthread_mutex_t pmutex;
|
|
-extern int thread_started;
|
|
|
|
struct clnt_info {
|
|
TAILQ_ENTRY(clnt_info) list;
|
|
+ int refcount;
|
|
int wd;
|
|
bool scanned;
|
|
char *name;
|
|
@@ -79,9 +76,9 @@ struct clnt_info {
|
|
int vers;
|
|
char *protocol;
|
|
int krb5_fd;
|
|
- struct event krb5_ev;
|
|
+ struct event *krb5_ev;
|
|
int gssd_fd;
|
|
- struct event gssd_ev;
|
|
+ struct event *gssd_ev;
|
|
struct sockaddr_storage addr;
|
|
};
|
|
|
|
@@ -94,6 +91,7 @@ struct clnt_upcall_info {
|
|
|
|
void handle_krb5_upcall(struct clnt_upcall_info *clp);
|
|
void handle_gssd_upcall(struct clnt_upcall_info *clp);
|
|
+void free_upcall_info(struct clnt_upcall_info *info);
|
|
|
|
|
|
#endif /* _RPC_GSSD_H_ */
|
|
diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c
|
|
index 8fe6605..e830f49 100644
|
|
--- a/utils/gssd/gssd_proc.c
|
|
+++ b/utils/gssd/gssd_proc.c
|
|
@@ -149,9 +149,10 @@ do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
|
|
char *buf = NULL, *p = NULL, *end = NULL;
|
|
unsigned int timeout = context_timeout;
|
|
unsigned int buf_size = 0;
|
|
+ pthread_t tid = pthread_self();
|
|
|
|
- printerr(2, "doing downcall: lifetime_rec=%u acceptor=%.*s\n",
|
|
- lifetime_rec, acceptor->length, acceptor->value);
|
|
+ printerr(2, "do_downcall(0x%x): lifetime_rec=%u acceptor=%.*s\n",
|
|
+ tid, lifetime_rec, acceptor->length, acceptor->value);
|
|
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 +
|
|
@@ -177,7 +178,7 @@ do_downcall(int k5_fd, uid_t uid, struct authgss_private_data *pd,
|
|
return;
|
|
out_err:
|
|
free(buf);
|
|
- printerr(1, "Failed to write downcall!\n");
|
|
+ printerr(1, "do_downcall(0x%x): Failed to write downcall!\n", tid);
|
|
return;
|
|
}
|
|
|
|
@@ -231,7 +232,7 @@ populate_port(struct sockaddr *sa, const socklen_t salen,
|
|
switch (sa->sa_family) {
|
|
case AF_INET:
|
|
if (s4->sin_port != 0) {
|
|
- printerr(2, "DEBUG: port already set to %d\n",
|
|
+ printerr(4, "DEBUG: port already set to %d\n",
|
|
ntohs(s4->sin_port));
|
|
return 1;
|
|
}
|
|
@@ -239,7 +240,7 @@ populate_port(struct sockaddr *sa, const socklen_t salen,
|
|
#ifdef IPV6_SUPPORTED
|
|
case AF_INET6:
|
|
if (s6->sin6_port != 0) {
|
|
- printerr(2, "DEBUG: port already set to %d\n",
|
|
+ printerr(4, "DEBUG: port already set to %d\n",
|
|
ntohs(s6->sin6_port));
|
|
return 1;
|
|
}
|
|
@@ -548,7 +549,7 @@ krb5_use_machine_creds(struct clnt_info *clp, uid_t uid,
|
|
uid, tgtname);
|
|
|
|
do {
|
|
- gssd_refresh_krb5_machine_credential(clp->servername, NULL,
|
|
+ gssd_refresh_krb5_machine_credential(clp->servername,
|
|
service, srchost);
|
|
/*
|
|
* Get a list of credential cache names and try each
|
|
@@ -730,7 +731,7 @@ handle_krb5_upcall(struct clnt_upcall_info *info)
|
|
printerr(2, "\n%s: uid %d (%s)\n", __func__, info->uid, clp->relpath);
|
|
|
|
process_krb5_upcall(clp, info->uid, clp->krb5_fd, NULL, NULL, NULL);
|
|
- free(info);
|
|
+ free_upcall_info(info);
|
|
}
|
|
|
|
void
|
|
@@ -747,8 +748,10 @@ handle_gssd_upcall(struct clnt_upcall_info *info)
|
|
char *enctypes = NULL;
|
|
char *upcall_str;
|
|
char *pbuf = info->lbuf;
|
|
+ pthread_t tid = pthread_self();
|
|
|
|
- printerr(2, "\n%s: '%s' (%s)\n", __func__, info->lbuf, clp->relpath);
|
|
+ printerr(2, "\n%s(0x%x): '%s' (%s)\n", __func__, tid,
|
|
+ info->lbuf, clp->relpath);
|
|
|
|
upcall_str = strdup(info->lbuf);
|
|
if (upcall_str == NULL) {
|
|
@@ -830,6 +833,6 @@ handle_gssd_upcall(struct clnt_upcall_info *info)
|
|
out:
|
|
free(upcall_str);
|
|
out_nomem:
|
|
- free(info);
|
|
+ free_upcall_info(info);
|
|
return;
|
|
}
|
|
diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c
|
|
index 8c73748..9bd74b0 100644
|
|
--- a/utils/gssd/krb5_util.c
|
|
+++ b/utils/gssd/krb5_util.c
|
|
@@ -130,9 +130,28 @@
|
|
#include "gss_util.h"
|
|
#include "krb5_util.h"
|
|
|
|
+/*
|
|
+ * List of principals from our keytab that we
|
|
+ * will try to use to obtain credentials
|
|
+ * (known as a principal list entry (ple))
|
|
+ */
|
|
+struct gssd_k5_kt_princ {
|
|
+ struct gssd_k5_kt_princ *next;
|
|
+ // Only protect against deletion, not modification
|
|
+ int refcount;
|
|
+ // Only set during creation in new_ple()
|
|
+ krb5_principal princ;
|
|
+ char *realm;
|
|
+ // Modified during usage by gssd_get_single_krb5_cred()
|
|
+ char *ccname;
|
|
+ krb5_timestamp endtime;
|
|
+};
|
|
+
|
|
+
|
|
/* Global list of principals/cache file names for machine credentials */
|
|
-struct gssd_k5_kt_princ *gssd_k5_kt_princ_list = NULL;
|
|
-pthread_mutex_t ple_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
+static struct gssd_k5_kt_princ *gssd_k5_kt_princ_list = NULL;
|
|
+/* This mutex protects list modification & ple->ccname */
|
|
+static pthread_mutex_t ple_lock = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
#ifdef HAVE_SET_ALLOWABLE_ENCTYPES
|
|
int limit_to_legacy_enctypes = 0;
|
|
@@ -146,10 +165,22 @@ static int select_krb5_ccache(const struct dirent *d);
|
|
static int gssd_find_existing_krb5_ccache(uid_t uid, char *dirname,
|
|
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);
|
|
+ krb5_keytab kt, struct gssd_k5_kt_princ *ple);
|
|
static int query_krb5_ccache(const char* cred_cache, char **ret_princname,
|
|
char **ret_realm);
|
|
|
|
+static void release_ple(krb5_context context, struct gssd_k5_kt_princ *ple)
|
|
+{
|
|
+ if (--ple->refcount)
|
|
+ return;
|
|
+
|
|
+ printerr(3, "freeing cached principal (ccname=%s, realm=%s)\n", ple->ccname, ple->realm);
|
|
+ krb5_free_principal(context, ple->princ);
|
|
+ free(ple->ccname);
|
|
+ free(ple->realm);
|
|
+ free(ple);
|
|
+}
|
|
+
|
|
/*
|
|
* Called from the scandir function to weed out potential krb5
|
|
* credentials cache files
|
|
@@ -192,7 +223,8 @@ gssd_find_existing_krb5_ccache(uid_t uid, char *dirname,
|
|
int found = 0;
|
|
struct dirent *best_match_dir = NULL;
|
|
struct stat best_match_stat, tmp_stat;
|
|
- char buf[PATH_MAX+4+2+256];
|
|
+ /* dirname + cctype + d_name + NULL */
|
|
+ char buf[PATH_MAX+5+256+1];
|
|
char *princname = NULL;
|
|
char *realm = NULL;
|
|
int score, best_match_score = 0, err = -EACCES;
|
|
@@ -349,8 +381,7 @@ gssd_check_if_cc_exists(struct gssd_k5_kt_princ *ple)
|
|
static int
|
|
gssd_get_single_krb5_cred(krb5_context context,
|
|
krb5_keytab kt,
|
|
- struct gssd_k5_kt_princ *ple,
|
|
- int nocache)
|
|
+ struct gssd_k5_kt_princ *ple)
|
|
{
|
|
#ifdef HAVE_KRB5_GET_INIT_CREDS_OPT_SET_ADDRESSLESS
|
|
krb5_get_init_creds_opt *init_opts = NULL;
|
|
@@ -367,22 +398,26 @@ gssd_get_single_krb5_cred(krb5_context context,
|
|
char *cache_type;
|
|
char *pname = NULL;
|
|
char *k5err = NULL;
|
|
+ int nocache = 0;
|
|
|
|
memset(&my_creds, 0, sizeof(my_creds));
|
|
|
|
- if (!nocache && !use_memcache)
|
|
+ if (!use_memcache)
|
|
nocache = gssd_check_if_cc_exists(ple);
|
|
/*
|
|
* Workaround for clock skew among NFS server, NFS client and KDC
|
|
* 300 because clock skew must be within 300sec for kerberos
|
|
*/
|
|
now += 300;
|
|
+ pthread_mutex_lock(&ple_lock);
|
|
if (ple->ccname && ple->endtime > now && !nocache) {
|
|
printerr(3, "INFO: Credentials in CC '%s' are good until %d\n",
|
|
ple->ccname, ple->endtime);
|
|
code = 0;
|
|
+ pthread_mutex_unlock(&ple_lock);
|
|
goto out;
|
|
}
|
|
+ pthread_mutex_unlock(&ple_lock);
|
|
|
|
if ((code = krb5_kt_get_name(context, kt, kt_name, BUFSIZ))) {
|
|
printerr(0, "ERROR: Unable to get keytab name in "
|
|
@@ -435,6 +470,7 @@ gssd_get_single_krb5_cred(krb5_context context,
|
|
* Initialize cache file which we're going to be using
|
|
*/
|
|
|
|
+ pthread_mutex_lock(&ple_lock);
|
|
if (use_memcache)
|
|
cache_type = "MEMORY";
|
|
else
|
|
@@ -444,15 +480,18 @@ gssd_get_single_krb5_cred(krb5_context context,
|
|
ccachesearch[0], GSSD_DEFAULT_CRED_PREFIX,
|
|
GSSD_DEFAULT_MACHINE_CRED_SUFFIX, ple->realm);
|
|
ple->endtime = my_creds.times.endtime;
|
|
- if (ple->ccname != NULL)
|
|
+ if (ple->ccname == NULL || strcmp(ple->ccname, cc_name) != 0) {
|
|
free(ple->ccname);
|
|
- ple->ccname = strdup(cc_name);
|
|
- if (ple->ccname == NULL) {
|
|
- printerr(0, "ERROR: no storage to duplicate credentials "
|
|
- "cache name '%s'\n", cc_name);
|
|
- code = ENOMEM;
|
|
- goto out;
|
|
+ ple->ccname = strdup(cc_name);
|
|
+ if (ple->ccname == NULL) {
|
|
+ printerr(0, "ERROR: no storage to duplicate credentials "
|
|
+ "cache name '%s'\n", cc_name);
|
|
+ code = ENOMEM;
|
|
+ pthread_mutex_unlock(&ple_lock);
|
|
+ goto out;
|
|
+ }
|
|
}
|
|
+ pthread_mutex_unlock(&ple_lock);
|
|
if ((code = krb5_cc_resolve(context, cc_name, &ccache))) {
|
|
k5err = gssd_k5_err_msg(context, code);
|
|
printerr(0, "ERROR: %s while opening credential cache '%s'\n",
|
|
@@ -484,12 +523,13 @@ gssd_get_single_krb5_cred(krb5_context context,
|
|
if (ccache)
|
|
krb5_cc_close(context, ccache);
|
|
krb5_free_cred_contents(context, &my_creds);
|
|
- krb5_free_string(context, k5err);
|
|
+ free(k5err);
|
|
return (code);
|
|
}
|
|
|
|
/*
|
|
* Given a principal, find a matching ple structure
|
|
+ * Called with mutex held
|
|
*/
|
|
static struct gssd_k5_kt_princ *
|
|
find_ple_by_princ(krb5_context context, krb5_principal princ)
|
|
@@ -506,6 +546,7 @@ find_ple_by_princ(krb5_context context, krb5_principal princ)
|
|
|
|
/*
|
|
* Create, initialize, and add a new ple structure to the global list
|
|
+ * Called with mutex held
|
|
*/
|
|
static struct gssd_k5_kt_princ *
|
|
new_ple(krb5_context context, krb5_principal princ)
|
|
@@ -557,6 +598,7 @@ new_ple(krb5_context context, krb5_principal princ)
|
|
p->next = ple;
|
|
}
|
|
|
|
+ ple->refcount = 1;
|
|
return ple;
|
|
outerr:
|
|
if (ple) {
|
|
@@ -575,13 +617,14 @@ get_ple_by_princ(krb5_context context, krb5_principal princ)
|
|
{
|
|
struct gssd_k5_kt_princ *ple;
|
|
|
|
- /* Need to serialize list if we ever become multi-threaded! */
|
|
-
|
|
pthread_mutex_lock(&ple_lock);
|
|
ple = find_ple_by_princ(context, princ);
|
|
if (ple == NULL) {
|
|
ple = new_ple(context, princ);
|
|
}
|
|
+ if (ple != NULL) {
|
|
+ ple->refcount++;
|
|
+ }
|
|
pthread_mutex_unlock(&ple_lock);
|
|
|
|
return ple;
|
|
@@ -715,6 +758,7 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt,
|
|
goto out;
|
|
}
|
|
|
|
+ printerr(4, "Scanning keytab for %s/*@%s\n", service, realm);
|
|
while ((code = krb5_kt_next_entry(context, kt, kte, &cursor)) == 0) {
|
|
if ((code = krb5_unparse_name(context, kte->principal,
|
|
&pname))) {
|
|
@@ -723,7 +767,7 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt,
|
|
"we failed to unparse principal name: %s\n",
|
|
k5err);
|
|
k5_free_kt_entry(context, kte);
|
|
- krb5_free_string(context, k5err);
|
|
+ free(k5err);
|
|
k5err = NULL;
|
|
continue;
|
|
}
|
|
@@ -746,6 +790,8 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt,
|
|
retval = ENOMEM;
|
|
k5_free_kt_entry(context, kte);
|
|
} else {
|
|
+ release_ple(context, ple);
|
|
+ ple = NULL;
|
|
retval = 0;
|
|
*found = 1;
|
|
}
|
|
@@ -770,7 +816,7 @@ gssd_search_krb5_keytab(krb5_context context, krb5_keytab kt,
|
|
if (retval < 0)
|
|
retval = 0;
|
|
out:
|
|
- krb5_free_string(context, k5err);
|
|
+ free(k5err);
|
|
return retval;
|
|
}
|
|
|
|
@@ -811,41 +857,42 @@ find_keytab_entry(krb5_context context, krb5_keytab kt,
|
|
/* Get full local hostname */
|
|
if (srchost) {
|
|
strcpy(myhostname, srchost);
|
|
- } else 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;
|
|
+ strcpy(myhostad, myhostname);
|
|
+ } else {
|
|
+ /* Borrow myhostad for gethostname(), we need it later anyways */
|
|
+ if (gethostname(myhostad, sizeof(myhostad)-1) == -1) {
|
|
+ retval = errno;
|
|
+ k5err = gssd_k5_err_msg(context, retval);
|
|
+ printerr(1, "%s while getting local hostname\n", k5err);
|
|
+ goto out;
|
|
+ }
|
|
+ retval = get_full_hostname(myhostad, myhostname, sizeof(myhostname));
|
|
+ if (retval) {
|
|
+ /* Don't use myhostname */
|
|
+ myhostname[0] = 0;
|
|
+ }
|
|
}
|
|
|
|
/* Compute the active directory machine name HOST$ */
|
|
- krb5_appdefault_string(context, "nfs", NULL, "ad_principal_name",
|
|
+ krb5_appdefault_string(context, "nfs", NULL, "ad_principal_name",
|
|
notsetstr, &adhostoverride);
|
|
- if (strcmp(adhostoverride, notsetstr) != 0) {
|
|
- printerr (1,
|
|
- "AD host string overridden with \"%s\" from appdefaults\n",
|
|
- adhostoverride);
|
|
- /* No overflow: Windows cannot handle strings longer than 19 chars */
|
|
- strcpy(myhostad, adhostoverride);
|
|
+ if (adhostoverride && strcmp(adhostoverride, notsetstr) != 0) {
|
|
+ printerr(1,
|
|
+ "AD host string overridden with \"%s\" from appdefaults\n",
|
|
+ adhostoverride);
|
|
+ /* No overflow: Windows cannot handle strings longer than 19 chars */
|
|
+ strcpy(myhostad, adhostoverride);
|
|
} else {
|
|
- strcpy(myhostad, myhostname);
|
|
- for (i = 0; myhostad[i] != 0; ++i) {
|
|
- if (myhostad[i] == '.') break;
|
|
- }
|
|
- myhostad[i] = '$';
|
|
- myhostad[i+1] = 0;
|
|
+ /* In this case, it's been pre-filled above */
|
|
+ for (i = 0; myhostad[i] != 0; ++i) {
|
|
+ if (myhostad[i] == '.') break;
|
|
+ }
|
|
+ myhostad[i] = '$';
|
|
+ myhostad[i+1] = 0;
|
|
}
|
|
if (adhostoverride)
|
|
krb5_free_string(context, adhostoverride);
|
|
|
|
- if (!srchost) {
|
|
- retval = get_full_hostname(myhostname, myhostname, sizeof(myhostname));
|
|
- if (retval) {
|
|
- /* Don't use myhostname */
|
|
- myhostname[0] = 0;
|
|
- }
|
|
- }
|
|
-
|
|
code = krb5_get_default_realm(context, &default_realm);
|
|
if (code) {
|
|
retval = code;
|
|
@@ -927,7 +974,7 @@ find_keytab_entry(krb5_context context, krb5_keytab kt,
|
|
k5err = gssd_k5_err_msg(context, code);
|
|
printerr(1, "%s while building principal for '%s'\n",
|
|
k5err, spn);
|
|
- krb5_free_string(context, k5err);
|
|
+ free(k5err);
|
|
k5err = NULL;
|
|
continue;
|
|
}
|
|
@@ -937,7 +984,7 @@ find_keytab_entry(krb5_context context, krb5_keytab kt,
|
|
k5err = gssd_k5_err_msg(context, code);
|
|
printerr(3, "%s while getting keytab entry for '%s'\n",
|
|
k5err, spn);
|
|
- krb5_free_string(context, k5err);
|
|
+ free(k5err);
|
|
k5err = NULL;
|
|
/*
|
|
* We tried the active directory machine account
|
|
@@ -986,7 +1033,7 @@ out:
|
|
k5_free_default_realm(context, default_realm);
|
|
if (realmnames)
|
|
krb5_free_host_realm(context, realmnames);
|
|
- krb5_free_string(context, k5err);
|
|
+ free(k5err);
|
|
return retval;
|
|
}
|
|
|
|
@@ -1078,6 +1125,93 @@ err_cache:
|
|
return (*ret_princname && *ret_realm);
|
|
}
|
|
|
|
+/*
|
|
+ * Obtain (or refresh if necessary) Kerberos machine credentials
|
|
+ * If a ple is passed in, it's reference will be released
|
|
+ */
|
|
+static int
|
|
+gssd_refresh_krb5_machine_credential_internal(char *hostname,
|
|
+ struct gssd_k5_kt_princ *ple,
|
|
+ char *service, char *srchost)
|
|
+{
|
|
+ krb5_error_code code = 0;
|
|
+ krb5_context context;
|
|
+ krb5_keytab kt = NULL;;
|
|
+ int retval = 0;
|
|
+ char *k5err = NULL;
|
|
+ const char *svcnames[] = { "$", "root", "nfs", "host", NULL };
|
|
+
|
|
+ printerr(2, "%s: hostname=%s ple=%p service=%s srchost=%s\n",
|
|
+ __func__, hostname, ple, service, srchost);
|
|
+
|
|
+ /*
|
|
+ * If a specific service name was specified, use it.
|
|
+ * Otherwise, use the default list.
|
|
+ */
|
|
+ if (service != NULL && strcmp(service, "*") != 0) {
|
|
+ svcnames[0] = service;
|
|
+ svcnames[1] = NULL;
|
|
+ }
|
|
+ if (hostname == NULL && ple == NULL)
|
|
+ return EINVAL;
|
|
+
|
|
+ code = krb5_init_context(&context);
|
|
+ if (code) {
|
|
+ k5err = gssd_k5_err_msg(NULL, code);
|
|
+ printerr(0, "ERROR: %s: %s while initializing krb5 context\n",
|
|
+ __func__, k5err);
|
|
+ retval = code;
|
|
+ goto out;
|
|
+ }
|
|
+
|
|
+ if ((code = krb5_kt_resolve(context, keytabfile, &kt))) {
|
|
+ k5err = gssd_k5_err_msg(context, code);
|
|
+ printerr(0, "ERROR: %s: %s while resolving keytab '%s'\n",
|
|
+ __func__, k5err, keytabfile);
|
|
+ goto out_free_context;
|
|
+ }
|
|
+
|
|
+ if (ple == NULL) {
|
|
+ krb5_keytab_entry kte;
|
|
+
|
|
+ code = find_keytab_entry(context, kt, srchost, hostname,
|
|
+ &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_free_kt;
|
|
+ }
|
|
+
|
|
+ ple = get_ple_by_princ(context, kte.principal);
|
|
+ k5_free_kt_entry(context, &kte);
|
|
+ if (ple == NULL) {
|
|
+ char *pname;
|
|
+ if ((krb5_unparse_name(context, kte.principal, &pname))) {
|
|
+ pname = NULL;
|
|
+ }
|
|
+ printerr(0, "ERROR: %s: Could not locate or create "
|
|
+ "ple struct for principal %s for connection "
|
|
+ "with host %s\n",
|
|
+ __FUNCTION__, pname ? pname : "<unparsable>",
|
|
+ hostname);
|
|
+ if (pname) k5_free_unparsed_name(context, pname);
|
|
+ goto out_free_kt;
|
|
+ }
|
|
+ }
|
|
+ retval = gssd_get_single_krb5_cred(context, kt, ple);
|
|
+out_free_kt:
|
|
+ krb5_kt_close(context, kt);
|
|
+out_free_context:
|
|
+ if (ple)
|
|
+ release_ple(context, ple);
|
|
+ krb5_free_context(context);
|
|
+out:
|
|
+ free(k5err);
|
|
+ return retval;
|
|
+}
|
|
+
|
|
/*==========================*/
|
|
/*=== External routines ===*/
|
|
/*==========================*/
|
|
@@ -1092,7 +1226,8 @@ err_cache:
|
|
int
|
|
gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername, char *dirpattern)
|
|
{
|
|
- char buf[PATH_MAX+2+256], dirname[PATH_MAX];
|
|
+ /* dirname + cctype + d_name + NULL */
|
|
+ char buf[PATH_MAX+5+256+1], dirname[PATH_MAX];
|
|
const char *cctype;
|
|
struct dirent *d;
|
|
int err, i, j;
|
|
@@ -1171,37 +1306,56 @@ gssd_get_krb5_machine_cred_list(char ***list)
|
|
goto out;
|
|
}
|
|
|
|
- /* Need to serialize list if we ever become multi-threaded! */
|
|
-
|
|
+ pthread_mutex_lock(&ple_lock);
|
|
for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) {
|
|
- if (ple->ccname) {
|
|
- /* Make sure cred is up-to-date before returning it */
|
|
- retval = gssd_refresh_krb5_machine_credential(NULL, ple,
|
|
- NULL, NULL);
|
|
- if (retval)
|
|
- continue;
|
|
- if (i + 1 > listsize) {
|
|
- listsize += listinc;
|
|
- l = (char **)
|
|
- realloc(l, listsize * sizeof(char *));
|
|
- if (l == NULL) {
|
|
- retval = ENOMEM;
|
|
- goto out;
|
|
- }
|
|
- }
|
|
- if ((l[i++] = strdup(ple->ccname)) == NULL) {
|
|
+ if (!ple->ccname)
|
|
+ continue;
|
|
+
|
|
+ /* Take advantage of the fact we only remove the ple
|
|
+ * from the list during shutdown. If it's modified
|
|
+ * concurrently at worst we'll just miss a new entry
|
|
+ * before the current ple
|
|
+ *
|
|
+ * gssd_refresh_krb5_machine_credential_internal() will
|
|
+ * release the ple refcount
|
|
+ */
|
|
+ ple->refcount++;
|
|
+ pthread_mutex_unlock(&ple_lock);
|
|
+ /* Make sure cred is up-to-date before returning it */
|
|
+ retval = gssd_refresh_krb5_machine_credential_internal(NULL, ple,
|
|
+ NULL, NULL);
|
|
+ pthread_mutex_lock(&ple_lock);
|
|
+ if (gssd_k5_kt_princ_list == NULL) {
|
|
+ /* Looks like we did shutdown... abort */
|
|
+ l[i] = NULL;
|
|
+ gssd_free_krb5_machine_cred_list(l);
|
|
+ retval = ENOMEM;
|
|
+ goto out_lock;
|
|
+ }
|
|
+ if (retval)
|
|
+ continue;
|
|
+ if (i + 1 > listsize) {
|
|
+ listsize += listinc;
|
|
+ l = (char **)
|
|
+ realloc(l, listsize * sizeof(char *));
|
|
+ if (l == NULL) {
|
|
retval = ENOMEM;
|
|
- goto out;
|
|
+ goto out_lock;
|
|
}
|
|
}
|
|
+ if ((l[i++] = strdup(ple->ccname)) == NULL) {
|
|
+ retval = ENOMEM;
|
|
+ goto out_lock;
|
|
+ }
|
|
}
|
|
if (i > 0) {
|
|
l[i] = NULL;
|
|
*list = l;
|
|
retval = 0;
|
|
- goto out;
|
|
} else
|
|
free((void *)l);
|
|
+out_lock:
|
|
+ pthread_mutex_unlock(&ple_lock);
|
|
out:
|
|
return retval;
|
|
}
|
|
@@ -1226,7 +1380,7 @@ gssd_free_krb5_machine_cred_list(char **list)
|
|
* Called upon exit. Destroys machine credentials.
|
|
*/
|
|
void
|
|
-gssd_destroy_krb5_machine_creds(void)
|
|
+gssd_destroy_krb5_principals(int destroy_machine_creds)
|
|
{
|
|
krb5_context context;
|
|
krb5_error_code code = 0;
|
|
@@ -1238,33 +1392,38 @@ gssd_destroy_krb5_machine_creds(void)
|
|
if (code) {
|
|
k5err = gssd_k5_err_msg(NULL, code);
|
|
printerr(0, "ERROR: %s while initializing krb5\n", k5err);
|
|
- goto out;
|
|
+ free(k5err);
|
|
+ return;
|
|
}
|
|
|
|
- for (ple = gssd_k5_kt_princ_list; ple; ple = ple->next) {
|
|
- if (!ple->ccname)
|
|
- continue;
|
|
- if ((code = krb5_cc_resolve(context, ple->ccname, &ccache))) {
|
|
- k5err = gssd_k5_err_msg(context, code);
|
|
- printerr(0, "WARNING: %s while resolving credential "
|
|
- "cache '%s' for destruction\n", k5err,
|
|
- ple->ccname);
|
|
- krb5_free_string(context, k5err);
|
|
- k5err = NULL;
|
|
- continue;
|
|
- }
|
|
+ pthread_mutex_lock(&ple_lock);
|
|
+ while (gssd_k5_kt_princ_list) {
|
|
+ ple = gssd_k5_kt_princ_list;
|
|
+ gssd_k5_kt_princ_list = ple->next;
|
|
|
|
- if ((code = krb5_cc_destroy(context, ccache))) {
|
|
- k5err = gssd_k5_err_msg(context, code);
|
|
- printerr(0, "WARNING: %s while destroying credential "
|
|
- "cache '%s'\n", k5err, ple->ccname);
|
|
- krb5_free_string(context, k5err);
|
|
- k5err = NULL;
|
|
+ if (destroy_machine_creds && ple->ccname) {
|
|
+ if ((code = krb5_cc_resolve(context, ple->ccname, &ccache))) {
|
|
+ k5err = gssd_k5_err_msg(context, code);
|
|
+ printerr(0, "WARNING: %s while resolving credential "
|
|
+ "cache '%s' for destruction\n", k5err,
|
|
+ ple->ccname);
|
|
+ free(k5err);
|
|
+ k5err = NULL;
|
|
+ }
|
|
+
|
|
+ if (!code && (code = krb5_cc_destroy(context, ccache))) {
|
|
+ k5err = gssd_k5_err_msg(context, code);
|
|
+ printerr(0, "WARNING: %s while destroying credential "
|
|
+ "cache '%s'\n", k5err, ple->ccname);
|
|
+ free(k5err);
|
|
+ k5err = NULL;
|
|
+ }
|
|
}
|
|
+
|
|
+ release_ple(context, ple);
|
|
}
|
|
+ pthread_mutex_unlock(&ple_lock);
|
|
krb5_free_context(context);
|
|
- out:
|
|
- krb5_free_string(context, k5err);
|
|
}
|
|
|
|
/*
|
|
@@ -1272,83 +1431,10 @@ gssd_destroy_krb5_machine_creds(void)
|
|
*/
|
|
int
|
|
gssd_refresh_krb5_machine_credential(char *hostname,
|
|
- struct gssd_k5_kt_princ *ple,
|
|
char *service, char *srchost)
|
|
{
|
|
- krb5_error_code code = 0;
|
|
- krb5_context context;
|
|
- krb5_keytab kt = NULL;;
|
|
- int retval = 0;
|
|
- char *k5err = NULL;
|
|
- const char *svcnames[] = { "$", "root", "nfs", "host", NULL };
|
|
-
|
|
- printerr(2, "%s: hostname=%s ple=%p service=%s srchost=%s\n",
|
|
- __func__, hostname, ple, service, srchost);
|
|
-
|
|
- /*
|
|
- * If a specific service name was specified, use it.
|
|
- * Otherwise, use the default list.
|
|
- */
|
|
- if (service != NULL && strcmp(service, "*") != 0) {
|
|
- svcnames[0] = service;
|
|
- svcnames[1] = NULL;
|
|
- }
|
|
- if (hostname == NULL && ple == NULL)
|
|
- return EINVAL;
|
|
-
|
|
- code = krb5_init_context(&context);
|
|
- if (code) {
|
|
- k5err = gssd_k5_err_msg(NULL, code);
|
|
- printerr(0, "ERROR: %s: %s while initializing krb5 context\n",
|
|
- __func__, k5err);
|
|
- retval = code;
|
|
- goto out;
|
|
- }
|
|
-
|
|
- if ((code = krb5_kt_resolve(context, keytabfile, &kt))) {
|
|
- k5err = gssd_k5_err_msg(context, code);
|
|
- printerr(0, "ERROR: %s: %s while resolving keytab '%s'\n",
|
|
- __func__, k5err, keytabfile);
|
|
- goto out_free_context;
|
|
- }
|
|
-
|
|
- if (ple == NULL) {
|
|
- krb5_keytab_entry kte;
|
|
-
|
|
- code = find_keytab_entry(context, kt, srchost, hostname,
|
|
- &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_free_kt;
|
|
- }
|
|
-
|
|
- ple = get_ple_by_princ(context, kte.principal);
|
|
- k5_free_kt_entry(context, &kte);
|
|
- if (ple == NULL) {
|
|
- char *pname;
|
|
- if ((krb5_unparse_name(context, kte.principal, &pname))) {
|
|
- pname = NULL;
|
|
- }
|
|
- printerr(0, "ERROR: %s: Could not locate or create "
|
|
- "ple struct for principal %s for connection "
|
|
- "with host %s\n",
|
|
- __FUNCTION__, pname ? pname : "<unparsable>",
|
|
- hostname);
|
|
- if (pname) k5_free_unparsed_name(context, pname);
|
|
- goto out_free_kt;
|
|
- }
|
|
- }
|
|
- retval = gssd_get_single_krb5_cred(context, kt, ple, 0);
|
|
-out_free_kt:
|
|
- krb5_kt_close(context, kt);
|
|
-out_free_context:
|
|
- krb5_free_context(context);
|
|
-out:
|
|
- krb5_free_string(context, k5err);
|
|
- return retval;
|
|
+ return gssd_refresh_krb5_machine_credential_internal(hostname, NULL,
|
|
+ service, srchost);
|
|
}
|
|
|
|
/*
|
|
diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h
|
|
index b000b44..2415205 100644
|
|
--- a/utils/gssd/krb5_util.h
|
|
+++ b/utils/gssd/krb5_util.h
|
|
@@ -9,27 +9,13 @@
|
|
#include "gss_oids.h"
|
|
#endif
|
|
|
|
-/*
|
|
- * List of principals from our keytab that we
|
|
- * will try to use to obtain credentials
|
|
- * (known as a principal list entry (ple))
|
|
- */
|
|
-struct gssd_k5_kt_princ {
|
|
- struct gssd_k5_kt_princ *next;
|
|
- krb5_principal princ;
|
|
- char *ccname;
|
|
- char *realm;
|
|
- krb5_timestamp endtime;
|
|
-};
|
|
-
|
|
|
|
int gssd_setup_krb5_user_gss_ccache(uid_t uid, char *servername,
|
|
char *dirname);
|
|
int gssd_get_krb5_machine_cred_list(char ***list);
|
|
void gssd_free_krb5_machine_cred_list(char **list);
|
|
-void gssd_destroy_krb5_machine_creds(void);
|
|
+void gssd_destroy_krb5_principals(int destroy_machine_creds);
|
|
int gssd_refresh_krb5_machine_credential(char *hostname,
|
|
- struct gssd_k5_kt_princ *ple,
|
|
char *service, char *srchost);
|
|
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.c b/utils/gssd/svcgssd.c
|
|
index ec49b61..3ab2100 100644
|
|
--- a/utils/gssd/svcgssd.c
|
|
+++ b/utils/gssd/svcgssd.c
|
|
@@ -57,20 +57,36 @@
|
|
#include <string.h>
|
|
#include <signal.h>
|
|
#include <nfsidmap.h>
|
|
+#include <event2/event.h>
|
|
+
|
|
#include "nfslib.h"
|
|
#include "svcgssd.h"
|
|
#include "gss_util.h"
|
|
#include "err_util.h"
|
|
#include "conffile.h"
|
|
+#include "misc.h"
|
|
+#include "svcgssd_krb5.h"
|
|
+
|
|
+struct state_paths etab; /* from cacheio.c */
|
|
+static bool signal_received = false;
|
|
+static struct event_base *evbase = NULL;
|
|
+static int nullrpc_fd = -1;
|
|
+static struct event *nullrpc_event = NULL;
|
|
+static struct event *wait_event = NULL;
|
|
|
|
-struct state_paths etab;
|
|
+#define NULLRPC_FILE "/proc/net/rpc/auth.rpcsec.init/channel"
|
|
|
|
static void
|
|
sig_die(int signal)
|
|
{
|
|
- /* destroy krb5 machine creds */
|
|
+ if (signal_received) {
|
|
+ /* destroy krb5 machine creds */
|
|
+ printerr(1, "forced exiting on signal %d\n", signal);
|
|
+ exit(0);
|
|
+ }
|
|
+ signal_received = true;
|
|
printerr(1, "exiting on signal %d\n", signal);
|
|
- exit(0);
|
|
+ event_base_loopexit(evbase, NULL);
|
|
}
|
|
|
|
static void
|
|
@@ -89,6 +105,84 @@ usage(char *progname)
|
|
exit(1);
|
|
}
|
|
|
|
+static void
|
|
+svcgssd_nullrpc_cb(int fd, short UNUSED(which), void *UNUSED(data))
|
|
+{
|
|
+ char lbuf[RPC_CHAN_BUF_SIZE];
|
|
+ int lbuflen = 0;
|
|
+
|
|
+ printerr(1, "reading null request\n");
|
|
+
|
|
+ lbuflen = read(fd, lbuf, sizeof(lbuf));
|
|
+ if (lbuflen <= 0 || lbuf[lbuflen-1] != '\n') {
|
|
+ printerr(0, "WARNING: handle_nullreq: failed reading request\n");
|
|
+ return;
|
|
+ }
|
|
+ lbuf[lbuflen-1] = 0;
|
|
+
|
|
+ handle_nullreq(lbuf);
|
|
+}
|
|
+
|
|
+static void
|
|
+svcgssd_nullrpc_close(void)
|
|
+{
|
|
+ if (nullrpc_event) {
|
|
+ printerr(2, "closing nullrpc channel %s\n", NULLRPC_FILE);
|
|
+ event_free(nullrpc_event);
|
|
+ nullrpc_event = NULL;
|
|
+ }
|
|
+ if (nullrpc_fd != -1) {
|
|
+ close(nullrpc_fd);
|
|
+ nullrpc_fd = -1;
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+svcgssd_nullrpc_open(void)
|
|
+{
|
|
+ nullrpc_fd = open(NULLRPC_FILE, O_RDWR);
|
|
+ if (nullrpc_fd < 0) {
|
|
+ printerr(0, "failed to open %s: %s\n",
|
|
+ NULLRPC_FILE, strerror(errno));
|
|
+ return;
|
|
+ }
|
|
+ nullrpc_event = event_new(evbase, nullrpc_fd, EV_READ | EV_PERSIST,
|
|
+ svcgssd_nullrpc_cb, NULL);
|
|
+ if (!nullrpc_event) {
|
|
+ printerr(0, "failed to create event for %s: %s\n",
|
|
+ NULLRPC_FILE, strerror(errno));
|
|
+ close(nullrpc_fd);
|
|
+ nullrpc_fd = -1;
|
|
+ return;
|
|
+ }
|
|
+ event_add(nullrpc_event, NULL);
|
|
+ printerr(2, "opened nullrpc channel %s\n", NULLRPC_FILE);
|
|
+}
|
|
+
|
|
+static void
|
|
+svcgssd_wait_cb(int UNUSED(fd), short UNUSED(which), void *UNUSED(data))
|
|
+{
|
|
+ static int times = 0;
|
|
+ int rc;
|
|
+
|
|
+ rc = access(NULLRPC_FILE, R_OK | W_OK);
|
|
+ if (rc != 0) {
|
|
+ struct timeval t = {times < 10 ? 1 : 10, 0};
|
|
+ times++;
|
|
+ if (times % 30 == 0)
|
|
+ printerr(2, "still waiting for nullrpc channel: %s\n",
|
|
+ NULLRPC_FILE);
|
|
+ evtimer_add(wait_event, &t);
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ svcgssd_nullrpc_open();
|
|
+ event_free(wait_event);
|
|
+ wait_event = NULL;
|
|
+}
|
|
+
|
|
+
|
|
+
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
@@ -102,6 +196,7 @@ main(int argc, char *argv[])
|
|
char *progname;
|
|
char *principal = NULL;
|
|
char *s;
|
|
+ int rc;
|
|
|
|
conf_init_file(NFS_CONFFILE);
|
|
|
|
@@ -117,6 +212,9 @@ main(int argc, char *argv[])
|
|
rpc_verbosity = conf_get_num("svcgssd", "RPC-Verbosity", rpc_verbosity);
|
|
idmap_verbosity = conf_get_num("svcgssd", "IDMAP-Verbosity", idmap_verbosity);
|
|
|
|
+ /* We don't need the config anymore */
|
|
+ conf_cleanup();
|
|
+
|
|
while ((opt = getopt(argc, argv, "fivrnp:")) != -1) {
|
|
switch (opt) {
|
|
case 'f':
|
|
@@ -182,6 +280,12 @@ main(int argc, char *argv[])
|
|
|
|
daemon_init(fg);
|
|
|
|
+ evbase = event_base_new();
|
|
+ if (!evbase) {
|
|
+ printerr(0, "ERROR: failed to create event base: %s\n", strerror(errno));
|
|
+ exit(EXIT_FAILURE);
|
|
+ }
|
|
+
|
|
signal(SIGINT, sig_die);
|
|
signal(SIGTERM, sig_die);
|
|
signal(SIGHUP, sig_hup);
|
|
@@ -209,10 +313,37 @@ main(int argc, char *argv[])
|
|
}
|
|
}
|
|
|
|
+ svcgssd_nullrpc_open();
|
|
+ if (!nullrpc_event) {
|
|
+ struct timeval t = {1, 0};
|
|
+
|
|
+ printerr(2, "waiting for nullrpc channel to appear\n");
|
|
+ wait_event = evtimer_new(evbase, svcgssd_wait_cb, NULL);
|
|
+ if (!wait_event) {
|
|
+ printerr(0, "ERROR: failed to create wait event: %s\n",
|
|
+ strerror(errno));
|
|
+ exit(EXIT_FAILURE);
|
|
+ }
|
|
+ evtimer_add(wait_event, &t);
|
|
+ }
|
|
+
|
|
daemon_ready();
|
|
|
|
nfs4_init_name_mapping(NULL); /* XXX: should only do this once */
|
|
- gssd_run();
|
|
- printerr(0, "gssd_run returned!\n");
|
|
- abort();
|
|
+
|
|
+ rc = event_base_dispatch(evbase);
|
|
+ if (rc < 0)
|
|
+ printerr(0, "event_base_dispatch() returned %i!\n", rc);
|
|
+
|
|
+ svcgssd_nullrpc_close();
|
|
+ if (wait_event)
|
|
+ event_free(wait_event);
|
|
+
|
|
+ event_base_free(evbase);
|
|
+
|
|
+ nfs4_term_name_mapping();
|
|
+ svcgssd_free_enctypes();
|
|
+ gssd_cleanup();
|
|
+
|
|
+ return EXIT_SUCCESS;
|
|
}
|
|
diff --git a/utils/gssd/svcgssd.h b/utils/gssd/svcgssd.h
|
|
index 02b5c7a..e229b98 100644
|
|
--- a/utils/gssd/svcgssd.h
|
|
+++ b/utils/gssd/svcgssd.h
|
|
@@ -35,8 +35,7 @@
|
|
#include <sys/queue.h>
|
|
#include <gssapi/gssapi.h>
|
|
|
|
-void handle_nullreq(int f);
|
|
-void gssd_run(void);
|
|
+void handle_nullreq(char *cp);
|
|
|
|
#define GSSD_SERVICE_NAME "nfs"
|
|
|
|
diff --git a/utils/gssd/svcgssd_krb5.c b/utils/gssd/svcgssd_krb5.c
|
|
index 1d44d34..305d475 100644
|
|
--- a/utils/gssd/svcgssd_krb5.c
|
|
+++ b/utils/gssd/svcgssd_krb5.c
|
|
@@ -74,13 +74,7 @@ parse_enctypes(char *enctypes)
|
|
return 0;
|
|
|
|
/* Free any existing cached_enctypes */
|
|
- free(cached_enctypes);
|
|
-
|
|
- if (parsed_enctypes != NULL) {
|
|
- free(parsed_enctypes);
|
|
- parsed_enctypes = NULL;
|
|
- parsed_num_enctypes = 0;
|
|
- }
|
|
+ svcgssd_free_enctypes();
|
|
|
|
/* count the number of commas */
|
|
for (curr = enctypes; curr && *curr != '\0'; curr = ++comma) {
|
|
@@ -162,6 +156,19 @@ out_clean_parsed:
|
|
/*=== External routines ===*/
|
|
/*==========================*/
|
|
|
|
+void
|
|
+svcgssd_free_enctypes(void)
|
|
+{
|
|
+ free(cached_enctypes);
|
|
+ cached_enctypes = NULL;
|
|
+
|
|
+ if (parsed_enctypes != NULL) {
|
|
+ free(parsed_enctypes);
|
|
+ parsed_enctypes = NULL;
|
|
+ parsed_num_enctypes = 0;
|
|
+ }
|
|
+}
|
|
+
|
|
/*
|
|
* Get encryption types supported by the kernel, and then
|
|
* call gss_krb5_set_allowable_enctypes() to limit the
|
|
diff --git a/utils/gssd/svcgssd_krb5.h b/utils/gssd/svcgssd_krb5.h
|
|
index 07d5eb9..78a90e9 100644
|
|
--- a/utils/gssd/svcgssd_krb5.h
|
|
+++ b/utils/gssd/svcgssd_krb5.h
|
|
@@ -32,5 +32,6 @@
|
|
#define SVCGSSD_KRB5_H
|
|
|
|
int svcgssd_limit_krb5_enctypes(void);
|
|
+void svcgssd_free_enctypes(void);
|
|
|
|
#endif /* SVCGSSD_KRB5_H */
|
|
diff --git a/utils/gssd/svcgssd_main_loop.c b/utils/gssd/svcgssd_main_loop.c
|
|
deleted file mode 100644
|
|
index 920520d..0000000
|
|
--- a/utils/gssd/svcgssd_main_loop.c
|
|
+++ /dev/null
|
|
@@ -1,94 +0,0 @@
|
|
-/*
|
|
- Copyright (c) 2004 The Regents of the University of Michigan.
|
|
- All rights reserved.
|
|
-
|
|
- Redistribution and use in source and binary forms, with or without
|
|
- modification, are permitted provided that the following conditions
|
|
- are met:
|
|
-
|
|
- 1. Redistributions of source code must retain the above copyright
|
|
- notice, this list of conditions and the following disclaimer.
|
|
- 2. Redistributions in binary form must reproduce the above copyright
|
|
- notice, this list of conditions and the following disclaimer in the
|
|
- documentation and/or other materials provided with the distribution.
|
|
- 3. Neither the name of the University nor the names of its
|
|
- contributors may be used to endorse or promote products derived
|
|
- from this software without specific prior written permission.
|
|
-
|
|
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
|
- WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
- MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
- DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
|
- FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
- CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
- SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
|
|
- BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
- LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
- NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|
- SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
-*/
|
|
-
|
|
-#ifdef HAVE_CONFIG_H
|
|
-#include <config.h>
|
|
-#endif /* HAVE_CONFIG_H */
|
|
-
|
|
-#include <sys/param.h>
|
|
-#include <sys/socket.h>
|
|
-#include <poll.h>
|
|
-#include <sys/types.h>
|
|
-#include <sys/stat.h>
|
|
-#include <netinet/in.h>
|
|
-
|
|
-#include <stdio.h>
|
|
-#include <stdlib.h>
|
|
-#include <string.h>
|
|
-#include <memory.h>
|
|
-#include <fcntl.h>
|
|
-#include <errno.h>
|
|
-#include <unistd.h>
|
|
-
|
|
-#include "svcgssd.h"
|
|
-#include "err_util.h"
|
|
-
|
|
-void
|
|
-gssd_run()
|
|
-{
|
|
- int ret;
|
|
- int f;
|
|
- struct pollfd pollfd;
|
|
-
|
|
-#define NULLRPC_FILE "/proc/net/rpc/auth.rpcsec.init/channel"
|
|
-
|
|
- f = open(NULLRPC_FILE, O_RDWR);
|
|
- if (f < 0) {
|
|
- printerr(0, "failed to open %s: %s\n",
|
|
- NULLRPC_FILE, strerror(errno));
|
|
- exit(1);
|
|
- }
|
|
- pollfd.fd = f;
|
|
- pollfd.events = POLLIN;
|
|
- while (1) {
|
|
- int save_err;
|
|
-
|
|
- pollfd.revents = 0;
|
|
- printerr(1, "entering poll\n");
|
|
- ret = poll(&pollfd, 1, -1);
|
|
- save_err = errno;
|
|
- printerr(1, "leaving poll\n");
|
|
- if (ret < 0) {
|
|
- if (save_err != EINTR)
|
|
- printerr(0, "error return from poll: %s\n",
|
|
- strerror(save_err));
|
|
- } else if (ret == 0) {
|
|
- /* timeout; shouldn't happen. */
|
|
- } else {
|
|
- if (ret != 1) {
|
|
- printerr(0, "bug: unexpected poll return %d\n",
|
|
- ret);
|
|
- exit(1);
|
|
- }
|
|
- if (pollfd.revents & POLLIN)
|
|
- handle_nullreq(f);
|
|
- }
|
|
- }
|
|
-}
|
|
diff --git a/utils/gssd/svcgssd_proc.c b/utils/gssd/svcgssd_proc.c
|
|
index 72ec254..b403143 100644
|
|
--- a/utils/gssd/svcgssd_proc.c
|
|
+++ b/utils/gssd/svcgssd_proc.c
|
|
@@ -318,7 +318,7 @@ print_hexl(const char *description, unsigned char *cp, int length)
|
|
#endif
|
|
|
|
void
|
|
-handle_nullreq(int f) {
|
|
+handle_nullreq(char *cp) {
|
|
/* XXX initialize to a random integer to reduce chances of unnecessary
|
|
* invalidation of existing ctx's on restarting svcgssd. */
|
|
static u_int32_t handle_seq = 0;
|
|
@@ -340,24 +340,11 @@ handle_nullreq(int f) {
|
|
u_int32_t maj_stat = GSS_S_FAILURE, min_stat = 0;
|
|
u_int32_t ignore_min_stat;
|
|
struct svc_cred cred;
|
|
- char lbuf[RPC_CHAN_BUF_SIZE];
|
|
- int lbuflen = 0;
|
|
- char *cp;
|
|
int32_t ctx_endtime;
|
|
char *hostbased_name = NULL;
|
|
|
|
printerr(1, "handling null request\n");
|
|
|
|
- lbuflen = read(f, lbuf, sizeof(lbuf));
|
|
- if (lbuflen <= 0 || lbuf[lbuflen-1] != '\n') {
|
|
- printerr(0, "WARNING: handle_nullreq: "
|
|
- "failed reading request\n");
|
|
- return;
|
|
- }
|
|
- lbuf[lbuflen-1] = 0;
|
|
-
|
|
- cp = lbuf;
|
|
-
|
|
in_handle.length = (size_t) qword_get(&cp, in_handle.value,
|
|
sizeof(in_handle_buf));
|
|
#ifdef DEBUG
|
|
diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c
|
|
index 893159f..f3d2314 100644
|
|
--- a/utils/idmapd/idmapd.c
|
|
+++ b/utils/idmapd/idmapd.c
|
|
@@ -49,7 +49,7 @@
|
|
|
|
#include <err.h>
|
|
#include <errno.h>
|
|
-#include <event.h>
|
|
+#include <event2/event.h>
|
|
#include <fcntl.h>
|
|
#include <dirent.h>
|
|
#include <unistd.h>
|
|
@@ -115,7 +115,7 @@ struct idmap_client {
|
|
int ic_fd;
|
|
int ic_dirfd;
|
|
int ic_scanned;
|
|
- struct event ic_event;
|
|
+ struct event *ic_event;
|
|
TAILQ_ENTRY(idmap_client) ic_next;
|
|
};
|
|
static struct idmap_client nfsd_ic[2] = {
|
|
@@ -155,6 +155,7 @@ static void idtonameres(struct idmap_msg *);
|
|
static void nametoidres(struct idmap_msg *);
|
|
|
|
static int nfsdopen(void);
|
|
+static void nfsdclose(void);
|
|
static int nfsdopenone(struct idmap_client *);
|
|
static void nfsdreopen_one(struct idmap_client *);
|
|
static void nfsdreopen(void);
|
|
@@ -166,6 +167,22 @@ static char pipefsdir[PATH_MAX];
|
|
static char *nobodyuser, *nobodygroup;
|
|
static uid_t nobodyuid;
|
|
static gid_t nobodygid;
|
|
+static struct event_base *evbase = NULL;
|
|
+static bool signal_received = false;
|
|
+static int inotify_fd = -1;
|
|
+
|
|
+static void
|
|
+sig_die(int signal)
|
|
+{
|
|
+ if (signal_received) {
|
|
+ xlog_warn("forced exiting on signal %d\n", signal);
|
|
+ exit(0);
|
|
+ }
|
|
+
|
|
+ signal_received = true;
|
|
+ xlog_warn("exiting on signal %d\n", signal);
|
|
+ event_base_loopexit(evbase, NULL);
|
|
+}
|
|
|
|
static int
|
|
flush_nfsd_cache(char *path, time_t now)
|
|
@@ -209,14 +226,14 @@ main(int argc, char **argv)
|
|
{
|
|
int wd = -1, opt, fg = 0, nfsdret = -1;
|
|
struct idmap_clientq icq;
|
|
- struct event rootdirev, clntdirev, svrdirev, inotifyev;
|
|
- struct event initialize;
|
|
+ struct event *rootdirev = NULL, *clntdirev = NULL,
|
|
+ *svrdirev = NULL, *inotifyev = NULL;
|
|
+ struct event *initialize = NULL;
|
|
struct passwd *pw;
|
|
struct group *gr;
|
|
struct stat sb;
|
|
char *xpipefsdir = NULL;
|
|
int serverstart = 1, clientstart = 1;
|
|
- int inotify_fd;
|
|
int ret;
|
|
char *progname;
|
|
char *conf_path = NULL;
|
|
@@ -289,6 +306,9 @@ main(int argc, char **argv)
|
|
serverstart = 0;
|
|
}
|
|
|
|
+ /* Config memory is no longer needed */
|
|
+ conf_cleanup();
|
|
+
|
|
while ((opt = getopt(argc, argv, GETOPTSTR)) != -1)
|
|
switch (opt) {
|
|
case 'v':
|
|
@@ -341,9 +361,11 @@ main(int argc, char **argv)
|
|
if (nfs4_init_name_mapping(conf_path))
|
|
errx(1, "Unable to create name to user id mappings.");
|
|
|
|
- event_init();
|
|
+ evbase = event_base_new();
|
|
+ if (evbase == NULL)
|
|
+ errx(1, "Failed to create event base.");
|
|
|
|
- if (verbose > 0)
|
|
+ if (verbose > 1)
|
|
xlog_warn("Expiration time is %d seconds.",
|
|
cache_entry_expiration);
|
|
if (serverstart) {
|
|
@@ -388,30 +410,44 @@ main(int argc, char **argv)
|
|
if (inotify_fd == -1) {
|
|
xlog_err("Unable to initialise inotify_init1: %s\n", strerror(errno));
|
|
} else {
|
|
- wd = inotify_add_watch(inotify_fd, pipefsdir, IN_CREATE | IN_DELETE | IN_MODIFY);
|
|
+ wd = inotify_add_watch(inotify_fd, pipefsdir, IN_CREATE | IN_DELETE);
|
|
if (wd < 0)
|
|
xlog_err("Unable to inotify_add_watch(%s): %s\n", pipefsdir, strerror(errno));
|
|
}
|
|
|
|
TAILQ_INIT(&icq);
|
|
|
|
+ signal(SIGINT, sig_die);
|
|
+ signal(SIGTERM, sig_die);
|
|
+
|
|
/* These events are persistent */
|
|
- signal_set(&rootdirev, SIGUSR1, dirscancb, &icq);
|
|
- signal_add(&rootdirev, NULL);
|
|
- signal_set(&clntdirev, SIGUSR2, clntscancb, &icq);
|
|
- signal_add(&clntdirev, NULL);
|
|
- signal_set(&svrdirev, SIGHUP, svrreopen, NULL);
|
|
- signal_add(&svrdirev, NULL);
|
|
+ rootdirev = evsignal_new(evbase, SIGUSR1, dirscancb, &icq);
|
|
+ if (rootdirev == NULL)
|
|
+ errx(1, "Failed to create SIGUSR1 event.");
|
|
+ evsignal_add(rootdirev, NULL);
|
|
+ clntdirev = evsignal_new(evbase, SIGUSR2, clntscancb, &icq);
|
|
+ if (clntdirev == NULL)
|
|
+ errx(1, "Failed to create SIGUSR2 event.");
|
|
+ evsignal_add(clntdirev, NULL);
|
|
+ svrdirev = evsignal_new(evbase, SIGHUP, svrreopen, NULL);
|
|
+ if (svrdirev == NULL)
|
|
+ errx(1, "Failed to create SIGHUP event.");
|
|
+ evsignal_add(svrdirev, NULL);
|
|
if ( wd >= 0) {
|
|
- event_set(&inotifyev, inotify_fd, EV_READ, dirscancb, &icq);
|
|
- event_add(&inotifyev, NULL);
|
|
+ inotifyev = event_new(evbase, inotify_fd,
|
|
+ EV_READ | EV_PERSIST, dirscancb, &icq);
|
|
+ if (inotifyev == NULL)
|
|
+ errx(1, "Failed to create inotify read event.");
|
|
+ event_add(inotifyev, NULL);
|
|
}
|
|
|
|
/* Fetch current state */
|
|
/* (Delay till start of event_dispatch to avoid possibly losing
|
|
* a SIGUSR1 between here and the call to event_dispatch().) */
|
|
- evtimer_set(&initialize, dirscancb, &icq);
|
|
- evtimer_add(&initialize, &now);
|
|
+ initialize = evtimer_new(evbase, dirscancb, &icq);
|
|
+ if (initialize == NULL)
|
|
+ errx(1, "Failed to create initialize event.");
|
|
+ evtimer_add(initialize, &now);
|
|
}
|
|
|
|
if (nfsdret != 0 && wd < 0)
|
|
@@ -419,15 +455,60 @@ main(int argc, char **argv)
|
|
|
|
daemon_ready();
|
|
|
|
- if (event_dispatch() < 0)
|
|
+ if (event_base_dispatch(evbase) < 0)
|
|
xlog_err("main: event_dispatch returns errno %d (%s)",
|
|
errno, strerror(errno));
|
|
- /* NOTREACHED */
|
|
+
|
|
+ nfs4_term_name_mapping();
|
|
+ nfsdclose();
|
|
+
|
|
+ if (inotifyev)
|
|
+ event_free(inotifyev);
|
|
+ if (inotify_fd != -1)
|
|
+ close(inotify_fd);
|
|
+
|
|
+ if (initialize)
|
|
+ event_free(initialize);
|
|
+ if (rootdirev)
|
|
+ event_free(rootdirev);
|
|
+ if (clntdirev)
|
|
+ event_free(clntdirev);
|
|
+ if (svrdirev)
|
|
+ event_free(svrdirev);
|
|
+ event_base_free(evbase);
|
|
+
|
|
return 1;
|
|
}
|
|
|
|
static void
|
|
-dirscancb(int UNUSED(fd), short UNUSED(which), void *data)
|
|
+flush_inotify(int fd)
|
|
+{
|
|
+ while (true) {
|
|
+ char buf[4096] __attribute__ ((aligned(__alignof__(struct inotify_event))));
|
|
+ const struct inotify_event *ev;
|
|
+ ssize_t len;
|
|
+ char *ptr;
|
|
+
|
|
+ len = read(fd, buf, sizeof(buf));
|
|
+ if (len == -1 && errno == EINTR)
|
|
+ continue;
|
|
+
|
|
+ if (len <= 0)
|
|
+ break;
|
|
+
|
|
+ for (ptr = buf; ptr < buf + len;
|
|
+ ptr += sizeof(struct inotify_event) + ev->len) {
|
|
+
|
|
+ ev = (const struct inotify_event *)ptr;
|
|
+ if (verbose > 2)
|
|
+ xlog_warn("pipefs inotify: wd=%i, mask=0x%08x, len=%i, name=%s",
|
|
+ ev->wd, ev->mask, ev->len, ev->len ? ev->name : "");
|
|
+ }
|
|
+ }
|
|
+}
|
|
+
|
|
+static void
|
|
+dirscancb(int fd, short UNUSED(which), void *data)
|
|
{
|
|
int nent, i;
|
|
struct dirent **ents;
|
|
@@ -435,6 +516,13 @@ dirscancb(int UNUSED(fd), short UNUSED(which), void *data)
|
|
char path[PATH_MAX+256]; /* + sizeof(d_name) */
|
|
struct idmap_clientq *icq = data;
|
|
|
|
+ if (fd != -1)
|
|
+ flush_inotify(fd);
|
|
+
|
|
+ TAILQ_FOREACH(ic, icq, ic_next) {
|
|
+ ic->ic_scanned = 0;
|
|
+ }
|
|
+
|
|
nent = scandir(pipefsdir, &ents, NULL, alphasort);
|
|
if (nent == -1) {
|
|
xlog_warn("dirscancb: scandir(%s): %s", pipefsdir, strerror(errno));
|
|
@@ -468,15 +556,15 @@ dirscancb(int UNUSED(fd), short UNUSED(which), void *data)
|
|
strlcat(path, "/idmap", sizeof(path));
|
|
strlcpy(ic->ic_path, path, sizeof(ic->ic_path));
|
|
|
|
- if (verbose > 0)
|
|
- xlog_warn("New client: %s", ic->ic_clid);
|
|
-
|
|
if (nfsopen(ic) == -1) {
|
|
close(ic->ic_dirfd);
|
|
free(ic);
|
|
goto out;
|
|
}
|
|
|
|
+ if (verbose > 2)
|
|
+ xlog_warn("New client: %s", ic->ic_clid);
|
|
+
|
|
ic->ic_id = "Client";
|
|
|
|
TAILQ_INSERT_TAIL(icq, ic, ic_next);
|
|
@@ -490,17 +578,19 @@ dirscancb(int UNUSED(fd), short UNUSED(which), void *data)
|
|
while(ic != NULL) {
|
|
nextic=TAILQ_NEXT(ic, ic_next);
|
|
if (!ic->ic_scanned) {
|
|
- event_del(&ic->ic_event);
|
|
- close(ic->ic_fd);
|
|
- close(ic->ic_dirfd);
|
|
+ if (ic->ic_event)
|
|
+ event_free(ic->ic_event);
|
|
+ if (ic->ic_fd != -1)
|
|
+ close(ic->ic_fd);
|
|
+ if (ic->ic_dirfd != -1)
|
|
+ close(ic->ic_dirfd);
|
|
TAILQ_REMOVE(icq, ic, ic_next);
|
|
- if (verbose > 0) {
|
|
+ if (verbose > 2) {
|
|
xlog_warn("Stale client: %s", ic->ic_clid);
|
|
xlog_warn("\t-> closed %s", ic->ic_path);
|
|
}
|
|
free(ic);
|
|
- } else
|
|
- ic->ic_scanned = 0;
|
|
+ }
|
|
ic = nextic;
|
|
}
|
|
|
|
@@ -546,7 +636,7 @@ nfsdcb(int UNUSED(fd), short which, void *data)
|
|
unsigned long tmp;
|
|
|
|
if (which != EV_READ)
|
|
- goto out;
|
|
+ return;
|
|
|
|
len = read(ic->ic_fd, buf, sizeof(buf));
|
|
if (len == 0)
|
|
@@ -569,13 +659,13 @@ nfsdcb(int UNUSED(fd), short which, void *data)
|
|
/* Authentication name -- ignored for now*/
|
|
if (getfield(&bp, authbuf, sizeof(authbuf)) == -1) {
|
|
xlog_warn("nfsdcb: bad authentication name in upcall\n");
|
|
- goto out;
|
|
+ return;
|
|
}
|
|
if (getfield(&bp, typebuf, sizeof(typebuf)) == -1) {
|
|
xlog_warn("nfsdcb: bad type in upcall\n");
|
|
- goto out;
|
|
+ return;
|
|
}
|
|
- if (verbose > 0)
|
|
+ if (verbose > 2)
|
|
xlog_warn("nfsdcb: authbuf=%s authtype=%s",
|
|
authbuf, typebuf);
|
|
|
|
@@ -587,26 +677,26 @@ nfsdcb(int UNUSED(fd), short which, void *data)
|
|
im.im_conv = IDMAP_CONV_NAMETOID;
|
|
if (getfield(&bp, im.im_name, sizeof(im.im_name)) == -1) {
|
|
xlog_warn("nfsdcb: bad name in upcall\n");
|
|
- goto out;
|
|
+ return;
|
|
}
|
|
break;
|
|
case IC_IDNAME:
|
|
im.im_conv = IDMAP_CONV_IDTONAME;
|
|
if (getfield(&bp, buf1, sizeof(buf1)) == -1) {
|
|
xlog_warn("nfsdcb: bad id in upcall\n");
|
|
- goto out;
|
|
+ return;
|
|
}
|
|
tmp = strtoul(buf1, (char **)NULL, 10);
|
|
im.im_id = (u_int32_t)tmp;
|
|
if ((tmp == ULONG_MAX && errno == ERANGE)
|
|
|| (unsigned long)im.im_id != tmp) {
|
|
xlog_warn("nfsdcb: id '%s' too big!\n", buf1);
|
|
- goto out;
|
|
+ return;
|
|
}
|
|
break;
|
|
default:
|
|
xlog_warn("nfsdcb: Unknown which type %d", ic->ic_which);
|
|
- goto out;
|
|
+ return;
|
|
}
|
|
|
|
imconv(ic, &im);
|
|
@@ -667,7 +757,7 @@ nfsdcb(int UNUSED(fd), short which, void *data)
|
|
break;
|
|
default:
|
|
xlog_warn("nfsdcb: Unknown which type %d", ic->ic_which);
|
|
- goto out;
|
|
+ return;
|
|
}
|
|
|
|
bsiz = sizeof(buf) - bsiz;
|
|
@@ -675,9 +765,6 @@ nfsdcb(int UNUSED(fd), short which, void *data)
|
|
if (atomicio((void*)write, ic->ic_fd, buf, bsiz) != bsiz)
|
|
xlog_warn("nfsdcb: write(%s) failed: errno %d (%s)",
|
|
ic->ic_path, errno, strerror(errno));
|
|
-
|
|
-out:
|
|
- event_add(&ic->ic_event, NULL);
|
|
}
|
|
|
|
static void
|
|
@@ -721,14 +808,12 @@ nfscb(int UNUSED(fd), short which, void *data)
|
|
struct idmap_msg im;
|
|
|
|
if (which != EV_READ)
|
|
- goto out;
|
|
+ return;
|
|
|
|
if (atomicio(read, ic->ic_fd, &im, sizeof(im)) != sizeof(im)) {
|
|
if (verbose > 0)
|
|
xlog_warn("nfscb: read(%s): %s", ic->ic_path, strerror(errno));
|
|
- if (errno == EPIPE)
|
|
- return;
|
|
- goto out;
|
|
+ return;
|
|
}
|
|
|
|
imconv(ic, &im);
|
|
@@ -742,8 +827,19 @@ nfscb(int UNUSED(fd), short which, void *data)
|
|
|
|
if (atomicio((void*)write, ic->ic_fd, &im, sizeof(im)) != sizeof(im))
|
|
xlog_warn("nfscb: write(%s): %s", ic->ic_path, strerror(errno));
|
|
-out:
|
|
- event_add(&ic->ic_event, NULL);
|
|
+}
|
|
+
|
|
+static void
|
|
+nfsdclose_one(struct idmap_client *ic)
|
|
+{
|
|
+ if (ic->ic_event) {
|
|
+ event_free(ic->ic_event);
|
|
+ ic->ic_event = NULL;
|
|
+ }
|
|
+ if (ic->ic_fd != -1) {
|
|
+ close(ic->ic_fd);
|
|
+ ic->ic_fd = -1;
|
|
+ }
|
|
}
|
|
|
|
static void
|
|
@@ -751,18 +847,22 @@ nfsdreopen_one(struct idmap_client *ic)
|
|
{
|
|
int fd;
|
|
|
|
- if (verbose > 0)
|
|
+ if (verbose > 2)
|
|
xlog_warn("ReOpening %s", ic->ic_path);
|
|
|
|
if ((fd = open(ic->ic_path, O_RDWR, 0)) != -1) {
|
|
- if ((event_initialized(&ic->ic_event)))
|
|
- event_del(&ic->ic_event);
|
|
- if (ic->ic_fd != -1)
|
|
- close(ic->ic_fd);
|
|
+ nfsdclose_one(ic);
|
|
|
|
- ic->ic_event.ev_fd = ic->ic_fd = fd;
|
|
- event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfsdcb, ic);
|
|
- event_add(&ic->ic_event, NULL);
|
|
+ ic->ic_fd = fd;
|
|
+ ic->ic_event = event_new(evbase, ic->ic_fd, EV_READ | EV_PERSIST, nfsdcb, ic);
|
|
+ if (ic->ic_event == NULL) {
|
|
+ xlog_warn("nfsdreopen: Failed to create event for '%s'",
|
|
+ ic->ic_path);
|
|
+ close(ic->ic_fd);
|
|
+ ic->ic_fd = -1;
|
|
+ return;
|
|
+ }
|
|
+ event_add(ic->ic_event, NULL);
|
|
} else {
|
|
xlog_warn("nfsdreopen: Opening '%s' failed: errno %d (%s)",
|
|
ic->ic_path, errno, strerror(errno));
|
|
@@ -784,6 +884,13 @@ nfsdopen(void)
|
|
nfsdopenone(&nfsd_ic[IC_IDNAME]) == 0) ? 0 : -1);
|
|
}
|
|
|
|
+static void
|
|
+nfsdclose(void)
|
|
+{
|
|
+ nfsdclose_one(&nfsd_ic[IC_NAMEID]);
|
|
+ nfsdclose_one(&nfsd_ic[IC_IDNAME]);
|
|
+}
|
|
+
|
|
static int
|
|
nfsdopenone(struct idmap_client *ic)
|
|
{
|
|
@@ -795,10 +902,18 @@ nfsdopenone(struct idmap_client *ic)
|
|
return (-1);
|
|
}
|
|
|
|
- event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfsdcb, ic);
|
|
- event_add(&ic->ic_event, NULL);
|
|
+ ic->ic_event = event_new(evbase, ic->ic_fd, EV_READ | EV_PERSIST, nfsdcb, ic);
|
|
+ if (ic->ic_event == NULL) {
|
|
+ if (verbose > 0)
|
|
+ xlog_warn("nfsdopenone: Create event for %s failed",
|
|
+ ic->ic_path);
|
|
+ close(ic->ic_fd);
|
|
+ ic->ic_fd = -1;
|
|
+ return (-1);
|
|
+ }
|
|
+ event_add(ic->ic_event, NULL);
|
|
|
|
- if (verbose > 0)
|
|
+ if (verbose > 2)
|
|
xlog_warn("Opened %s", ic->ic_path);
|
|
|
|
return (0);
|
|
@@ -808,25 +923,35 @@ static int
|
|
nfsopen(struct idmap_client *ic)
|
|
{
|
|
if ((ic->ic_fd = open(ic->ic_path, O_RDWR, 0)) == -1) {
|
|
- switch (errno) {
|
|
- case ENOENT:
|
|
- fcntl(ic->ic_dirfd, F_SETSIG, SIGUSR2);
|
|
- fcntl(ic->ic_dirfd, F_NOTIFY,
|
|
- DN_CREATE | DN_DELETE | DN_MULTISHOT);
|
|
- break;
|
|
- default:
|
|
- xlog_warn("nfsopen: open(%s): %s", ic->ic_path, strerror(errno));
|
|
- return (-1);
|
|
+ if (errno == ENOENT) {
|
|
+ char *slash;
|
|
+
|
|
+ slash = strrchr(ic->ic_path, '/');
|
|
+ if (!slash)
|
|
+ return -1;
|
|
+ *slash = 0;
|
|
+ inotify_add_watch(inotify_fd, ic->ic_path, IN_CREATE | IN_ONLYDIR | IN_ONESHOT);
|
|
+ *slash = '/';
|
|
+ if (verbose > 2)
|
|
+ xlog_warn("Path %s not available. waiting...", ic->ic_path);
|
|
+ return -1;
|
|
}
|
|
- } else {
|
|
- event_set(&ic->ic_event, ic->ic_fd, EV_READ, nfscb, ic);
|
|
- event_add(&ic->ic_event, NULL);
|
|
- fcntl(ic->ic_dirfd, F_NOTIFY, 0);
|
|
- fcntl(ic->ic_dirfd, F_SETSIG, 0);
|
|
- if (verbose > 0)
|
|
- xlog_warn("Opened %s", ic->ic_path);
|
|
+
|
|
+ xlog_warn("nfsopen: open(%s): %s", ic->ic_path, strerror(errno));
|
|
+ return (-1);
|
|
}
|
|
|
|
+ ic->ic_event = event_new(evbase, ic->ic_fd, EV_READ | EV_PERSIST, nfscb, ic);
|
|
+ if (ic->ic_event == NULL) {
|
|
+ xlog_warn("nfsopen: Create event for %s failed", ic->ic_path);
|
|
+ close(ic->ic_fd);
|
|
+ ic->ic_fd = -1;
|
|
+ return -1;
|
|
+ }
|
|
+ event_add(ic->ic_event, NULL);
|
|
+ if (verbose > 2)
|
|
+ xlog_warn("Opened %s", ic->ic_path);
|
|
+
|
|
return (0);
|
|
}
|
|
|
|
diff --git a/utils/mount/network.c b/utils/mount/network.c
|
|
index 6ac913d..d9c0b51 100644
|
|
--- a/utils/mount/network.c
|
|
+++ b/utils/mount/network.c
|
|
@@ -1268,14 +1268,14 @@ nfs_nfs_program(struct mount_options *options, unsigned long *program)
|
|
int
|
|
nfs_nfs_version(char *type, struct mount_options *options, struct nfs_version *version)
|
|
{
|
|
- char *version_key, *version_val, *cptr;
|
|
+ char *version_key, *version_val = NULL, *cptr;
|
|
int i, found = 0;
|
|
|
|
version->v_mode = V_DEFAULT;
|
|
|
|
for (i = 0; nfs_version_opttbl[i]; i++) {
|
|
if (po_contains_prefix(options, nfs_version_opttbl[i],
|
|
- &version_key) == PO_FOUND) {
|
|
+ &version_key) == PO_FOUND) {
|
|
found++;
|
|
break;
|
|
}
|
|
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
|
|
index 901f995..91a976b 100644
|
|
--- a/utils/mount/stropts.c
|
|
+++ b/utils/mount/stropts.c
|
|
@@ -1094,9 +1094,7 @@ static int nfsmount_fg(struct nfsmount_info *mi)
|
|
if (nfs_try_mount(mi))
|
|
return EX_SUCCESS;
|
|
|
|
-#pragma GCC diagnostic ignored "-Wdiscarded-qualifiers"
|
|
if (errno == EBUSY && is_mountpoint(mi->node)) {
|
|
-#pragma GCC diagnostic warning "-Wdiscarded-qualifiers"
|
|
/*
|
|
* EBUSY can happen when mounting a filesystem that
|
|
* is already mounted or when the context= are
|
|
diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c
|
|
index 6cba288..ea74067 100644
|
|
--- a/utils/mountd/cache.c
|
|
+++ b/utils/mountd/cache.c
|
|
@@ -57,7 +57,7 @@ enum nfsd_fsid {
|
|
};
|
|
|
|
#undef is_mountpoint
|
|
-static int is_mountpoint(char *path)
|
|
+static int is_mountpoint(const char *path)
|
|
{
|
|
return check_is_mountpoint(path, nfsd_path_lstat);
|
|
}
|
|
diff --git a/utils/nfsdcld/cld-internal.h b/utils/nfsdcld/cld-internal.h
|
|
index cc283da..3576515 100644
|
|
--- a/utils/nfsdcld/cld-internal.h
|
|
+++ b/utils/nfsdcld/cld-internal.h
|
|
@@ -26,7 +26,7 @@
|
|
|
|
struct cld_client {
|
|
int cl_fd;
|
|
- struct event cl_event;
|
|
+ struct event *cl_event;
|
|
union {
|
|
struct cld_msg cl_msg;
|
|
#if UPCALL_VERSION >= 2
|
|
diff --git a/utils/nfsdcld/legacy.c b/utils/nfsdcld/legacy.c
|
|
index 3c6bea6..b89374c 100644
|
|
--- a/utils/nfsdcld/legacy.c
|
|
+++ b/utils/nfsdcld/legacy.c
|
|
@@ -48,35 +48,28 @@ legacy_load_clients_from_recdir(int *num_records)
|
|
int fd;
|
|
DIR *v4recovery;
|
|
struct dirent *entry;
|
|
- char recdirname[PATH_MAX];
|
|
+ char recdirname[PATH_MAX+1];
|
|
char buf[NFS4_OPAQUE_LIMIT];
|
|
- struct stat st;
|
|
char *nl;
|
|
+ ssize_t n;
|
|
|
|
fd = open(NFSD_RECDIR_FILE, O_RDONLY);
|
|
if (fd < 0) {
|
|
xlog(D_GENERAL, "Unable to open %s: %m", NFSD_RECDIR_FILE);
|
|
return;
|
|
}
|
|
- if (read(fd, recdirname, PATH_MAX) < 0) {
|
|
+ n = read(fd, recdirname, PATH_MAX);
|
|
+ close(fd);
|
|
+ if (n < 0) {
|
|
xlog(D_GENERAL, "Unable to read from %s: %m", NFSD_RECDIR_FILE);
|
|
return;
|
|
}
|
|
- close(fd);
|
|
/* the output from the proc file isn't null-terminated */
|
|
+ recdirname[PATH_MAX] = '\0';
|
|
nl = strchr(recdirname, '\n');
|
|
if (!nl)
|
|
return;
|
|
*nl = '\0';
|
|
- if (stat(recdirname, &st) < 0) {
|
|
- xlog(D_GENERAL, "Unable to stat %s: %d", recdirname, errno);
|
|
- return;
|
|
- }
|
|
- if (!S_ISDIR(st.st_mode)) {
|
|
- xlog(D_GENERAL, "%s is not a directory: mode=0%o", recdirname
|
|
- , st.st_mode);
|
|
- return;
|
|
- }
|
|
v4recovery = opendir(recdirname);
|
|
if (!v4recovery)
|
|
return;
|
|
@@ -123,35 +116,28 @@ legacy_clear_recdir(void)
|
|
int fd;
|
|
DIR *v4recovery;
|
|
struct dirent *entry;
|
|
- char recdirname[PATH_MAX];
|
|
+ char recdirname[PATH_MAX+1];
|
|
char dirname[PATH_MAX];
|
|
- struct stat st;
|
|
char *nl;
|
|
+ ssize_t n;
|
|
|
|
fd = open(NFSD_RECDIR_FILE, O_RDONLY);
|
|
if (fd < 0) {
|
|
xlog(D_GENERAL, "Unable to open %s: %m", NFSD_RECDIR_FILE);
|
|
return;
|
|
}
|
|
- if (read(fd, recdirname, PATH_MAX) < 0) {
|
|
+ n = read(fd, recdirname, PATH_MAX);
|
|
+ close(fd);
|
|
+ if (n < 0) {
|
|
xlog(D_GENERAL, "Unable to read from %s: %m", NFSD_RECDIR_FILE);
|
|
return;
|
|
}
|
|
- close(fd);
|
|
/* the output from the proc file isn't null-terminated */
|
|
+ recdirname[PATH_MAX] = '\0';
|
|
nl = strchr(recdirname, '\n');
|
|
if (!nl)
|
|
return;
|
|
*nl = '\0';
|
|
- if (stat(recdirname, &st) < 0) {
|
|
- xlog(D_GENERAL, "Unable to stat %s: %d", recdirname, errno);
|
|
- return;
|
|
- }
|
|
- if (!S_ISDIR(st.st_mode)) {
|
|
- xlog(D_GENERAL, "%s is not a directory: mode=0%o", recdirname
|
|
- , st.st_mode);
|
|
- return;
|
|
- }
|
|
v4recovery = opendir(recdirname);
|
|
if (!v4recovery)
|
|
return;
|
|
diff --git a/utils/nfsdcld/nfsdcld.c b/utils/nfsdcld/nfsdcld.c
|
|
index be65562..636c398 100644
|
|
--- a/utils/nfsdcld/nfsdcld.c
|
|
+++ b/utils/nfsdcld/nfsdcld.c
|
|
@@ -24,9 +24,10 @@
|
|
#endif /* HAVE_CONFIG_H */
|
|
|
|
#include <errno.h>
|
|
-#include <event.h>
|
|
+#include <event2/event.h>
|
|
#include <stdbool.h>
|
|
#include <getopt.h>
|
|
+#include <signal.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
@@ -66,8 +67,10 @@
|
|
static char pipefs_dir[PATH_MAX] = DEFAULT_PIPEFS_DIR;
|
|
static char pipepath[PATH_MAX];
|
|
static int inotify_fd = -1;
|
|
-static struct event pipedir_event;
|
|
+static struct event *pipedir_event;
|
|
+static struct event_base *evbase;
|
|
static bool old_kernel = false;
|
|
+static bool signal_received = false;
|
|
|
|
uint64_t current_epoch;
|
|
uint64_t recovery_epoch;
|
|
@@ -88,6 +91,19 @@ static struct option longopts[] =
|
|
/* forward declarations */
|
|
static void cldcb(int UNUSED(fd), short which, void *data);
|
|
|
|
+static void
|
|
+sig_die(int signal)
|
|
+{
|
|
+ if (signal_received) {
|
|
+ xlog(D_GENERAL, "forced exiting on signal %d\n", signal);
|
|
+ exit(0);
|
|
+ }
|
|
+
|
|
+ signal_received = true;
|
|
+ xlog(D_GENERAL, "exiting on signal %d\n", signal);
|
|
+ event_base_loopexit(evbase, NULL);
|
|
+}
|
|
+
|
|
static void
|
|
usage(char *progname)
|
|
{
|
|
@@ -141,6 +157,7 @@ static int
|
|
cld_pipe_open(struct cld_client *clnt)
|
|
{
|
|
int fd;
|
|
+ struct event *ev;
|
|
|
|
xlog(D_GENERAL, "%s: opening upcall pipe %s", __func__, pipepath);
|
|
fd = open(pipepath, O_RDWR, 0);
|
|
@@ -149,13 +166,22 @@ cld_pipe_open(struct cld_client *clnt)
|
|
return -errno;
|
|
}
|
|
|
|
- if (event_initialized(&clnt->cl_event))
|
|
- event_del(&clnt->cl_event);
|
|
+ ev = event_new(evbase, fd, EV_READ, cldcb, clnt);
|
|
+ if (ev == NULL) {
|
|
+ xlog(D_GENERAL, "%s: failed to create event for %s", __func__, pipepath);
|
|
+ close(fd);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+
|
|
+ if (clnt->cl_event && event_initialized(clnt->cl_event)) {
|
|
+ event_del(clnt->cl_event);
|
|
+ event_free(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);
|
|
+ clnt->cl_event = ev;
|
|
/* event_add is done by the caller */
|
|
return 0;
|
|
}
|
|
@@ -208,7 +234,7 @@ cld_inotify_cb(int UNUSED(fd), short which, void *data)
|
|
switch (ret) {
|
|
case 0:
|
|
/* readd the event for the cl_event pipe */
|
|
- event_add(&clnt->cl_event, NULL);
|
|
+ event_add(clnt->cl_event, NULL);
|
|
break;
|
|
case -ENOENT:
|
|
/* pipe must have disappeared, wait for it to come back */
|
|
@@ -221,7 +247,7 @@ cld_inotify_cb(int UNUSED(fd), short which, void *data)
|
|
}
|
|
|
|
out:
|
|
- event_add(&pipedir_event, NULL);
|
|
+ event_add(pipedir_event, NULL);
|
|
free(dirc);
|
|
}
|
|
|
|
@@ -252,11 +278,12 @@ cld_inotify_setup(void)
|
|
xlog_err("%s: inotify_add_watch failed: %m", __func__);
|
|
ret = -errno;
|
|
goto out_err;
|
|
- }
|
|
+ } else
|
|
+ ret = 0;
|
|
|
|
out_free:
|
|
free(dirc);
|
|
- return 0;
|
|
+ return ret;
|
|
out_err:
|
|
close(inotify_fd);
|
|
goto out_free;
|
|
@@ -286,7 +313,7 @@ cld_pipe_init(struct cld_client *clnt)
|
|
switch (ret) {
|
|
case 0:
|
|
/* add the event and we're good to go */
|
|
- event_add(&clnt->cl_event, NULL);
|
|
+ event_add(clnt->cl_event, NULL);
|
|
break;
|
|
case -ENOENT:
|
|
/* ignore this error -- cld_inotify_cb will handle it */
|
|
@@ -299,8 +326,12 @@ cld_pipe_init(struct cld_client *clnt)
|
|
}
|
|
|
|
/* set event for inotify read */
|
|
- event_set(&pipedir_event, inotify_fd, EV_READ, cld_inotify_cb, clnt);
|
|
- event_add(&pipedir_event, NULL);
|
|
+ pipedir_event = event_new(evbase, inotify_fd, EV_READ, cld_inotify_cb, clnt);
|
|
+ if (pipedir_event == NULL) {
|
|
+ close(inotify_fd);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ event_add(pipedir_event, NULL);
|
|
out:
|
|
return ret;
|
|
}
|
|
@@ -331,6 +362,7 @@ cld_check_grace_period(void)
|
|
if (read(fd, &c, 1) < 0) {
|
|
xlog(L_WARNING, "Unable to read from %s: %m",
|
|
NFSD_END_GRACE_FILE);
|
|
+ close(fd);
|
|
return 1;
|
|
}
|
|
close(fd);
|
|
@@ -737,7 +769,7 @@ cldcb(int UNUSED(fd), short which, void *data)
|
|
cld_not_implemented(clnt);
|
|
}
|
|
out:
|
|
- event_add(&clnt->cl_event, NULL);
|
|
+ event_add(clnt->cl_event, NULL);
|
|
}
|
|
|
|
int
|
|
@@ -762,7 +794,11 @@ main(int argc, char **argv)
|
|
return 1;
|
|
}
|
|
|
|
- event_init();
|
|
+ evbase = event_base_new();
|
|
+ if (evbase == NULL) {
|
|
+ fprintf(stderr, "%s: unable to allocate event base.\n", argv[0]);
|
|
+ return 1;
|
|
+ }
|
|
xlog_syslog(0);
|
|
xlog_stderr(1);
|
|
|
|
@@ -795,6 +831,7 @@ main(int argc, char **argv)
|
|
break;
|
|
default:
|
|
usage(progname);
|
|
+ free(progname);
|
|
return 0;
|
|
}
|
|
}
|
|
@@ -859,14 +896,27 @@ main(int argc, char **argv)
|
|
if (rc)
|
|
goto out;
|
|
|
|
+ signal(SIGINT, sig_die);
|
|
+ signal(SIGTERM, sig_die);
|
|
+
|
|
xlog(D_GENERAL, "%s: Starting event dispatch handler.", __func__);
|
|
- rc = event_dispatch();
|
|
+ rc = event_base_dispatch(evbase);
|
|
if (rc < 0)
|
|
xlog(L_ERROR, "%s: event_dispatch failed: %m", __func__);
|
|
|
|
- close(clnt.cl_fd);
|
|
- close(inotify_fd);
|
|
out:
|
|
+ if (clnt.cl_event)
|
|
+ event_free(clnt.cl_event);
|
|
+ if (clnt.cl_fd != -1)
|
|
+ close(clnt.cl_fd);
|
|
+ if (pipedir_event)
|
|
+ event_free(pipedir_event);
|
|
+ if (inotify_fd != -1)
|
|
+ close(inotify_fd);
|
|
+
|
|
+ event_base_free(evbase);
|
|
+ sqlite_shutdown();
|
|
+
|
|
free(progname);
|
|
return rc;
|
|
}
|
|
diff --git a/utils/nfsdcld/sqlite.c b/utils/nfsdcld/sqlite.c
|
|
index 6666c86..03016fb 100644
|
|
--- a/utils/nfsdcld/sqlite.c
|
|
+++ b/utils/nfsdcld/sqlite.c
|
|
@@ -48,7 +48,6 @@
|
|
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
-#include <event.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
@@ -380,7 +379,7 @@ sqlite_maindb_init_v4(void)
|
|
&err);
|
|
if (ret != SQLITE_OK) {
|
|
xlog(L_ERROR, "Unable to begin transaction: %s", err);
|
|
- return ret;
|
|
+ goto out;
|
|
}
|
|
|
|
/*
|
|
@@ -831,7 +830,6 @@ sqlite_prepare_dbh(const char *topdir)
|
|
switch (ret) {
|
|
case CLD_SQLITE_LATEST_SCHEMA_VERSION:
|
|
/* DB is already set up. Do nothing */
|
|
- ret = 0;
|
|
break;
|
|
case 3:
|
|
/* Old DB -- update to new schema */
|
|
@@ -868,6 +866,8 @@ sqlite_prepare_dbh(const char *topdir)
|
|
}
|
|
|
|
ret = sqlite_startup_query_grace();
|
|
+ if (ret)
|
|
+ goto out_close;
|
|
|
|
ret = sqlite_query_first_time(&first_time);
|
|
if (ret)
|
|
@@ -1330,20 +1330,26 @@ sqlite_iterate_recovery(int (*cb)(struct cld_client *clnt), struct cld_client *c
|
|
}
|
|
|
|
while ((ret = sqlite3_step(stmt)) == SQLITE_ROW) {
|
|
+ const void *id;
|
|
+ int id_len;
|
|
+
|
|
+ id = sqlite3_column_blob(stmt, 0);
|
|
+ id_len = sqlite3_column_bytes(stmt, 0);
|
|
+ if (id_len > NFS4_OPAQUE_LIMIT)
|
|
+ id_len = NFS4_OPAQUE_LIMIT;
|
|
+
|
|
memset(&cmsg->cm_u, 0, sizeof(cmsg->cm_u));
|
|
#if UPCALL_VERSION >= 2
|
|
- memcpy(&cmsg->cm_u.cm_clntinfo.cc_name.cn_id,
|
|
- sqlite3_column_blob(stmt, 0), NFS4_OPAQUE_LIMIT);
|
|
- cmsg->cm_u.cm_clntinfo.cc_name.cn_len = sqlite3_column_bytes(stmt, 0);
|
|
+ memcpy(&cmsg->cm_u.cm_clntinfo.cc_name.cn_id, id, id_len);
|
|
+ cmsg->cm_u.cm_clntinfo.cc_name.cn_len = id_len;
|
|
if (sqlite3_column_bytes(stmt, 1) > 0) {
|
|
memcpy(&cmsg->cm_u.cm_clntinfo.cc_princhash.cp_data,
|
|
sqlite3_column_blob(stmt, 1), SHA256_DIGEST_SIZE);
|
|
cmsg->cm_u.cm_clntinfo.cc_princhash.cp_len = sqlite3_column_bytes(stmt, 1);
|
|
}
|
|
#else
|
|
- memcpy(&cmsg->cm_u.cm_name.cn_id, sqlite3_column_blob(stmt, 0),
|
|
- NFS4_OPAQUE_LIMIT);
|
|
- cmsg->cm_u.cm_name.cn_len = sqlite3_column_bytes(stmt, 0);
|
|
+ memcpy(&cmsg->cm_u.cm_name.cn_id, id, id_len);
|
|
+ cmsg->cm_u.cm_name.cn_len = id_len;
|
|
#endif
|
|
cb(clnt);
|
|
}
|
|
@@ -1404,3 +1410,18 @@ sqlite_first_time_done(void)
|
|
sqlite3_free(err);
|
|
return ret;
|
|
}
|
|
+
|
|
+/*
|
|
+ * Closes all sqlite3 resources and shuts down the library.
|
|
+ *
|
|
+ */
|
|
+void
|
|
+sqlite_shutdown(void)
|
|
+{
|
|
+ if (dbh != NULL) {
|
|
+ sqlite3_close(dbh);
|
|
+ dbh = NULL;
|
|
+ }
|
|
+
|
|
+ sqlite3_shutdown();
|
|
+}
|
|
diff --git a/utils/nfsdcld/sqlite.h b/utils/nfsdcld/sqlite.h
|
|
index 0a26ad6..044236c 100644
|
|
--- a/utils/nfsdcld/sqlite.h
|
|
+++ b/utils/nfsdcld/sqlite.h
|
|
@@ -34,4 +34,5 @@ int sqlite_iterate_recovery(int (*cb)(struct cld_client *clnt), struct cld_clien
|
|
int sqlite_delete_cltrack_records(void);
|
|
int sqlite_first_time_done(void);
|
|
|
|
+void sqlite_shutdown(void);
|
|
#endif /* _SQLITE_H */
|
|
diff --git a/utils/nfsdcltrack/sqlite.c b/utils/nfsdcltrack/sqlite.c
|
|
index 2801201..f79aebb 100644
|
|
--- a/utils/nfsdcltrack/sqlite.c
|
|
+++ b/utils/nfsdcltrack/sqlite.c
|
|
@@ -40,7 +40,7 @@
|
|
|
|
#include <dirent.h>
|
|
#include <errno.h>
|
|
-#include <event.h>
|
|
+#include <stdio.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|