X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fmountd%2Fcache.c;h=f70f4d6e81a7e1ee7b57061f34b7d1c6d68ba162;hp=2468bc5916084e06323341ed6aeab006378beef9;hb=706bfd7c94d48659a1411fdef2a3a61d4719f1aa;hpb=0fe42a6e2cd7252c5c12a5f4edb4c27789b0c043 diff --git a/utils/mountd/cache.c b/utils/mountd/cache.c index 2468bc5..f70f4d6 100644 --- a/utils/mountd/cache.c +++ b/utils/mountd/cache.c @@ -37,6 +37,11 @@ #include "blkid/blkid.h" #endif +/* + * Invoked by RPC service loop + */ +void cache_set_fds(fd_set *fdset); +int cache_process_req(fd_set *readfds); enum nfsd_fsid { FSID_DEV = 0, @@ -57,14 +62,14 @@ enum nfsd_fsid { * Record is terminated with newline. * */ -int cache_export_ent(char *domain, struct exportent *exp, char *p); +static int cache_export_ent(char *domain, struct exportent *exp, char *p); char *lbuf = NULL; int lbuflen = 0; extern int use_ipaddr; -void auth_unix_ip(FILE *f) +static void auth_unix_ip(FILE *f) { /* requests are * class IP-ADDR @@ -75,10 +80,10 @@ void auth_unix_ip(FILE *f) */ char *cp; char class[20]; - char ipaddr[20]; + char ipaddr[INET6_ADDRSTRLEN]; 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; @@ -90,20 +95,23 @@ void auth_unix_ip(FILE *f) strcmp(class, "nfsd") != 0) return; - if (qword_get(&cp, ipaddr, 20) <= 0) + if (qword_get(&cp, ipaddr, sizeof(ipaddr)) <= 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,18 +122,17 @@ 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) +static void auth_unix_gid(FILE *f) { /* Request are * uid * reply is * uid expiry count list of group ids */ - int uid; + uid_t uid; struct passwd *pw; gid_t glist[100], *groups = glist; int ngroups = 100; @@ -136,7 +143,7 @@ void auth_unix_gid(FILE *f) return; cp = lbuf; - if (qword_get_int(&cp, &uid) != 0) + if (qword_get_uint(&cp, &uid) != 0) return; pw = getpwuid(uid); @@ -153,14 +160,14 @@ void auth_unix_gid(FILE *f) groups, &ngroups); } } - qword_printint(f, uid); - qword_printint(f, time(0)+30*60); + qword_printuint(f, uid); + qword_printuint(f, time(0)+30*60); if (rv >= 0) { - qword_printint(f, ngroups); + qword_printuint(f, ngroups); for (i=0; imnt_dir; } -void nfsd_fh(FILE *f) +static void nfsd_fh(FILE *f) { /* request are: * domain fsidtype fsid @@ -294,8 +345,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 +448,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 +512,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,21 +592,20 @@ 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; } -static void write_fsloc(FILE *f, struct exportent *ep, char *path) +static void write_fsloc(FILE *f, struct exportent *ep) { struct servers *servers; if (ep->e_fslocmethod == FSLOC_NONE) return; - servers = replicas_lookup(ep->e_fslocmethod, ep->e_fslocdata, path); + servers = replicas_lookup(ep->e_fslocmethod, ep->e_fslocdata); if (!servers) return; qword_print(f, "fsloc"); @@ -596,17 +653,17 @@ static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *ex qword_printint(f, exp->e_anonuid); qword_printint(f, exp->e_anongid); qword_printint(f, exp->e_fsid); - write_fsloc(f, exp, path); + write_fsloc(f, exp); 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); } @@ -614,12 +671,12 @@ static int dump_to_cache(FILE *f, char *domain, char *path, struct exportent *ex return qword_eol(f); } -static int is_subdirectory(char *subpath, char *path) +static int is_subdirectory(char *child, char *parent) { - int l = strlen(path); + int l = strlen(parent); - return strcmp(subpath, path) == 0 - || (strncmp(subpath, path, l) == 0 && path[l] == '/'); + return strcmp(child, parent) == 0 + || (strncmp(child, parent, l) == 0 && child[l] == '/'); } static int path_matches(nfs_export *exp, char *path) @@ -629,19 +686,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,13 +710,18 @@ 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; found_type = i; continue; } + + /* Always prefer non-V4ROOT mounts */ + if (found->m_export.e_flags & NFSEXP_V4ROOT) + continue; + /* If one is a CROSSMOUNT, then prefer the longest path */ if (((found->m_export.e_flags & NFSEXP_CROSSMOUNT) || (exp->m_export.e_flags & NFSEXP_CROSSMOUNT)) && @@ -682,7 +747,7 @@ static nfs_export *lookup_export(char *dom, char *path, struct hostent *he) return found; } -void nfsd_export(FILE *f) +static void nfsd_export(FILE *f) { /* requests are: * domain path @@ -693,9 +758,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; @@ -717,12 +780,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) { @@ -738,7 +805,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); } @@ -747,14 +814,19 @@ struct { void (*cache_handle)(FILE *f); FILE *f; } cachelist[] = { - { "auth.unix.ip", auth_unix_ip}, - { "auth.unix.gid", auth_unix_gid}, - { "nfsd.export", nfsd_export}, - { "nfsd.fh", nfsd_fh}, - { NULL, NULL } + { "auth.unix.ip", auth_unix_ip, NULL}, + { "auth.unix.gid", auth_unix_gid, NULL}, + { "nfsd.export", nfsd_export, NULL}, + { "nfsd.fh", nfsd_fh, NULL}, + { NULL, NULL, NULL } }; extern int manage_gids; + +/** + * cache_open - prepare communications channels with kernel RPC caches + * + */ void cache_open(void) { int i; @@ -767,6 +839,10 @@ void cache_open(void) } } +/** + * cache_set_fds - prepare cache file descriptors for one iteration of the service loop + * @fdset: pointer to fd_set to prepare + */ void cache_set_fds(fd_set *fdset) { int i; @@ -776,6 +852,10 @@ void cache_set_fds(fd_set *fdset) } } +/** + * cache_process_req - process any active cache file descriptors during service loop iteration + * @fdset: pointer to fd_set to examine for activity + */ int cache_process_req(fd_set *readfds) { int i; @@ -798,7 +878,7 @@ int cache_process_req(fd_set *readfds) * % echo $domain $path $[now+30*60] $options $anonuid $anongid $fsid > /proc/net/rpc/nfsd.export/channel */ -int cache_export_ent(char *domain, struct exportent *exp, char *path) +static int cache_export_ent(char *domain, struct exportent *exp, char *path) { int err; FILE *f = fopen("/proc/net/rpc/nfsd.export/channel", "w"); @@ -819,8 +899,8 @@ int cache_export_ent(char *domain, struct exportent *exp, char *path) * and export them with the same options */ struct stat stb; - int l = strlen(exp->e_path); - int dev; + size_t l = strlen(exp->e_path); + __dev_t dev; if (strlen(path) <= l || path[l] != '/' || strncmp(exp->e_path, path, l) != 0) @@ -856,8 +936,14 @@ int cache_export_ent(char *domain, struct exportent *exp, char *path) return err; } +/** + * cache_export - Inform kernel of a new nfs_export + * @exp: target nfs_export + * @path: NUL-terminated C string containing export path + */ int cache_export(nfs_export *exp, char *path) { + char buf[INET6_ADDRSTRLEN]; int err; FILE *f; @@ -865,8 +951,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); @@ -878,7 +966,14 @@ int cache_export(nfs_export *exp, char *path) return err; } -/* Get a filehandle. +/** + * cache_get_filehandle - given an nfs_export, get its root filehandle + * @exp: target nfs_export + * @len: length of requested file handle + * @p: NUL-terminated C string containing export path + * + * Returns pointer to NFS file handle of root directory of export + * * { * echo $domain $path $length * read filehandle <&0 @@ -912,4 +1007,3 @@ cache_get_filehandle(nfs_export *exp, int len, char *p) fh.fh_size = qword_get(&bp, (char *)fh.fh_handle, NFS3_FHSIZE); return &fh; } -