static ssize_t write_getfs(struct file *file, char *buf, size_t size) { struct nfsctl_fsparm *data; struct sockaddr_in *sin; struct auth_domain *clp; int err = 0; struct knfsd_fh *res; if (size < sizeof(*data)) return -EINVAL; data = (struct nfsctl_fsparm*)buf; err = -EPROTONOSUPPORT; if (data->gd_addr.sa_family != AF_INET) goto out; sin = (struct sockaddr_in *)&data->gd_addr; if (data->gd_maxlen > NFS3_FHSIZE) data->gd_maxlen = NFS3_FHSIZE; res = (struct knfsd_fh*)buf; exp_readlock(); if (!(clp = auth_unix_lookup(sin->sin_addr))) err = -EPERM; else { err = exp_rootfh(clp, data->gd_path, res, data->gd_maxlen); auth_domain_put(clp); } exp_readunlock(); if (err == 0) err = res->fh_size + (int)&((struct knfsd_fh*)0)->fh_base; out: return err; }
static inline int nfsctl_getfh(struct nfsctl_fhparm *data, __u8 *res) { struct sockaddr_in *sin; struct svc_client *clp; int err = 0; struct knfsd_fh fh; if (data->gf_addr.sa_family != AF_INET) return -EPROTONOSUPPORT; if (data->gf_version < 2 || data->gf_version > NFSSVC_MAXVERS) return -EINVAL; sin = (struct sockaddr_in *)&data->gf_addr; exp_readlock(); if (!(clp = exp_getclient(sin))) err = -EPERM; else err = exp_rootfh(clp, to_kdev_t(data->gf_dev), data->gf_ino, NULL, &fh, NFS_FHSIZE); exp_unlock(); if (err == 0) { if (fh.fh_size > NFS_FHSIZE) err = -EINVAL; else { memset(res,0, NFS_FHSIZE); memcpy(res, &fh.fh_base, fh.fh_size); } } return err; }
static ssize_t write_filehandle(struct file *file, char *buf, size_t size) { /* request is: * domain path maxsize * response is * filehandle * * qword quoting is used, so filehandle will be \x.... */ char *dname, *path; int maxsize; char *mesg = buf; int len; struct auth_domain *dom; struct knfsd_fh fh; if (size == 0) return -EINVAL; if (buf[size-1] != '\n') return -EINVAL; buf[size-1] = 0; dname = mesg; len = qword_get(&mesg, dname, size); if (len <= 0) return -EINVAL; path = dname+len+1; len = qword_get(&mesg, path, size); if (len <= 0) return -EINVAL; len = get_int(&mesg, &maxsize); if (len) return len; if (maxsize < NFS_FHSIZE) return -EINVAL; if (maxsize > NFS3_FHSIZE) maxsize = NFS3_FHSIZE; if (qword_get(&mesg, mesg, size)>0) return -EINVAL; /* we have all the words, they are in buf.. */ dom = unix_domain_find(dname); if (!dom) return -ENOMEM; len = exp_rootfh(dom, path, &fh, maxsize); auth_domain_put(dom); if (len) return len; mesg = buf; len = SIMPLE_TRANSACTION_LIMIT; qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size); mesg[-1] = '\n'; return mesg - buf; }
static ssize_t write_filehandle(struct file *file, char *buf, size_t size) { char *dname, *path; int uninitialized_var(maxsize); char *mesg = buf; int len; struct auth_domain *dom; struct knfsd_fh fh; if (size == 0) return -EINVAL; if (buf[size-1] != '\n') return -EINVAL; buf[size-1] = 0; dname = mesg; len = qword_get(&mesg, dname, size); if (len <= 0) return -EINVAL; path = dname+len+1; len = qword_get(&mesg, path, size); if (len <= 0) return -EINVAL; len = get_int(&mesg, &maxsize); if (len) return len; if (maxsize < NFS_FHSIZE) return -EINVAL; if (maxsize > NFS3_FHSIZE) maxsize = NFS3_FHSIZE; if (qword_get(&mesg, mesg, size)>0) return -EINVAL; dom = unix_domain_find(dname); if (!dom) return -ENOMEM; len = exp_rootfh(dom, path, &fh, maxsize); auth_domain_put(dom); if (len) return len; mesg = buf; len = SIMPLE_TRANSACTION_LIMIT; qword_addhex(&mesg, &len, (char*)&fh.fh_base, fh.fh_size); mesg[-1] = '\n'; return mesg - buf; }
/** * write_getfd - Get a fixed-length NFS file handle by path (used by mountd) * * Deprecated. /proc/fs/nfsd/filehandle is preferred. * Function remains to support old versions of nfs-utils. * * Input: * buf: struct nfsctl_fdparm * gd_addr: socket address of client * gd_path: '\0'-terminated C string * containing pathname of * directory in local file system * gd_version: fdparm structure version * size: size in bytes of passed in nfsctl_fdparm * Output: * On success: passed-in buffer filled with nfsctl_res * (a fixed-length raw NFS file handle); * return code is the size in bytes of the file handle * On error: return code is negative errno value * * Note: Only AF_INET client addresses are passed in, since gd_addr * is the same size as a struct sockaddr_in. */ static ssize_t write_getfd(struct file *file, char *buf, size_t size) { struct nfsctl_fdparm *data; struct sockaddr_in *sin; struct auth_domain *clp; int err = 0; struct knfsd_fh fh; char *res; struct in6_addr in6; if (size < sizeof(*data)) return -EINVAL; data = (struct nfsctl_fdparm*)buf; err = -EPROTONOSUPPORT; if (data->gd_addr.sa_family != AF_INET) goto out; err = -EINVAL; if (data->gd_version < 2 || data->gd_version > NFSSVC_MAXVERS) goto out; res = buf; sin = (struct sockaddr_in *)&data->gd_addr; exp_readlock(); ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &in6); clp = auth_unix_lookup(&init_net, &in6); if (!clp) err = -EPERM; else { err = exp_rootfh(clp, data->gd_path, &fh, NFS_FHSIZE); auth_domain_put(clp); } exp_readunlock(); if (err == 0) { memset(res,0, NFS_FHSIZE); memcpy(res, &fh.fh_base, fh.fh_size); err = NFS_FHSIZE; } out: return err; }
static inline int nfsctl_getfs(struct nfsctl_fsparm *data, struct knfsd_fh *res) { struct sockaddr_in *sin; struct svc_client *clp; int err = 0; if (data->gd_addr.sa_family != AF_INET) return -EPROTONOSUPPORT; sin = (struct sockaddr_in *)&data->gd_addr; if (data->gd_maxlen > NFS3_FHSIZE) data->gd_maxlen = NFS3_FHSIZE; exp_readlock(); if (!(clp = exp_getclient(sin))) err = -EPERM; else err = exp_rootfh(clp, 0, 0, data->gd_path, res, data->gd_maxlen); exp_unlock(); return err; }