X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=support%2Fexport%2Fclient.c;h=57176d880077a53e40b0e27532643ecd7b4e2620;hp=076b0c069dd1ff2991d374ee8c498087601321e8;hb=a980156c122e975cc185a6c41ef705f166a5765f;hpb=4d961554071d2308017062c8bc39f37f5de55b5f diff --git a/support/export/client.c b/support/export/client.c index 076b0c0..57176d8 100644 --- a/support/export/client.c +++ b/support/export/client.c @@ -32,8 +32,12 @@ static int client_checkaddr(nfs_client *clp, struct in_addr addr); nfs_client *clientlist[MCL_MAXTYPES] = { NULL, }; +/* if canonical is set, then we *know* this is already a canonical name + * so hostname lookup is avoided. + * This is used when reading /proc/fs/nfs/exports + */ nfs_client * -client_lookup(char *hname) +client_lookup(char *hname, int canonical) { nfs_client *clp = NULL; int htype; @@ -41,7 +45,7 @@ client_lookup(char *hname) htype = client_gettype(hname); - if (htype == MCL_FQDN) { + if (htype == MCL_FQDN && !canonical) { struct hostent *hp2; hp = gethostbyname(hname); if (hp == NULL || hp->h_addrtype != AF_INET) { @@ -53,8 +57,17 @@ client_lookup(char *hname) 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; @@ -66,7 +79,7 @@ client_lookup(char *hname) } } else { for (clp = clientlist[htype]; clp; clp = clp->m_next) { - if (strcmp(hname, clp->m_hostname)==0) + if (strcasecmp(hname, clp->m_hostname)==0) break; } } @@ -125,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, '.')) { @@ -216,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. @@ -281,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); } @@ -314,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"); @@ -328,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; }