X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fmountd%2Fcache.c;h=6947203c0f9b91ee362458602a405173f3a816f6;hp=e8bb99106e2872ef23ded11a05f6ff41e3e0a1e7;hb=e91ff0175602cc56f223f1d92de6511099fa40d1;hpb=53c5bd65c74e032947d8fb5b140024be008aaa6b diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c index e8bb991..6947203 100644 --- a/utils/mountd/cache.c +++ b/utils/mountd/cache.c @@ -6,7 +6,10 @@ * and listen for requests (using my_svc_run) * */ -#include "config.h" + +#ifdef HAVE_CONFIG_H +#include +#endif #include #include @@ -24,6 +27,20 @@ #include "mountd.h" #include "xmalloc.h" +#include "blkid/blkid.h" + + +enum nfsd_fsid { + FSID_DEV = 0, + FSID_NUM, + FSID_MAJOR_MINOR, + FSID_ENCODE_DEV, + FSID_UUID4_INUM, + FSID_UUID8, + FSID_UUID16, + FSID_UUID16_INUM, +}; + /* * Support routines for text-based upcalls. * Fields are separated by spaces. @@ -32,7 +49,7 @@ * Record is terminated with newline. * */ -void cache_export_ent(char *domain, struct exportent *exp); +int cache_export_ent(char *domain, struct exportent *exp); char *lbuf = NULL; @@ -80,13 +97,76 @@ void auth_unix_ip(FILE *f) qword_print(f, *client?client:"DEFAULT"); qword_eol(f); - if (client && strcmp(ipaddr, client)) - mountlist_add(ipaddr, *client?client:"DEFAULT"); - if (client) free(client); } +int get_uuid(char *path, char *uuid, 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 + */ + int i = 0; + const char *val; + + if (path) { + static blkid_cache cache = NULL; + struct stat stb; + char *devname; + blkid_tag_iterate iter; + blkid_dev dev; + const char *type; + if (cache == NULL) + blkid_get_cache(&cache, NULL); + + blkid_probe_all_new(cache); + + if (stat(path, &stb) != 0) + return 0; + devname = blkid_devno_to_devname(stb.st_dev); + if (!devname) + return 0; + dev = blkid_get_dev(cache, devname, BLKID_DEV_NORMAL); + free(devname); + if (!dev) + return 0; + iter = blkid_tag_iterate_begin(dev); + if (!iter) + return 0; + while (blkid_tag_next(iter, &type, &val) == 0) + if (strcmp(type, "UUID") == 0) + break; + blkid_tag_iterate_end(iter); + if (!type) + return 0; + } else { + val = uuid; + } + + memset(u, 0, uuidlen); + for ( ; *val ; val++) { + char c = *val; + if (!isxdigit(c)) + continue; + if (isalpha(c)) { + if (isupper(c)) + c = c - 'A' + 10; + else + c = c - 'a' + 10; + } else + c = c - '0' + 0; + if ((i&1) == 0) + c <<= 4; + u[i/2] ^= c; + i++; + if (i == uuidlen*2) + i = 0; + } + return 1; +} + + void nfsd_fh(FILE *f) { /* request are: @@ -100,12 +180,15 @@ void nfsd_fh(FILE *f) int fsidlen; unsigned int dev, major=0, minor=0; unsigned int inode=0; + unsigned long long inode64; unsigned int fsidnum=0; char fsid[32]; struct exportent *found = NULL; nfs_export *exp; int i; int dev_missing = 0; + int uuidlen = 0; + char *fhuuid = NULL; if (readline(fileno(f), &lbuf, &lbuflen) != 1) return; @@ -119,12 +202,12 @@ void nfsd_fh(FILE *f) goto out; if (qword_get_int(&cp, &fsidtype) != 0) goto out; - if (fsidtype < 0 || fsidtype > 1) + if (fsidtype < 0 || fsidtype > 7) goto out; /* unknown type */ if ((fsidlen = qword_get(&cp, fsid, 32)) <= 0) goto out; switch(fsidtype) { - case 0: /* 4 bytes: 2 major, 2 minor, 4 inode */ + case FSID_DEV: /* 4 bytes: 2 major, 2 minor, 4 inode */ if (fsidlen != 8) goto out; memcpy(&dev, fsid, 4); @@ -133,11 +216,62 @@ void nfsd_fh(FILE *f) minor = ntohl(dev) & 0xFFFF; break; - case 1: /* 4 bytes - fsid */ + case FSID_NUM: /* 4 bytes - fsid */ if (fsidlen != 4) goto out; memcpy(&fsidnum, fsid, 4); break; + + case FSID_MAJOR_MINOR: /* 12 bytes: 4 major, 4 minor, 4 inode + * This format is never actually used but was + * an historical accident + */ + if (fsidlen != 12) + goto out; + memcpy(&dev, fsid, 4); major = ntohl(dev); + memcpy(&dev, fsid+4, 4); minor = ntohl(dev); + memcpy(&inode, fsid+8, 4); + break; + + case FSID_ENCODE_DEV: /* 8 bytes: 4 byte packed device number, 4 inode */ + /* This is *host* endian, not net-byte-order, because + * no-one outside this host has any business interpreting it + */ + if (fsidlen != 8) + goto out; + memcpy(&dev, fsid, 4); + memcpy(&inode, fsid+4, 4); + major = (dev & 0xfff00) >> 8; + minor = (dev & 0xff) | ((dev >> 12) & 0xfff00); + break; + + case FSID_UUID4_INUM: /* 4 byte inode number and 4 byte uuid */ + if (fsidlen != 8) + goto out; + memcpy(&inode, fsid, 4); + uuidlen = 4; + fhuuid = fsid+4; + break; + case FSID_UUID8: /* 8 byte uuid */ + if (fsidlen != 8) + goto out; + uuidlen = 8; + fhuuid = fsid; + break; + case FSID_UUID16: /* 16 byte uuid */ + if (fsidlen != 16) + goto out; + uuidlen = 16; + fhuuid = fsid; + break; + case FSID_UUID16_INUM: /* 8 byte inode number and 16 byte uuid */ + if (fsidlen != 24) + goto out; + memcpy(&inode64, fsid, 8); + inode = inode64; + uuidlen = 16; + fhuuid = fsid+8; + break; } auth_reload(); @@ -146,6 +280,7 @@ void nfsd_fh(FILE *f) for (i=0 ; i < MCL_MAXTYPES; i++) { for (exp = exportlist[i]; exp; exp = exp->m_next) { struct stat stb; + char u[16]; if (!client_member(dom, exp->m_client->m_hostname)) continue; @@ -156,16 +291,41 @@ void nfsd_fh(FILE *f) dev_missing ++; if (stat(exp->m_export.e_path, &stb) != 0) continue; - if (fsidtype == 1 && - ((exp->m_export.e_flags & NFSEXP_FSID) == 0 || - exp->m_export.e_fsid != fsidnum)) - continue; - if (fsidtype == 0) { + switch(fsidtype){ + case FSID_DEV: + case FSID_MAJOR_MINOR: + case FSID_ENCODE_DEV: if (stb.st_ino != inode) continue; if (major != major(stb.st_dev) || minor != minor(stb.st_dev)) continue; + break; + case FSID_NUM: + if (((exp->m_export.e_flags & NFSEXP_FSID) == 0 || + exp->m_export.e_fsid != fsidnum)) + continue; + break; + case FSID_UUID4_INUM: + case FSID_UUID16_INUM: + if (stb.st_ino != inode) + continue; + goto check_uuid; + case FSID_UUID8: + case FSID_UUID16: + if (!is_mountpoint(exp->m_export.e_path)) + continue; + check_uuid: + if (exp->m_export.e_uuid) + get_uuid(NULL, exp->m_export.e_uuid, + uuidlen, u); + else if (get_uuid(exp->m_export.e_path, NULL, + uuidlen, u) == 0) + continue; + + if (memcmp(u, fhuuid, uuidlen) != 0) + continue; + break; } /* It's a match !! */ if (!found) @@ -212,6 +372,30 @@ void nfsd_fh(FILE *f) return; } +static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *exp) +{ + qword_print(f, domain); + qword_print(f, path); + qword_printint(f, time(0)+30*60); + if (exp) { + qword_printint(f, exp->e_flags); + qword_printint(f, exp->e_anonuid); + qword_printint(f, exp->e_anongid); + qword_printint(f, exp->e_fsid); + if (exp->e_uuid == NULL) { + char u[16]; + if (get_uuid(exp->e_path, NULL, 16, u)) { + qword_print(f, "uuid"); + qword_printhex(f, u, 16); + } + } else if (exp->e_uuid) { + qword_print(f, "uuid"); + qword_printhex(f, exp->e_uuid, 16); + } + } + return qword_eol(f); +} + void nfsd_export(FILE *f) { /* requests are: @@ -260,17 +444,12 @@ void nfsd_export(FILE *f) } } - qword_print(f, dom); - qword_print(f, path); - qword_printint(f, time(0)+30*60); if (found) { - qword_printint(f, found->m_export.e_flags); - qword_printint(f, found->m_export.e_anonuid); - qword_printint(f, found->m_export.e_anongid); - qword_printint(f, found->m_export.e_fsid); + dump_to_cache(f, dom, path, &found->m_export); mountlist_add(dom, path); + } else { + dump_to_cache(f, dom, path, NULL); } - qword_eol(f); out: if (dom) free(dom); if (path) free(path); @@ -329,47 +508,45 @@ int cache_process_req(fd_set *readfds) * % echo $domain $path $[now+30*60] $options $anonuid $anongid $fsid > /proc/net/rpc/nfsd.export/channel */ -void cache_export_ent(char *domain, struct exportent *exp) +int cache_export_ent(char *domain, struct exportent *exp) { - + int err; FILE *f = fopen("/proc/net/rpc/nfsd.export/channel", "w"); if (!f) - return; - - qword_print(f, domain); - qword_print(f, exp->e_path); - qword_printint(f, time(0)+30*60); - qword_printint(f, exp->e_flags); - qword_printint(f, exp->e_anonuid); - qword_printint(f, exp->e_anongid); - qword_printint(f, exp->e_fsid); - qword_eol(f); + return -1; + err = dump_to_cache(f, domain, exp->e_path, exp); fclose(f); - mountlist_add(domain, exp->e_path); + return err; } -void cache_export(nfs_export *exp) +int cache_export(nfs_export *exp) { + int err; FILE *f; + if (exp->m_export.e_maptype != CLE_MAP_IDENT) { + xlog(L_ERROR, "%s: unsupported mapping; kernel supports only 'identity' (default)", + exp->m_export.m_path); + return; + } + f = fopen("/proc/net/rpc/auth.unix.ip/channel", "w"); if (!f) - return; + return -1; qword_print(f, "nfsd"); qword_print(f, inet_ntoa(exp->m_client->m_addrlist[0])); qword_printint(f, time(0)+30*60); qword_print(f, exp->m_client->m_hostname); - qword_eol(f); + err = qword_eol(f); fclose(f); - if (strcmp(inet_ntoa(exp->m_client->m_addrlist[0]), exp->m_client->m_hostname)) - mountlist_add(inet_ntoa(exp->m_client->m_addrlist[0]), exp->m_client->m_hostname); - - cache_export_ent(exp->m_client->m_hostname, &exp->m_export); + err = cache_export_ent(exp->m_client->m_hostname, &exp->m_export) + || err; + return err; } /* Get a filehandle. @@ -395,14 +572,15 @@ cache_get_filehandle(nfs_export *exp, int len, char *p) qword_print(f, exp->m_client->m_hostname); qword_print(f, p); qword_printint(f, len); - qword_eol(f); + failed = qword_eol(f); - failed = (fgets(buf, sizeof(buf), f) == NULL); + if (!failed) + failed = (fgets(buf, sizeof(buf), f) == NULL); fclose(f); if (failed) return NULL; memset(fh.fh_handle, 0, sizeof(fh.fh_handle)); - fh.fh_size = qword_get(&bp, fh.fh_handle, NFS3_FHSIZE); + fh.fh_size = qword_get(&bp, (char *)fh.fh_handle, NFS3_FHSIZE); return &fh; }