summaryrefslogtreecommitdiffstats
path: root/support/export/client.c
diff options
context:
space:
mode:
Diffstat (limited to 'support/export/client.c')
-rw-r--r--support/export/client.c298
1 files changed, 298 insertions, 0 deletions
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;
+}