X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fmountd%2Fcache.c;h=9e1b16402009daeae9e828ebf47f3bb268701e56;hp=6343325b106395767c1c781cbf71f76303564555;hb=0509d3428f523776ddd9d6e9fa318587d3ec7d84;hpb=70c59e231e7257ac93b68ba4b844f8d10a6af4a8 diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c index 6343325..9e1b164 100644 --- a/utils/mountd/cache.c +++ b/utils/mountd/cache.c @@ -77,8 +77,8 @@ void auth_unix_ip(FILE *f) char class[20]; char ipaddr[20]; char *client = NULL; - struct in_addr addr; - struct hostent *he = NULL; + struct addrinfo *tmp = NULL; + struct addrinfo *ai = NULL; if (readline(fileno(f), &lbuf, &lbuflen) != 1) return; @@ -93,17 +93,20 @@ void auth_unix_ip(FILE *f) if (qword_get(&cp, ipaddr, 20) <= 0) return; - if (inet_aton(ipaddr, &addr)==0) + tmp = host_pton(ipaddr); + if (tmp == NULL) return; auth_reload(); /* addr is a valid, interesting address, find the domain name... */ if (!use_ipaddr) { - he = client_resolve(addr); - client = client_compose(he); + ai = client_resolve(tmp->ai_addr); + client = client_compose(ai); + freeaddrinfo(ai); } - + freeaddrinfo(tmp); + qword_print(f, "nfsd"); qword_print(f, ipaddr); qword_printint(f, time(0)+30*60); @@ -114,8 +117,7 @@ void auth_unix_ip(FILE *f) qword_eol(f); xlog(D_CALL, "auth_unix_ip: client %p '%s'", client, client?client: "DEFAULT"); - if (client) free(client); - free(he); + free(client); } void auth_unix_gid(FILE *f) @@ -170,13 +172,16 @@ void auth_unix_gid(FILE *f) #if USE_BLKID static const char *get_uuid_blkdev(char *path) { + /* We set *safe if we know that we need the + * fsid from statfs too. + */ static blkid_cache cache = NULL; struct stat stb; char *devname; blkid_tag_iterate iter; blkid_dev dev; const char *type; - const char *val = NULL; + const char *val, *uuid = NULL; if (cache == NULL) blkid_get_cache(&cache, NULL); @@ -193,42 +198,29 @@ static const char *get_uuid_blkdev(char *path) iter = blkid_tag_iterate_begin(dev); if (!iter) return NULL; - while (blkid_tag_next(iter, &type, &val) == 0) + while (blkid_tag_next(iter, &type, &val) == 0) { if (strcmp(type, "UUID") == 0) + uuid = val; + if (strcmp(type, "TYPE") == 0 && + strcmp(val, "btrfs") == 0) { + uuid = NULL; break; + } + } blkid_tag_iterate_end(iter); - return val; + return uuid; } #else #define get_uuid_blkdev(path) (NULL) #endif -int get_uuid(char *path, char *uuid, int uuidlen, char *u) +int get_uuid(const char *val, int uuidlen, char *u) { /* extract hex digits from uuidstr and compose a uuid * of the given length (max 16), xoring bytes to make - * a smaller uuid. Then compare with uuid + * a smaller uuid. */ int i = 0; - const char *val = NULL; - char fsid_val[17]; - - if (path) { - val = get_uuid_blkdev(path); - if (!val) { - struct statfs64 st; - - if (statfs64(path, &st)) - return 0; - if (!st.f_fsid.__val[0] && !st.f_fsid.__val[1]) - return 0; - snprintf(fsid_val, 17, "%08x%08x", - st.f_fsid.__val[0], st.f_fsid.__val[1]); - val = fsid_val; - } - } else { - val = uuid; - } memset(u, 0, uuidlen); for ( ; *val ; val++) { @@ -252,6 +244,60 @@ int get_uuid(char *path, char *uuid, int uuidlen, char *u) return 1; } +int uuid_by_path(char *path, int type, int uuidlen, char *uuid) +{ + /* get a uuid for the filesystem found at 'path'. + * There are several possible ways of generating the + * uuids (types). + * Type 0 is used for new filehandles, while other types + * may be used to interpret old filehandle - to ensure smooth + * forward migration. + * We return 1 if a uuid was found (and it might be worth + * trying the next type) or 0 if no more uuid types can be + * extracted. + */ + + /* Possible sources of uuid are + * - blkid uuid + * - statfs64 uuid + * + * On some filesystems (e.g. vfat) the statfs64 uuid is simply an + * encoding of the device that the filesystem is mounted from, so + * it we be very bad to use that (as device numbers change). blkid + * must be preferred. + * On other filesystems (e.g. btrfs) the statfs64 uuid contains + * important info that the blkid uuid cannot contain: This happens + * when multiple subvolumes are exported (they have the same + * blkid uuid but different statfs64 uuids). + * We rely on get_uuid_blkdev *knowing* which is which and not returning + * a uuid for filesystems where the statfs64 uuid is better. + * + */ + struct statfs64 st; + char fsid_val[17]; + const char *blkid_val; + const char *val; + + blkid_val = get_uuid_blkdev(path); + + if (statfs64(path, &st) == 0 && + (st.f_fsid.__val[0] || st.f_fsid.__val[1])) + snprintf(fsid_val, 17, "%08x%08x", + st.f_fsid.__val[0], st.f_fsid.__val[1]); + else + fsid_val[0] = 0; + + if (blkid_val && (type--) == 0) + val = blkid_val; + else if (fsid_val[0] && (type--) == 0) + val = fsid_val; + else + return 0; + + get_uuid(val, uuidlen, uuid); + return 1; +} + /* Iterate through /etc/mtab, finding mountpoints * at or below a given path */ @@ -294,8 +340,7 @@ void nfsd_fh(FILE *f) unsigned int fsidnum=0; char fsid[32]; struct exportent *found = NULL; - struct hostent *he = NULL; - struct in_addr addr; + struct addrinfo *ai = NULL; char *found_path = NULL; nfs_export *exp; int i; @@ -398,6 +443,7 @@ void nfsd_fh(FILE *f) struct stat stb; char u[16]; char *path; + int type; if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT) { static nfs_export *prev = NULL; @@ -461,22 +507,29 @@ void nfsd_fh(FILE *f) continue; check_uuid: if (exp->m_export.e_uuid) - get_uuid(NULL, exp->m_export.e_uuid, + get_uuid(exp->m_export.e_uuid, uuidlen, u); - else if (get_uuid(path, NULL, uuidlen, u) == 0) - continue; + else + for (type = 0; + uuid_by_path(path, type, uuidlen, u); + type++) + if (memcmp(u, fhuuid, uuidlen) != 0) + break; if (memcmp(u, fhuuid, uuidlen) != 0) continue; break; } if (use_ipaddr) { - if (he == NULL) { - if (!inet_aton(dom, &addr)) + if (ai == NULL) { + struct addrinfo *tmp; + tmp = host_pton(dom); + if (tmp == NULL) goto out; - he = client_resolve(addr); + ai = client_resolve(tmp->ai_addr); + freeaddrinfo(tmp); } - if (!client_check(exp->m_client, he)) + if (!client_check(exp->m_client, ai)) continue; } /* It's a match !! */ @@ -534,8 +587,7 @@ void nfsd_fh(FILE *f) out: if (found_path) free(found_path); - if (he) - free(he); + freeaddrinfo(ai); free(dom); xlog(D_CALL, "nfsd_fh: found %p path %s", found, found ? found->e_path : NULL); return; @@ -600,13 +652,13 @@ static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *ex write_secinfo(f, exp, flag_mask); if (exp->e_uuid == NULL || different_fs) { char u[16]; - if (get_uuid(path, NULL, 16, u)) { + if (uuid_by_path(path, 0, 16, u)) { qword_print(f, "uuid"); qword_printhex(f, u, 16); } } else { char u[16]; - get_uuid(NULL, exp->e_uuid, 16, u); + get_uuid(exp->e_uuid, 16, u); qword_print(f, "uuid"); qword_printhex(f, u, 16); } @@ -629,19 +681,22 @@ static int path_matches(nfs_export *exp, char *path) return strcmp(path, exp->m_export.e_path) == 0; } -static int client_matches(nfs_export *exp, char *dom, struct hostent *he) +static int +client_matches(nfs_export *exp, char *dom, struct addrinfo *ai) { if (use_ipaddr) - return client_check(exp->m_client, he); + return client_check(exp->m_client, ai); return client_member(dom, exp->m_client->m_hostname); } -static int export_matches(nfs_export *exp, char *dom, char *path, struct hostent *he) +static int +export_matches(nfs_export *exp, char *dom, char *path, struct addrinfo *ai) { - return path_matches(exp, path) && client_matches(exp, dom, he); + return path_matches(exp, path) && client_matches(exp, dom, ai); } -static nfs_export *lookup_export(char *dom, char *path, struct hostent *he) +static nfs_export * +lookup_export(char *dom, char *path, struct addrinfo *ai) { nfs_export *exp; nfs_export *found = NULL; @@ -650,7 +705,7 @@ static nfs_export *lookup_export(char *dom, char *path, struct hostent *he) for (i=0 ; i < MCL_MAXTYPES; i++) { for (exp = exportlist[i].p_head; exp; exp = exp->m_next) { - if (!export_matches(exp, dom, path, he)) + if (!export_matches(exp, dom, path, ai)) continue; if (!found) { found = exp; @@ -698,9 +753,7 @@ void nfsd_export(FILE *f) char *cp; char *dom, *path; nfs_export *found = NULL; - struct in_addr addr; - struct hostent *he = NULL; - + struct addrinfo *ai = NULL; if (readline(fileno(f), &lbuf, &lbuflen) != 1) return; @@ -722,12 +775,16 @@ void nfsd_export(FILE *f) auth_reload(); if (use_ipaddr) { - if (!inet_aton(dom, &addr)) + struct addrinfo *tmp; + tmp = host_pton(dom); + if (tmp == NULL) + goto out; + ai = client_resolve(tmp->ai_addr); + freeaddrinfo(tmp); goto out; - he = client_resolve(addr); } - found = lookup_export(dom, path, he); + found = lookup_export(dom, path, ai); if (found) { if (dump_to_cache(f, dom, path, &found->m_export) < 0) { @@ -743,7 +800,7 @@ void nfsd_export(FILE *f) xlog(D_CALL, "nfsd_export: found %p path %s", found, path ? path : NULL); if (dom) free(dom); if (path) free(path); - if (he) free(he); + freeaddrinfo(ai); } @@ -863,6 +920,7 @@ int cache_export_ent(char *domain, struct exportent *exp, char *path) int cache_export(nfs_export *exp, char *path) { + char buf[INET_ADDRSTRLEN]; int err; FILE *f; @@ -870,8 +928,10 @@ int cache_export(nfs_export *exp, char *path) if (!f) return -1; + qword_print(f, "nfsd"); - qword_print(f, inet_ntoa(exp->m_client->m_addrlist[0])); + qword_print(f, + host_ntop(get_addrlist(exp->m_client, 0), buf, sizeof(buf))); qword_printint(f, time(0)+30*60); qword_print(f, exp->m_client->m_hostname); err = qword_eol(f);