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;
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);
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)
#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);
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++) {
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
*/
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;
struct stat stb;
char u[16];
char *path;
+ int type;
if (exp->m_export.e_flags & NFSEXP_CROSSMOUNT) {
static nfs_export *prev = NULL;
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 !! */
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;
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);
}
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)
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;
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;
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;
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) {
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);
}
int cache_export(nfs_export *exp, char *path)
{
+ char buf[INET_ADDRSTRLEN];
int err;
FILE *f;
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);