nfs: have NFSv3 try server-specified auth flavors in turn
[platform/adaptation/renesas_rcar/renesas_kernel.git] / fs / nfs / super.c
index ceb60c7..8d51101 100644 (file)
@@ -1608,16 +1608,13 @@ out_security_failure:
 }
 
 /*
- * Select a security flavor for this mount.  The selected flavor
- * is planted in args->auth_flavors[0].
- *
- * Returns 0 on success, -EACCES on failure.
+ * Ensure that the specified authtype in args->auth_flavors[0] is supported by
+ * the server. Returns 0 if it's ok, and -EACCES if not.
  */
-static int nfs_select_flavor(struct nfs_parsed_mount_data *args,
-                             struct nfs_mount_request *request)
+static int nfs_verify_authflavor(struct nfs_parsed_mount_data *args,
+                       rpc_authflavor_t *server_authlist, unsigned int count)
 {
-       unsigned int i, count = *(request->auth_flav_len);
-       rpc_authflavor_t flavor;
+       unsigned int i;
 
        /*
         * If the sec= mount option is used, the specified flavor or AUTH_NULL
@@ -1627,60 +1624,19 @@ static int nfs_select_flavor(struct nfs_parsed_mount_data *args,
         * means that the server will ignore the rpc creds, so any flavor
         * can be used.
         */
-       if (args->auth_flavors[0] != RPC_AUTH_MAXFLAVOR) {
-               for (i = 0; i < count; i++) {
-                       if (args->auth_flavors[0] == request->auth_flavs[i] ||
-                           request->auth_flavs[i] == RPC_AUTH_NULL)
-                               goto out;
-               }
-               dfprintk(MOUNT, "NFS: auth flavor %d not supported by server\n",
-                       args->auth_flavors[0]);
-               goto out_err;
-       }
-
-       /*
-        * RFC 2623, section 2.7 suggests we SHOULD prefer the
-        * flavor listed first.  However, some servers list
-        * AUTH_NULL first.  Avoid ever choosing AUTH_NULL.
-        */
        for (i = 0; i < count; i++) {
-               struct rpcsec_gss_info info;
-
-               flavor = request->auth_flavs[i];
-               switch (flavor) {
-               case RPC_AUTH_UNIX:
-                       goto out_set;
-               case RPC_AUTH_NULL:
-                       continue;
-               default:
-                       if (rpcauth_get_gssinfo(flavor, &info) == 0)
-                               goto out_set;
-               }
+               if (args->auth_flavors[0] == server_authlist[i] ||
+                   server_authlist[i] == RPC_AUTH_NULL)
+                       goto out;
        }
 
-       /*
-        * As a last chance, see if the server list contains AUTH_NULL -
-        * if it does, use the default flavor.
-        */
-       for (i = 0; i < count; i++) {
-               if (request->auth_flavs[i] == RPC_AUTH_NULL)
-                       goto out_default;
-       }
-
-       dfprintk(MOUNT, "NFS: no auth flavors in common with server\n");
-       goto out_err;
+       dfprintk(MOUNT, "NFS: auth flavor %u not supported by server\n",
+               args->auth_flavors[0]);
+       return -EACCES;
 
-out_default:
-       /* use default if flavor not already set */
-       flavor = (args->auth_flavors[0] == RPC_AUTH_MAXFLAVOR) ?
-               RPC_AUTH_UNIX : args->auth_flavors[0];
-out_set:
-       args->auth_flavors[0] = flavor;
 out:
-       dfprintk(MOUNT, "NFS: using auth flavor %d\n", args->auth_flavors[0]);
+       dfprintk(MOUNT, "NFS: using auth flavor %u\n", args->auth_flavors[0]);
        return 0;
-out_err:
-       return -EACCES;
 }
 
 /*
@@ -1743,13 +1699,17 @@ static int nfs_request_mount(struct nfs_parsed_mount_data *args,
                return status;
        }
 
-       return nfs_select_flavor(args, &request);
+       return 0;
 }
 
 static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_info,
                                        struct nfs_subversion *nfs_mod)
 {
        int status;
+       unsigned int i;
+       bool tried_auth_unix = false;
+       bool auth_null_in_list = false;
+       struct nfs_server *server = ERR_PTR(-EACCES);
        struct nfs_parsed_mount_data *args = mount_info->parsed;
        rpc_authflavor_t authlist[NFS_MAX_SECFLAVORS];
        unsigned int authlist_len = ARRAY_SIZE(authlist);
@@ -1759,6 +1719,58 @@ static struct nfs_server *nfs_try_mount_request(struct nfs_mount_info *mount_inf
        if (status)
                return ERR_PTR(status);
 
+       /*
+        * Was a sec= authflavor specified in the options? First, verify
+        * whether the server supports it, and then just try to use it if so.
+        */
+       if (args->auth_flavors[0] != RPC_AUTH_MAXFLAVOR) {
+               status = nfs_verify_authflavor(args, authlist, authlist_len);
+               dfprintk(MOUNT, "NFS: using auth flavor %u\n", args->auth_flavors[0]);
+               if (status)
+                       return ERR_PTR(status);
+               return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
+       }
+
+       /*
+        * No sec= option was provided. RFC 2623, section 2.7 suggests we
+        * SHOULD prefer the flavor listed first. However, some servers list
+        * AUTH_NULL first. Avoid ever choosing AUTH_NULL.
+        */
+       for (i = 0; i < authlist_len; ++i) {
+               rpc_authflavor_t flavor;
+               struct rpcsec_gss_info info;
+
+               flavor = authlist[i];
+               switch (flavor) {
+               case RPC_AUTH_UNIX:
+                       tried_auth_unix = true;
+                       break;
+               case RPC_AUTH_NULL:
+                       auth_null_in_list = true;
+                       continue;
+               default:
+                       if (rpcauth_get_gssinfo(flavor, &info) != 0)
+                               continue;
+                       /* Fallthrough */
+               }
+               dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", flavor);
+               args->auth_flavors[0] = flavor;
+               server = nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
+               if (!IS_ERR(server))
+                       return server;
+       }
+
+       /*
+        * Nothing we tried so far worked. At this point, give up if we've
+        * already tried AUTH_UNIX or if the server's list doesn't contain
+        * AUTH_NULL
+        */
+       if (tried_auth_unix || !auth_null_in_list)
+               return server;
+
+       /* Last chance! Try AUTH_UNIX */
+       dfprintk(MOUNT, "NFS: attempting to use auth flavor %u\n", RPC_AUTH_UNIX);
+       args->auth_flavors[0] = RPC_AUTH_UNIX;
        return nfs_mod->rpc_ops->create_server(mount_info, nfs_mod);
 }