]> git.decadent.org.uk Git - nfs-utils.git/blobdiff - support/export/client.c
2005-08-26 Kevin Coffman <kwc@citi.umich.edu>
[nfs-utils.git] / support / export / client.c
index 03f791721774b5937642cf83d150a8c8442636f4..57176d880077a53e40b0e27532643ecd7b4e2620 100644 (file)
@@ -57,8 +57,17 @@ client_lookup(char *hname, int canonical)
                hp = gethostbyaddr(hp2->h_addr, hp2->h_length,
                                   hp2->h_addrtype);
                if (hp) {
-                       free(hp2);
                        hp = hostent_dup(hp);
+                       /* but now we might not have all addresses... */
+                       if (hp2->h_addr_list[1]) {
+                               struct hostent *hp3 =
+                                       gethostbyname(hp->h_name);
+                               if (hp3) {
+                                       free(hp);
+                                       hp = hostent_dup(hp3);
+                               }
+                       }
+                       free(hp2);
                } else
                        hp = hp2;
 
@@ -129,7 +138,9 @@ client_init(nfs_client *clp, const char *hname, struct hostent *hp)
 
        if (clp->m_type == MCL_SUBNETWORK) {
                char    *cp = strchr(clp->m_hostname, '/');
+               static char slash32[] = "/32";
 
+               if(!cp) cp = slash32;
                *cp = '\0';
                clp->m_addrlist[0].s_addr = inet_addr(clp->m_hostname);
                if (strchr(cp + 1, '.')) {
@@ -220,6 +231,104 @@ client_find(struct hostent *hp)
        return NULL;
 }
 
+/*
+ * Find client name given an IP address
+ * This is found by gathering all known names that match that IP address,
+ * sorting them and joining them with '+'
+ *
+ */
+static char *add_name(char *old, char *add);
+
+char *
+client_compose(struct in_addr addr)
+{
+       struct hostent *he = NULL;
+       char *name = NULL;
+       int i;
+
+       if (clientlist[MCL_WILDCARD] || clientlist[MCL_NETGROUP])
+               he = get_reliable_hostbyaddr((const char*)&addr, sizeof(addr), AF_INET);
+       if (he == NULL)
+               he = get_hostent((const char*)&addr, sizeof(addr), AF_INET);
+
+       for (i = 0 ; i < MCL_MAXTYPES; i++) {
+               nfs_client      *clp;
+               for (clp = clientlist[i]; clp ; clp = clp->m_next) {
+                       if (!client_check(clp, he))
+                               continue;
+                       name = add_name(name, clp->m_hostname);
+               }
+       }
+       return name;
+}
+
+int 
+client_member(char *client, char *name)
+{
+       /* check if "client" (a ',' separated list of names)
+        * contains 'name' as a member 
+        */
+       int l = strlen(name);
+       while (*client) {
+               if (strncmp(client, name, l) == 0 &&
+                   (client[l] == ',' || client[l] == '\0'))
+                       return 1;
+               client = strchr(client, ',');
+               if (client == NULL)
+                       return 0;
+               client++;
+       }
+       return 0;
+}
+
+
+int 
+name_cmp(char *a, char *b)
+{
+       /* compare strings a and b, but only upto ',' in a */
+       while (*a && *b && *a != ',' && *a == *b)
+               a++, b++;
+       if (!*b && (!*a || !a == ',') )
+               return 0;
+       if (!*b) return 1;
+       if (!*a || *a == ',') return -1;
+       return *a - *b;
+}
+
+static char *
+add_name(char *old, char *add)
+{
+       int len = strlen(add)+2;
+       char *new;
+       char *cp;
+       if (old) len += strlen(old);
+       
+       new = malloc(len);
+       if (!new) {
+               free(old);
+               return NULL;
+       }
+       cp = old;
+       while (cp && *cp && name_cmp(cp, add) < 0) {
+               /* step cp forward over a name */
+               char *e = strchr(cp, ',');
+               if (e)
+                       cp = e+1;
+               else
+                       cp = cp + strlen(cp);
+       }
+       strncpy(new, old, cp-old);
+       new[cp-old] = 0;
+       if (cp != old && !*cp)
+               strcat(new, ",");
+       strcat(new, add);
+       if (cp && *cp) {
+               strcat(new, ",");
+               strcat(new, cp);
+       }
+       return new;
+}
+
 /*
  * Match a host (given its hostent record) to a client record. This
  * is usually called from mountd.
@@ -285,6 +394,8 @@ client_check(nfs_client *clp, struct hostent *hp)
 #endif
        case MCL_ANONYMOUS:
                return 1;
+       case MCL_GSS:
+               return 0;
        default:
                xlog(L_FATAL, "internal: bad client type %d", clp->m_type);
        }
@@ -318,6 +429,8 @@ client_gettype(char *ident)
 
        if (ident[0] == '\0' || strcmp(ident, "*")==0)
                return MCL_ANONYMOUS;
+       if (strncmp(ident, "gss/", 4) == 0)
+               return MCL_GSS;
        if (ident[0] == '@') {
 #ifndef HAVE_INNETGR
                xlog(L_WARNING, "netgroup support not compiled in");
@@ -332,5 +445,12 @@ client_gettype(char *ident)
                if (*sp == '\\' && sp[1])
                        sp++;
        }
-       return MCL_FQDN;
+       /* check for N.N.N.N */
+       sp = ident;
+       if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '.') return MCL_FQDN;
+       sp++; if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '.') return MCL_FQDN;
+       sp++; if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '.') return MCL_FQDN;
+       sp++; if(!isdigit(*sp) || strtoul(sp, &sp, 10) > 255 || *sp != '\0') return MCL_FQDN;
+       /* we lie here a bit. but technically N.N.N.N == N.N.N.N/32 :) */
+       return MCL_SUBNETWORK;
 }