summaryrefslogtreecommitdiffstats
path: root/support/nfs
diff options
context:
space:
mode:
authorhjl <hjl>1999-10-18 23:21:12 +0000
committerhjl <hjl>1999-10-18 23:21:12 +0000
commit8b7ad01b14df1e7529b9ba8a1ea17df0d6004ef9 (patch)
tree0904ef8554ed680fe3244fa618685e1fb7ea148b /support/nfs
downloadnfs-utils-8b7ad01b14df1e7529b9ba8a1ea17df0d6004ef9.tar.gz
nfs-utils-8b7ad01b14df1e7529b9ba8a1ea17df0d6004ef9.tar.xz
nfs-utils-8b7ad01b14df1e7529b9ba8a1ea17df0d6004ef9.zip
Initial revision
Diffstat (limited to 'support/nfs')
-rw-r--r--support/nfs/Makefile13
-rw-r--r--support/nfs/clients.c324
-rw-r--r--support/nfs/exports.c440
-rw-r--r--support/nfs/getfh.c55
-rw-r--r--support/nfs/keytab.c129
-rw-r--r--support/nfs/lockdsvc.c20
-rw-r--r--support/nfs/nfsclient.c32
-rw-r--r--support/nfs/nfsctl.c24
-rw-r--r--support/nfs/nfsexport.c32
-rw-r--r--support/nfs/nfssvc.c22
-rw-r--r--support/nfs/rmtab.c122
-rw-r--r--support/nfs/rpcdispatch.c112
-rw-r--r--support/nfs/rpcmisc.c230
-rw-r--r--support/nfs/wildmat.c177
-rw-r--r--support/nfs/xio.c151
-rw-r--r--support/nfs/xlog.c189
-rw-r--r--support/nfs/xmalloc.c48
-rw-r--r--support/nfs/ypupdate_xdr.c29
18 files changed, 2149 insertions, 0 deletions
diff --git a/support/nfs/Makefile b/support/nfs/Makefile
new file mode 100644
index 0000000..ed1e1ff
--- /dev/null
+++ b/support/nfs/Makefile
@@ -0,0 +1,13 @@
+#
+# linux-nfs/support/nfs/Makefile
+#
+
+LIBNAME = libnfs.a
+OBJS = exports.o rmtab.o xio.o \
+ rpcmisc.o rpcdispatch.o xlog.o xmalloc.o wildmat.o \
+ nfssvc.o nfsclient.o nfsexport.o getfh.o nfsctl.o lockdsvc.o
+
+include $(TOP)rules.mk
+
+install::
+ @:
diff --git a/support/nfs/clients.c b/support/nfs/clients.c
new file mode 100644
index 0000000..b1970e0
--- /dev/null
+++ b/support/nfs/clients.c
@@ -0,0 +1,324 @@
+/*
+ * support/nfs/nfsclient.c
+ *
+ * Parse the nfsclients file.
+ *
+ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <ctype.h>
+#include "xmalloc.h"
+#include "nfslib.h"
+#include "exportfs.h"
+#include "xio.h"
+
+static XFILE *cfp = NULL;
+static int *squash_uids = NULL,
+ *squash_gids = NULL;
+static int squash_uidlen = 0,
+ squash_gidlen = 0;
+static char *hosts = NULL;
+
+static int parsesquash(char *list, int **idp, int *lenp);
+static int parsenum(char **cpp);
+static int parsekey(struct nfskey *keyp, char *str);
+static int hexdigit(char c);
+static int gettag(char *tag, int len);
+static int getattr(char *attr, int alen, char *value, int vlen);
+static void syntaxerr(char *msg);
+
+#ifndef isblank
+#define isblank(c) ((c) == ' ' || (c) == '\t')
+#endif
+
+void
+setnfsclntent(char *fname)
+{
+ if (cfp)
+ xfclose(cfp);
+ if (!fname)
+ fname = _PATH_NFSCLIENTS;
+ if ((cfp = xfopen(fname)) == NULL)
+ xlog(L_ERROR, "can't open %s for reading", fname);
+}
+
+struct nfsclntent *
+getnfsclntent(void)
+{
+ static struct nfsclntent cle;
+ static char *hostptr = NULL;
+ char attr[32], val[512], *sp;
+ int ok;
+
+ if (!cfp)
+ endnfsclntent();
+
+again:
+ if (hosts) {
+ if (hostptr)
+ goto nexthost;
+ xfree(hosts);
+ hosts = NULL;
+ }
+
+ if ((ok = gettag(cle.c_tag, sizeof(cle.c_tag))) < 0)
+ syntaxerr("expected tag");
+ if (ok <= 0)
+ return NULL;
+
+ cle.c_hostname[0] = '\0';
+ cle.c_fhkey.k_type = CLE_KEY_NONE;
+ cle.c_mapping = CLE_MAP_IDENT;
+ cle.c_anonuid = -2;
+ cle.c_anongid = -2;
+
+ if (squash_uids)
+ xfree(squash_uids);
+ if (squash_gids)
+ xfree(squash_gids);
+ squash_uids = squash_gids = NULL;
+ squash_uidlen = squash_gidlen = 0;
+
+ while (ok) {
+ if ((ok = getattr(attr, sizeof(attr), val, sizeof(val))) < 0)
+ return NULL;
+ if (!ok)
+ break;
+ if (attr[0] == 'h' && !strcmp(attr, "hosts")) {
+ int l0 = hosts? strlen(hosts) : 0;
+
+ hosts = (char *) xrealloc(hosts, l0+strlen(val)+2);
+ if (l0)
+ hosts[l0++] = ':';
+ strcpy(hosts+l0, val);
+ } else
+ if (attr[0] == 'f' && !strcmp(attr, "fhmac")) {
+ if (!parsekey(&cle.c_fhkey, val))
+ return NULL;
+ } else
+ if (attr[0] == 'm' && !strcmp(attr, "mapping")) {
+ if (!strcmp(val, "identity"))
+ cle.c_mapping = CLE_MAP_IDENT;
+ else if (!strcmp(val, "file"))
+ cle.c_mapping = CLE_MAP_FILE;
+ else if (!strcmp(val, "daemon"))
+ cle.c_mapping = CLE_MAP_UGIDD;
+ else {
+ syntaxerr("invalid mapping type");
+ return NULL;
+ }
+ } else
+ if (attr[0] == 's' && !strcmp(attr, "squash_uids")) {
+ if (!parsesquash(val, &squash_uids, &squash_uidlen))
+ return NULL;
+ } else
+ if (attr[0] == 's' && !strcmp(attr, "squash_gids")) {
+ if (!parsesquash(val, &squash_gids, &squash_gidlen))
+ return NULL;
+ } else
+ if (attr[0] == 'a' && !strcmp(attr, "anonuid"))
+ cle.c_anonuid = atoi(val);
+ else
+ if (attr[0] == 'a' && !strcmp(attr, "anongid"))
+ cle.c_anongid = atoi(val);
+ else
+ syntaxerr("unknown attribute");
+ }
+
+ cle.c_squashuids = squash_uids;
+ cle.c_squashgids = squash_gids;
+
+ /* This is the anon entry */
+ if (!hosts) {
+ if (strcmp(cle.c_tag, "anonymous")) {
+ xlog(L_ERROR, "nfsclients entry %s allows anonymous "
+ "access. Ignored.", cle.c_tag);
+ goto again;
+ }
+ return &cle;
+ }
+ hostptr = hosts;
+
+nexthost:
+ if (*hostptr == ':' && strcmp(cle.c_tag, "anonymous")) {
+ xlog(L_ERROR, "nfsclients entry %s allows anonymous "
+ "access. Ignored.", cle.c_tag);
+ while (*hostptr == ':')
+ hostptr++;
+ }
+
+ /* Ignore trailing colons */
+ if (!*hostptr) {
+ hostptr = NULL;
+ goto again;
+ }
+
+ sp = hostptr;
+ hostptr = strchr(hostptr, ':');
+ if (hostptr)
+ *hostptr++ = '\0';
+ strncpy(cle.c_hostname, sp, sizeof(cle.c_hostname) - 1);
+ cle.c_hostname [sizeof(cle.c_hostname) - 1] = '\0';
+ return &cle;
+}
+
+void
+endnfsclntent(void)
+{
+ if (cfp)
+ xfclose(cfp);
+ if (squash_uids)
+ xfree(squash_uids);
+ if (squash_gids)
+ xfree(squash_gids);
+ if (hosts)
+ xfree(hosts);
+ cfp = NULL;
+ squash_uids = NULL;
+ squash_gids = NULL;
+ hosts = NULL;
+}
+
+static int
+parsekey(struct nfskey *keyp, char *str)
+{
+ char *sp;
+ int i, l, x0, x1;
+
+
+ if ((sp = strchr(str, ':')) != NULL)
+ *sp++ = '\0';
+ if (!strcmp(str, "null"))
+ keyp->k_type = CLE_KEY_NULL;
+ else if (!strcmp(str, "md5"))
+ keyp->k_type = CLE_KEY_MD5;
+ else if (!strcmp(str, "sha"))
+ keyp->k_type = CLE_KEY_SHA;
+ else {
+ syntaxerr("unknown key type");
+ return 0;
+ }
+ if (keyp->k_type == CLE_KEY_NULL) {
+ keyp->k_len = 0;
+ if (sp)
+ syntaxerr("unexpected key data for null key");
+ return sp? 0 : 1;
+ } else if (sp) {
+ if ((l = strlen(sp)) & 1) {
+ syntaxerr("odd key length");
+ return 0;
+ }
+
+ l >>= 1;
+ for (i = 0; i < l && i < sizeof(keyp->k_key); i++, sp += 2) {
+ if ((x0 = hexdigit(sp[0])) == 0xff ||
+ (x1 = hexdigit(sp[1])) == 0xff) {
+ syntaxerr("bad key digit");
+ return 0;
+ }
+ keyp->k_key[i] = (x0 << 4) | x1;
+ }
+ keyp->k_len = i;
+ return 1;
+ }
+ return 0;
+}
+
+static int
+hexdigit(char c)
+{
+ if ((c = tolower(c)) >= '0' && c <= '9')
+ return c - '0';
+ if (c >= 'a' && c <= 'f')
+ return c - 'a' + 10;
+ return 0xff;
+}
+
+static int
+parsesquash(char *list, int **idp, int *lenp)
+{
+ char *cp = list;
+ int id0, id1;
+ int len = *lenp;
+ int *id = *idp;
+
+ do {
+ id0 = parsenum(&cp);
+ if (*cp == '-') {
+ cp++;
+ id1 = parsenum(&cp);
+ } else {
+ id1 = id0;
+ }
+ if (id0 == -1 || id1 == -1) {
+ syntaxerr("uid/gid -1 not permitted");
+ return 0;
+ }
+ if ((len % 8) == 0)
+ id = (int *) xrealloc(id, (len + 9) * sizeof(*id));
+ id[len++] = id0;
+ id[len++] = id1;
+ if (!*cp)
+ break;
+ if (*cp != ',') {
+ syntaxerr("bad uid/gid list");
+ return 0;
+ }
+ cp++;
+ } while(1);
+
+ id[len] = -1;
+ *lenp = len;
+ *idp = id;
+ return 1;
+}
+
+static int
+parsenum(char **cpp)
+{
+ char *cp = *cpp, c;
+ int num = 0;
+
+ if (**cpp == '-')
+ (*cpp)++;
+ while (isdigit(**cpp))
+ (*cpp)++;
+ c = **cpp; **cpp = '\0'; num = atoi(cp); **cpp = c;
+ return num;
+}
+
+static int
+gettag(char *tag, int len)
+{
+ xskip(cfp, " \t\n");
+ return xgettok(cfp, ':', tag, len);
+}
+
+static int
+getattr(char *attr, int alen, char *value, int vlen)
+{
+ int ok;
+
+ xskip(cfp, " \t");
+ if ((ok = xgettok(cfp, '=', attr, alen)) < 0)
+ xlog(L_ERROR, "error parsing attribute");
+ if (ok <= 0)
+ return ok;
+ xskip(cfp, " \t=");
+
+ return xgettok(cfp, 0, value, vlen);
+}
+
+static void
+syntaxerr(char *msg)
+{
+ xlog(L_ERROR, "syntax error in nfsclients file (line %d): %s",
+ cfp->x_line, msg);
+}
+
diff --git a/support/nfs/exports.c b/support/nfs/exports.c
new file mode 100644
index 0000000..21b85be
--- /dev/null
+++ b/support/nfs/exports.c
@@ -0,0 +1,440 @@
+/*
+ * support/nfs/export.c
+ *
+ * Parse the exports file. Derived from the unfsd implementation.
+ *
+ * Authors: Donald J. Becker, <becker@super.org>
+ * Rick Sladkey, <jrs@world.std.com>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Olaf Kirch, <okir@monad.swb.de>
+ * Alexander O. Yuriev, <alex@bach.cis.temple.edu>
+ *
+ * This software maybe be used for any purpose provided
+ * the above copyright notice is retained. It is supplied
+ * as is, with no warranty expressed or implied.
+ */
+
+#include "config.h"
+
+#include <sys/param.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <unistd.h>
+#include "nfslib.h"
+#include "exportfs.h"
+#include "xmalloc.h"
+#include "xlog.h"
+#include "xio.h"
+
+#define EXPORT_DEFAULT_FLAGS \
+ (NFSEXP_ASYNC|NFSEXP_READONLY|NFSEXP_ROOTSQUASH|NFSEXP_GATHERED_WRITES)
+
+static XFILE *efp = NULL;
+static int first;
+static int *squids = NULL, nsquids = 0,
+ *sqgids = NULL, nsqgids = 0;
+
+static int getexport(char *exp, int len);
+static int getpath(char *path, int len);
+static int parseopts(char *cp, struct exportent *ep);
+static int parsesquash(char *list, int **idp, int *lenp, char **ep);
+static int parsenum(char **cpp);
+static int parsemaptype(char *type);
+static void freesquash(void);
+static void syntaxerr(char *msg);
+
+void
+setexportent(char *fname, char *type)
+{
+ if (efp)
+ endexportent();
+ if (!fname)
+ fname = _PATH_EXPORTS;
+ if (!(efp = xfopen(fname, type)))
+ xlog(L_ERROR, "can't open %s for %sing",
+ fname, strcmp(type, "r")? "writ" : "read");
+ first = 1;
+}
+
+struct exportent *
+getexportent(void)
+{
+ static struct exportent ee;
+ char exp[512];
+ char rpath[MAXPATHLEN+1];
+ char *opt, *sp;
+ int ok;
+
+ if (!efp)
+ return NULL;
+
+ freesquash();
+ ee.e_flags = EXPORT_DEFAULT_FLAGS;
+ ee.e_maptype = CLE_MAP_IDENT;
+ ee.e_anonuid = -2;
+ ee.e_anongid = -2;
+ ee.e_squids = NULL;
+ ee.e_sqgids = NULL;
+ ee.e_nsquids = 0;
+ ee.e_nsqgids = 0;
+
+ if (first || (ok = getexport(exp, sizeof(exp))) == 0) {
+ ok = getpath(ee.e_path, sizeof(ee.e_path));
+ if (ok <= 0)
+ return NULL;
+ strncpy (ee.m_path, ee.e_path, sizeof (ee.m_path) - 1);
+ ee.m_path [sizeof (ee.m_path) - 1] = '\0';
+ ok = getexport(exp, sizeof(exp));
+ }
+ if (ok < 0) {
+ xlog(L_ERROR, "expected client(options...)");
+ return NULL;
+ }
+ first = 0;
+
+ /* Check for default client */
+ if (ok == 0)
+ exp[0] = '\0';
+ if ((opt = strchr(exp, '(')) != NULL) {
+ *opt++ = '\0';
+ if (!(sp = strchr(opt, ')')) || sp[1] != '\0') {
+ syntaxerr("bad option list");
+ return NULL;
+ }
+ *sp = '\0';
+ if (parseopts(opt, &ee) < 0)
+ return NULL;
+ }
+ if (strlen(exp) >= sizeof(ee.e_hostname)) {
+ syntaxerr("client name too long");
+ return NULL;
+ }
+ strncpy(ee.e_hostname, exp, sizeof (ee.e_hostname) - 1);
+ ee.e_hostname[sizeof (ee.e_hostname) - 1] = '\0';
+
+ /* resolve symlinks */
+ if (realpath(ee.e_path, rpath) != NULL) {
+ rpath[sizeof (rpath) - 1] = '\0';
+ strncpy(ee.e_path, rpath, sizeof (ee.e_path) - 1);
+ ee.e_path[sizeof (ee.e_path) - 1] = '\0';
+ strncpy (ee.m_path, ee.e_path, sizeof (ee.m_path) - 1);
+ ee.m_path [sizeof (ee.m_path) - 1] = '\0';
+ }
+
+ return &ee;
+}
+
+void
+putexportent(struct exportent *ep)
+{
+ FILE *fp;
+ int *id, i;
+
+ if (!efp)
+ return;
+
+ fp = efp->x_fp;
+ fprintf(fp, "%s\t%s(", ep->e_path, ep->e_hostname);
+ fprintf(fp, "%s,", (ep->e_flags & NFSEXP_READONLY)? "ro" : "rw");
+ fprintf(fp, "%ssync,", (ep->e_flags & NFSEXP_ASYNC)? "a" : "");
+ fprintf(fp, "%swdelay,", (ep->e_flags & NFSEXP_GATHERED_WRITES)?
+ "" : "no_");
+ fprintf(fp, "%ssecure,", (ep->e_flags & NFSEXP_INSECURE_PORT)?
+ "in" : "");
+ fprintf(fp, "%sroot_squash,", (ep->e_flags & NFSEXP_ROOTSQUASH)?
+ "" : "no_");
+ fprintf(fp, "%sall_squash,", (ep->e_flags & NFSEXP_ALLSQUASH)?
+ "" : "no_");
+
+ fprintf(fp, "mapping=");
+ switch (ep->e_maptype) {
+ case CLE_MAP_IDENT:
+ fprintf(fp, "identity,");
+ break;
+ case CLE_MAP_UGIDD:
+ fprintf(fp, "ugidd,");
+ break;
+ case CLE_MAP_FILE:
+ fprintf(fp, "file,");
+ break;
+ default:
+ xlog(L_ERROR, "unknown mapping type for %s:%s",
+ ep->e_hostname, ep->e_path);
+ }
+ if ((id = ep->e_squids) != NULL) {
+ fprintf(fp, "squash_uids=");
+ for (i = 0; i < ep->e_nsquids; i += 2)
+ if (id[i] != id[i+1])
+ fprintf(fp, "%d-%d,", id[i], id[i+1]);
+ else
+ fprintf(fp, "%d,", id[i]);
+ }
+ if ((id = ep->e_sqgids) != NULL) {
+ fprintf(fp, "squash_gids=");
+ for (i = 0; i < ep->e_nsquids; i += 2)
+ if (id[i] != id[i+1])
+ fprintf(fp, "%d-%d,", id[i], id[i+1]);
+ else
+ fprintf(fp, "%d,", id[i]);
+ }
+ fprintf(fp, "anonuid=%d,anongid=%d)\n", ep->e_anonuid, ep->e_anongid);
+}
+
+void
+endexportent(void)
+{
+ if (efp)
+ xfclose(efp);
+ efp = NULL;
+ freesquash();
+}
+
+void
+dupexportent(struct exportent *dst, struct exportent *src)
+{
+ int n;
+
+ *dst = *src;
+ if ((n = src->e_nsquids) != 0) {
+ dst->e_squids = (int *) xmalloc(n * sizeof(int));
+ memcpy(dst->e_squids, src->e_squids, n * sizeof(int));
+ }
+ if ((n = src->e_nsqgids) != 0) {
+ dst->e_sqgids = (int *) xmalloc(n * sizeof(int));
+ memcpy(dst->e_sqgids, src->e_sqgids, n * sizeof(int));
+ }
+}
+
+struct exportent *
+mkexportent(char *hname, char *path, char *options)
+{
+ static struct exportent ee;
+
+ ee.e_flags = EXPORT_DEFAULT_FLAGS;
+ ee.e_maptype = CLE_MAP_IDENT;
+ ee.e_anonuid = -2;
+ ee.e_anongid = -2;
+ ee.e_squids = NULL;
+ ee.e_sqgids = NULL;
+ ee.e_nsquids = 0;
+ ee.e_nsqgids = 0;
+
+ if (strlen(hname) >= sizeof(ee.e_hostname)) {
+ xlog(L_WARNING, "client name %s too long", hname);
+ return NULL;
+ }
+ strncpy(ee.e_hostname, hname, sizeof (ee.e_hostname) - 1);
+ ee.e_hostname[sizeof (ee.e_hostname) - 1] = '\0';
+ if (strlen(path) >= sizeof(ee.e_path)) {
+ xlog(L_WARNING, "path name %s too long", path);
+ return NULL;
+ }
+ strncpy(ee.e_path, path, sizeof (ee.e_path));
+ ee.e_path[sizeof (ee.e_path) - 1] = '\0';
+ strncpy (ee.m_path, ee.e_path, sizeof (ee.m_path) - 1);
+ ee.m_path [sizeof (ee.m_path) - 1] = '\0';
+ if (options && parseopts(options, &ee) < 0)
+ return NULL;
+ return &ee;
+}
+
+int
+updateexportent(struct exportent *eep, char *options)
+{
+ if (options && parseopts(options, eep) < 0)
+ return 0;
+ return 1;
+}
+
+/*
+ * Parse option string pointed to by s and set mount options accordingly.
+ */
+static int
+parseopts(char *cp, struct exportent *ep)
+{
+ char *opt;
+
+ squids = ep->e_squids; nsquids = ep->e_nsquids;
+ sqgids = ep->e_sqgids; nsqgids = ep->e_nsqgids;
+
+ while (isblank(*cp))
+ cp++;
+ while (*cp) {
+ opt = cp;
+ while (*cp && *cp != ',')
+ cp++;
+ if (*cp)
+ *cp++ = '\0';
+
+ /* process keyword */
+ if (strcmp(opt, "ro") == 0)
+ ep->e_flags |= NFSEXP_READONLY;
+ else if (strcmp(opt, "rw") == 0)
+ ep->e_flags &= ~NFSEXP_READONLY;
+ else if (!strcmp(opt, "secure"))
+ ep->e_flags &= ~NFSEXP_INSECURE_PORT;
+ else if (!strcmp(opt, "insecure"))
+ ep->e_flags |= NFSEXP_INSECURE_PORT;
+ else if (!strcmp(opt, "sync"))
+ ep->e_flags &= ~NFSEXP_ASYNC;
+ else if (!strcmp(opt, "async"))
+ ep->e_flags |= NFSEXP_ASYNC;
+ else if (!strcmp(opt, "wdelay"))
+ ep->e_flags |= NFSEXP_GATHERED_WRITES;
+ else if (!strcmp(opt, "no_wdelay"))
+ ep->e_flags &= ~NFSEXP_GATHERED_WRITES;
+ else if (strcmp(opt, "root_squash") == 0)
+ ep->e_flags |= NFSEXP_ROOTSQUASH;
+ else if (!strcmp(opt, "no_root_squash"))
+ ep->e_flags &= ~NFSEXP_ROOTSQUASH;
+ else if (strcmp(opt, "all_squash") == 0)
+ ep->e_flags |= NFSEXP_ALLSQUASH;
+ else if (strcmp(opt, "no_all_squash") == 0)
+ ep->e_flags &= ~NFSEXP_ALLSQUASH;
+ else if (strncmp(opt, "mapping=", 8) == 0)
+ ep->e_maptype = parsemaptype(opt+8);
+ else if (strcmp(opt, "map_identity") == 0) /* old style */
+ ep->e_maptype = CLE_MAP_IDENT;
+ else if (strcmp(opt, "map_daemon") == 0) /* old style */
+ ep->e_maptype = CLE_MAP_UGIDD;
+ else if (strncmp(opt, "anonuid=", 8) == 0)
+ ep->e_anonuid = atoi(opt+8);
+ else if (strncmp(opt, "anongid=", 8) == 0)
+ ep->e_anongid = atoi(opt+8);
+ else if (strncmp(opt, "squash_uids=", 12) == 0) {
+ if (parsesquash(opt+12, &squids, &nsquids, &cp) < 0)
+ return -1;
+ } else if (strncmp(opt, "squash_gids=", 12) == 0) {
+ if (parsesquash(opt+12, &sqgids, &nsqgids, &cp) < 0)
+ return -1;
+ } else {
+ xlog(L_ERROR,
+ "Unknown keyword \"%s\" in export file\n",
+ opt);
+ ep->e_flags |= NFSEXP_ALLSQUASH | NFSEXP_READONLY;
+ return -1;
+ }
+ while (isblank(*cp))
+ cp++;
+ }
+
+ ep->e_squids = squids;
+ ep->e_sqgids = sqgids;
+ ep->e_nsquids = nsquids;
+ ep->e_nsqgids = nsqgids;
+
+ return 1;
+}
+
+static int
+parsesquash(char *list, int **idp, int *lenp, char **ep)
+{
+ char *cp = list;
+ int id0, id1;
+ int len = *lenp;
+ int *id = *idp;
+
+ if (**ep)
+ *--(*ep) = ',';
+
+ do {
+ id0 = parsenum(&cp);
+ if (*cp == '-') {
+ cp++;
+ id1 = parsenum(&cp);
+ } else {
+ id1 = id0;
+ }
+ if (id0 == -1 || id1 == -1) {
+ syntaxerr("uid/gid -1 not permitted");
+ return -1;
+ }
+ if ((len % 8) == 0)
+ id = (int *) xrealloc(id, (len + 8) * sizeof(*id));
+ id[len++] = id0;
+ id[len++] = id1;
+ if (!*cp || *cp == ')' || (*cp == ',' && !isdigit(cp[1])))
+ break;
+ if (*cp != ',') {
+ syntaxerr("bad uid/gid list");
+ return -1;
+ }
+ cp++;
+ } while(1);
+
+ if (*cp == ',') *ep = cp+1;
+
+ *lenp = len;
+ *idp = id;
+ return 1;
+}
+
+static void
+freesquash(void)
+{
+ if (squids) {
+ xfree (squids);
+ squids = NULL;
+ nsquids = 0;
+ }
+ if (sqgids) {
+ xfree (sqgids);
+ sqgids = NULL;
+ nsqgids = 0;
+ }
+}
+
+static int
+parsenum(char **cpp)
+{
+ char *cp = *cpp, c;
+ int num = 0;
+
+ if (**cpp == '-')
+ (*cpp)++;
+ while (isdigit(**cpp))
+ (*cpp)++;
+ c = **cpp; **cpp = '\0'; num = atoi(cp); **cpp = c;
+ return num;
+}
+
+static int
+parsemaptype(char *type)
+{
+ if (!strcmp(type, "identity"))
+ return CLE_MAP_IDENT;
+ if (!strcmp(type, "ugidd"))
+ return CLE_MAP_UGIDD;
+ if (!strcmp(type, "file"))
+ return CLE_MAP_FILE;
+ syntaxerr("invalid map type");
+ return CLE_MAP_IDENT; /* default */
+}
+
+static int
+getpath(char *path, int len)
+{
+ xskip(efp, " \t\n");
+ return xgettok(efp, 0, path, len);
+}
+
+static int
+getexport(char *exp, int len)
+{
+ int ok;
+
+ xskip(efp, " \t");
+ if ((ok = xgettok(efp, 0, exp, len)) < 0)
+ xlog(L_ERROR, "error parsing export entry");
+ return ok;
+}
+
+static void
+syntaxerr(char *msg)
+{
+ xlog(L_ERROR, "syntax error in exports file (line %d): %s",
+ efp->x_line, msg);
+}
+
diff --git a/support/nfs/getfh.c b/support/nfs/getfh.c
new file mode 100644
index 0000000..5a6f1a4
--- /dev/null
+++ b/support/nfs/getfh.c
@@ -0,0 +1,55 @@
+/*
+ * support/nfs/getfh.c
+ *
+ * Get the FH for a given client and directory. This function takes
+ * the NFS protocol version number as an additional argument.
+ *
+ * This function has nothing in common with the SunOS getfh function,
+ * which is a front-end to the RPC mount call.
+ *
+ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <sys/types.h>
+#include <errno.h>
+#include "nfslib.h"
+
+struct knfs_fh *
+getfh_old (struct sockaddr *addr, dev_t dev, ino_t ino)
+{
+ static union nfsctl_res res;
+ struct nfsctl_arg arg;
+
+ arg.ca_version = NFSCTL_VERSION;
+ arg.ca_getfh.gf_version = 2; /* obsolete */
+ arg.ca_getfh.gf_dev = dev;
+ arg.ca_getfh.gf_ino = ino;
+ memcpy(&arg.ca_getfh.gf_addr, addr, sizeof(struct sockaddr_in));
+
+ if (nfsctl(NFSCTL_GETFH, &arg, &res) < 0)
+ return NULL;
+
+ return &res.cr_getfh;
+}
+
+struct knfs_fh *
+getfh(struct sockaddr *addr, const char *path)
+{
+ static union nfsctl_res res;
+ struct nfsctl_arg arg;
+
+ arg.ca_version = NFSCTL_VERSION;
+ arg.ca_getfd.gd_version = 2; /* obsolete */
+ strncpy(arg.ca_getfd.gd_path, path,
+ sizeof(arg.ca_getfd.gd_path) - 1);
+ arg.ca_getfd.gd_path[sizeof (arg.ca_getfd.gd_path) - 1] = '\0';
+ memcpy(&arg.ca_getfd.gd_addr, addr, sizeof(struct sockaddr_in));
+
+ if (nfsctl(NFSCTL_GETFD, &arg, &res) < 0)
+ return NULL;
+
+ return &res.cr_getfh;
+}
diff --git a/support/nfs/keytab.c b/support/nfs/keytab.c
new file mode 100644
index 0000000..e33dded
--- /dev/null
+++ b/support/nfs/keytab.c
@@ -0,0 +1,129 @@
+/*
+ * support/nfs/keytab.c
+ *
+ * Manage the nfskeys database.
+ *
+ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <syslog.h>
+#include <ctype.h>
+#include "xmalloc.h"
+#include "nfslib.h"
+#include "exportfs.h"
+#include "xio.h"
+
+static FILE *cfp = NULL;
+
+int
+setnfskeyent(char *fname)
+{
+ if (cfp)
+ fclose(cfp);
+ if (!fname)
+ fname = _PATH_NFSKEYS;
+ cfp = fsetnfskeyent(fname, "r");
+ return cfp != NULL;
+}
+
+FILE *
+fsetnfskeyent(char *fname, char *type)
+{
+#if 0
+ FILE *fp;
+
+ if ((fp = fopen(fname, type)) == NULL)
+ xlog(L_ERROR, "can't open %s for %sing\n",
+ fname, type[0] == 'r'? "read" : "writ");
+ return fp;
+#else
+ return fopen(fname, type);
+#endif
+}
+
+struct nfskeyent *
+getnfskeyent(void)
+{
+ return fgetnfskeyent(cfp);
+}
+
+struct nfskeyent *
+fgetnfskeyent(FILE *fp)
+{
+ static struct nfskeyent ke;
+
+ if (!fp)
+ return NULL;
+
+ do {
+ if (fread(&ke, sizeof(ke), 1, fp) != 1)
+ return NULL;
+ } while(ke.k_hostname[0] == '\0');
+ return &ke;
+}
+
+void
+endnfskeyent(void)
+{
+ if (cfp)
+ fclose(cfp);
+ cfp = NULL;
+}
+
+void
+fendnfskeyent(FILE *fp)
+{
+ if (fp)
+ fclose(fp);
+}
+
+void
+fputnfskeyent(FILE *fp, struct nfskeyent *kep)
+{
+ fwrite(kep, sizeof(*kep), 1, fp);
+}
+
+int
+getnfskeytype(char *st)
+{
+ if (!strcasecmp(st, "null"))
+ return CLE_KEY_NULL;
+ if (!strcasecmp(st, "md5"))
+ return CLE_KEY_MD5;
+ if (!strcasecmp(st, "sha"))
+ return CLE_KEY_SHA;
+ return CLE_KEY_NONE;
+}
+
+char *
+getnfskeyname(int type)
+{
+ switch (type) {
+ case CLE_KEY_NONE:
+ return "none";
+ case CLE_KEY_NULL:
+ return "null";
+ case CLE_KEY_MD5:
+ return "md5";
+ case CLE_KEY_SHA:
+ return "sha";
+ }
+ return "unk";
+}
+
+int
+getnfskeysize(int type)
+{
+ switch (type) {
+ case CLE_KEY_MD5:
+ return 16;
+ case CLE_KEY_SHA:
+ return 20;
+ }
+ return 0;
+}
diff --git a/support/nfs/lockdsvc.c b/support/nfs/lockdsvc.c
new file mode 100644
index 0000000..532e721
--- /dev/null
+++ b/support/nfs/lockdsvc.c
@@ -0,0 +1,20 @@
+/*
+ * support/nfs/nfssvc.c
+ *
+ * Run an NFS daemon.
+ *
+ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include "config.h"
+
+#include "nfslib.h"
+
+int
+lockdsvc()
+{
+ struct nfsctl_arg arg;
+
+ arg.ca_version = NFSCTL_VERSION;
+ return nfsctl(LOCKDCTL_SVC, &arg, NULL);
+}
diff --git a/support/nfs/nfsclient.c b/support/nfs/nfsclient.c
new file mode 100644
index 0000000..5886484
--- /dev/null
+++ b/support/nfs/nfsclient.c
@@ -0,0 +1,32 @@
+/*
+ * support/nfs/client.c
+ *
+ * Add or delete an NFS client in knfsd.
+ *
+ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include "nfslib.h"
+
+int
+nfsaddclient(struct nfsctl_client *clp)
+{
+ struct nfsctl_arg arg;
+
+ arg.ca_version = NFSCTL_VERSION;
+ memcpy(&arg.ca_client, clp, sizeof(arg.ca_client));
+ return nfsctl(NFSCTL_ADDCLIENT, &arg, NULL);
+}
+
+int
+nfsdelclient(struct nfsctl_client *clp)
+{
+ struct nfsctl_arg arg;
+
+ arg.ca_version = NFSCTL_VERSION;
+ memcpy(&arg.ca_client, clp, sizeof(arg.ca_client));
+ return nfsctl(NFSCTL_DELCLIENT, &arg, NULL);
+}
diff --git a/support/nfs/nfsctl.c b/support/nfs/nfsctl.c
new file mode 100644
index 0000000..c04588f
--- /dev/null
+++ b/support/nfs/nfsctl.c
@@ -0,0 +1,24 @@
+/*
+ * support/nfs/nfsctl.c
+ *
+ * Central syscall to the nfsd kernel module.
+ *
+ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include "config.h"
+
+#include <unistd.h>
+#include <asm/unistd.h>
+#include "nfslib.h"
+
+/* compatibility hack... */
+#ifndef __NR_nfsctl
+#define __NR_nfsctl __NR_nfsservctl
+#endif
+
+int
+nfsctl (int cmd, struct nfsctl_arg * argp, union nfsctl_res * resp)
+{
+ return syscall (__NR_nfsctl, cmd, argp, resp);
+}
diff --git a/support/nfs/nfsexport.c b/support/nfs/nfsexport.c
new file mode 100644
index 0000000..ce8b867
--- /dev/null
+++ b/support/nfs/nfsexport.c
@@ -0,0 +1,32 @@
+/*
+ * support/nfs/export.c
+ *
+ * Add or delete an NFS export in knfsd.
+ *
+ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include "nfslib.h"
+
+int
+nfsexport(struct nfsctl_export *exp)
+{
+ struct nfsctl_arg arg;
+
+ arg.ca_version = NFSCTL_VERSION;
+ memcpy(&arg.ca_export, exp, sizeof(arg.ca_export));
+ return nfsctl(NFSCTL_EXPORT, &arg, NULL);
+}
+
+int
+nfsunexport(struct nfsctl_export *exp)
+{
+ struct nfsctl_arg arg;
+
+ arg.ca_version = NFSCTL_VERSION;
+ memcpy(&arg.ca_export, exp, sizeof(arg.ca_export));
+ return nfsctl(NFSCTL_UNEXPORT, &arg, NULL);
+}
diff --git a/support/nfs/nfssvc.c b/support/nfs/nfssvc.c
new file mode 100644
index 0000000..7419baf
--- /dev/null
+++ b/support/nfs/nfssvc.c
@@ -0,0 +1,22 @@
+/*
+ * support/nfs/nfssvc.c
+ *
+ * Run an NFS daemon.
+ *
+ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include "config.h"
+
+#include "nfslib.h"
+
+int
+nfssvc(int port, int nrservs)
+{
+ struct nfsctl_arg arg;
+
+ arg.ca_version = NFSCTL_VERSION;
+ arg.ca_svc.svc_nthreads = nrservs;
+ arg.ca_svc.svc_port = port;
+ return nfsctl(NFSCTL_SVC, &arg, NULL);
+}
diff --git a/support/nfs/rmtab.c b/support/nfs/rmtab.c
new file mode 100644
index 0000000..b9b5ff1
--- /dev/null
+++ b/support/nfs/rmtab.c
@@ -0,0 +1,122 @@
+/*
+ * support/nfs/rmtab.c
+ *
+ * Handling for rmtab.
+ *
+ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include "config.h"
+
+#include <sys/fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+#include "nfslib.h"
+
+static FILE *rmfp = NULL;
+
+int
+setrmtabent(char *type)
+{
+ if (rmfp)
+ fclose(rmfp);
+ rmfp = fsetrmtabent(_PATH_RMTAB, type);
+ return (rmfp != NULL);
+}
+
+FILE *
+fsetrmtabent(char *fname, char *type)
+{
+ int readonly = !strcmp(type, "r");
+ FILE *fp;
+
+ if (!fname)
+ return NULL;
+ if ((fp = fopen(fname, type)) == NULL) {
+ xlog(L_ERROR, "can't open %s for %sing", fname,
+ readonly ? "read" : "writ");
+ return NULL;
+ }
+ return fp;
+}
+
+struct rmtabent *
+getrmtabent(int log)
+{
+ return fgetrmtabent(rmfp, log);
+}
+
+struct rmtabent *
+fgetrmtabent(FILE *fp, int log)
+{
+ static struct rmtabent re;
+ char buf[2048], *sp;
+
+ errno = 0;
+ if (!fp)
+ return NULL;
+ do {
+ if (fgets(buf, sizeof(buf)-1, fp) == NULL)
+ return NULL;
+ if ((sp = strchr(buf, '\n')) != NULL)
+ *sp = '\0';
+ if (!(sp = strchr(buf, ':'))) {
+ if (log)
+ xlog(L_ERROR, "malformed entry in rmtab file");
+ errno = EINVAL;
+ return NULL;
+ }
+ *sp++ = '\0';
+ } while (0);
+ strncpy(re.r_client, buf, sizeof (re.r_client) - 1);
+ re.r_client[sizeof (re.r_client) - 1] = '\0';
+ strncpy(re.r_path, sp, sizeof (re.r_path) - 1);
+ re.r_path[sizeof (re.r_path) - 1] = '\0';
+ return &re;
+}
+
+void
+putrmtabent(struct rmtabent *rep)
+{
+ fputrmtabent(rmfp, rep);
+}
+
+void
+fputrmtabent(FILE *fp, struct rmtabent *rep)
+{
+ if (!fp)
+ return;
+ fprintf(fp, "%s:%s\n", rep->r_client, rep->r_path);
+}
+
+void
+endrmtabent(void)
+{
+ fendrmtabent(rmfp);
+ rmfp = NULL;
+}
+
+void
+fendrmtabent(FILE *fp)
+{
+ if (fp)
+ fclose(fp);
+}
+
+void
+rewindrmtabent(void)
+{
+ if (rmfp)
+ rewind(rmfp);
+}
+
+void
+frewindrmtabent(FILE *fp)
+{
+ if (fp)
+ rewind (fp);
+}
diff --git a/support/nfs/rpcdispatch.c b/support/nfs/rpcdispatch.c
new file mode 100644
index 0000000..e798ea5
--- /dev/null
+++ b/support/nfs/rpcdispatch.c
@@ -0,0 +1,112 @@
+/*
+ * support/nfs/rcpdispatch.c
+ *
+ * Generic RPC dispatcher.
+ *
+ * Copyright (C) 1995, 1996, Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+#include <signal.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <string.h>
+#include "rpcmisc.h"
+#include "xlog.h"
+
+void
+rpc_dispatch(struct svc_req *rqstp, SVCXPRT *transp,
+ struct rpc_dtable *dtable, int nvers,
+ void *argp, void *resp)
+{
+ struct rpc_dentry *dent;
+
+ if (rqstp->rq_vers > nvers) {
+ svcerr_progvers(transp, 1, nvers);
+ return;
+ }
+ dtable += (rqstp->rq_vers - 1);
+ if (rqstp->rq_proc > dtable->nproc) {
+ svcerr_noproc(transp);
+ return;
+ }
+
+ dent = dtable->entries + rqstp->rq_proc;
+
+ if (dent->func == NULL) {
+ svcerr_noproc(transp);
+ return;
+ }
+
+ memset(argp, 0, dent->xdr_arg_size);
+ memset(resp, 0, dent->xdr_res_size);
+
+ if (!svc_getargs(transp, dent->xdr_arg_fn, argp)) {
+ svcerr_decode(transp);
+ return;
+ }
+
+ if ((dent->func)(rqstp, argp, resp) && resp != 0) {
+ if (!svc_sendreply(transp, dent->xdr_res_fn, (caddr_t)resp))
+ svcerr_systemerr(transp);
+ }
+ if (!svc_freeargs(transp, dent->xdr_arg_fn, argp)) {
+ xlog(L_ERROR, "failed to free RPC arguments");
+ exit (2);
+ }
+}
+
+#if 0
+/*
+ * This is our replacement for svc_run. It turns off some signals while
+ * executing the server procedures to avoid nasty race conditions.
+ */
+void
+rpc_svcrun(fd_set *morefds, void (*func)(int fd))
+{
+ sigset_t block, current;
+ fd_set readfds;
+
+ for (;;) {
+ readfds = svc_fdset;
+ if (morefds) {
+ int i;
+
+ /* most efficient */
+ for (i = 0; i < FD_SETSIZE; i++)
+ if (FD_ISSET(i, morefds))
+ FD_SET(i, &readfs);
+ }
+ switch (select(FD_SETSIZE, &readfds, NULL, NULL, NULL)) {
+ case -1:
+ if (errno == EINTR)
+ continue;
+ xlog(L_ERROR, "svc_run: - select failed");
+ break;
+ case 0:
+ continue;
+ default:
+ if (morefds) {
+ int i;
+
+ /* most efficient */
+ for (i = 0; i < FD_SETSIZE; i++)
+ if (FD_ISSET(i, morefds) &&
+ FD_ISSET(i, &readfds))
+ func(i);
+ }
+ sigemptyset(&block);
+ sigaddset(&block, SIGALRM);
+ sigaddset(&block, SIGVTALRM);
+ sigaddset(&block, SIGIO);
+ sigprocmask(SIG_BLOCK, &block, &current);
+ svc_getreqset(&readfds);
+ sigprocmask(SIG_SETMASK, &current, NULL);
+ }
+ }
+}
+#endif
diff --git a/support/nfs/rpcmisc.c b/support/nfs/rpcmisc.c
new file mode 100644
index 0000000..7b182fd
--- /dev/null
+++ b/support/nfs/rpcmisc.c
@@ -0,0 +1,230 @@
+/*
+ * support/nfs/rpcmisc.c
+ *
+ * Miscellaneous functions for RPC startup and shutdown.
+ * This code is partially snarfed from rpcgen -s tcp -s udp,
+ * partly written by Mark Shand, Donald Becker, and Rick
+ * Sladkey. It was tweaked slightly by Olaf Kirch to be
+ * usable by both unfsd and mountd.
+ *
+ * This software may be used for any purpose provided
+ * the above copyright notice is retained. It is supplied
+ * as is, with no warranty expressed or implied.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <rpc/rpc.h>
+#include <rpc/pmap_clnt.h>
+#include <netinet/in.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <memory.h>
+#include <errno.h>
+#include <unistd.h>
+#include "nfslib.h"
+
+static void closedown(int sig);
+static int makesock(int port, int proto, int socksz);
+
+#define _RPCSVC_CLOSEDOWN 120
+int _rpcpmstart = 0;
+int _rpcfdtype = 0;
+int _rpcsvcdirty = 0;
+
+void
+rpc_init(char *name, int prog, int vers, void (*dispatch)(), int defport,
+ int bufsiz)
+{
+ struct sockaddr_in saddr;
+ SVCXPRT *transp;
+ int sock;
+ int asize;
+
+ asize = sizeof(saddr);
+ sock = 0;
+ _rpcfdtype = 0;
+ if (getsockname(0, (struct sockaddr *) &saddr, &asize) == 0) {
+ int ssize = sizeof (int);
+ if (saddr.sin_family != AF_INET)
+ xlog(L_FATAL, "init: stdin is bound to non-inet addr");
+ if (getsockopt(0, SOL_SOCKET, SO_TYPE,
+ (char *)&_rpcfdtype, &ssize) == -1)
+ xlog(L_FATAL, "getsockopt failed: %s", strerror(errno));
+ _rpcpmstart = 1;
+ } else {
+ pmap_unset(prog, vers);
+ sock = RPC_ANYSOCK;
+ }
+
+ if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_DGRAM)) {
+ if (_rpcfdtype == 0 && defport != 0 &&
+ ((sock = makesock(defport, IPPROTO_UDP, bufsiz)) < 0)) {
+ xlog(L_FATAL, "%s: could not make a UDP socket\n",
+ name);
+ }
+ transp = svcudp_create(sock);
+ if (transp == NULL) {
+ xlog(L_FATAL, "cannot create udp service.");
+ }
+ if (!svc_register(transp, prog, vers, dispatch, IPPROTO_UDP)) {
+ xlog(L_FATAL, "unable to register (%s, %d, udp).",
+ name, vers);
+ }
+ }
+
+ if ((_rpcfdtype == 0) || (_rpcfdtype == SOCK_STREAM)) {
+ if (_rpcfdtype == 0 && defport != 0 &&
+ ((sock = makesock(defport, IPPROTO_TCP, bufsiz)) < 0)) {
+ xlog(L_FATAL, "%s: could not make a TCP socket\n",
+ name);
+ }
+ transp = svctcp_create(sock, 0, 0);
+ if (transp == NULL) {
+ xlog(L_FATAL, "cannot create tcp service.");
+ }
+ if (!svc_register(transp, prog, vers, dispatch, IPPROTO_TCP)) {
+ xlog(L_FATAL, "unable to register (%s, %d, tcp).",
+ name, vers);
+ }
+ }
+
+ if (_rpcpmstart) {
+ signal (SIGALRM, closedown);
+ alarm (_RPCSVC_CLOSEDOWN);
+ }
+}
+
+static void closedown(sig)
+int sig;
+{
+ (void) signal(sig, closedown);
+ if (_rpcsvcdirty == 0) {
+ extern fd_set svc_fdset;
+ static int size;
+ int i, openfd;
+
+ if (_rpcfdtype == SOCK_DGRAM)
+ exit(0);
+ if (size == 0) {
+ size = getdtablesize();
+ }
+ for (i = 0, openfd = 0; i < size && openfd < 2; i++)
+ if (FD_ISSET(i, &svc_fdset))
+ openfd++;
+ if (openfd <= 1)
+ exit(0);
+ }
+ (void) alarm(_RPCSVC_CLOSEDOWN);
+}
+
+static int makesock(port, proto, socksz)
+int port;
+int proto;
+int socksz;
+{
+ struct sockaddr_in sin;
+ int s;
+ int sock_type;
+ int val;
+
+ sock_type = (proto == IPPROTO_UDP) ? SOCK_DGRAM : SOCK_STREAM;
+ s = socket(AF_INET, sock_type, proto);
+ if (s < 0) {
+ xlog(L_FATAL, "Could not make a socket: %s\n",
+ strerror(errno));
+ return (-1);
+ }
+ memset((char *) &sin, 0, sizeof(sin));
+ sin.sin_family = AF_INET;
+ sin.sin_addr.s_addr = INADDR_ANY;
+ sin.sin_port = htons(port);
+
+ val = 1;
+ if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)) < 0)
+ xlog(L_ERROR, "setsockopt failed: %s\n", strerror(errno));
+
+#ifdef SO_SNDBUF
+ {
+ int sblen, rblen;
+
+ /* 1024 for rpc & transport overheads */
+ sblen = rblen = socksz + 1024;
+ if (setsockopt(s, SOL_SOCKET, SO_SNDBUF, &sblen, sizeof sblen) < 0 ||
+ setsockopt(s, SOL_SOCKET, SO_RCVBUF, &rblen, sizeof rblen) < 0)
+ xlog(L_ERROR, "setsockopt failed: %s\n", strerror(errno));
+ }
+#endif /* SO_SNDBUF */
+
+ if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) == -1) {
+ xlog(L_FATAL, "Could not bind name to socket: %s\n",
+ strerror(errno));
+ return (-1);
+ }
+ return (s);
+}
+
+
+/* Log an incoming call. */
+void
+rpc_logcall(struct svc_req *rqstp, char *xname, char *arg)
+{
+ char buff[1024];
+ int buflen=sizeof(buff);
+ int len;
+ char *sp;
+ int i;
+
+ if (!xlog_enabled(D_CALL))
+ return;
+
+ sp = buff;
+ switch (rqstp->rq_cred.oa_flavor) {
+ case AUTH_NULL:
+ sprintf(sp, "NULL");
+ break;
+ case AUTH_UNIX: {
+ struct authunix_parms *unix_cred;
+ struct tm *tm;
+
+ unix_cred = (struct authunix_parms *) rqstp->rq_clntcred;
+ tm = localtime(&unix_cred->aup_time);
+ snprintf(sp, buflen, "UNIX %d/%d/%d %02d:%02d:%02d %s %d.%d",
+ tm->tm_year, tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_hour, tm->tm_min, tm->tm_sec,
+ unix_cred->aup_machname,
+ unix_cred->aup_uid,
+ unix_cred->aup_gid);
+ sp[buflen-1] = 0;
+ len = strlen(sp);
+ sp += buflen;
+ buflen -= len;
+ if ((int) unix_cred->aup_len > 0) {
+ snprintf(sp, buflen, "+%d", unix_cred->aup_gids[0]);
+ sp[buflen-1] = 0;
+ len = strlen(sp);
+ sp += buflen;
+ buflen -= len;
+ for (i = 1; i < unix_cred->aup_len; i++) {
+ snprintf(sp, buflen, ",%d",
+ unix_cred->aup_gids[i]);
+ sp[buflen-1] = 0;
+ len = strlen(sp);
+ sp += buflen;
+ buflen -= len;
+ }
+ }
+ }
+ break;
+ default:
+ sprintf(sp, "CRED %d", rqstp->rq_cred.oa_flavor);
+ }
+ xlog(D_CALL, "%s [%s]\n\t%s\n", xname, buff, arg);
+}
diff --git a/support/nfs/wildmat.c b/support/nfs/wildmat.c
new file mode 100644
index 0000000..8f7b760
--- /dev/null
+++ b/support/nfs/wildmat.c
@@ -0,0 +1,177 @@
+/* $Revision: 0.2.18.1 $
+**
+** Do shell-style pattern matching for ?, \, [], and * characters.
+** Might not be robust in face of malformed patterns; e.g., "foo[a-"
+** could cause a segmentation violation. It is 8bit clean.
+**
+** Written by Rich $alz, mirror!rs, Wed Nov 26 19:03:17 EST 1986.
+** Rich $alz is now <rsalz@osf.org>.
+** April, 1991: Replaced mutually-recursive calls with in-line code
+** for the star character.
+**
+** Special thanks to Lars Mathiesen <thorinn@diku.dk> for the ABORT code.
+** This can greatly speed up failing wildcard patterns. For example:
+** pattern: -*-*-*-*-*-*-12-*-*-*-m-*-*-*
+** text 1: -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1
+** text 2: -adobe-courier-bold-o-normal--12-120-75-75-X-70-iso8859-1
+** Text 1 matches with 51 calls, while text 2 fails with 54 calls. Without
+** the ABORT code, it takes 22310 calls to fail. Ugh. The following
+** explanation is from Lars:
+** The precondition that must be fulfilled is that DoMatch will consume
+** at least one character in text. This is true if *p is neither '*' nor
+** '\0'.) The last return has ABORT instead of FALSE to avoid quadratic
+** behaviour in cases like pattern "*a*b*c*d" with text "abcxxxxx". With
+** FALSE, each star-loop has to run to the end of the text; with ABORT
+** only the last one does.
+**
+** Once the control of one instance of DoMatch enters the star-loop, that
+** instance will return either TRUE or ABORT, and any calling instance
+** will therefore return immediately after (without calling recursively
+** again). In effect, only one star-loop is ever active. It would be
+** possible to modify the code to maintain this context explicitly,
+** eliminating all recursive calls at the cost of some complication and
+** loss of clarity (and the ABORT stuff seems to be unclear enough by
+** itself). I think it would be unwise to try to get this into a
+** released version unless you have a good test data base to try it out
+** on.
+*/
+
+#include "config.h"
+
+#include <ctype.h>
+
+#define TRUE 1
+#define FALSE 0
+#define ABORT -1
+
+
+ /* What character marks an inverted character class? */
+#define NEGATE_CLASS '^'
+ /* Is "*" a common pattern? */
+#define OPTIMIZE_JUST_STAR
+ /* Do tar(1) matching rules, which ignore a trailing slash? */
+#undef MATCH_TAR_PATTERN
+
+
+/*
+** Match text and p, return TRUE, FALSE, or ABORT.
+*/
+static int
+DoMatch(text, p)
+ register char *text;
+ register char *p;
+{
+ register int last;
+ register int matched;
+ register int reverse;
+
+ for ( ; *p; text++, p++) {
+ if (*text == '\0' && *p != '*')
+ return ABORT;
+ switch (*p) {
+ case '\\':
+ /* Literal match with following character. */
+ p++;
+ /* FALLTHROUGH */
+ default:
+ if (toupper (*text) != toupper (*p))
+ return FALSE;
+ continue;
+ case '?':
+ /* Match anything. */
+ continue;
+ case '*':
+ while (*++p == '*')
+ /* Consecutive stars act just like one. */
+ continue;
+ if (*p == '\0')
+ /* Trailing star matches everything. */
+ return TRUE;
+ while (*text)
+ if ((matched = DoMatch(text++, p)) != FALSE)
+ return matched;
+ return ABORT;
+ case '[':
+ reverse = p[1] == NEGATE_CLASS ? TRUE : FALSE;
+ if (reverse)
+ /* Inverted character class. */
+ p++;
+ matched = FALSE;
+ if (p[1] == ']' || p[1] == '-')
+ if (toupper (*++p) == toupper(*text))
+ matched = TRUE;
+ for (last = *p; *++p && *p != ']'; last = *p)
+ /* This next line requires a good C compiler. */
+ if (*p == '-' && p[1] != ']'
+ ? *text <= *++p && *text >= last
+ : toupper (*text) == toupper (*p))
+ matched = TRUE;
+ if (matched == reverse)
+ return FALSE;
+ continue;
+ }
+ }
+
+#ifdef MATCH_TAR_PATTERN
+ if (*text == '/')
+ return TRUE;
+#endif /* MATCH_TAR_ATTERN */
+ return *text == '\0';
+}
+
+
+/*
+** User-level routine. Returns TRUE or FALSE.
+*/
+int
+wildmat(text, p)
+ char *text;
+ char *p;
+{
+#ifdef OPTIMIZE_JUST_STAR
+ if (p[0] == '*' && p[1] == '\0')
+ return TRUE;
+#endif /* OPTIMIZE_JUST_STAR */
+ return DoMatch(text, p) == TRUE;
+}
+
+
+
+#if defined(TEST)
+#include <stdio.h>
+
+/* Yes, we use gets not fgets. Sue me. */
+extern char *gets();
+
+
+int
+main()
+{
+ char p[80];
+ char text[80];
+
+ printf("Wildmat tester. Enter pattern, then strings to test.\n");
+ printf("A blank line gets prompts for a new pattern; a blank pattern\n");
+ printf("exits the program.\n");
+
+ for ( ; ; ) {
+ printf("\nEnter pattern: ");
+ (void)fflush(stdout);
+ if (gets(p) == NULL || p[0] == '\0')
+ break;
+ for ( ; ; ) {
+ printf("Enter text: ");
+ (void)fflush(stdout);
+ if (gets(text) == NULL)
+ exit(0);
+ if (text[0] == '\0')
+ /* Blank line; go back and get a new pattern. */
+ break;
+ printf(" %s\n", wildmat(text, p) ? "YES" : "NO");
+ }
+ }
+
+ exit(0);
+ /* NOTREACHED */
+}
+#endif /* defined(TEST) */
diff --git a/support/nfs/xio.c b/support/nfs/xio.c
new file mode 100644
index 0000000..1bcd41b
--- /dev/null
+++ b/support/nfs/xio.c
@@ -0,0 +1,151 @@
+/*
+ * support/nfs/xio.c
+ *
+ * Simple I/O functions for the parsing of /etc/exports and /etc/nfsclients.
+ *
+ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include "config.h"
+
+#include <sys/fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <signal.h>
+#include <unistd.h>
+#include "xmalloc.h"
+#include "xlog.h"
+#include "xio.h"
+
+XFILE *
+xfopen(char *fname, char *type)
+{
+ XFILE *xfp;
+ FILE *fp;
+
+ if (!(fp = fopen(fname, type)))
+ return NULL;
+ xfp = (XFILE *) xmalloc(sizeof(*xfp));
+ xfp->x_fp = fp;
+ xfp->x_line = 0;
+
+ return xfp;
+}
+
+void
+xfclose(XFILE *xfp)
+{
+ fclose(xfp->x_fp);
+ xfree(xfp);
+}
+
+static void
+doalarm(int sig)
+{
+ return;
+}
+
+int
+xflock(char *fname, char *type)
+{
+ struct sigaction sa, oldsa;
+ int readonly = !strcmp(type, "r");
+ struct flock fl = { readonly? F_RDLCK : F_WRLCK, SEEK_SET, 0, 0, 0 };
+ int fd;
+
+ if ((fd = open(fname, readonly? O_RDONLY : O_RDWR)) < 0) {
+ xlog(L_WARNING, "could not open %s for locking", fname);
+ return -1;
+ }
+ sa.sa_handler = doalarm;
+ sa.sa_flags = 0;
+ sigemptyset(&sa.sa_mask);
+ sigaction(SIGALRM, &sa, &oldsa);
+ alarm(10);
+ if (fcntl(fd, F_SETLKW, &fl) < 0) {
+ alarm(0);
+ xlog(L_WARNING, "failed to lock %s", fname);
+ close(fd);
+ fd = 0;
+ } else {
+ alarm(0);
+ }
+ sigaction(SIGALRM, &oldsa, NULL);
+
+ return fd;
+}
+
+void
+xfunlock(int fd)
+{
+ close(fd);
+}
+
+int
+xgettok(XFILE *xfp, char sepa, char *tok, int len)
+{
+ int i = 0;
+ char c = 0;
+
+ while (i < len && (c = xgetc(xfp)) != EOF && c != sepa && !isspace(c))
+ tok[i++] = c;
+ if (c == '\n')
+ ungetc(c, xfp->x_fp);
+ if (!i)
+ return 0;
+ if (i >= len || (sepa && c != sepa))
+ return -1;
+ tok[i] = '\0';
+ return 1;
+}
+
+char
+xgetc(XFILE *xfp)
+{
+ char c = getc(xfp->x_fp);
+
+ if (c == EOF)
+ return c;
+ if (c == '\\') {
+ if ((c = getc(xfp->x_fp)) != '\n') {
+ ungetc(c, xfp->x_fp);
+ return '\\';
+ }
+ xfp->x_line++;
+ while ((c = getc(xfp->x_fp)) == ' ' || c == '\t');
+ ungetc(c, xfp->x_fp);
+ return ' ';
+ }
+ if (c == '#')
+ c = xskipcomment(xfp);
+ if (c == '\n')
+ xfp->x_line++;
+ return c;
+}
+
+void
+xungetc(char c, XFILE *xfp)
+{
+ if (c != EOF)
+ ungetc(c, xfp->x_fp);
+}
+
+void
+xskip(XFILE *xfp, char *str)
+{
+ char c;
+
+ while ((c = xgetc(xfp)) != EOF && strchr(str, c));
+ ungetc(c, xfp->x_fp);
+}
+
+char
+xskipcomment(XFILE *xfp)
+{
+ char c;
+
+ while ((c = getc(xfp->x_fp)) != EOF && c != '\n');
+ return c;
+}
diff --git a/support/nfs/xlog.c b/support/nfs/xlog.c
new file mode 100644
index 0000000..90c7e63
--- /dev/null
+++ b/support/nfs/xlog.c
@@ -0,0 +1,189 @@
+/*
+ * support/nfs/xlog.c
+ *
+ * This module handles the logging of requests.
+ *
+ * TODO: Merge the two "XXX_log() calls.
+ *
+ * Authors: Donald J. Becker, <becker@super.org>
+ * Rick Sladkey, <jrs@world.std.com>
+ * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
+ * Olaf Kirch, <okir@monad.swb.de>
+ *
+ * This software maybe be used for any purpose provided
+ * the above copyright notice is retained. It is supplied
+ * as is, with no warranty expressed or implied.
+ */
+
+#include "config.h"
+
+#include <unistd.h>
+#include <signal.h>
+#include <time.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <syslog.h>
+#include "nfslib.h"
+
+#undef VERBOSE_PRINTF
+
+static int foreground = 1; /* not a daemon initially */
+static int logging = 0; /* enable/disable DEBUG logs */
+static int logmask = 0; /* What will be logged */
+static char log_name[256]; /* name of this program */
+static int log_pid = -1; /* PID of this program */
+static FILE *log_fp = (FILE *)NULL; /* fp for the log file */
+
+static void xlog_toggle(int sig);
+static struct xlog_debugfac debugnames[] = {
+ { "general", D_GENERAL, },
+ { "call", D_CALL, },
+ { "auth", D_AUTH, },
+ { "parse", D_PARSE, },
+ { "all", D_ALL, },
+ { NULL, 0, },
+};
+
+void
+xlog_open(char *progname)
+{
+ openlog(progname, LOG_PID, LOG_DAEMON);
+ if (foreground) {
+ log_fp = stderr;
+ if (log_fp != NULL)
+ setbuf(log_fp, NULL);
+ }
+
+ strncpy(log_name, progname, sizeof (log_name) - 1);
+ log_name [sizeof (log_name) - 1] = '\0';
+ log_pid = getpid();
+
+ signal(SIGUSR1, xlog_toggle);
+ signal(SIGUSR2, xlog_toggle);
+}
+
+void
+xlog_background(void)
+{
+ foreground = 0;
+}
+
+static void
+xlog_toggle(int sig)
+{
+ unsigned int tmp, i;
+
+ if (sig == SIGUSR1) {
+ if ((logmask & D_ALL) && !logging) {
+ xlog(D_GENERAL, "turned on logging");
+ logging = 1;
+ return;
+ }
+ tmp = ~logmask;
+ logmask |= ((logmask & D_ALL) << 1) | D_GENERAL;
+ for (i = -1, tmp &= logmask; tmp; tmp >>= 1, i++)
+ if (tmp & 1)
+ xlog(D_GENERAL,
+ "turned on logging level %d", i);
+ } else {
+ xlog(D_GENERAL, "turned off logging");
+ logging = 0;
+ }
+ signal(sig, xlog_toggle);
+}
+
+void
+xlog_config(int fac, int on)
+{
+ if (on)
+ logmask |= fac;
+ else
+ logmask &= ~fac;
+ if (on)
+ logging = 1;
+}
+
+void
+xlog_sconfig(char *kind, int on)
+{
+ struct xlog_debugfac *tbl = debugnames;
+
+ while (tbl->df_name != NULL && strcasecmp(tbl->df_name, kind))
+ tbl++;
+ if (!tbl->df_name) {
+ xlog (L_WARNING, "Invalid debug facility: %s\n", kind);
+ return;
+ }
+ xlog_config(tbl->df_fac, on);
+}
+
+int
+xlog_enabled(int fac)
+{
+ return (logging && (fac & logmask));
+}
+
+
+/* Write something to the system logfile. */
+void
+xlog(int kind, const char *fmt, ...)
+{
+ char buff[1024];
+ va_list args;
+ int logged = 1, n;
+#ifdef VERBOSE_PRINTF
+ time_t now;
+ struct tm *tm;
+#endif
+
+ if (!(kind & (L_ALL)) && !(logging && (kind & logmask)))
+ return;
+
+ va_start(args, fmt);
+ vsnprintf(buff, sizeof (buff), fmt, args);
+ va_end(args);
+ buff[sizeof (buff) - 1] = 0;
+
+ if ((n = strlen(buff)) > 0 && buff[n-1] != '\n') {
+ buff[n++] = '\n'; buff[n++] = '\0';
+ }
+
+ switch (kind) {
+ case L_FATAL:
+ syslog(LOG_ERR, "%s", buff);
+ break;
+ case L_ERROR:
+ syslog(LOG_ERR, "%s", buff);
+ break;
+ case L_WARNING:
+ syslog(LOG_WARNING, "%s", buff);
+ break;
+ case L_NOTICE:
+ syslog(LOG_NOTICE, "%s", buff);
+ break;
+ default:
+ logged = 0;
+ break;
+ }
+ if (!logged || foreground) {
+ if (!logged && log_fp == NULL) {
+ syslog(LOG_DEBUG, "%s", buff);
+ } else if (log_fp != NULL) {
+#ifdef VERBOSE_PRINTF
+ time(&now);
+ tm = localtime(&now);
+ fprintf(log_fp, "%s[%d] %02d/%02d/%02d %02d:%02d %s\n",
+ log_name, log_pid,
+ tm->tm_mon + 1, tm->tm_mday,
+ tm->tm_year, tm->tm_hour, tm->tm_min,
+ buff);
+#else
+ fprintf(log_fp, "%s: %s", log_name, buff);
+#endif
+ }
+ }
+ if (kind == L_FATAL)
+ exit(1);
+}
diff --git a/support/nfs/xmalloc.c b/support/nfs/xmalloc.c
new file mode 100644
index 0000000..9523afc
--- /dev/null
+++ b/support/nfs/xmalloc.c
@@ -0,0 +1,48 @@
+/*
+ * support/nfs/xmalloc.c
+ *
+ * malloc with NULL checking.
+ *
+ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include "xmalloc.h"
+#include "xlog.h"
+
+void *
+xmalloc(size_t size)
+{
+ void *ptr;
+
+ if (!(ptr = malloc(size)))
+ xlog(L_FATAL, "malloc: out of memory");
+ return ptr;
+}
+
+void *
+xrealloc(void *ptr, size_t size)
+{
+ if (!(ptr = realloc(ptr, size)))
+ xlog(L_FATAL, "realloc: out of memory");
+ return ptr;
+}
+
+void
+xfree(void *ptr)
+{
+ free(ptr);
+}
+
+char *
+xstrdup(const char *str)
+{
+ char *ret;
+
+ if (!(ret = strdup(str)))
+ xlog(L_FATAL, "strdup: out of memory");
+ return ret;
+}
diff --git a/support/nfs/ypupdate_xdr.c b/support/nfs/ypupdate_xdr.c
new file mode 100644
index 0000000..9fe1098
--- /dev/null
+++ b/support/nfs/ypupdate_xdr.c
@@ -0,0 +1,29 @@
+/*
+ * support/nfs/ypupdate_xdr.c
+ *
+ * This file contains the XDR code for the ypupdate protocol.
+ *
+ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include "config.h"
+
+#include <ypupdate.h>
+
+bool_t
+xdr_ypupdate_args(XDR *xdrs, ypupdate_args *objp)
+{
+ return xdr_string(xdrs, &objp->mapname, MAXMAPNAMELEN) &&
+ xdr_bytes(xdrs, &objp->key.yp_buf_val,
+ &objp->key.yp_buf_len, MAXYPDATALEN) &&
+ xdr_bytes(xdrs, &objp->datum.yp_buf_val,
+ &objp->datum.yp_buf_len, MAXYPDATALEN);
+}
+
+bool_t
+xdr_ypdelete_args(XDR *xdrs, ypdelete_args *objp)
+{
+ return xdr_string(xdrs, &objp->mapname, MAXMAPNAMELEN) &&
+ xdr_bytes(xdrs, &objp->key.yp_buf_val,
+ &objp->key.yp_buf_len, MAXYPDATALEN);
+}