|
@@ -813,6 +813,89 @@ static void nfs4_fill_super(struct super_block *sb)
|
|
|
nfs_initialise_sb(sb);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Validate NFSv4 mount options
|
|
|
+ */
|
|
|
+static int nfs4_validate_mount_data(struct nfs4_mount_data **options,
|
|
|
+ const char *dev_name,
|
|
|
+ struct sockaddr_in *addr,
|
|
|
+ rpc_authflavor_t *authflavour,
|
|
|
+ char **hostname,
|
|
|
+ char **mntpath,
|
|
|
+ char **ip_addr)
|
|
|
+{
|
|
|
+ struct nfs4_mount_data *data = *options;
|
|
|
+ char *c;
|
|
|
+
|
|
|
+ if (data == NULL)
|
|
|
+ goto out_no_data;
|
|
|
+
|
|
|
+ switch (data->version) {
|
|
|
+ case 1:
|
|
|
+ if (data->host_addrlen != sizeof(*addr))
|
|
|
+ goto out_no_address;
|
|
|
+ if (copy_from_user(addr, data->host_addr, sizeof(*addr)))
|
|
|
+ return -EFAULT;
|
|
|
+ if (addr->sin_port == 0)
|
|
|
+ addr->sin_port = htons(NFS_PORT);
|
|
|
+ if (!nfs_verify_server_address((struct sockaddr *) addr))
|
|
|
+ goto out_no_address;
|
|
|
+
|
|
|
+ switch (data->auth_flavourlen) {
|
|
|
+ case 0:
|
|
|
+ *authflavour = RPC_AUTH_UNIX;
|
|
|
+ break;
|
|
|
+ case 1:
|
|
|
+ if (copy_from_user(authflavour, data->auth_flavours,
|
|
|
+ sizeof(*authflavour)))
|
|
|
+ return -EFAULT;
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ goto out_inval_auth;
|
|
|
+ }
|
|
|
+
|
|
|
+ c = strndup_user(data->hostname.data, NFS4_MAXNAMLEN);
|
|
|
+ if (IS_ERR(c))
|
|
|
+ return PTR_ERR(c);
|
|
|
+ *hostname = c;
|
|
|
+
|
|
|
+ c = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN);
|
|
|
+ if (IS_ERR(c))
|
|
|
+ return PTR_ERR(c);
|
|
|
+ *mntpath = c;
|
|
|
+ dfprintk(MOUNT, "NFS: MNTPATH: '%s'\n", *mntpath);
|
|
|
+
|
|
|
+ c = strndup_user(data->client_addr.data, 16);
|
|
|
+ if (IS_ERR(c))
|
|
|
+ return PTR_ERR(c);
|
|
|
+ *ip_addr = c;
|
|
|
+
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ goto out_bad_version;
|
|
|
+ }
|
|
|
+
|
|
|
+ return 0;
|
|
|
+
|
|
|
+out_no_data:
|
|
|
+ dfprintk(MOUNT, "NFS4: mount program didn't pass any mount data\n");
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+out_inval_auth:
|
|
|
+ dfprintk(MOUNT, "NFS4: Invalid number of RPC auth flavours %d\n",
|
|
|
+ data->auth_flavourlen);
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+out_no_address:
|
|
|
+ dfprintk(MOUNT, "NFS4: mount program didn't pass remote address\n");
|
|
|
+ return -EINVAL;
|
|
|
+
|
|
|
+out_bad_version:
|
|
|
+ dfprintk(MOUNT, "NFS4: bad nfs_mount_data version %d\n",
|
|
|
+ data->version);
|
|
|
+ return -EINVAL;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Get the superblock for an NFS4 mountpoint
|
|
|
*/
|
|
@@ -826,68 +909,14 @@ static int nfs4_get_sb(struct file_system_type *fs_type,
|
|
|
rpc_authflavor_t authflavour;
|
|
|
struct nfs_fh mntfh;
|
|
|
struct dentry *mntroot;
|
|
|
- char *p, *mntpath = NULL, *hostname = NULL, *ip_addr = NULL;
|
|
|
+ char *mntpath = NULL, *hostname = NULL, *ip_addr = NULL;
|
|
|
int error;
|
|
|
|
|
|
- if (data == NULL) {
|
|
|
- dprintk("%s: missing data argument\n", __FUNCTION__);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
- if (data->version <= 0 || data->version > NFS4_MOUNT_VERSION) {
|
|
|
- dprintk("%s: bad mount version\n", __FUNCTION__);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- /* We now require that the mount process passes the remote address */
|
|
|
- if (data->host_addrlen != sizeof(addr))
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- if (copy_from_user(&addr, data->host_addr, sizeof(addr)))
|
|
|
- return -EFAULT;
|
|
|
-
|
|
|
- if (!nfs_verify_server_address((struct sockaddr *) &addr)) {
|
|
|
- dprintk("%s: mount program didn't pass remote IP address!\n",
|
|
|
- __FUNCTION__);
|
|
|
- return -EINVAL;
|
|
|
- }
|
|
|
-
|
|
|
- /* RFC3530: The default port for NFS is 2049 */
|
|
|
- if (addr.sin_port == 0)
|
|
|
- addr.sin_port = htons(NFS_PORT);
|
|
|
-
|
|
|
- /* Grab the authentication type */
|
|
|
- authflavour = RPC_AUTH_UNIX;
|
|
|
- if (data->auth_flavourlen != 0) {
|
|
|
- if (data->auth_flavourlen != 1) {
|
|
|
- dprintk("%s: Invalid number of RPC auth flavours %d.\n",
|
|
|
- __FUNCTION__, data->auth_flavourlen);
|
|
|
- error = -EINVAL;
|
|
|
- goto out;
|
|
|
- }
|
|
|
-
|
|
|
- if (copy_from_user(&authflavour, data->auth_flavours,
|
|
|
- sizeof(authflavour))) {
|
|
|
- error = -EFAULT;
|
|
|
- goto out;
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- p = strndup_user(data->hostname.data, NFS4_MAXNAMLEN);
|
|
|
- if (IS_ERR(p))
|
|
|
- goto out_err;
|
|
|
- hostname = p;
|
|
|
-
|
|
|
- p = strndup_user(data->mnt_path.data, NFS4_MAXPATHLEN);
|
|
|
- if (IS_ERR(p))
|
|
|
- goto out_err;
|
|
|
- mntpath = p;
|
|
|
-
|
|
|
- dprintk("MNTPATH: %s\n", mntpath);
|
|
|
-
|
|
|
- p = strndup_user(data->client_addr.data, 16);
|
|
|
- if (IS_ERR(p))
|
|
|
- goto out_err;
|
|
|
- ip_addr = p;
|
|
|
+ /* Validate the mount data */
|
|
|
+ error = nfs4_validate_mount_data(&data, dev_name, &addr, &authflavour,
|
|
|
+ &hostname, &mntpath, &ip_addr);
|
|
|
+ if (error < 0)
|
|
|
+ goto out;
|
|
|
|
|
|
/* Get a volume representation */
|
|
|
server = nfs4_create_server(data, hostname, &addr, mntpath, ip_addr,
|
|
@@ -932,10 +961,6 @@ out:
|
|
|
kfree(hostname);
|
|
|
return error;
|
|
|
|
|
|
-out_err:
|
|
|
- error = PTR_ERR(p);
|
|
|
- goto out;
|
|
|
-
|
|
|
out_free:
|
|
|
nfs_free_server(server);
|
|
|
goto out;
|