From 9a794c316aace5d070a4a3caec679ed89d897eae Mon Sep 17 00:00:00 2001 From: Steve Dickson Date: Wed, 22 Jan 2014 12:53:18 -0500 Subject: [PATCH] - Updated to latest upstream RC release: nfs-utils-1-2-10-rc3 - gssd: Improve first attempt at acquiring GSS credentials (bz 1055077) - gssd: set $HOME to prevent recursion (bz 1052902) Signed-off-by: Steve Dickson --- nfs-utils-1.2.10-rc3.patch | 1344 +++++++++++++++++++++++++++++++ nfs-utils-1.2.9-gssd-home.patch | 53 ++ nfs-utils.spec | 9 +- 3 files changed, 1405 insertions(+), 1 deletion(-) create mode 100644 nfs-utils-1.2.10-rc3.patch create mode 100644 nfs-utils-1.2.9-gssd-home.patch diff --git a/nfs-utils-1.2.10-rc3.patch b/nfs-utils-1.2.10-rc3.patch new file mode 100644 index 0000000..c4e9a90 --- /dev/null +++ b/nfs-utils-1.2.10-rc3.patch @@ -0,0 +1,1344 @@ +diff --git a/support/include/nfs/nfs.h b/support/include/nfs/nfs.h +index 38db5b5..df4ad76 100644 +--- a/support/include/nfs/nfs.h ++++ b/support/include/nfs/nfs.h +@@ -17,7 +17,6 @@ + + #define NFS4_MINMINOR 1 + #define NFS4_MAXMINOR 2 +-#define NFS4_VERDEFAULT 0x1 /* minor verion 1 */ + + struct nfs_fh_len { + int fh_size; +diff --git a/support/include/nfslib.h b/support/include/nfslib.h +index f210a06..ce4b14b 100644 +--- a/support/include/nfslib.h ++++ b/support/include/nfslib.h +@@ -128,6 +128,10 @@ void fputrmtabent(FILE *fp, struct rmtabent *xep, long *pos); + void fendrmtabent(FILE *fp); + void frewindrmtabent(FILE *fp); + ++/* mydaemon */ ++void mydaemon(int nochdir, int noclose, int *pipefds); ++void release_parent(int *pipefds); ++ + /* + * wildmat borrowed from INN + */ +diff --git a/support/nfs/Makefile.am b/support/nfs/Makefile.am +index 05c2fc4..fb9b8c1 100644 +--- a/support/nfs/Makefile.am ++++ b/support/nfs/Makefile.am +@@ -2,7 +2,7 @@ + + noinst_LIBRARIES = libnfs.a + libnfs_a_SOURCES = exports.c rmtab.c xio.c rpcmisc.c rpcdispatch.c \ +- xlog.c xcommon.c wildmat.c nfsclient.c \ ++ xlog.c xcommon.c wildmat.c mydaemon.c nfsclient.c \ + nfsexport.c getfh.c nfsctl.c rpc_socket.c getport.c \ + svc_socket.c cacheio.c closeall.c nfs_mntent.c conffile.c \ + svc_create.c atomicio.c strlcpy.c strlcat.c +diff --git a/support/nfs/exports.c b/support/nfs/exports.c +index d18667f..819d6c4 100644 +--- a/support/nfs/exports.c ++++ b/support/nfs/exports.c +@@ -366,7 +366,7 @@ mkexportent(char *hname, char *path, char *options) + ee.e_hostname = xstrdup(hname); + + if (strlen(path) >= sizeof(ee.e_path)) { +- xlog(L_WARNING, "path name %s too long", path); ++ xlog(L_ERROR, "path name %s too long", path); + return NULL; + } + strncpy(ee.e_path, path, sizeof (ee.e_path)); +diff --git a/support/nfs/mydaemon.c b/support/nfs/mydaemon.c +new file mode 100644 +index 0000000..e885d60 +--- /dev/null ++++ b/support/nfs/mydaemon.c +@@ -0,0 +1,148 @@ ++/* ++ mydaemon.c ++ ++ Copyright (c) 2000 The Regents of the University of Michigan. ++ All rights reserved. ++ ++ Copyright (c) 2000 Dug Song . ++ Copyright (c) 2002 Andy Adamson . ++ Copyright (c) 2002 Marius Aamodt Eriksen . ++ Copyright (c) 2002 J. Bruce Fields . ++ Copyright (c) 2013 Jeff Layton ++ ++ All rights reserved, all wrongs reversed. ++ ++ 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. ++ ++*/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/** ++ * mydaemon - daemonize, but have parent wait to exit ++ * @nochdir: skip chdir()'ing the child to / after forking if true ++ * @noclose: skip closing stdin/stdout/stderr if true ++ * @pipefds: pointer to 2 element array of pipefds ++ * ++ * This function is like daemon(), but with our own special sauce to delay ++ * the exit of the parent until the child is set up properly. A pipe is created ++ * between parent and child. The parent process will wait to exit until the ++ * child dies or writes a '1' on the pipe signaling that it started ++ * successfully. ++ */ ++void ++mydaemon(int nochdir, int noclose, int *pipefds) ++{ ++ int pid, status, tempfd; ++ ++ if (pipe(pipefds) < 0) { ++ xlog_err("mydaemon: pipe() failed: errno %d (%s)\n", ++ errno, strerror(errno)); ++ exit(1); ++ } ++ if ((pid = fork ()) < 0) { ++ xlog_err("mydaemon: fork() failed: errno %d (%s)\n", ++ errno, strerror(errno)); ++ exit(1); ++ } ++ ++ if (pid != 0) { ++ /* ++ * Parent. Wait for status from child. ++ */ ++ close(pipefds[1]); ++ if (read(pipefds[0], &status, 1) != 1) ++ exit(1); ++ exit (0); ++ } ++ /* Child. */ ++ close(pipefds[0]); ++ setsid (); ++ if (nochdir == 0) { ++ if (chdir ("/") == -1) { ++ xlog_err("mydaemon: chdir() failed: errno %d (%s)\n", ++ errno, strerror(errno)); ++ exit(1); ++ } ++ } ++ ++ while (pipefds[1] <= 2) { ++ pipefds[1] = dup(pipefds[1]); ++ if (pipefds[1] < 0) { ++ xlog_err("mydaemon: dup() failed: errno %d (%s)\n", ++ errno, strerror(errno)); ++ exit(1); ++ } ++ } ++ ++ if (noclose == 0) { ++ tempfd = open("/dev/null", O_RDWR); ++ if (tempfd >= 0) { ++ dup2(tempfd, 0); ++ dup2(tempfd, 1); ++ dup2(tempfd, 2); ++ close(tempfd); ++ } else { ++ xlog_err("mydaemon: can't open /dev/null: errno %d " ++ "(%s)\n", errno, strerror(errno)); ++ exit(1); ++ } ++ } ++ ++ return; ++} ++ ++/** ++ * release_parent - tell the parent that it can exit now ++ * @pipefds: pipefd array that was previously passed to mydaemon() ++ * ++ * This function tells the parent process of mydaemon() that it's now clear ++ * to exit(0). ++ */ ++void ++release_parent(int *pipefds) ++{ ++ int status; ++ ++ if (pipefds[1] > 0) { ++ if (write(pipefds[1], &status, 1) != 1) { ++ xlog_err("WARN: writing to parent pipe failed: errno " ++ "%d (%s)\n", errno, strerror(errno)); ++ } ++ close(pipefds[1]); ++ pipefds[1] = -1; ++ } ++} ++ +diff --git a/utils/exportfs/exportfs.c b/utils/exportfs/exportfs.c +index da5fe21..8c86790 100644 +--- a/utils/exportfs/exportfs.c ++++ b/utils/exportfs/exportfs.c +@@ -27,6 +27,10 @@ + #include + #include + #include ++#include ++#include ++ ++#define INT_TO_LONG_THRESHOLD_SECS (INT_MAX - (60 * 60 * 24)) + + #include "sockaddr.h" + #include "misc.h" +@@ -61,19 +65,19 @@ static int _lockfd = -1; + * writes A+B writes A+C + * + * The locking in support/export/xtab.c will prevent mountd from +- * seeing a partially written version of etab, and will prevent ++ * seeing a partially written version of etab, and will prevent + * the two writers above from writing simultaneously and + * corrupting etab, but to prevent problems like the above we + * need these additional lockfile() routines. + */ +-static void ++static void + grab_lockfile() + { + _lockfd = open(lockfile, O_CREAT|O_RDWR, 0666); +- if (_lockfd != -1) ++ if (_lockfd != -1) + lockf(_lockfd, F_LOCK, 0); + } +-static void ++static void + release_lockfile() + { + if (_lockfd != -1) +@@ -267,7 +271,7 @@ exports_update(int verbose) + exports_update_one(exp, verbose); + } + } +- ++ + /* + * export_all finds all entries and + * marks them xtabent and mayexport so that they get exported +@@ -282,7 +286,7 @@ export_all(int verbose) + for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { + if (verbose) + printf("exporting %s:%s\n", +- exp->m_client->m_hostname, ++ exp->m_client->m_hostname, + exp->m_export.e_path); + exp->m_xtabent = 1; + exp->m_mayexport = 1; +@@ -329,7 +333,7 @@ exportfs(char *arg, char *options, int verbose) + goto out; + + if (verbose) +- printf("exporting %s:%s\n", exp->m_client->m_hostname, ++ printf("exporting %s:%s\n", exp->m_client->m_hostname, + exp->m_export.e_path); + exp->m_xtabent = 1; + exp->m_mayexport = 1; +@@ -387,7 +391,7 @@ unexportfs(char *arg, int verbose) + else + #endif + printf("unexporting %s:%s\n", +- exp->m_client->m_hostname, ++ exp->m_client->m_hostname, + exp->m_export.e_path); + } + #if 0 +@@ -398,7 +402,7 @@ unexportfs(char *arg, int verbose) + exp->m_mayexport = 0; + success = 1; + } +- if (!success) ++ if (!success) + xlog(L_ERROR, "Could not find '%s:%s' to unexport.", arg, path); + + freeaddrinfo(ai); +@@ -406,17 +410,33 @@ unexportfs(char *arg, int verbose) + + static int can_test(void) + { ++ char buf[1024]; + int fd; + int n; +- char *setup = "nfsd 0.0.0.0 2147483647 -test-client-\n"; ++ + fd = open("/proc/net/rpc/auth.unix.ip/channel", O_WRONLY); +- if ( fd < 0) return 0; +- n = write(fd, setup, strlen(setup)); ++ if (fd < 0) ++ return 0; ++ ++ /* ++ * We introduce tolerance of 1 day to ensure that we use a ++ * LONG_MAX for the expiry timestamp before it is actually ++ * needed. To use LONG_MAX, the kernel code must have ++ * commit 2f74f972 (sunrpc: prepare NFS for 2038). ++ */ ++ if (time(NULL) > INT_TO_LONG_THRESHOLD_SECS) ++ sprintf(buf, "nfsd 0.0.0.0 %ld -test-client-\n", LONG_MAX); ++ else ++ sprintf(buf, "nfsd 0.0.0.0 %d -test-client-\n", INT_MAX); ++ ++ n = write(fd, buf, strlen(buf)); + close(fd); + if (n < 0) + return 0; ++ + fd = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY); +- if ( fd < 0) return 0; ++ if (fd < 0) ++ return 0; + close(fd); + return 1; + } +@@ -424,11 +444,17 @@ static int can_test(void) + static int test_export(char *path, int with_fsid) + { + char buf[1024]; ++ char *bp = buf; ++ int len = sizeof(buf); + int fd, n; + +- sprintf(buf, "-test-client- %s 3 %d 65534 65534 0\n", +- path, +- with_fsid ? NFSEXP_FSID : 0); ++ n = snprintf(buf, len, "-test-client- "); ++ bp += n; ++ len -= n; ++ qword_add(&bp, &len, path); ++ if (len < 1) ++ return 0; ++ snprintf(bp, len, " 3 %d 65534 65534 0\n", with_fsid ? NFSEXP_FSID : 0); + fd = open("/proc/net/rpc/nfsd.export/channel", O_WRONLY); + if (fd < 0) + return 0; +@@ -596,7 +622,7 @@ export_d_read(const char *dname) + int fname_len; + + +- if (d->d_type != DT_UNKNOWN ++ if (d->d_type != DT_UNKNOWN + && d->d_type != DT_REG + && d->d_type != DT_LNK) + continue; +@@ -605,7 +631,7 @@ export_d_read(const char *dname) + + #define _EXT_EXPORT_SIZ (sizeof(_EXT_EXPORT) - 1) + namesz = strlen(d->d_name); +- if (!namesz ++ if (!namesz + || namesz < _EXT_EXPORT_SIZ + 1 + || strcmp(d->d_name + (namesz - _EXT_EXPORT_SIZ), + _EXT_EXPORT)) +@@ -619,7 +645,7 @@ export_d_read(const char *dname) + + export_read(fname); + } +- ++ + for (i = 0; i < n; i++) + free(namelist[i]); + free(namelist); +@@ -642,6 +668,9 @@ dumpopt(char c, char *fmt, ...) + static void + dump(int verbose, int export_format) + { ++ char buf[1024]; ++ char *bp; ++ int len; + nfs_export *exp; + struct exportent *ep; + int htype; +@@ -659,7 +688,15 @@ dump(int verbose, int export_format) + if (strlen(ep->e_path) > 14 && !export_format) + printf("%-14s\n\t\t%s", ep->e_path, hname); + else +- printf(((export_format)? "%s %s" : "%-14s\t%s"), ep->e_path, hname); ++ if (export_format) { ++ bp = buf; ++ len = sizeof(buf) - 1; ++ qword_add(&bp, &len, ep->e_path); ++ *bp = '\0'; ++ printf("%s %s", buf, hname); ++ } else { ++ printf("%-14s\t%s", ep->e_path, hname); ++ } + + if (!verbose && !export_format) { + printf("\n"); +@@ -697,8 +734,8 @@ dump(int verbose, int export_format) + if (ep->e_uuid) + c = dumpopt(c, "fsid=%s", ep->e_uuid); + if (ep->e_mountpoint) +- c = dumpopt(c, "mountpoint%s%s", +- ep->e_mountpoint[0]?"=":"", ++ c = dumpopt(c, "mountpoint%s%s", ++ ep->e_mountpoint[0]?"=":"", + ep->e_mountpoint); + if (ep->e_anonuid != 65534) + c = dumpopt(c, "anonuid=%d", ep->e_anonuid); +diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c +index 8ee478b..fdad153 100644 +--- a/utils/gssd/gssd.c ++++ b/utils/gssd/gssd.c +@@ -54,6 +54,7 @@ + #include "err_util.h" + #include "gss_util.h" + #include "krb5_util.h" ++#include "nfslib.h" + + char pipefs_dir[PATH_MAX] = GSSD_PIPEFS_DIR; + char keytabfile[PATH_MAX] = GSSD_DEFAULT_KEYTAB_FILE; +@@ -63,6 +64,7 @@ int use_memcache = 0; + int root_uses_machine_creds = 1; + unsigned int context_timeout = 0; + char *preferred_realm = NULL; ++int pipefds[2] = { -1, -1 }; + + void + sig_die(int signal) +@@ -187,8 +189,8 @@ main(int argc, char *argv[]) + if (gssd_check_mechs() != 0) + errx(1, "Problem with gssapi library"); + +- if (!fg && daemon(0, 0) < 0) +- errx(1, "fork"); ++ if (!fg) ++ mydaemon(0, 0, pipefds); + + signal(SIGINT, sig_die); + signal(SIGTERM, sig_die); +diff --git a/utils/gssd/gssd.h b/utils/gssd/gssd.h +index 86472a1..56a18d6 100644 +--- a/utils/gssd/gssd.h ++++ b/utils/gssd/gssd.h +@@ -67,12 +67,14 @@ extern int use_memcache; + extern int root_uses_machine_creds; + extern unsigned int context_timeout; + extern char *preferred_realm; ++extern int pipefds[2]; + + TAILQ_HEAD(clnt_list_head, clnt_info) clnt_list; + + struct clnt_info { + TAILQ_ENTRY(clnt_info) list; + char *dirname; ++ char *pdir; + int dir_fd; + char *servicename; + char *servername; +diff --git a/utils/gssd/gssd_main_loop.c b/utils/gssd/gssd_main_loop.c +index ccf7fe5..9970028 100644 +--- a/utils/gssd/gssd_main_loop.c ++++ b/utils/gssd/gssd_main_loop.c +@@ -53,6 +53,7 @@ + + #include "gssd.h" + #include "err_util.h" ++#include "nfslib.h" + + extern struct pollfd *pollarray; + extern unsigned long pollsize; +@@ -245,6 +246,9 @@ gssd_run() + /* Error msg is already printed */ + exit(1); + } ++ ++ /* release the parent after the initial dir scan */ ++ release_parent(pipefds); + } + gssd_poll(pollarray, pollsize); + } +diff --git a/utils/gssd/gssd_proc.c b/utils/gssd/gssd_proc.c +index b48d163..33cfeb2 100644 +--- a/utils/gssd/gssd_proc.c ++++ b/utils/gssd/gssd_proc.c +@@ -256,6 +256,7 @@ read_service_info(char *info_file_name, char **servicename, char **servername, + if ((nbytes = read(fd, buf, INFOBUFLEN)) == -1) + goto fail; + close(fd); ++ fd = -1; + buf[nbytes] = '\0'; + + numfields = sscanf(buf,"RPC server: %127s\n" +@@ -322,6 +323,7 @@ destroy_client(struct clnt_info *clp) + if (clp->krb5_fd != -1) close(clp->krb5_fd); + if (clp->gssd_fd != -1) close(clp->gssd_fd); + free(clp->dirname); ++ free(clp->pdir); + free(clp->servicename); + free(clp->servername); + free(clp->protocol); +@@ -403,11 +405,10 @@ process_clnt_dir_files(struct clnt_info * clp) + return -1; + snprintf(info_file_name, sizeof(info_file_name), "%s/info", + clp->dirname); +- if ((clp->servicename == NULL) && +- read_service_info(info_file_name, &clp->servicename, +- &clp->servername, &clp->prog, &clp->vers, +- &clp->protocol, (struct sockaddr *) &clp->addr)) +- return -1; ++ if (clp->prog == 0) ++ read_service_info(info_file_name, &clp->servicename, ++ &clp->servername, &clp->prog, &clp->vers, ++ &clp->protocol, (struct sockaddr *) &clp->addr); + return 0; + } + +@@ -463,6 +464,9 @@ process_clnt_dir(char *dir, char *pdir) + if (!(clp = insert_new_clnt())) + goto fail_destroy_client; + ++ if (!(clp->pdir = strdup(pdir))) ++ goto fail_destroy_client; ++ + /* An extra for the '/', and an extra for the null */ + if (!(clp->dirname = calloc(strlen(dir) + strlen(pdir) + 2, 1))) { + goto fail_destroy_client; +@@ -527,7 +531,7 @@ update_old_clients(struct dirent **namelist, int size, char *pdir) + /* only compare entries in the global list that are from the + * same pipefs parent directory as "pdir" + */ +- if (strcmp(clp->dirname, pdir) != 0) continue; ++ if (strcmp(clp->pdir, pdir) != 0) continue; + + stillhere = 0; + for (i=0; i < size; i++) { +@@ -1040,7 +1044,10 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, + return; + default: + /* Parent: just wait on child to exit and return */ +- wait(&err); ++ do { ++ pid = wait(&err); ++ } while(pid == -1 && errno != -ECHILD); ++ + if (WIFSIGNALED(err)) + printerr(0, "WARNING: forked child was killed with signal %d\n", + WTERMSIG(err)); +@@ -1088,7 +1095,7 @@ process_krb5_upcall(struct clnt_info *clp, uid_t uid, int fd, char *tgtname, + + /* Tell krb5 gss which credentials cache to use */ + /* Try first to acquire credentials directly via GSSAPI */ +- err = gssd_acquire_user_cred(uid, &gss_cred); ++ err = gssd_acquire_user_cred(&gss_cred); + if (!err) + create_resp = create_auth_rpc_client(clp, tgtname, &rpc_clnt, &auth, uid, + AUTHTYPE_KRB5, gss_cred); +@@ -1320,11 +1327,14 @@ handle_gssd_upcall(struct clnt_info *clp) + } + } + +- if (strcmp(mech, "krb5") == 0) ++ if (strcmp(mech, "krb5") == 0 && clp->servername) + process_krb5_upcall(clp, uid, clp->gssd_fd, target, service); +- else +- printerr(0, "WARNING: handle_gssd_upcall: " +- "received unknown gss mech '%s'\n", mech); ++ else { ++ if (clp->servername) ++ printerr(0, "WARNING: handle_gssd_upcall: " ++ "received unknown gss mech '%s'\n", mech); ++ do_error_downcall(clp->gssd_fd, uid, -EACCES); ++ } + + out: + free(lbuf); +diff --git a/utils/gssd/krb5_util.c b/utils/gssd/krb5_util.c +index 697d1d2..208c72b 100644 +--- a/utils/gssd/krb5_util.c ++++ b/utils/gssd/krb5_util.c +@@ -1359,12 +1359,12 @@ gssd_k5_get_default_realm(char **def_realm) + } + + static int +-gssd_acquire_krb5_cred(gss_name_t name, gss_cred_id_t *gss_cred) ++gssd_acquire_krb5_cred(gss_cred_id_t *gss_cred) + { + OM_uint32 maj_stat, min_stat; + gss_OID_set_desc desired_mechs = { 1, &krb5oid }; + +- maj_stat = gss_acquire_cred(&min_stat, name, GSS_C_INDEFINITE, ++ maj_stat = gss_acquire_cred(&min_stat, GSS_C_NO_NAME, GSS_C_INDEFINITE, + &desired_mechs, GSS_C_INITIATE, + gss_cred, NULL, NULL); + +@@ -1379,31 +1379,12 @@ gssd_acquire_krb5_cred(gss_name_t name, gss_cred_id_t *gss_cred) + } + + int +-gssd_acquire_user_cred(uid_t uid, gss_cred_id_t *gss_cred) ++gssd_acquire_user_cred(gss_cred_id_t *gss_cred) + { +- OM_uint32 maj_stat, min_stat; +- gss_buffer_desc name_buf; +- gss_name_t name; +- char buf[11]; ++ OM_uint32 min_stat; + int ret; + +- ret = snprintf(buf, 11, "%u", uid); +- if (ret < 1 || ret > 10) { +- return -1; +- } +- name_buf.value = buf; +- name_buf.length = ret + 1; +- +- maj_stat = gss_import_name(&min_stat, &name_buf, +- GSS_C_NT_STRING_UID_NAME, &name); +- if (maj_stat != GSS_S_COMPLETE) { +- if (get_verbosity() > 0) +- pgsserr("gss_import_name", +- maj_stat, min_stat, &krb5oid); +- return -1; +- } +- +- ret = gssd_acquire_krb5_cred(name, gss_cred); ++ ret = gssd_acquire_krb5_cred(gss_cred); + + /* force validation of cred to check for expiry */ + if (ret == 0) { +@@ -1412,7 +1393,6 @@ gssd_acquire_user_cred(uid_t uid, gss_cred_id_t *gss_cred) + ret = -1; + } + +- maj_stat = gss_release_name(&min_stat, &name); + return ret; + } + +@@ -1443,7 +1423,7 @@ limit_krb5_enctypes(struct rpc_gss_sec *sec) + int err = -1; + + if (sec->cred == GSS_C_NO_CREDENTIAL) { +- err = gssd_acquire_krb5_cred(GSS_C_NO_NAME, &sec->cred); ++ err = gssd_acquire_krb5_cred(&sec->cred); + if (err) + return -1; + } +diff --git a/utils/gssd/krb5_util.h b/utils/gssd/krb5_util.h +index 3f0723e..a319588 100644 +--- a/utils/gssd/krb5_util.h ++++ b/utils/gssd/krb5_util.h +@@ -35,7 +35,7 @@ int gssd_refresh_krb5_machine_credential(char *hostname, + char *gssd_k5_err_msg(krb5_context context, krb5_error_code code); + void gssd_k5_get_default_realm(char **def_realm); + +-int gssd_acquire_user_cred(uid_t uid, gss_cred_id_t *gss_cred); ++int gssd_acquire_user_cred(gss_cred_id_t *gss_cred); + + #ifdef HAVE_SET_ALLOWABLE_ENCTYPES + extern int limit_to_legacy_enctypes; +diff --git a/utils/gssd/svcgssd.c b/utils/gssd/svcgssd.c +index 8aee3b2..0385725 100644 +--- a/utils/gssd/svcgssd.c ++++ b/utils/gssd/svcgssd.c +@@ -62,91 +62,7 @@ + #include "gss_util.h" + #include "err_util.h" + +-/* +- * mydaemon creates a pipe between the partent and child +- * process. The parent process will wait until the +- * child dies or writes a '1' on the pipe signaling +- * that it started successfully. +- */ +-int pipefds[2] = { -1, -1}; +- +-static void +-mydaemon(int nochdir, int noclose) +-{ +- int pid, status, tempfd; +- +- if (pipe(pipefds) < 0) { +- printerr(1, "mydaemon: pipe() failed: errno %d (%s)\n", +- errno, strerror(errno)); +- exit(1); +- } +- if ((pid = fork ()) < 0) { +- printerr(1, "mydaemon: fork() failed: errno %d (%s)\n", +- errno, strerror(errno)); +- exit(1); +- } +- +- if (pid != 0) { +- /* +- * Parent. Wait for status from child. +- */ +- close(pipefds[1]); +- if (read(pipefds[0], &status, 1) != 1) +- exit(1); +- exit (0); +- } +- /* Child. */ +- close(pipefds[0]); +- setsid (); +- if (nochdir == 0) { +- if (chdir ("/") == -1) { +- printerr(1, "mydaemon: chdir() failed: errno %d (%s)\n", +- errno, strerror(errno)); +- exit(1); +- } +- } +- +- while (pipefds[1] <= 2) { +- pipefds[1] = dup(pipefds[1]); +- if (pipefds[1] < 0) { +- printerr(1, "mydaemon: dup() failed: errno %d (%s)\n", +- errno, strerror(errno)); +- exit(1); +- } +- } +- +- if (noclose == 0) { +- tempfd = open("/dev/null", O_RDWR); +- if (tempfd >= 0) { +- dup2(tempfd, 0); +- dup2(tempfd, 1); +- dup2(tempfd, 2); +- close(tempfd); +- } else { +- printerr(1, "mydaemon: can't open /dev/null: errno %d " +- "(%s)\n", errno, strerror(errno)); +- exit(1); +- } +- } +- +- return; +-} +- +-static void +-release_parent(void) +-{ +- int status; +- +- if (pipefds[1] > 0) { +- if (write(pipefds[1], &status, 1) != 1) { +- printerr(1, +- "WARN: writing to parent pipe failed: errno %d (%s)\n", +- errno, strerror(errno)); +- } +- close(pipefds[1]); +- pipefds[1] = -1; +- } +-} ++static int pipefds[2] = { -1, -1 }; + + void + sig_die(int signal) +@@ -242,7 +158,7 @@ main(int argc, char *argv[]) + } + + if (!fg) +- mydaemon(0, 0); ++ mydaemon(0, 0, pipefds); + + signal(SIGINT, sig_die); + signal(SIGTERM, sig_die); +@@ -272,7 +188,7 @@ main(int argc, char *argv[]) + } + + if (!fg) +- release_parent(); ++ release_parent(pipefds); + + nfs4_init_name_mapping(NULL); /* XXX: should only do this once */ + gssd_run(); +diff --git a/utils/idmapd/idmapd.c b/utils/idmapd/idmapd.c +index b6c6231..c02849b 100644 +--- a/utils/idmapd/idmapd.c ++++ b/utils/idmapd/idmapd.c +@@ -157,9 +157,6 @@ static int nfsdopenone(struct idmap_client *); + static void nfsdreopen_one(struct idmap_client *); + static void nfsdreopen(void); + +-void mydaemon(int, int); +-void release_parent(void); +- + static int verbose = 0; + #define DEFAULT_IDMAP_CACHE_EXPIRY 600 /* seconds */ + static int cache_entry_expiration = 0; +@@ -167,6 +164,7 @@ static char pipefsdir[PATH_MAX]; + static char *nobodyuser, *nobodygroup; + static uid_t nobodyuid; + static gid_t nobodygid; ++static int pipefds[2] = { -1, -1 }; + + /* Used by conffile.c in libnfs.a */ + char *conf_path; +@@ -305,7 +303,7 @@ main(int argc, char **argv) + errx(1, "Unable to create name to user id mappings."); + + if (!fg) +- mydaemon(0, 0); ++ mydaemon(0, 0, pipefds); + + event_init(); + +@@ -382,7 +380,7 @@ main(int argc, char **argv) + if (nfsdret != 0 && fd == 0) + xlog_err("main: Neither NFS client nor NFSd found"); + +- release_parent(); ++ release_parent(pipefds); + + if (event_dispatch() < 0) + xlog_err("main: event_dispatch returns errno %d (%s)", +@@ -929,77 +927,3 @@ getfield(char **bpp, char *fld, size_t fldsz) + + return (0); + } +-/* +- * mydaemon creates a pipe between the partent and child +- * process. The parent process will wait until the +- * child dies or writes a '1' on the pipe signaling +- * that it started successfully. +- */ +-int pipefds[2] = { -1, -1}; +- +-void +-mydaemon(int nochdir, int noclose) +-{ +- int pid, status, tempfd; +- +- if (pipe(pipefds) < 0) +- err(1, "mydaemon: pipe() failed: errno %d", errno); +- +- if ((pid = fork ()) < 0) +- err(1, "mydaemon: fork() failed: errno %d", errno); +- +- if (pid != 0) { +- /* +- * Parent. Wait for status from child. +- */ +- close(pipefds[1]); +- if (read(pipefds[0], &status, 1) != 1) +- exit(1); +- exit (0); +- } +- /* Child. */ +- close(pipefds[0]); +- setsid (); +- if (nochdir == 0) { +- if (chdir ("/") == -1) +- err(1, "mydaemon: chdir() failed: errno %d", errno); +- } +- +- while (pipefds[1] <= 2) { +- pipefds[1] = dup(pipefds[1]); +- if (pipefds[1] < 0) +- err(1, "mydaemon: dup() failed: errno %d", errno); +- } +- +- if (noclose == 0) { +- tempfd = open("/dev/null", O_RDWR); +- if (tempfd < 0) +- tempfd = open("/", O_RDONLY); +- if (tempfd >= 0) { +- dup2(tempfd, 0); +- dup2(tempfd, 1); +- dup2(tempfd, 2); +- close(tempfd); +- } else { +- err(1, "mydaemon: can't open /dev/null: errno %d", +- errno); +- exit(1); +- } +- } +- +- return; +-} +-void +-release_parent(void) +-{ +- int status; +- +- if (pipefds[1] > 0) { +- if (write(pipefds[1], &status, 1) != 1) { +- err(1, "Writing to parent pipe failed: errno %d (%s)\n", +- errno, strerror(errno)); +- } +- close(pipefds[1]); +- pipefds[1] = -1; +- } +-} +diff --git a/utils/idmapd/idmapd.man b/utils/idmapd/idmapd.man +index 58ea9f2..185cd1b 100644 +--- a/utils/idmapd/idmapd.man ++++ b/utils/idmapd/idmapd.man +@@ -12,10 +12,7 @@ + .Nm rpc.idmapd + .Op Fl v + .Op Fl f +-.Op Fl d Ar domain + .Op Fl p Ar path +-.Op Fl U Ar username +-.Op Fl G Ar groupname + .Op Fl c Ar path + .Sh DESCRIPTION + .Nm +@@ -31,25 +28,10 @@ Increases the verbosity level (can be specified multiple times). + Runs + .Nm + in the foreground and prints all output to the terminal. +-.It Fl d Ar domain +-Set domain to +-.Ar domain . +-This is used internally by NFSv4 and is typically assigned by the +-system administrator. By default, +-.Ar domain +-is set to be the FQDN of the host, minus the hostname. + .It Fl p Ar path + Specifies the location of the RPC pipefs to be + .Ar path . + The default value is \&"/var/lib/nfs/rpc_pipefs\&". +-.It Fl U Ar username +-Specifies the NFSv4 nobody user to be +-.Ar username . +-The default value is \&"nobody\&". +-.It Fl G Ar groupname +-Specifies the NFSv4 nobody group to be +-.Ar groupname . +-The default value is \&"nobody\&". + .It Fl c Ar path + Use configuration file + .Ar path . +@@ -59,11 +41,11 @@ Client-only: perform no idmapping for any NFS server, even if one is detected. + Server-only: perform no idmapping for any NFS client, even if one is detected. + .El + .Sh EXAMPLES +-.Cm rpc.idmapd -d \&"citi.umich.edu\&" -f -vvv ++.Cm rpc.idmapd -f -vvv + .Pp + Runs + .Nm +-with the domain \&"citi.umich.edu\&" in the foreground, printing all ++printing all + messages to console, and with a verbosity level of 3. + .\" This next request is for sections 2 and 3 function return values only. + .\" .Sh RETURN VALUES +diff --git a/utils/mount/network.c b/utils/mount/network.c +index e8e55a5..2fdd2c0 100644 +--- a/utils/mount/network.c ++++ b/utils/mount/network.c +@@ -92,6 +92,9 @@ static const char *nfs_version_opttbl[] = { + "v4", + "vers", + "nfsvers", ++ "v4.0", ++ "v4.1", ++ "v4.2", + NULL, + }; + +@@ -1242,6 +1245,8 @@ nfs_nfs_version(struct mount_options *options, unsigned long *version) + *version = tmp; + return 1; + } ++ nfs_error(_("%s: parsing error on 'vers=' option\n"), ++ progname); + return 0; + case PO_NOT_FOUND: + nfs_error(_("%s: parsing error on 'vers=' option\n"), +@@ -1259,6 +1264,8 @@ nfs_nfs_version(struct mount_options *options, unsigned long *version) + *version = tmp; + return 1; + } ++ nfs_error(_("%s: parsing error on 'nfsvers=' option\n"), ++ progname); + return 0; + case PO_NOT_FOUND: + nfs_error(_("%s: parsing error on 'nfsvers=' option\n"), +@@ -1269,6 +1276,11 @@ nfs_nfs_version(struct mount_options *options, unsigned long *version) + progname); + return 0; + } ++ case 5: /* v4.0 */ ++ case 6: /* v4.1 */ ++ case 7: /* v4.2 */ ++ *version = 4; ++ return 1; + } + + /* +diff --git a/utils/mount/nfs.man b/utils/mount/nfs.man +index 67031b5..ef09a31 100644 +--- a/utils/mount/nfs.man ++++ b/utils/mount/nfs.man +@@ -288,6 +288,8 @@ attributes of a regular file before it requests + fresh attribute information from a server. + If this option is not specified, the NFS client uses + a 3-second minimum. ++See the DATA AND METADATA COHERENCE section ++for a full discussion of attribute caching. + .TP 1.5i + .BI acregmax= n + The maximum time (in seconds) that the NFS client caches +@@ -295,6 +297,8 @@ attributes of a regular file before it requests + fresh attribute information from a server. + If this option is not specified, the NFS client uses + a 60-second maximum. ++See the DATA AND METADATA COHERENCE section ++for a full discussion of attribute caching. + .TP 1.5i + .BI acdirmin= n + The minimum time (in seconds) that the NFS client caches +@@ -302,6 +306,8 @@ attributes of a directory before it requests + fresh attribute information from a server. + If this option is not specified, the NFS client uses + a 30-second minimum. ++See the DATA AND METADATA COHERENCE section ++for a full discussion of attribute caching. + .TP 1.5i + .BI acdirmax= n + The maximum time (in seconds) that the NFS client caches +@@ -309,6 +315,8 @@ attributes of a directory before it requests + fresh attribute information from a server. + If this option is not specified, the NFS client uses + a 60-second maximum. ++See the DATA AND METADATA COHERENCE section ++for a full discussion of attribute caching. + .TP 1.5i + .BI actimeo= n + Using +@@ -856,6 +864,26 @@ In the presence of multiple client network interfaces, + special routing policies, + or atypical network topologies, + the exact address to use for callbacks may be nontrivial to determine. ++.TP 1.5i ++.BR migration " / " nomigration ++Selects whether the client uses an identification string that is compatible ++with NFSv4 Transparent State Migration (TSM). ++If the mounted server supports NFSv4 migration with TSM, specify the ++.B migration ++option. ++.IP ++Some server features misbehave in the face of a migration-compatible ++identification string. ++The ++.B nomigration ++option retains the use of a traditional client indentification string ++which is compatible with legacy NFS servers. ++This is also the behavior if neither option is specified. ++A client's open and lock state cannot be migrated transparently ++when it identifies itself via a traditional identification string. ++.IP ++This mount option has no effect with NFSv4 minor versions newer than zero, ++which always use TSM-compatible client identification strings. + .SH nfs4 FILE SYSTEM TYPE + The + .BR nfs4 +@@ -1161,24 +1189,33 @@ perfect cache coherence among their clients. + Perfect cache coherence among disparate NFS clients + is expensive to achieve, especially on wide area networks. + As such, NFS settles for weaker cache coherence that +-satisfies the requirements of most file sharing types. Normally, +-file sharing is completely sequential: +-first client A opens a file, writes something to it, then closes it; +-then client B opens the same file, and reads the changes. +-.DT ++satisfies the requirements of most file sharing types. + .SS "Close-to-open cache consistency" +-When an application opens a file stored on an NFS server, +-the NFS client checks that it still exists on the server ++Typically file sharing is completely sequential. ++First client A opens a file, writes something to it, then closes it. ++Then client B opens the same file, and reads the changes. ++.P ++When an application opens a file stored on an NFS version 3 server, ++the NFS client checks that the file exists on the server + and is permitted to the opener by sending a GETATTR or ACCESS request. ++The NFS client sends these requests ++regardless of the freshness of the file's cached attributes. ++.P + When the application closes the file, + the NFS client writes back any pending changes + to the file so that the next opener can view the changes. + This also gives the NFS client an opportunity to report +-any server write errors to the application +-via the return code from ++write errors to the application via the return code from + .BR close (2). ++.P + The behavior of checking at open time and flushing at close time +-is referred to as close-to-open cache consistency. ++is referred to as ++.IR "close-to-open cache consistency" , ++or ++.IR CTO . ++It can be disabled for an entire mount point using the ++.B nocto ++mount option. + .SS "Weak cache consistency" + There are still opportunities for a client's data cache + to contain stale data. +@@ -1227,6 +1264,65 @@ If absolute cache coherence among clients is required, + applications should use file locking. Alternatively, applications + can also open their files with the O_DIRECT flag + to disable data caching entirely. ++.SS "File timestamp maintainence" ++NFS servers are responsible for managing file and directory timestamps ++.RB ( atime , ++.BR ctime ", and" ++.BR mtime ). ++When a file is accessed or updated on an NFS server, ++the file's timestamps are updated just like they would be on a filesystem ++local to an application. ++.P ++NFS clients cache file attributes, including timestamps. ++A file's timestamps are updated on NFS clients when its attributes ++are retrieved from the NFS server. ++Thus there may be some delay before timestamp updates ++on an NFS server appear to applications on NFS clients. ++.P ++To comply with the POSIX filesystem standard, the Linux NFS client ++relies on NFS servers to keep a file's ++.B mtime ++and ++.B ctime ++timestamps properly up to date. ++It does this by flushing local data changes to the server ++before reporting ++.B mtime ++to applications via system calls such as ++.BR stat (2). ++.P ++The Linux client handles ++.B atime ++updates more loosely, however. ++NFS clients maintain good performance by caching data, ++but that means that application reads, which normally update ++.BR atime , ++are not reflected to the server where a file's ++.B atime ++is actually maintained. ++.P ++Because of this caching behavior, ++the Linux NFS client does not support generic atime-related mount options. ++See ++.BR mount (8) ++for details on these options. ++.P ++In particular, the ++.BR atime / noatime , ++.BR diratime / nodiratime , ++.BR relatime / norelatime , ++and ++.BR strictatime / nostrictatime ++mount options have no effect on NFS mounts. ++.P ++.I /proc/mounts ++may report that the ++.B relatime ++mount option is set on NFS mounts, but in fact the ++.B atime ++semantics are always as described here, and are not like ++.B relatime ++semantics. + .SS "Directory entry caching" + The Linux NFS client caches the result of all NFS LOOKUP requests. + If the requested directory entry exists on the server, +diff --git a/utils/mount/utils.c b/utils/mount/utils.c +index 2778ed7..ede77a8 100644 +--- a/utils/mount/utils.c ++++ b/utils/mount/utils.c +@@ -93,7 +93,7 @@ void print_one(char *spec, char *node, char *type, char *opts) + + void mount_usage(void) + { +- printf(_("usage: %s remotetarget dir [-rvVwfnsih] [-o nfsoptions]\n"), ++ printf(_("usage: %s remotetarget dir [-rvVwfnsh] [-o nfsoptions]\n"), + progname); + printf(_("options:\n")); + printf(_("\t-r\t\tMount file system readonly\n")); +diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c +index e04b86e..ca35de2 100644 +--- a/utils/mountd/cache.c ++++ b/utils/mountd/cache.c +@@ -266,6 +266,27 @@ static int get_uuid(const char *val, size_t uuidlen, char *u) + return 1; + } + ++ ++/* ++ * Don't ask libblkid for these filesystems. Note that BTRF is ignored, because ++ * we generate the identifier from statfs->f_fsid. The rest are network or ++ * pseudo filesystems. (See for the basic IDs.) ++ */ ++static const long int nonblkid_filesystems[] = { ++ 0x2fc12fc1, /* ZFS_SUPER_MAGIC */ ++ 0x9123683E, /* BTRFS_SUPER_MAGIC */ ++ 0xFF534D42, /* CIFS_MAGIC_NUMBER */ ++ 0x1373, /* DEVFS_SUPER_MAGIC */ ++ 0x73757245, /* CODA_SUPER_MAGIC */ ++ 0x564C, /* NCP_SUPER_MAGIC */ ++ 0x6969, /* NFS_SUPER_MAGIC */ ++ 0x9FA0, /* PROC_SUPER_MAGIC */ ++ 0x62656572, /* SYSFS_MAGIC */ ++ 0x517B, /* SMB_SUPER_MAGIC */ ++ 0x01021994, /* TMPFS_SUPER_MAGIC */ ++ 0 /* last */ ++}; ++ + static int uuid_by_path(char *path, int type, size_t uuidlen, char *uuid) + { + /* get a uuid for the filesystem found at 'path'. +@@ -297,12 +318,23 @@ static int uuid_by_path(char *path, int type, size_t uuidlen, char *uuid) + */ + struct statfs64 st; + char fsid_val[17]; +- const char *blkid_val; ++ const char *blkid_val = NULL; + const char *val; ++ int rc; + +- blkid_val = get_uuid_blkdev(path); ++ rc = statfs64(path, &st); ++ ++ if (type == 0 && rc == 0) { ++ const long int *bad; ++ for (bad = nonblkid_filesystems; *bad; bad++) { ++ if (*bad == st.f_type) ++ break; ++ } ++ if (*bad == 0) ++ blkid_val = get_uuid_blkdev(path); ++ } + +- if (statfs64(path, &st) == 0 && ++ if (rc == 0 && + (st.f_fsid.__val[0] || st.f_fsid.__val[1])) + snprintf(fsid_val, 17, "%08x%08x", + st.f_fsid.__val[0], st.f_fsid.__val[1]); +diff --git a/utils/nfsd/nfsd.c b/utils/nfsd/nfsd.c +index 6db92f0..a9d77ab 100644 +--- a/utils/nfsd/nfsd.c ++++ b/utils/nfsd/nfsd.c +@@ -99,7 +99,7 @@ main(int argc, char **argv) + char *p, *progname, *port; + char *haddr = NULL; + int socket_up = 0; +- int minorvers = NFS4_VERDEFAULT; /* nfsv4 minor version */ ++ int minorvers[NFS4_MAXMINOR + 1] = {0}; + unsigned int versbits = NFSCTL_VERDEFAULT; + unsigned int protobits = NFSCTL_ALLBITS; + unsigned int proto4 = 0; +@@ -164,7 +164,7 @@ main(int argc, char **argv) + fprintf(stderr, "%s: unsupported minor version\n", optarg); + exit(1); + } +- NFSCTL_VERUNSET(minorvers, i); ++ minorvers[i] = -1; + break; + } + case 3: +@@ -185,7 +185,7 @@ main(int argc, char **argv) + fprintf(stderr, "%s: unsupported minor version\n", optarg); + exit(1); + } +- NFSCTL_VERSET(minorvers, i); ++ minorvers[i] = 1; + break; + } + case 3: +diff --git a/utils/nfsd/nfssvc.c b/utils/nfsd/nfssvc.c +index 8b85846..1b50aba 100644 +--- a/utils/nfsd/nfssvc.c ++++ b/utils/nfsd/nfssvc.c +@@ -269,7 +269,7 @@ nfssvc_set_sockets(const int family, const unsigned int protobits, + } + + void +-nfssvc_setvers(unsigned int ctlbits, int minorvers) ++nfssvc_setvers(unsigned int ctlbits, int minorvers[]) + { + int fd, n, off; + char *ptr; +@@ -281,9 +281,9 @@ nfssvc_setvers(unsigned int ctlbits, int minorvers) + return; + + for (n = NFS4_MINMINOR; n <= NFS4_MAXMINOR; n++) { +- if (NFSCTL_VERISSET(minorvers, n)) ++ if (minorvers[n] == 1) + off += snprintf(ptr+off, sizeof(buf) - off, "+4.%d ", n); +- else ++ else if (minorvers[n] == -1) + off += snprintf(ptr+off, sizeof(buf) - off, "-4.%d ", n); + } + for (n = NFSD_MINVERS; n <= NFSD_MAXVERS; n++) { +diff --git a/utils/nfsd/nfssvc.h b/utils/nfsd/nfssvc.h +index 08de0fe..2bbd3d3 100644 +--- a/utils/nfsd/nfssvc.h ++++ b/utils/nfsd/nfssvc.h +@@ -24,5 +24,5 @@ void nfssvc_mount_nfsdfs(char *progname); + int nfssvc_inuse(void); + int nfssvc_set_sockets(const int family, const unsigned int protobits, + const char *host, const char *port); +-void nfssvc_setvers(unsigned int ctlbits, int minorvers4); ++void nfssvc_setvers(unsigned int ctlbits, int minorvers4[]); + int nfssvc_threads(unsigned short port, int nrservs); +diff --git a/utils/statd/statd.c b/utils/statd/statd.c +index 8c51bcc..8f31111 100644 +--- a/utils/statd/statd.c ++++ b/utils/statd/statd.c +@@ -238,12 +238,6 @@ int main (int argc, char **argv) + /* Set hostname */ + MY_NAME = NULL; + +- /* Refuse to start if another statd is running */ +- if (nfs_probe_statd()) { +- fprintf(stderr, "Statd service already running!\n"); +- exit(1); +- } +- + /* Process command line switches */ + while ((arg = getopt_long(argc, argv, "h?vVFNH:dn:p:o:P:L", longopts, NULL)) != EOF) { + switch (arg) { +@@ -306,6 +300,12 @@ int main (int argc, char **argv) + } + } + ++ /* Refuse to start if another statd is running */ ++ if (nfs_probe_statd()) { ++ fprintf(stderr, "Statd service already running!\n"); ++ exit(1); ++ } ++ + if (port == out_port && port != 0) { + fprintf(stderr, "Listening and outgoing ports cannot be the same!\n"); + exit(-1); diff --git a/nfs-utils-1.2.9-gssd-home.patch b/nfs-utils-1.2.9-gssd-home.patch new file mode 100644 index 0000000..dcec453 --- /dev/null +++ b/nfs-utils-1.2.9-gssd-home.patch @@ -0,0 +1,53 @@ +commit 2f682f25c642fcfe7c511d04bc9d67e732282348 +Author: Jeff Layton +Date: Wed Jan 22 11:17:19 2014 -0500 + + gssd: set $HOME to prevent recursion when home dirs are on kerberized NFS mount + + Some krb5 routines will attempt to access files in the user's home + directory. This is problematic for gssd when the user's homedir is + on a kerberized NFS mount as it will end up deadlocked. + + Fix this by setting $HOME unconditionally to "/". + + Fixes this Fedora bug: + + https://bugzilla.redhat.com/show_bug.cgi?id=1052902 + + Reported-by: Enrico Scholz + Reported-by: nmorey + Tested-by: Michael Young + Signed-off-by: Jeff Layton + Signed-off-by: Steve Dickson + +diff --git a/utils/gssd/gssd.c b/utils/gssd/gssd.c +index fdad153..611ef1a 100644 +--- a/utils/gssd/gssd.c ++++ b/utils/gssd/gssd.c +@@ -46,6 +46,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -161,6 +162,18 @@ main(int argc, char *argv[]) + } + } + ++ /* ++ * Some krb5 routines try to scrape info out of files in the user's ++ * home directory. This can easily deadlock when that homedir is on a ++ * kerberized NFS mount. By setting $HOME unconditionally to "/", we ++ * prevent this behavior in routines that use $HOME in preference to ++ * the results of getpw*. ++ */ ++ if (setenv("HOME", "/", 1)) { ++ printerr(1, "Unable to set $HOME: %s\n", strerror(errno)); ++ exit(1); ++ } ++ + i = 0; + ccachesearch[i++] = strtok(ccachedir, ":"); + do { diff --git a/nfs-utils.spec b/nfs-utils.spec index bd8714c..9c94c15 100644 --- a/nfs-utils.spec +++ b/nfs-utils.spec @@ -36,7 +36,8 @@ Source51: nfs-server.preconfig Source52: nfs-server.postconfig %define nfs_configs %{SOURCE50} %{SOURCE51} %{SOURCE52} -Patch001: nfs-utils-1.2.10-rc2.patch +Patch001: nfs-utils-1.2.10-rc3.patch +Patch002: nfs-utils-1.2.9-gssd-home.patch Patch100: nfs-utils-1.2.1-statdpath-man.patch Patch101: nfs-utils-1.2.1-exp-subtree-warn-off.patch @@ -95,6 +96,7 @@ This package also contains the mount.nfs and umount.nfs program. %setup -q %patch001 -p1 +%patch002 -p1 %patch100 -p1 %patch101 -p1 @@ -311,6 +313,11 @@ fi /sbin/umount.nfs4 %changelog +* Wed Jan 22 2014 Steve Dickson 1.2.9-3.0 +- Updated to latest upstream RC release: nfs-utils-1-2-10-rc3 + - gssd: Improve first attempt at acquiring GSS credentials (bz 1055077) +- gssd: set $HOME to prevent recursion (bz 1052902) + * Fri Jan 10 2014 Steve Dickson 1.2.9-2.1 - Fixed typo in nfs-service file. (bz 1047972)