nfs-utils/nfs-utils-2.5.2-rc4.patch

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>