summaryrefslogtreecommitdiffstats
path: root/support/export
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/export
downloadnfs-utils-8b7ad01b14df1e7529b9ba8a1ea17df0d6004ef9.tar.gz
nfs-utils-8b7ad01b14df1e7529b9ba8a1ea17df0d6004ef9.tar.xz
nfs-utils-8b7ad01b14df1e7529b9ba8a1ea17df0d6004ef9.zip
Initial revision
Diffstat (limited to 'support/export')
-rw-r--r--support/export/Makefile27
-rw-r--r--support/export/client.c298
-rw-r--r--support/export/export.c259
-rw-r--r--support/export/hostname.c262
-rw-r--r--support/export/keys.c72
-rw-r--r--support/export/mount.x345
-rw-r--r--support/export/nfsctl.c105
-rw-r--r--support/export/rmtab.c79
-rw-r--r--support/export/xtab.c133
9 files changed, 1580 insertions, 0 deletions
diff --git a/support/export/Makefile b/support/export/Makefile
new file mode 100644
index 0000000..1243305
--- /dev/null
+++ b/support/export/Makefile
@@ -0,0 +1,27 @@
+#
+# libexport.a
+# Miscellaneous utility functions related to exporting and mounting
+# of NFS volumes.
+#
+
+LIBNAME = libexport.a
+SRCS = $(RPCSRCS) client.c export.c hostname.c nfsctl.c rmtab.c \
+ xtab.c
+OBJS = $(SRCS:.c=.o)
+
+RPCSRCS = mount_clnt.c mount_xdr.c
+RPCHDRS = mount.h
+
+include $(TOP)rules.mk
+
+$(RPCHDRS) $(RPCSRCS): mount.x
+ $(RM) $(RPCHDRS) $(RPCSRCS)
+ $(RPCGEN) -h -o mount.h $<
+ $(RPCGEN) -l -o mount_clnt.c $<
+ $(RPCGEN) -c -o mount_xdr.c $<
+
+clean distclean::
+ $(RM) $(RPCHDRS) $(RPCSRCS)
+
+install::
+ @:
diff --git a/support/export/client.c b/support/export/client.c
new file mode 100644
index 0000000..8c5200a
--- /dev/null
+++ b/support/export/client.c
@@ -0,0 +1,298 @@
+/*
+ * support/export/client.c
+ *
+ * Maintain list of nfsd clients.
+ *
+ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <string.h>
+#include <netdb.h>
+#include "xmalloc.h"
+#include "misc.h"
+#include "nfslib.h"
+#include "exportfs.h"
+
+/* netgroup stuff never seems to be defined in any header file. Linux is
+ * not alone in this.
+ */
+#if !defined(__GLIBC__) || __GLIBC__ < 2
+extern int innetgr(char *netgr, char *host, char *, char *);
+#endif
+static void client_init(nfs_client *clp, const char *hname,
+ struct hostent *hp);
+static int client_checkaddr(nfs_client *clp, struct in_addr addr);
+
+nfs_client *clientlist[MCL_MAXTYPES] = { NULL, };
+
+
+nfs_client *
+client_lookup(char *hname)
+{
+ nfs_client *clp = NULL;
+ int htype;
+ struct hostent *hp = NULL;
+
+ htype = client_gettype(hname);
+
+ if (htype == MCL_FQDN) {
+ hp = gethostbyname(hname);
+ if (hp == NULL || hp->h_addrtype != AF_INET) {
+ xlog(L_ERROR, "%s has non-inet addr", hname);
+ return NULL;
+ }
+ hp = hostent_dup (hp);
+ hname = (char *) hp->h_name;
+
+ for (clp = clientlist[htype]; clp; clp = clp->m_next) {
+ if (client_check(clp, hp))
+ break;
+ }
+ } else {
+ for (clp = clientlist[htype]; clp; clp = clp->m_next) {
+ if (strcmp(hname, clp->m_hostname)==0)
+ break;
+ }
+ }
+
+ if (!clp) {
+ clp = (nfs_client *) xmalloc(sizeof(*clp));
+ memset(clp, 0, sizeof(*clp));
+ clp->m_type = htype;
+ client_init(clp, hname, NULL);
+ client_add(clp);
+ }
+
+ if (htype == MCL_FQDN && clp->m_naddr == 0 && hp != NULL) {
+ char **ap = hp->h_addr_list;
+ int i;
+
+ for (i = 0; *ap && i < NFSCLNT_ADDRMAX; i++, ap++)
+ clp->m_addrlist[i] = *(struct in_addr *)*ap;
+ clp->m_naddr = i;
+ }
+
+ if (hp)
+ free (hp);
+
+ return clp;
+}
+
+nfs_client *
+client_dup(nfs_client *clp, struct hostent *hp)
+{
+ nfs_client *new;
+
+ new = (nfs_client *) xmalloc(sizeof(*new));
+ memcpy(new, clp, sizeof(*new));
+ new->m_type = MCL_FQDN;
+
+ client_init(new, (char *) hp->h_name, hp);
+ client_add(new);
+ return new;
+}
+
+static void
+client_init(nfs_client *clp, const char *hname, struct hostent *hp)
+{
+ if (hp) {
+ strncpy(clp->m_hostname, hp->h_name,
+ sizeof (clp->m_hostname) - 1);
+ } else {
+ strncpy(clp->m_hostname, hname,
+ sizeof (clp->m_hostname) - 1);
+ }
+ clp->m_hostname[sizeof (clp->m_hostname) - 1] = '\0';
+
+ clp->m_exported = 0;
+ clp->m_count = 0;
+
+ if (clp->m_type == MCL_SUBNETWORK) {
+ char *cp = strchr(clp->m_hostname, '/');
+
+ *cp = '\0';
+ clp->m_addrlist[0].s_addr = inet_addr(clp->m_hostname);
+ clp->m_addrlist[1].s_addr = inet_addr(cp+1);
+ *cp = '/';
+ clp->m_naddr = 0;
+ } else if (!hp) {
+ clp->m_naddr = 0;
+ } else {
+ char **ap = hp->h_addr_list;
+ int i;
+
+ for (i = 0; *ap && i < NFSCLNT_ADDRMAX; i++, ap++) {
+ clp->m_addrlist[i] = *(struct in_addr *)*ap;
+ }
+ clp->m_naddr = i;
+ }
+}
+
+void
+client_add(nfs_client *clp)
+{
+ nfs_client **cpp;
+
+ if (clp->m_type < 0 || clp->m_type >= MCL_MAXTYPES)
+ xlog(L_FATAL, "unknown client type in client_add");
+ cpp = clientlist + clp->m_type;
+ while (*cpp)
+ cpp = &((*cpp)->m_next);
+ clp->m_next = NULL;
+ *cpp = clp;
+}
+
+void
+client_release(nfs_client *clp)
+{
+ if (clp->m_count <= 0)
+ xlog(L_FATAL, "client_free: m_count <= 0!");
+ clp->m_count--;
+}
+
+void
+client_freeall(void)
+{
+ nfs_client *clp, **head;
+ int i;
+
+ for (i = 0; i < MCL_MAXTYPES; i++) {
+ head = clientlist + i;
+ while (*head) {
+ *head = (clp = *head)->m_next;
+ xfree(clp);
+ }
+ }
+}
+
+nfs_client *
+client_find(struct hostent *hp)
+{
+ nfs_client *clp;
+ int i;
+
+ for (i = 0; i < MCL_MAXTYPES; i++) {
+ for (clp = clientlist[i]; clp; clp = clp->m_next) {
+ if (!client_check(clp, hp))
+ continue;
+#ifdef notdef
+ if (clp->m_type == MCL_FQDN)
+ return clp;
+ return client_dup(clp, hp);
+#else
+ return clp;
+#endif
+ }
+ }
+ return NULL;
+}
+
+/*
+ * Match a host (given its hostent record) to a client record. This
+ * is usually called from mountd.
+ */
+int
+client_check(nfs_client *clp, struct hostent *hp)
+{
+ char *hname = (char *) hp->h_name;
+ char *cname = clp->m_hostname;
+ char **ap;
+
+ switch (clp->m_type) {
+ case MCL_FQDN:
+ case MCL_SUBNETWORK:
+ for (ap = hp->h_addr_list; *ap; ap++) {
+ if (client_checkaddr(clp, *(struct in_addr *) *ap))
+ return 1;
+ }
+ return 0;
+ case MCL_WILDCARD:
+ if (wildmat(hname, cname))
+ return 1;
+ else {
+ for (ap = hp->h_aliases; *ap; ap++)
+ if (wildmat(*ap, cname))
+ return 1;
+ }
+ return 0;
+ case MCL_NETGROUP:
+#ifdef HAVE_INNETGR
+ {
+ char *dot;
+ int match;
+
+ /* First, try to match the hostname without
+ * splitting off the domain */
+ if (innetgr(cname+1, hname, NULL, NULL))
+ return 1;
+
+ /* Okay, strip off the domain (if we have one) */
+ if ((dot = strchr(hname, '.')) == NULL)
+ return 0;
+
+ *dot = '\0';
+ match = innetgr(cname+1, hname, NULL, dot + 1);
+ *dot = '.';
+
+ return match;
+ }
+#else
+ return 0;
+#endif
+ case MCL_ANONYMOUS:
+ return 1;
+ default:
+ xlog(L_FATAL, "internal: bad client type %d", clp->m_type);
+ }
+
+ return 0;
+}
+
+static int
+client_checkaddr(nfs_client *clp, struct in_addr addr)
+{
+ int i;
+
+ switch (clp->m_type) {
+ case MCL_FQDN:
+ for (i = 0; i < clp->m_naddr; i++) {
+ if (clp->m_addrlist[i].s_addr == addr.s_addr)
+ return 1;
+ }
+ return 0;
+ case MCL_SUBNETWORK:
+ return !((clp->m_addrlist[0].s_addr ^ addr.s_addr)
+ & clp->m_addrlist[1].s_addr);
+ }
+ return 0;
+}
+
+int
+client_gettype(char *ident)
+{
+ char *sp;
+
+ if (ident[0] == '\0')
+ return MCL_ANONYMOUS;
+ if (ident[0] == '@') {
+#ifndef HAVE_INNETGR
+ xlog(L_WARNING, "netgroup support not compiled in");
+#endif
+ return MCL_NETGROUP;
+ }
+ for (sp = ident; *sp; sp++) {
+ if (*sp == '*' || *sp == '?' || *sp == '[')
+ return MCL_WILDCARD;
+ if (*sp == '/')
+ return MCL_SUBNETWORK;
+ if (*sp == '\\' && sp[1])
+ sp++;
+ }
+ return MCL_FQDN;
+}
diff --git a/support/export/export.c b/support/export/export.c
new file mode 100644
index 0000000..09efaa8
--- /dev/null
+++ b/support/export/export.c
@@ -0,0 +1,259 @@
+/*
+ * support/export/export.c
+ *
+ * Maintain list of exported file systems.
+ *
+ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include "xmalloc.h"
+#include "nfslib.h"
+#include "exportfs.h"
+
+nfs_export *exportlist[MCL_MAXTYPES] = { NULL, };
+
+static void export_init(nfs_export *exp, nfs_client *clp,
+ struct exportent *nep);
+static int export_check(nfs_export *, struct hostent *, char *);
+static nfs_export *
+ export_allowed_internal(struct hostent *hp, char *path);
+
+int
+export_read(char *fname)
+{
+ struct exportent *eep;
+ nfs_export *exp;
+
+ setexportent(fname, "r");
+ while ((eep = getexportent()) != NULL) {
+ exp = export_lookup(eep->e_hostname, eep->e_path);
+ if (!exp)
+ export_create(eep);
+ else {
+ if (exp->m_export.e_flags != eep->e_flags) {
+ xlog(L_ERROR, "incompatible dupilcated export entries:");
+ xlog(L_ERROR, "\t%s:%s (0x%x) [IGNORED]", eep->e_hostname,
+ eep->e_path, eep->e_flags);
+ xlog(L_ERROR, "\t%s:%s (0x%x)", exp->m_export.e_hostname,
+ exp->m_export.e_path, exp->m_export.e_flags);
+ }
+ else {
+ xlog(L_ERROR, "dupilcated export entries:");
+ xlog(L_ERROR, "\t%s:%s", eep->e_hostname, eep->e_path);
+ xlog(L_ERROR, "\t%s:%s", exp->m_export.e_hostname,
+ exp->m_export.e_path);
+ }
+ }
+ }
+ endexportent();
+
+ return 0;
+}
+
+/*
+ * Create an in-core export struct from an export entry.
+ */
+nfs_export *
+export_create(struct exportent *xep)
+{
+ nfs_client *clp;
+ nfs_export *exp;
+
+ if (!(clp = client_lookup(xep->e_hostname))) {
+ /* bad export entry; complaint already logged */
+ return NULL;
+ }
+ exp = (nfs_export *) xmalloc(sizeof(*exp));
+ export_init(exp, clp, xep);
+ export_add(exp);
+
+ return exp;
+}
+
+static void
+export_init(nfs_export *exp, nfs_client *clp, struct exportent *nep)
+{
+ struct exportent *e = &exp->m_export;
+
+ dupexportent(e, nep);
+
+ exp->m_exported = 0;
+ exp->m_xtabent = 0;
+ exp->m_mayexport = 0;
+ exp->m_changed = 0;
+ exp->m_client = clp;
+ clp->m_count++;
+}
+
+/*
+ * Duplicate exports data. The in-core export struct retains the
+ * original hostname from /etc/exports, while the in-core client struct
+ * gets the newly found FQDN.
+ */
+nfs_export *
+export_dup(nfs_export *exp, struct hostent *hp)
+{
+ nfs_export *new;
+ nfs_client *clp;
+
+ new = (nfs_export *) xmalloc(sizeof(*new));
+ memcpy(new, exp, sizeof(*new));
+ dupexportent(&new->m_export, &exp->m_export);
+ clp = client_dup(exp->m_client, hp);
+ clp->m_count++;
+ new->m_client = clp;
+ new->m_mayexport = exp->m_mayexport;
+ new->m_exported = 0;
+ new->m_xtabent = 0;
+ new->m_changed = 0;
+ export_add(new);
+
+ return new;
+}
+
+void
+export_add(nfs_export *exp)
+{
+ nfs_export **epp;
+ int type = exp->m_client->m_type;
+ int slen = strlen(exp->m_export.e_path);
+
+ if (type < 0 || type >= MCL_MAXTYPES)
+ xlog(L_FATAL, "unknown client type in export_add");
+
+ epp = exportlist + type;
+ while (*epp && slen < strlen((*epp)->m_export.e_path))
+ epp = &((*epp)->m_next);
+ exp->m_next = *epp;
+ *epp = exp;
+}
+
+nfs_export *
+export_find(struct hostent *hp, char *path)
+{
+ nfs_export *exp;
+ int i;
+
+ for (i = 0; i < MCL_MAXTYPES; i++) {
+ for (exp = exportlist[i]; exp; exp = exp->m_next) {
+ if (!export_check(exp, hp, path))
+ continue;
+ if (exp->m_client->m_type == MCL_FQDN)
+ return exp;
+ return export_dup(exp, hp);
+ }
+ }
+
+ return NULL;
+}
+
+static nfs_export *
+export_allowed_internal (struct hostent *hp, char *path)
+{
+ nfs_export *exp;
+ int i;
+
+ for (i = 0; i < MCL_MAXTYPES; i++) {
+ for (exp = exportlist[i]; exp; exp = exp->m_next) {
+ if (!exp->m_mayexport ||
+ !export_check(exp, hp, path))
+ continue;
+ return exp;
+ }
+ }
+
+ return NULL;
+}
+
+struct exportent *
+export_allowed(struct hostent *hp, char *path)
+{
+ static struct exportent ee;
+ nfs_export *exp;
+ char epath[MAXPATHLEN+1];
+ char *p = NULL;
+
+ if (path [0] != '/') return NULL;
+
+ strncpy(epath, path, sizeof (epath) - 1);
+ epath[sizeof (epath) - 1] = '\0';
+
+ /* Try the longest matching exported pathname. */
+ while (1) {
+ exp = export_allowed_internal (hp, epath);
+ if (exp) {
+ dupexportent(&ee, &exp->m_export);
+ return &ee;
+ }
+ /* We have to treat the root, "/", specially. */
+ if (p == &epath[1]) break;
+ p = strrchr(epath, '/');
+ if (p == epath) p++;
+ *p = '\0';
+ }
+
+ return NULL;
+}
+
+nfs_export *
+export_lookup(char *hname, char *path)
+{
+ nfs_client *clp;
+ nfs_export *exp;
+
+ if (!(clp = client_lookup(hname)))
+ return NULL;
+ for (exp = exportlist[clp->m_type]; exp; exp = exp->m_next)
+ if (exp->m_client == clp && !strcmp(exp->m_export.e_path, path))
+ return exp;
+ return NULL;
+}
+
+static int
+export_check(nfs_export *exp, struct hostent *hp, char *path)
+{
+ if (strcmp(path, exp->m_export.e_path))
+ return 0;
+
+ return client_check(exp->m_client, hp);
+}
+
+void
+export_freeall(void)
+{
+ nfs_export *exp, *nxt;
+ int i;
+
+ for (i = 0; i < MCL_MAXTYPES; i++) {
+ for (exp = exportlist[i]; exp; exp = nxt) {
+ nxt = exp->m_next;
+ client_release(exp->m_client);
+ if (exp->m_export.e_squids)
+ xfree(exp->m_export.e_squids);
+ if (exp->m_export.e_sqgids)
+ xfree(exp->m_export.e_sqgids);
+ xfree(exp);
+ }
+ exportlist[i] = NULL;
+ }
+ client_freeall();
+}
+
+void
+export_reset(nfs_export *exp)
+{
+ if (!exp)
+ return;
+
+ /* Restore m_path. */
+ strncpy(exp->m_export.m_path, exp->m_export.e_path,
+ sizeof (exp->m_export.m_path) - 1);
+ exp->m_export.m_path[sizeof (exp->m_export.m_path) - 1] = '\0';
+}
diff --git a/support/export/hostname.c b/support/export/hostname.c
new file mode 100644
index 0000000..a37d4de
--- /dev/null
+++ b/support/export/hostname.c
@@ -0,0 +1,262 @@
+/*
+ * support/export/hostname.c
+ *
+ * Functions for hostname.
+ *
+ */
+
+#include "config.h"
+
+/*
+#define TEST
+*/
+
+#include <string.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#ifdef TEST
+#define xmalloc malloc
+#else
+#include "xmalloc.h"
+#include "misc.h"
+#endif
+
+#define ALIGNMENT sizeof (char *)
+
+static int
+align (int len, int al)
+{
+ int i;
+ i = len % al;
+ if (i)
+ len += al - i;
+ return len;
+}
+
+struct hostent *
+get_hostent (const char *addr, int len, int type)
+{
+ struct hostent *cp;
+ int len_ent;
+ const char *name;
+ int len_name;
+ int num_aliases = 1;
+ int len_aliases = sizeof (char *);
+ int num_addr_list = 1;
+ int len_addr_list = sizeof (char *);
+ int pos;
+ struct in_addr *ipv4;
+
+ switch (type)
+ {
+ case AF_INET:
+ ipv4 = (struct in_addr *) addr;
+ name = inet_ntoa (*ipv4);
+ break;
+
+ default:
+ return NULL;
+ }
+
+ len_ent = align (sizeof (*cp), ALIGNMENT);
+ len_name = align (strlen (name) + 1, ALIGNMENT);
+
+ num_addr_list++;
+ len_addr_list += align (len, ALIGNMENT) + sizeof (char *);
+
+ cp = (struct hostent *) xmalloc (len_ent + len_name + len_aliases
+ + len_addr_list);
+
+ cp->h_addrtype = type;
+ cp->h_length = len;
+ pos = len_ent;
+ cp->h_name = (char *) &(((char *) cp) [pos]);
+ strcpy (cp->h_name, name);
+
+ pos += len_name;
+ cp->h_aliases = (char **) &(((char *) cp) [pos]);
+ pos += num_aliases * sizeof (char *);
+ cp->h_aliases [0] = NULL;
+
+ pos = len_ent + len_name + len_aliases;
+ cp->h_addr_list = (char **) &(((char *) cp) [pos]);
+ pos += num_addr_list * sizeof (char *);
+ cp->h_addr_list [0] = (char *) &(((char *) cp) [pos]);
+ memcpy (cp->h_addr_list [0], addr, cp->h_length);
+ pos += align (cp->h_length, ALIGNMENT);
+ cp->h_addr_list [1] = NULL;
+
+ return cp;
+}
+
+struct hostent *
+hostent_dup (struct hostent *hp)
+{
+ int len_ent = align (sizeof (*hp), ALIGNMENT);
+ int len_name = align (strlen (hp->h_name) + 1, ALIGNMENT);
+ int num_aliases = 1;
+ int len_aliases = sizeof (char *);
+ int num_addr_list = 1;
+ int len_addr_list = sizeof (char *);
+ int pos, i;
+ char **sp;
+ struct hostent *cp;
+
+ for (sp = hp->h_aliases; *sp; sp++)
+ {
+ num_aliases++;
+ len_aliases += align (strlen (*sp) + 1, ALIGNMENT)
+ + sizeof (char *);
+ }
+
+ for (sp = hp->h_addr_list; *sp; sp++)
+ {
+ num_addr_list++;
+ len_addr_list += align (hp->h_length, ALIGNMENT)
+ + sizeof (char *);
+ }
+
+ cp = (struct hostent *) xmalloc (len_ent + len_name + len_aliases
+ + len_addr_list);
+
+ *cp = *hp;
+ pos = len_ent;
+ cp->h_name = (char *) &(((char *) cp) [pos]);
+ strcpy (cp->h_name, hp->h_name);
+
+ pos += len_name;
+ cp->h_aliases = (char **) &(((char *) cp) [pos]);
+ pos += num_aliases * sizeof (char *);
+ for (sp = hp->h_aliases, i = 0; i < num_aliases; i++, sp++)
+ if (*sp)
+ {
+ cp->h_aliases [i] = (char *) &(((char *) cp) [pos]);
+ strcpy (cp->h_aliases [i], *sp);
+ pos += align (strlen (*sp) + 1, ALIGNMENT);
+ }
+ else
+ cp->h_aliases [i] = *sp;
+
+ pos = len_ent + len_name + len_aliases;
+ cp->h_addr_list = (char **) &(((char *) cp) [pos]);
+ pos += num_addr_list * sizeof (char *);
+ for (sp = hp->h_addr_list, i = 0; i < num_addr_list; i++, sp++)
+ if (*sp)
+ {
+ cp->h_addr_list [i] = (char *) &(((char *) cp) [pos]);
+ memcpy (cp->h_addr_list [i], *sp, hp->h_length);
+ pos += align (hp->h_length, ALIGNMENT);
+ }
+ else
+ cp->h_addr_list [i] = *sp;
+
+ return cp;
+}
+
+static int
+is_hostname(const char *sp)
+{
+ if (*sp == '\0' || *sp == '@')
+ return 0;
+
+ for (; *sp; sp++)
+ {
+ if (*sp == '*' || *sp == '?' || *sp == '[' || *sp == '/')
+ return 0;
+ if (*sp == '\\' && sp[1])
+ sp++;
+ }
+
+ return 1;
+}
+
+int
+matchhostname (const char *h1, const char *h2)
+{
+ struct hostent *hp1, *hp2;
+ int status;
+
+ if (strcasecmp (h1, h2) == 0)
+ return 1;
+
+ if (!is_hostname (h1) || !is_hostname (h2))
+ return 0;
+
+ hp1 = gethostbyname (h1);
+ if (hp1 == NULL)
+ return 0;
+
+ hp1 = hostent_dup (hp1);
+
+ hp2 = gethostbyname (h2);
+ if (hp2)
+ {
+ if (strcasecmp (hp1->h_name, hp2->h_name) == 0)
+ status = 1;
+ else
+ {
+ char **ap1, **ap2;
+
+ status = 0;
+ for (ap1 = hp1->h_addr_list; *ap1 && status == 0; ap1++)
+ for (ap2 = hp2->h_addr_list; *ap2; ap2++)
+ if (memcmp (*ap1, *ap2, sizeof (struct in_addr)) == 0)
+ {
+ status = 1;
+ break;
+ }
+ }
+ }
+ else
+ status = 0;
+
+ free (hp1);
+ return status;
+}
+
+#ifdef TEST
+void
+print_host (struct hostent *hp)
+{
+ char **sp;
+
+ if (hp)
+ {
+ printf ("official hostname: %s\n", hp->h_name);
+ printf ("aliases:\n");
+ for (sp = hp->h_aliases; *sp; sp++)
+ printf (" %s\n", *sp);
+ printf ("IP addresses:\n");
+ for (sp = hp->h_addr_list; *sp; sp++)
+ printf (" %s\n", inet_ntoa (*(struct in_addr *) *sp));
+ }
+ else
+ printf ("Not host information\n");
+}
+
+int
+main (int argc, char **argv)
+{
+ struct hostent *hp = gethostbyname (argv [1]);
+ struct hostent *cp;
+ struct in_addr addr;
+
+ print_host (hp);
+
+ if (hp)
+ {
+ cp = hostent_dup (hp);
+ print_host (cp);
+ free (cp);
+ }
+ printf ("127.0.0.1 == %s: %d\n", argv [1],
+ matchhostname ("127.0.0.1", argv [1]));
+ addr.s_addr = inet_addr(argv [2]);
+ printf ("%s\n", inet_ntoa (addr));
+ cp = get_hostent ((const char *)&addr, sizeof(addr), AF_INET);
+ print_host (cp);
+ return 0;
+}
+#endif
diff --git a/support/export/keys.c b/support/export/keys.c
new file mode 100644
index 0000000..4814808
--- /dev/null
+++ b/support/export/keys.c
@@ -0,0 +1,72 @@
+/*
+ * keys.c Key management for nfsd. Currently, keys
+ * are kept in a single file only, but eventually,
+ * support for a key server should be added.
+ *
+ * Copyright (C) 1995 Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include "config.h"
+
+#include <sys/stat.h>
+#include "nfslib.h"
+#include "exportfs.h"
+#include "xmalloc.h"
+
+struct keycache {
+ struct keycache * k_next;
+ struct nfskeyent k_data;
+};
+
+static struct keycache * keycache = NULL;
+static time_t lastmod = 0;
+
+static void key_reload(void);
+
+
+struct nfskey *
+key_lookup(char *hname)
+{
+ struct keycache *kc;
+
+ key_reload();
+
+ for (kc = keycache; kc; kc = kc->k_next) {
+#if 0
+ if (matchhostname(kc->k_data.k_hostname, hname))
+#else
+ if (!strcmp(kc->k_data.k_hostname, hname))
+#endif
+ return &kc->k_data.k_key;
+ }
+
+ return NULL;
+}
+
+static void
+key_reload(void)
+{
+ struct stat stb;
+ struct keycache *cp;
+ struct nfskeyent *kp;
+
+ if (stat(_PATH_NFSKEYS, &stb) >= 0 && stb.st_mtime == lastmod)
+ return;
+
+ while (keycache) {
+ cp = keycache->k_next;
+ xfree(keycache);
+ keycache = cp;
+ }
+
+ setnfskeyent(_PATH_NFSKEYS);
+ while ((kp = getnfskeyent()) != NULL) {
+ cp = (struct keycache *) xmalloc(sizeof(*cp));
+ cp->k_data = *kp;
+ cp->k_next = keycache;
+ keycache = cp;
+ }
+ endnfskeyent();
+
+ lastmod = stb.st_mtime;
+}
diff --git a/support/export/mount.x b/support/export/mount.x
new file mode 100644
index 0000000..f504e7c
--- /dev/null
+++ b/support/export/mount.x
@@ -0,0 +1,345 @@
+%/*
+% * Sun RPC is a product of Sun Microsystems, Inc. and is provided for
+% * unrestricted use provided that this legend is included on all tape
+% * media and as a part of the software program in whole or part. Users
+% * may copy or modify Sun RPC without charge, but are not authorized
+% * to license or distribute it to anyone else except as part of a product or
+% * program developed by the user or with the express written consent of
+% * Sun Microsystems, Inc.
+% *
+% * SUN RPC IS PROVIDED AS IS WITH NO WARRANTIES OF ANY KIND INCLUDING THE
+% * WARRANTIES OF DESIGN, MERCHANTIBILITY AND FITNESS FOR A PARTICULAR
+% * PURPOSE, OR ARISING FROM A COURSE OF DEALING, USAGE OR TRADE PRACTICE.
+% *
+% * Sun RPC is provided with no support and without any obligation on the
+% * part of Sun Microsystems, Inc. to assist in its use, correction,
+% * modification or enhancement.
+% *
+% * SUN MICROSYSTEMS, INC. SHALL HAVE NO LIABILITY WITH RESPECT TO THE
+% * INFRINGEMENT OF COPYRIGHTS, TRADE SECRETS OR ANY PATENTS BY SUN RPC
+% * OR ANY PART THEREOF.
+% *
+% * In no event will Sun Microsystems, Inc. be liable for any lost revenue
+% * or profits or other special, indirect and consequential damages, even if
+% * Sun has been advised of the possibility of such damages.
+% *
+% * Sun Microsystems, Inc.
+% * 2550 Garcia Avenue
+% * Mountain View, California 94043
+% */
+
+%/*
+% * Copyright (c) 1985, 1990 by Sun Microsystems, Inc.
+% */
+%
+%/* from @(#)mount.x 1.3 91/03/11 TIRPC 1.0 */
+
+/*
+ * Protocol description for the mount program
+ */
+
+#ifdef RPC_HDR
+%#ifndef _rpcsvc_mount_h
+%#define _rpcsvc_mount_h
+%#include <memory.h>
+#endif
+
+const MNTPATHLEN = 1024; /* maximum bytes in a pathname argument */
+const MNTNAMLEN = 255; /* maximum bytes in a name argument */
+const FHSIZE = 32; /* size in bytes of a file handle */
+
+/*
+ * The fhandle is the file handle that the server passes to the client.
+ * All file operations are done using the file handles to refer to a file
+ * or a directory. The file handle can contain whatever information the
+ * server needs to distinguish an individual file.
+ */
+typedef opaque fhandle[FHSIZE];
+
+/*
+ * If a status of zero is returned, the call completed successfully, and
+ * a file handle for the directory follows. A non-zero status indicates
+ * some sort of error. The status corresponds with UNIX error numbers.
+ */
+union fhstatus switch (unsigned fhs_status) {
+case 0:
+ fhandle fhs_fhandle;
+default:
+ void;
+};
+
+/*
+ * The type dirpath is the pathname of a directory
+ */
+typedef string dirpath<MNTPATHLEN>;
+
+/*
+ * The type name is used for arbitrary names (hostnames, groupnames)
+ */
+typedef string name<MNTNAMLEN>;
+
+/*
+ * A list of who has what mounted
+ */
+typedef struct mountbody *mountlist;
+struct mountbody {
+ name ml_hostname;
+ dirpath ml_directory;
+ mountlist ml_next;
+};
+
+/*
+ * A list of netgroups
+ */
+typedef struct groupnode *groups;
+struct groupnode {
+ name gr_name;
+ groups gr_next;
+};
+
+/*
+ * A list of what is exported and to whom
+ */
+typedef struct exportnode *exports;
+struct exportnode {
+ dirpath ex_dir;
+ groups ex_groups;
+ exports ex_next;
+};
+
+/*
+ * POSIX pathconf information
+ */
+struct ppathcnf {
+ int pc_link_max; /* max links allowed */
+ short pc_max_canon; /* max line len for a tty */
+ short pc_max_input; /* input a tty can eat all at once */
+ short pc_name_max; /* max file name length (dir entry) */
+ short pc_path_max; /* max path name length (/x/y/x/.. ) */
+ short pc_pipe_buf; /* size of a pipe (bytes) */
+ u_char pc_vdisable; /* safe char to turn off c_cc[i] */
+ char pc_xxx; /* alignment padding; cc_t == char */
+ short pc_mask[2]; /* validity and boolean bits */
+};
+
+/*
+ * NFSv3 file handle
+ */
+const FHSIZE3 = 64; /* max size of NFSv3 file handle in bytes */
+typedef opaque fhandle3<FHSIZE3>;
+
+/*
+ * NFSv3 mount status
+ */
+enum mountstat3 {
+ MNT_OK = 0, /* no error */
+ MNT3ERR_PERM = 1, /* not owner */
+ MNT3ERR_NOENT = 2, /* no such file or directory */
+ MNT3ERR_IO = 5, /* I/O error */
+ MNT3ERR_ACCES = 13, /* Permission denied */
+ MNT3ERR_NOTDIR = 20, /* Not a directory */
+ MNT3ERR_INVAL = 22, /* Invalid argument */
+ MNT3ERR_NAMETOOLONG = 63, /* File name too long */
+ MNT3ERR_NOTSUPP = 10004,/* Operation not supported */
+ MNT3ERR_SERVERFAULT = 10006 /* A failure on the server */
+};
+
+/*
+ * NFSv3 mount result
+ */
+struct mountres3_ok {
+ fhandle3 fhandle;
+ int auth_flavors<>;
+};
+
+union mountres3 switch (mountstat3 fhs_status) {
+case MNT_OK:
+ mountres3_ok mountinfo; /* File handle and supported flavors */
+default:
+ void;
+};
+
+program MOUNTPROG {
+ /*
+ * Version one of the mount protocol communicates with version two
+ * of the NFS protocol. The only connecting point is the fhandle
+ * structure, which is the same for both protocols.
+ */
+ version MOUNTVERS {
+ /*
+ * Does no work. It is made available in all RPC services
+ * to allow server reponse testing and timing
+ */
+ void
+ MOUNTPROC_NULL(void) = 0;
+
+ /*
+ * If fhs_status is 0, then fhs_fhandle contains the
+ * file handle for the directory. This file handle may
+ * be used in the NFS protocol. This procedure also adds
+ * a new entry to the mount list for this client mounting
+ * the directory.
+ * Unix authentication required.
+ */
+ fhstatus
+ MOUNTPROC_MNT(dirpath) = 1;
+
+ /*
+ * Returns the list of remotely mounted filesystems. The
+ * mountlist contains one entry for each hostname and
+ * directory pair.
+ */
+ mountlist
+ MOUNTPROC_DUMP(void) = 2;
+
+ /*
+ * Removes the mount list entry for the directory
+ * Unix authentication required.
+ */
+ void
+ MOUNTPROC_UMNT(dirpath) = 3;
+
+ /*
+ * Removes all of the mount list entries for this client
+ * Unix authentication required.
+ */
+ void
+ MOUNTPROC_UMNTALL(void) = 4;
+
+ /*
+ * Returns a list of all the exported filesystems, and which
+ * machines are allowed to import it.
+ */
+ exports
+ MOUNTPROC_EXPORT(void) = 5;
+
+ /*
+ * Identical to MOUNTPROC_EXPORT above
+ */
+ exports
+ MOUNTPROC_EXPORTALL(void) = 6;
+ } = 1;
+
+ /*
+ * Version two of the mount protocol communicates with version two
+ * of the NFS protocol.
+ * The only difference from version one is the addition of a POSIX
+ * pathconf call.
+ */
+ version MOUNTVERS_POSIX {
+ /*
+ * Does no work. It is made available in all RPC services
+ * to allow server reponse testing and timing
+ */
+ void
+ MOUNTPROC_NULL(void) = 0;
+
+ /*
+ * If fhs_status is 0, then fhs_fhandle contains the
+ * file handle for the directory. This file handle may
+ * be used in the NFS protocol. This procedure also adds
+ * a new entry to the mount list for this client mounting
+ * the directory.
+ * Unix authentication required.
+ */
+ fhstatus
+ MOUNTPROC_MNT(dirpath) = 1;
+
+ /*
+ * Returns the list of remotely mounted filesystems. The
+ * mountlist contains one entry for each hostname and
+ * directory pair.
+ */
+ mountlist
+ MOUNTPROC_DUMP(void) = 2;
+
+ /*
+ * Removes the mount list entry for the directory
+ * Unix authentication required.
+ */
+ void
+ MOUNTPROC_UMNT(dirpath) = 3;
+
+ /*
+ * Removes all of the mount list entries for this client
+ * Unix authentication required.
+ */
+ void
+ MOUNTPROC_UMNTALL(void) = 4;
+
+ /*
+ * Returns a list of all the exported filesystems, and which
+ * machines are allowed to import it.
+ */
+ exports
+ MOUNTPROC_EXPORT(void) = 5;
+
+ /*
+ * Identical to MOUNTPROC_EXPORT above
+ */
+ exports
+ MOUNTPROC_EXPORTALL(void) = 6;
+
+ /*
+ * POSIX pathconf info (Sun hack)
+ */
+ ppathcnf
+ MOUNTPROC_PATHCONF(dirpath) = 7;
+ } = 2;
+
+ /*
+ * Version 3 of the protocol is for NFSv3
+ */
+ version MOUNTVERS_NFSV3 {
+ /*
+ * Does no work. It is made available in all RPC services
+ * to allow server reponse testing and timing
+ */
+ void
+ MOUNTPROC3_NULL(void) = 0;
+
+ /*
+ * If fhs_status is 0, then fhs_fhandle contains the
+ * file handle for the directory. This file handle may
+ * be used in the NFS protocol. This procedure also adds
+ * a new entry to the mount list for this client mounting
+ * the directory.
+ * Unix authentication required.
+ */
+ mountres3
+ MOUNTPROC3_MNT(dirpath) = 1;
+
+ /*
+ * Returns the list of remotely mounted filesystems. The
+ * mountlist contains one entry for each hostname and
+ * directory pair.
+ */
+ mountlist
+ MOUNTPROC3_DUMP(void) = 2;
+
+ /*
+ * Removes the mount list entry for the directory
+ * Unix authentication required.
+ */
+ void
+ MOUNTPROC3_UMNT(dirpath) = 3;
+
+ /*
+ * Removes all of the mount list entries for this client
+ * Unix authentication required.
+ */
+ void
+ MOUNTPROC3_UMNTALL(void) = 4;
+
+ /*
+ * Returns a list of all the exported filesystems, and which
+ * machines are allowed to import it.
+ */
+ exports
+ MOUNTPROC3_EXPORT(void) = 5;
+ } = 3;
+} = 100005;
+
+#ifdef RPC_HDR
+%#endif /*!_rpcsvc_mount_h*/
+#endif
diff --git a/support/export/nfsctl.c b/support/export/nfsctl.c
new file mode 100644
index 0000000..6612a76
--- /dev/null
+++ b/support/export/nfsctl.c
@@ -0,0 +1,105 @@
+/*
+ * support/export/nfsctl.c
+ *
+ * Communicate export information to knfsd.
+ *
+ * Copyright (C) 1995 Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include "config.h"
+
+#include <sys/stat.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "nfslib.h"
+#include "exportfs.h"
+#include "xio.h"
+
+static int expsetup(struct nfsctl_export *exparg, nfs_export *exp);
+static int cltsetup(struct nfsctl_client *cltarg, nfs_client *clp);
+
+int
+export_export(nfs_export *exp)
+{
+ nfs_client * clp = exp->m_client;
+ struct nfsctl_export exparg;
+ struct nfsctl_client cltarg;
+
+ if (!clp->m_exported) {
+ if (!cltsetup(&cltarg, clp))
+ return 0;
+ if (nfsaddclient(&cltarg) < 0)
+ return 0;
+ clp->m_exported = 1;
+ }
+ if (!expsetup(&exparg, exp))
+ return 0;
+ if (nfsexport(&exparg) < 0)
+ return 0;
+ exp->m_exported = 1;
+ return 1;
+}
+
+int
+export_unexport(nfs_export *exp)
+{
+ struct nfsctl_export exparg;
+
+ if (!expsetup(&exparg, exp) || nfsunexport(&exparg) < 0)
+ return 0;
+ exp->m_exported = 0;
+ return 1;
+}
+
+static void
+str_tolower(char *s)
+{
+ for ( ; *s; s++)
+ if (isupper(*s))
+ *s = tolower(*s);
+}
+
+static int
+cltsetup(struct nfsctl_client *cltarg, nfs_client *clp)
+{
+ int i;
+
+ if (clp->m_type != MCL_FQDN) {
+ xlog(L_ERROR, "internal: can't export non-FQDN host");
+ return 0;
+ }
+ memset(cltarg, 0, sizeof(*cltarg));
+ strncpy(cltarg->cl_ident, clp->m_hostname,
+ sizeof (cltarg->cl_ident) - 1);
+ str_tolower(cltarg->cl_ident);
+ cltarg->cl_naddr = clp->m_naddr;
+ for (i = 0; i < cltarg->cl_naddr && i < NFSCLNT_ADDRMAX; i++)
+ cltarg->cl_addrlist[i] = clp->m_addrlist[i];
+
+ return 1;
+}
+
+static int
+expsetup(struct nfsctl_export *exparg, nfs_export *exp)
+{
+ nfs_client *clp = exp->m_client;
+ struct stat stb;
+
+ if (stat(exp->m_export.m_path, &stb) < 0)
+ return 0;
+
+ memset(exparg, 0, sizeof(*exparg));
+ strncpy(exparg->ex_path, exp->m_export.m_path,
+ sizeof (exparg->ex_path) - 1);
+ strncpy(exparg->ex_client, clp->m_hostname,
+ sizeof (exparg->ex_client) - 1);
+ str_tolower(exparg->ex_client);
+ exparg->ex_flags = exp->m_export.e_flags;
+ exparg->ex_dev = stb.st_dev;
+ exparg->ex_ino = stb.st_ino;
+ exparg->ex_anon_uid = exp->m_export.e_anonuid;
+ exparg->ex_anon_gid = exp->m_export.e_anongid;
+
+ return 1;
+}
diff --git a/support/export/rmtab.c b/support/export/rmtab.c
new file mode 100644
index 0000000..44a0edc
--- /dev/null
+++ b/support/export/rmtab.c
@@ -0,0 +1,79 @@
+/*
+ * support/export/rmntab.c
+ *
+ * Interface to the rmnt file.
+ *
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include "xmalloc.h"
+#include "misc.h"
+#include "nfslib.h"
+#include "exportfs.h"
+#include "xio.h"
+#include "xlog.h"
+
+int
+rmtab_read(void)
+{
+ struct rmtabent *rep;
+ nfs_export *exp;
+
+ setrmtabent("r");
+ while ((rep = getrmtabent(1)) != NULL) {
+ exp = export_lookup(rep->r_client, rep->r_path);
+ if (!exp) {
+ struct exportent *xp;
+ struct hostent *hp;
+ int htype;
+
+ htype = client_gettype(rep->r_client);
+ if (htype == MCL_FQDN
+ && (hp = gethostbyname (rep->r_client), hp)
+ && (hp = hostent_dup (hp),
+ xp = export_allowed (hp, rep->r_path))) {
+ strncpy (xp->e_hostname, rep->r_client,
+ sizeof (xp->e_hostname) - 1);
+ xp->e_hostname[sizeof (xp->e_hostname) -1] = '\0';
+ exp = export_create(xp);
+ free (hp);
+ }
+
+ if (!exp)
+ continue;
+ exp->m_mayexport = 1;
+ }
+ }
+ if (errno == EINVAL) {
+ /* Something goes wrong. We need to fix the rmtab
+ file. */
+ int lockid;
+ FILE *fp;
+ if ((lockid = xflock(_PATH_RMTAB, "w")) < 0)
+ return -1;
+ rewindrmtabent();
+ if (!(fp = fsetrmtabent(_PATH_RMTABTMP, "w"))) {
+ endrmtabent ();
+ xfunlock(lockid);
+ return -1;
+ }
+ while ((rep = getrmtabent(0)) != NULL) {
+ fputrmtabent(fp, rep);
+ }
+ if (rename(_PATH_RMTABTMP, _PATH_RMTAB) < 0) {
+ xlog(L_ERROR, "couldn't rename %s to %s",
+ _PATH_RMTABTMP, _PATH_RMTAB);
+ }
+ endrmtabent();
+ fendrmtabent(fp);
+ xfunlock(lockid);
+ }
+ else {
+ endrmtabent();
+ }
+ return 0;
+}
diff --git a/support/export/xtab.c b/support/export/xtab.c
new file mode 100644
index 0000000..4289d7c
--- /dev/null
+++ b/support/export/xtab.c
@@ -0,0 +1,133 @@
+/*
+ * support/export/xtab.c
+ *
+ * Interface to the xtab file.
+ *
+ * Copyright (C) 1995, 1996 Olaf Kirch <okir@monad.swb.de>
+ */
+
+#include "config.h"
+
+#include <sys/fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include "xmalloc.h"
+#include "nfslib.h"
+#include "exportfs.h"
+#include "xio.h"
+#include "xlog.h"
+
+static int
+xtab_read(char *xtab, int is_export)
+{
+ struct exportent *xp;
+ nfs_export *exp;
+ int lockid;
+
+ if ((lockid = xflock(xtab, "r")) < 0)
+ return 0;
+ setexportent(xtab, "r");
+ while ((xp = getexportent()) != NULL) {
+ if (!(exp = export_lookup(xp->e_hostname, xp->e_path)) &&
+ !(exp = export_create(xp))) {
+ continue;
+ }
+ if (is_export) {
+ exp->m_xtabent = 1;
+ exp->m_mayexport = 1;
+ } else
+ exp->m_exported = 1;
+ }
+ endexportent();
+ xfunlock(lockid);
+
+ return 0;
+}
+
+int
+xtab_mount_read(void)
+{
+ int fd;
+ if ((fd=open(_PATH_PROC_EXPORTS, O_RDONLY))>=0) {
+ close(fd);
+ return xtab_read(_PATH_PROC_EXPORTS, 0);
+ } else
+ return xtab_read(_PATH_XTAB, 0);
+}
+
+int
+xtab_export_read(void)
+{
+ return xtab_read(_PATH_ETAB, 1);
+}
+
+static int
+xtab_write(char *xtab, char *xtabtmp, int is_export)
+{
+ struct exportent xe;
+ nfs_export *exp;
+ int lockid, i;
+
+ if ((lockid = xflock(xtab, "w")) < 0) {
+ xlog(L_ERROR, "can't lock %s for writing", xtab);
+ return 0;
+ }
+ setexportent(xtabtmp, "w");
+
+ for (i = 0; i < MCL_MAXTYPES; i++) {
+ for (exp = exportlist[i]; exp; exp = exp->m_next) {
+ if (is_export && !exp->m_xtabent)
+ continue;
+ if (!is_export && ! exp->m_exported)
+ continue;
+
+ /* write out the export entry using the FQDN */
+ xe = exp->m_export;
+ strncpy(xe.e_hostname,
+ exp->m_client->m_hostname,
+ sizeof (xe.e_hostname) - 1);
+ xe.e_hostname[sizeof (xe.e_hostname) - 1] = '\0';
+ putexportent(&xe);
+ }
+ }
+ endexportent();
+
+ rename(xtabtmp, xtab);
+
+ xfunlock(lockid);
+
+ return 1;
+}
+
+int
+xtab_export_write()
+{
+ return xtab_write(_PATH_ETAB, _PATH_ETABTMP, 1);
+}
+
+int
+xtab_mount_write()
+{
+ return xtab_write(_PATH_XTAB, _PATH_XTABTMP, 0);
+}
+
+void
+xtab_append(nfs_export *exp)
+{
+ struct exportent xe;
+ int lockid;
+
+ if ((lockid = xflock(_PATH_XTAB, "w")) < 0)
+ return;
+ setexportent(_PATH_XTAB, "a");
+ xe = exp->m_export;
+ strncpy(xe.e_hostname, exp->m_client->m_hostname,
+ sizeof (xe.e_hostname) - 1);
+ xe.e_hostname[sizeof (xe.e_hostname) - 1] = '\0';
+ putexportent(&xe);
+ endexportent();
+ xfunlock(lockid);
+ exp->m_xtabent = 1;
+}
+