LCOV - code coverage report
Current view: top level - fs/nfs - idmap.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 0 264 0.0 %
Date: 2014-02-18 Functions: 0 31 0.0 %
Branches: 0 128 0.0 %

           Branch data     Line data    Source code
       1                 :            : /*
       2                 :            :  * fs/nfs/idmap.c
       3                 :            :  *
       4                 :            :  *  UID and GID to name mapping for clients.
       5                 :            :  *
       6                 :            :  *  Copyright (c) 2002 The Regents of the University of Michigan.
       7                 :            :  *  All rights reserved.
       8                 :            :  *
       9                 :            :  *  Marius Aamodt Eriksen <marius@umich.edu>
      10                 :            :  *
      11                 :            :  *  Redistribution and use in source and binary forms, with or without
      12                 :            :  *  modification, are permitted provided that the following conditions
      13                 :            :  *  are met:
      14                 :            :  *
      15                 :            :  *  1. Redistributions of source code must retain the above copyright
      16                 :            :  *     notice, this list of conditions and the following disclaimer.
      17                 :            :  *  2. Redistributions in binary form must reproduce the above copyright
      18                 :            :  *     notice, this list of conditions and the following disclaimer in the
      19                 :            :  *     documentation and/or other materials provided with the distribution.
      20                 :            :  *  3. Neither the name of the University nor the names of its
      21                 :            :  *     contributors may be used to endorse or promote products derived
      22                 :            :  *     from this software without specific prior written permission.
      23                 :            :  *
      24                 :            :  *  THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
      25                 :            :  *  WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
      26                 :            :  *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
      27                 :            :  *  DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
      28                 :            :  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
      29                 :            :  *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
      30                 :            :  *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
      31                 :            :  *  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
      32                 :            :  *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
      33                 :            :  *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
      34                 :            :  *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
      35                 :            :  */
      36                 :            : #include <linux/types.h>
      37                 :            : #include <linux/parser.h>
      38                 :            : #include <linux/fs.h>
      39                 :            : #include <linux/nfs_idmap.h>
      40                 :            : #include <net/net_namespace.h>
      41                 :            : #include <linux/sunrpc/rpc_pipe_fs.h>
      42                 :            : #include <linux/nfs_fs.h>
      43                 :            : #include <linux/nfs_fs_sb.h>
      44                 :            : #include <linux/key.h>
      45                 :            : #include <linux/keyctl.h>
      46                 :            : #include <linux/key-type.h>
      47                 :            : #include <keys/user-type.h>
      48                 :            : #include <linux/module.h>
      49                 :            : 
      50                 :            : #include "internal.h"
      51                 :            : #include "netns.h"
      52                 :            : #include "nfs4trace.h"
      53                 :            : 
      54                 :            : #define NFS_UINT_MAXLEN 11
      55                 :            : 
      56                 :            : static const struct cred *id_resolver_cache;
      57                 :            : static struct key_type key_type_id_resolver_legacy;
      58                 :            : 
      59                 :            : struct idmap_legacy_upcalldata {
      60                 :            :         struct rpc_pipe_msg pipe_msg;
      61                 :            :         struct idmap_msg idmap_msg;
      62                 :            :         struct key_construction *key_cons;
      63                 :            :         struct idmap *idmap;
      64                 :            : };
      65                 :            : 
      66                 :            : struct idmap {
      67                 :            :         struct rpc_pipe_dir_object idmap_pdo;
      68                 :            :         struct rpc_pipe         *idmap_pipe;
      69                 :            :         struct idmap_legacy_upcalldata *idmap_upcall_data;
      70                 :            :         struct mutex            idmap_mutex;
      71                 :            : };
      72                 :            : 
      73                 :            : /**
      74                 :            :  * nfs_fattr_init_names - initialise the nfs_fattr owner_name/group_name fields
      75                 :            :  * @fattr: fully initialised struct nfs_fattr
      76                 :            :  * @owner_name: owner name string cache
      77                 :            :  * @group_name: group name string cache
      78                 :            :  */
      79                 :          0 : void nfs_fattr_init_names(struct nfs_fattr *fattr,
      80                 :            :                 struct nfs4_string *owner_name,
      81                 :            :                 struct nfs4_string *group_name)
      82                 :            : {
      83                 :          0 :         fattr->owner_name = owner_name;
      84                 :          0 :         fattr->group_name = group_name;
      85                 :          0 : }
      86                 :            : 
      87                 :            : static void nfs_fattr_free_owner_name(struct nfs_fattr *fattr)
      88                 :            : {
      89                 :          0 :         fattr->valid &= ~NFS_ATTR_FATTR_OWNER_NAME;
      90                 :          0 :         kfree(fattr->owner_name->data);
      91                 :            : }
      92                 :            : 
      93                 :            : static void nfs_fattr_free_group_name(struct nfs_fattr *fattr)
      94                 :            : {
      95                 :          0 :         fattr->valid &= ~NFS_ATTR_FATTR_GROUP_NAME;
      96                 :          0 :         kfree(fattr->group_name->data);
      97                 :            : }
      98                 :            : 
      99                 :          0 : static bool nfs_fattr_map_owner_name(struct nfs_server *server, struct nfs_fattr *fattr)
     100                 :            : {
     101                 :          0 :         struct nfs4_string *owner = fattr->owner_name;
     102                 :            :         kuid_t uid;
     103                 :            : 
     104         [ #  # ]:          0 :         if (!(fattr->valid & NFS_ATTR_FATTR_OWNER_NAME))
     105                 :            :                 return false;
     106         [ #  # ]:          0 :         if (nfs_map_name_to_uid(server, owner->data, owner->len, &uid) == 0) {
     107                 :          0 :                 fattr->uid = uid;
     108                 :          0 :                 fattr->valid |= NFS_ATTR_FATTR_OWNER;
     109                 :            :         }
     110                 :            :         return true;
     111                 :            : }
     112                 :            : 
     113                 :          0 : static bool nfs_fattr_map_group_name(struct nfs_server *server, struct nfs_fattr *fattr)
     114                 :            : {
     115                 :          0 :         struct nfs4_string *group = fattr->group_name;
     116                 :            :         kgid_t gid;
     117                 :            : 
     118         [ #  # ]:          0 :         if (!(fattr->valid & NFS_ATTR_FATTR_GROUP_NAME))
     119                 :            :                 return false;
     120         [ #  # ]:          0 :         if (nfs_map_group_to_gid(server, group->data, group->len, &gid) == 0) {
     121                 :          0 :                 fattr->gid = gid;
     122                 :          0 :                 fattr->valid |= NFS_ATTR_FATTR_GROUP;
     123                 :            :         }
     124                 :            :         return true;
     125                 :            : }
     126                 :            : 
     127                 :            : /**
     128                 :            :  * nfs_fattr_free_names - free up the NFSv4 owner and group strings
     129                 :            :  * @fattr: a fully initialised nfs_fattr structure
     130                 :            :  */
     131                 :          0 : void nfs_fattr_free_names(struct nfs_fattr *fattr)
     132                 :            : {
     133         [ #  # ]:          0 :         if (fattr->valid & NFS_ATTR_FATTR_OWNER_NAME)
     134                 :            :                 nfs_fattr_free_owner_name(fattr);
     135         [ #  # ]:          0 :         if (fattr->valid & NFS_ATTR_FATTR_GROUP_NAME)
     136                 :            :                 nfs_fattr_free_group_name(fattr);
     137                 :          0 : }
     138                 :            : 
     139                 :            : /**
     140                 :            :  * nfs_fattr_map_and_free_names - map owner/group strings into uid/gid and free
     141                 :            :  * @server: pointer to the filesystem nfs_server structure
     142                 :            :  * @fattr: a fully initialised nfs_fattr structure
     143                 :            :  *
     144                 :            :  * This helper maps the cached NFSv4 owner/group strings in fattr into
     145                 :            :  * their numeric uid/gid equivalents, and then frees the cached strings.
     146                 :            :  */
     147                 :          0 : void nfs_fattr_map_and_free_names(struct nfs_server *server, struct nfs_fattr *fattr)
     148                 :            : {
     149         [ #  # ]:          0 :         if (nfs_fattr_map_owner_name(server, fattr))
     150                 :            :                 nfs_fattr_free_owner_name(fattr);
     151         [ #  # ]:          0 :         if (nfs_fattr_map_group_name(server, fattr))
     152                 :            :                 nfs_fattr_free_group_name(fattr);
     153                 :          0 : }
     154                 :            : 
     155                 :          0 : static int nfs_map_string_to_numeric(const char *name, size_t namelen, __u32 *res)
     156                 :            : {
     157                 :            :         unsigned long val;
     158                 :            :         char buf[16];
     159                 :            : 
     160 [ #  # ][ #  # ]:          0 :         if (memchr(name, '@', namelen) != NULL || namelen >= sizeof(buf))
     161                 :            :                 return 0;
     162                 :          0 :         memcpy(buf, name, namelen);
     163                 :          0 :         buf[namelen] = '\0';
     164         [ #  # ]:          0 :         if (kstrtoul(buf, 0, &val) != 0)
     165                 :            :                 return 0;
     166                 :          0 :         *res = val;
     167                 :          0 :         return 1;
     168                 :            : }
     169                 :            : 
     170                 :            : static int nfs_map_numeric_to_string(__u32 id, char *buf, size_t buflen)
     171                 :            : {
     172                 :          0 :         return snprintf(buf, buflen, "%u", id);
     173                 :            : }
     174                 :            : 
     175                 :            : static struct key_type key_type_id_resolver = {
     176                 :            :         .name           = "id_resolver",
     177                 :            :         .instantiate    = user_instantiate,
     178                 :            :         .match          = user_match,
     179                 :            :         .revoke         = user_revoke,
     180                 :            :         .destroy        = user_destroy,
     181                 :            :         .describe       = user_describe,
     182                 :            :         .read           = user_read,
     183                 :            : };
     184                 :            : 
     185                 :          0 : static int nfs_idmap_init_keyring(void)
     186                 :            : {
     187                 :            :         struct cred *cred;
     188                 :            :         struct key *keyring;
     189                 :            :         int ret = 0;
     190                 :            : 
     191                 :          0 :         printk(KERN_NOTICE "NFS: Registering the %s key type\n",
     192                 :            :                 key_type_id_resolver.name);
     193                 :            : 
     194                 :          0 :         cred = prepare_kernel_cred(NULL);
     195         [ #  # ]:          0 :         if (!cred)
     196                 :            :                 return -ENOMEM;
     197                 :            : 
     198                 :          0 :         keyring = keyring_alloc(".id_resolver",
     199                 :            :                                 GLOBAL_ROOT_UID, GLOBAL_ROOT_GID, cred,
     200                 :            :                                 (KEY_POS_ALL & ~KEY_POS_SETATTR) |
     201                 :            :                                 KEY_USR_VIEW | KEY_USR_READ,
     202                 :            :                                 KEY_ALLOC_NOT_IN_QUOTA, NULL);
     203         [ #  # ]:          0 :         if (IS_ERR(keyring)) {
     204                 :            :                 ret = PTR_ERR(keyring);
     205                 :          0 :                 goto failed_put_cred;
     206                 :            :         }
     207                 :            : 
     208                 :          0 :         ret = register_key_type(&key_type_id_resolver);
     209         [ #  # ]:          0 :         if (ret < 0)
     210                 :            :                 goto failed_put_key;
     211                 :            : 
     212                 :          0 :         ret = register_key_type(&key_type_id_resolver_legacy);
     213         [ #  # ]:          0 :         if (ret < 0)
     214                 :            :                 goto failed_reg_legacy;
     215                 :            : 
     216                 :          0 :         set_bit(KEY_FLAG_ROOT_CAN_CLEAR, &keyring->flags);
     217                 :          0 :         cred->thread_keyring = keyring;
     218                 :          0 :         cred->jit_keyring = KEY_REQKEY_DEFL_THREAD_KEYRING;
     219                 :          0 :         id_resolver_cache = cred;
     220                 :          0 :         return 0;
     221                 :            : 
     222                 :            : failed_reg_legacy:
     223                 :          0 :         unregister_key_type(&key_type_id_resolver);
     224                 :            : failed_put_key:
     225                 :          0 :         key_put(keyring);
     226                 :            : failed_put_cred:
     227                 :            :         put_cred(cred);
     228                 :          0 :         return ret;
     229                 :            : }
     230                 :            : 
     231                 :          0 : static void nfs_idmap_quit_keyring(void)
     232                 :            : {
     233                 :          0 :         key_revoke(id_resolver_cache->thread_keyring);
     234                 :          0 :         unregister_key_type(&key_type_id_resolver);
     235                 :          0 :         unregister_key_type(&key_type_id_resolver_legacy);
     236                 :          0 :         put_cred(id_resolver_cache);
     237                 :          0 : }
     238                 :            : 
     239                 :            : /*
     240                 :            :  * Assemble the description to pass to request_key()
     241                 :            :  * This function will allocate a new string and update dest to point
     242                 :            :  * at it.  The caller is responsible for freeing dest.
     243                 :            :  *
     244                 :            :  * On error 0 is returned.  Otherwise, the length of dest is returned.
     245                 :            :  */
     246                 :          0 : static ssize_t nfs_idmap_get_desc(const char *name, size_t namelen,
     247                 :            :                                 const char *type, size_t typelen, char **desc)
     248                 :            : {
     249                 :            :         char *cp;
     250                 :          0 :         size_t desclen = typelen + namelen + 2;
     251                 :            : 
     252                 :          0 :         *desc = kmalloc(desclen, GFP_KERNEL);
     253         [ #  # ]:          0 :         if (!*desc)
     254                 :            :                 return -ENOMEM;
     255                 :            : 
     256                 :            :         cp = *desc;
     257                 :          0 :         memcpy(cp, type, typelen);
     258                 :          0 :         cp += typelen;
     259                 :          0 :         *cp++ = ':';
     260                 :            : 
     261                 :          0 :         memcpy(cp, name, namelen);
     262                 :          0 :         cp += namelen;
     263                 :          0 :         *cp = '\0';
     264                 :          0 :         return desclen;
     265                 :            : }
     266                 :            : 
     267                 :          0 : static struct key *nfs_idmap_request_key(const char *name, size_t namelen,
     268                 :            :                                          const char *type, struct idmap *idmap)
     269                 :            : {
     270                 :            :         char *desc;
     271                 :            :         struct key *rkey;
     272                 :            :         ssize_t ret;
     273                 :            : 
     274                 :          0 :         ret = nfs_idmap_get_desc(name, namelen, type, strlen(type), &desc);
     275         [ #  # ]:          0 :         if (ret <= 0)
     276                 :          0 :                 return ERR_PTR(ret);
     277                 :            : 
     278                 :          0 :         rkey = request_key(&key_type_id_resolver, desc, "");
     279         [ #  # ]:          0 :         if (IS_ERR(rkey)) {
     280                 :          0 :                 mutex_lock(&idmap->idmap_mutex);
     281                 :          0 :                 rkey = request_key_with_auxdata(&key_type_id_resolver_legacy,
     282                 :            :                                                 desc, "", 0, idmap);
     283                 :          0 :                 mutex_unlock(&idmap->idmap_mutex);
     284                 :            :         }
     285                 :            : 
     286                 :          0 :         kfree(desc);
     287                 :          0 :         return rkey;
     288                 :            : }
     289                 :            : 
     290                 :          0 : static ssize_t nfs_idmap_get_key(const char *name, size_t namelen,
     291                 :            :                                  const char *type, void *data,
     292                 :            :                                  size_t data_size, struct idmap *idmap)
     293                 :            : {
     294                 :            :         const struct cred *saved_cred;
     295                 :            :         struct key *rkey;
     296                 :            :         struct user_key_payload *payload;
     297                 :            :         ssize_t ret;
     298                 :            : 
     299                 :          0 :         saved_cred = override_creds(id_resolver_cache);
     300                 :          0 :         rkey = nfs_idmap_request_key(name, namelen, type, idmap);
     301                 :          0 :         revert_creds(saved_cred);
     302                 :            : 
     303         [ #  # ]:          0 :         if (IS_ERR(rkey)) {
     304                 :            :                 ret = PTR_ERR(rkey);
     305                 :          0 :                 goto out;
     306                 :            :         }
     307                 :            : 
     308                 :            :         rcu_read_lock();
     309                 :          0 :         rkey->perm |= KEY_USR_VIEW;
     310                 :            : 
     311                 :          0 :         ret = key_validate(rkey);
     312         [ #  # ]:          0 :         if (ret < 0)
     313                 :            :                 goto out_up;
     314                 :            : 
     315                 :          0 :         payload = rcu_dereference(rkey->payload.rcudata);
     316         [ #  # ]:          0 :         if (IS_ERR_OR_NULL(payload)) {
     317                 :            :                 ret = PTR_ERR(payload);
     318                 :          0 :                 goto out_up;
     319                 :            :         }
     320                 :            : 
     321                 :          0 :         ret = payload->datalen;
     322         [ #  # ]:          0 :         if (ret > 0 && ret <= data_size)
     323                 :          0 :                 memcpy(data, payload->data, ret);
     324                 :            :         else
     325                 :            :                 ret = -EINVAL;
     326                 :            : 
     327                 :            : out_up:
     328                 :            :         rcu_read_unlock();
     329                 :          0 :         key_put(rkey);
     330                 :            : out:
     331                 :          0 :         return ret;
     332                 :            : }
     333                 :            : 
     334                 :            : /* ID -> Name */
     335                 :          0 : static ssize_t nfs_idmap_lookup_name(__u32 id, const char *type, char *buf,
     336                 :            :                                      size_t buflen, struct idmap *idmap)
     337                 :            : {
     338                 :            :         char id_str[NFS_UINT_MAXLEN];
     339                 :            :         int id_len;
     340                 :            :         ssize_t ret;
     341                 :            : 
     342                 :          0 :         id_len = snprintf(id_str, sizeof(id_str), "%u", id);
     343                 :          0 :         ret = nfs_idmap_get_key(id_str, id_len, type, buf, buflen, idmap);
     344         [ #  # ]:          0 :         if (ret < 0)
     345                 :            :                 return -EINVAL;
     346                 :          0 :         return ret;
     347                 :            : }
     348                 :            : 
     349                 :            : /* Name -> ID */
     350                 :          0 : static int nfs_idmap_lookup_id(const char *name, size_t namelen, const char *type,
     351                 :            :                                __u32 *id, struct idmap *idmap)
     352                 :            : {
     353                 :            :         char id_str[NFS_UINT_MAXLEN];
     354                 :            :         long id_long;
     355                 :            :         ssize_t data_size;
     356                 :            :         int ret = 0;
     357                 :            : 
     358                 :          0 :         data_size = nfs_idmap_get_key(name, namelen, type, id_str, NFS_UINT_MAXLEN, idmap);
     359         [ #  # ]:          0 :         if (data_size <= 0) {
     360                 :            :                 ret = -EINVAL;
     361                 :            :         } else {
     362                 :            :                 ret = kstrtol(id_str, 10, &id_long);
     363                 :          0 :                 *id = (__u32)id_long;
     364                 :            :         }
     365                 :          0 :         return ret;
     366                 :            : }
     367                 :            : 
     368                 :            : /* idmap classic begins here */
     369                 :            : 
     370                 :            : enum {
     371                 :            :         Opt_find_uid, Opt_find_gid, Opt_find_user, Opt_find_group, Opt_find_err
     372                 :            : };
     373                 :            : 
     374                 :            : static const match_table_t nfs_idmap_tokens = {
     375                 :            :         { Opt_find_uid, "uid:%s" },
     376                 :            :         { Opt_find_gid, "gid:%s" },
     377                 :            :         { Opt_find_user, "user:%s" },
     378                 :            :         { Opt_find_group, "group:%s" },
     379                 :            :         { Opt_find_err, NULL }
     380                 :            : };
     381                 :            : 
     382                 :            : static int nfs_idmap_legacy_upcall(struct key_construction *, const char *, void *);
     383                 :            : static ssize_t idmap_pipe_downcall(struct file *, const char __user *,
     384                 :            :                                    size_t);
     385                 :            : static void idmap_release_pipe(struct inode *);
     386                 :            : static void idmap_pipe_destroy_msg(struct rpc_pipe_msg *);
     387                 :            : 
     388                 :            : static const struct rpc_pipe_ops idmap_upcall_ops = {
     389                 :            :         .upcall         = rpc_pipe_generic_upcall,
     390                 :            :         .downcall       = idmap_pipe_downcall,
     391                 :            :         .release_pipe   = idmap_release_pipe,
     392                 :            :         .destroy_msg    = idmap_pipe_destroy_msg,
     393                 :            : };
     394                 :            : 
     395                 :            : static struct key_type key_type_id_resolver_legacy = {
     396                 :            :         .name           = "id_legacy",
     397                 :            :         .instantiate    = user_instantiate,
     398                 :            :         .match          = user_match,
     399                 :            :         .revoke         = user_revoke,
     400                 :            :         .destroy        = user_destroy,
     401                 :            :         .describe       = user_describe,
     402                 :            :         .read           = user_read,
     403                 :            :         .request_key    = nfs_idmap_legacy_upcall,
     404                 :            : };
     405                 :            : 
     406                 :          0 : static void nfs_idmap_pipe_destroy(struct dentry *dir,
     407                 :            :                 struct rpc_pipe_dir_object *pdo)
     408                 :            : {
     409                 :          0 :         struct idmap *idmap = pdo->pdo_data;
     410                 :          0 :         struct rpc_pipe *pipe = idmap->idmap_pipe;
     411                 :            : 
     412         [ #  # ]:          0 :         if (pipe->dentry) {
     413                 :          0 :                 rpc_unlink(pipe->dentry);
     414                 :          0 :                 pipe->dentry = NULL;
     415                 :            :         }
     416                 :          0 : }
     417                 :            : 
     418                 :          0 : static int nfs_idmap_pipe_create(struct dentry *dir,
     419                 :            :                 struct rpc_pipe_dir_object *pdo)
     420                 :            : {
     421                 :          0 :         struct idmap *idmap = pdo->pdo_data;
     422                 :          0 :         struct rpc_pipe *pipe = idmap->idmap_pipe;
     423                 :            :         struct dentry *dentry;
     424                 :            : 
     425                 :          0 :         dentry = rpc_mkpipe_dentry(dir, "idmap", idmap, pipe);
     426         [ #  # ]:          0 :         if (IS_ERR(dentry))
     427                 :          0 :                 return PTR_ERR(dentry);
     428                 :          0 :         pipe->dentry = dentry;
     429                 :          0 :         return 0;
     430                 :            : }
     431                 :            : 
     432                 :            : static const struct rpc_pipe_dir_object_ops nfs_idmap_pipe_dir_object_ops = {
     433                 :            :         .create = nfs_idmap_pipe_create,
     434                 :            :         .destroy = nfs_idmap_pipe_destroy,
     435                 :            : };
     436                 :            : 
     437                 :            : int
     438                 :          0 : nfs_idmap_new(struct nfs_client *clp)
     439                 :            : {
     440                 :            :         struct idmap *idmap;
     441                 :            :         struct rpc_pipe *pipe;
     442                 :            :         int error;
     443                 :            : 
     444                 :            :         idmap = kzalloc(sizeof(*idmap), GFP_KERNEL);
     445         [ #  # ]:          0 :         if (idmap == NULL)
     446                 :            :                 return -ENOMEM;
     447                 :            : 
     448                 :          0 :         rpc_init_pipe_dir_object(&idmap->idmap_pdo,
     449                 :            :                         &nfs_idmap_pipe_dir_object_ops,
     450                 :            :                         idmap);
     451                 :            : 
     452                 :          0 :         pipe = rpc_mkpipe_data(&idmap_upcall_ops, 0);
     453         [ #  # ]:          0 :         if (IS_ERR(pipe)) {
     454                 :            :                 error = PTR_ERR(pipe);
     455                 :          0 :                 goto err;
     456                 :            :         }
     457                 :          0 :         idmap->idmap_pipe = pipe;
     458                 :          0 :         mutex_init(&idmap->idmap_mutex);
     459                 :            : 
     460                 :          0 :         error = rpc_add_pipe_dir_object(clp->cl_net,
     461                 :          0 :                         &clp->cl_rpcclient->cl_pipedir_objects,
     462                 :            :                         &idmap->idmap_pdo);
     463         [ #  # ]:          0 :         if (error)
     464                 :            :                 goto err_destroy_pipe;
     465                 :            : 
     466                 :          0 :         clp->cl_idmap = idmap;
     467                 :          0 :         return 0;
     468                 :            : err_destroy_pipe:
     469                 :          0 :         rpc_destroy_pipe_data(idmap->idmap_pipe);
     470                 :            : err:
     471                 :          0 :         kfree(idmap);
     472                 :          0 :         return error;
     473                 :            : }
     474                 :            : 
     475                 :            : void
     476                 :          0 : nfs_idmap_delete(struct nfs_client *clp)
     477                 :            : {
     478                 :          0 :         struct idmap *idmap = clp->cl_idmap;
     479                 :            : 
     480         [ #  # ]:          0 :         if (!idmap)
     481                 :          0 :                 return;
     482                 :          0 :         clp->cl_idmap = NULL;
     483                 :          0 :         rpc_remove_pipe_dir_object(clp->cl_net,
     484                 :          0 :                         &clp->cl_rpcclient->cl_pipedir_objects,
     485                 :            :                         &idmap->idmap_pdo);
     486                 :          0 :         rpc_destroy_pipe_data(idmap->idmap_pipe);
     487                 :          0 :         kfree(idmap);
     488                 :            : }
     489                 :            : 
     490                 :          0 : int nfs_idmap_init(void)
     491                 :            : {
     492                 :            :         int ret;
     493                 :          0 :         ret = nfs_idmap_init_keyring();
     494                 :            :         if (ret != 0)
     495                 :            :                 goto out;
     496                 :            : out:
     497                 :          0 :         return ret;
     498                 :            : }
     499                 :            : 
     500                 :          0 : void nfs_idmap_quit(void)
     501                 :            : {
     502                 :          0 :         nfs_idmap_quit_keyring();
     503                 :          0 : }
     504                 :            : 
     505                 :          0 : static int nfs_idmap_prepare_message(char *desc, struct idmap *idmap,
     506                 :            :                                      struct idmap_msg *im,
     507                 :            :                                      struct rpc_pipe_msg *msg)
     508                 :            : {
     509                 :            :         substring_t substr;
     510                 :            :         int token, ret;
     511                 :            : 
     512                 :          0 :         im->im_type = IDMAP_TYPE_GROUP;
     513                 :          0 :         token = match_token(desc, nfs_idmap_tokens, &substr);
     514                 :            : 
     515   [ #  #  #  #  :          0 :         switch (token) {
                      # ]
     516                 :            :         case Opt_find_uid:
     517                 :          0 :                 im->im_type = IDMAP_TYPE_USER;
     518                 :            :         case Opt_find_gid:
     519                 :          0 :                 im->im_conv = IDMAP_CONV_NAMETOID;
     520                 :          0 :                 ret = match_strlcpy(im->im_name, &substr, IDMAP_NAMESZ);
     521                 :            :                 break;
     522                 :            : 
     523                 :            :         case Opt_find_user:
     524                 :          0 :                 im->im_type = IDMAP_TYPE_USER;
     525                 :            :         case Opt_find_group:
     526                 :          0 :                 im->im_conv = IDMAP_CONV_IDTONAME;
     527                 :          0 :                 ret = match_int(&substr, &im->im_id);
     528                 :            :                 break;
     529                 :            : 
     530                 :            :         default:
     531                 :            :                 ret = -EINVAL;
     532                 :            :                 goto out;
     533                 :            :         }
     534                 :            : 
     535                 :          0 :         msg->data = im;
     536                 :          0 :         msg->len  = sizeof(struct idmap_msg);
     537                 :            : 
     538                 :            : out:
     539                 :          0 :         return ret;
     540                 :            : }
     541                 :            : 
     542                 :            : static bool
     543                 :          0 : nfs_idmap_prepare_pipe_upcall(struct idmap *idmap,
     544                 :            :                 struct idmap_legacy_upcalldata *data)
     545                 :            : {
     546         [ #  # ]:          0 :         if (idmap->idmap_upcall_data != NULL) {
     547 [ #  # ][ #  # ]:          0 :                 WARN_ON_ONCE(1);
     548                 :            :                 return false;
     549                 :            :         }
     550                 :          0 :         idmap->idmap_upcall_data = data;
     551                 :            :         return true;
     552                 :            : }
     553                 :            : 
     554                 :            : static void
     555                 :          0 : nfs_idmap_complete_pipe_upcall_locked(struct idmap *idmap, int ret)
     556                 :            : {
     557                 :          0 :         struct key_construction *cons = idmap->idmap_upcall_data->key_cons;
     558                 :            : 
     559                 :          0 :         kfree(idmap->idmap_upcall_data);
     560                 :          0 :         idmap->idmap_upcall_data = NULL;
     561                 :          0 :         complete_request_key(cons, ret);
     562                 :          0 : }
     563                 :            : 
     564                 :            : static void
     565                 :            : nfs_idmap_abort_pipe_upcall(struct idmap *idmap, int ret)
     566                 :            : {
     567 [ #  # ][ #  # ]:          0 :         if (idmap->idmap_upcall_data != NULL)
                 [ #  # ]
     568                 :          0 :                 nfs_idmap_complete_pipe_upcall_locked(idmap, ret);
     569                 :            : }
     570                 :            : 
     571                 :          0 : static int nfs_idmap_legacy_upcall(struct key_construction *cons,
     572                 :            :                                    const char *op,
     573                 :            :                                    void *aux)
     574                 :            : {
     575                 :            :         struct idmap_legacy_upcalldata *data;
     576                 :            :         struct rpc_pipe_msg *msg;
     577                 :            :         struct idmap_msg *im;
     578                 :            :         struct idmap *idmap = (struct idmap *)aux;
     579                 :          0 :         struct key *key = cons->key;
     580                 :            :         int ret = -ENOMEM;
     581                 :            : 
     582                 :            :         /* msg and im are freed in idmap_pipe_destroy_msg */
     583                 :            :         data = kzalloc(sizeof(*data), GFP_KERNEL);
     584         [ #  # ]:          0 :         if (!data)
     585                 :            :                 goto out1;
     586                 :            : 
     587                 :          0 :         msg = &data->pipe_msg;
     588                 :          0 :         im = &data->idmap_msg;
     589                 :          0 :         data->idmap = idmap;
     590                 :          0 :         data->key_cons = cons;
     591                 :            : 
     592                 :          0 :         ret = nfs_idmap_prepare_message(key->description, idmap, im, msg);
     593         [ #  # ]:          0 :         if (ret < 0)
     594                 :            :                 goto out2;
     595                 :            : 
     596                 :            :         ret = -EAGAIN;
     597         [ #  # ]:          0 :         if (!nfs_idmap_prepare_pipe_upcall(idmap, data))
     598                 :            :                 goto out2;
     599                 :            : 
     600                 :          0 :         ret = rpc_queue_upcall(idmap->idmap_pipe, msg);
     601         [ #  # ]:          0 :         if (ret < 0)
     602                 :            :                 nfs_idmap_abort_pipe_upcall(idmap, ret);
     603                 :            : 
     604                 :          0 :         return ret;
     605                 :            : out2:
     606                 :          0 :         kfree(data);
     607                 :            : out1:
     608                 :          0 :         complete_request_key(cons, ret);
     609                 :          0 :         return ret;
     610                 :            : }
     611                 :            : 
     612                 :            : static int nfs_idmap_instantiate(struct key *key, struct key *authkey, char *data, size_t datalen)
     613                 :            : {
     614                 :          0 :         return key_instantiate_and_link(key, data, datalen,
     615                 :          0 :                                         id_resolver_cache->thread_keyring,
     616                 :            :                                         authkey);
     617                 :            : }
     618                 :            : 
     619                 :          0 : static int nfs_idmap_read_and_verify_message(struct idmap_msg *im,
     620                 :            :                 struct idmap_msg *upcall,
     621                 :            :                 struct key *key, struct key *authkey)
     622                 :            : {
     623                 :            :         char id_str[NFS_UINT_MAXLEN];
     624                 :            :         size_t len;
     625                 :            :         int ret = -ENOKEY;
     626                 :            : 
     627                 :            :         /* ret = -ENOKEY */
     628         [ #  # ]:          0 :         if (upcall->im_type != im->im_type || upcall->im_conv != im->im_conv)
     629                 :            :                 goto out;
     630      [ #  #  # ]:          0 :         switch (im->im_conv) {
     631                 :            :         case IDMAP_CONV_NAMETOID:
     632         [ #  # ]:          0 :                 if (strcmp(upcall->im_name, im->im_name) != 0)
     633                 :            :                         break;
     634                 :            :                 /* Note: here we store the NUL terminator too */
     635                 :          0 :                 len = sprintf(id_str, "%d", im->im_id) + 1;
     636                 :            :                 ret = nfs_idmap_instantiate(key, authkey, id_str, len);
     637                 :          0 :                 break;
     638                 :            :         case IDMAP_CONV_IDTONAME:
     639         [ #  # ]:          0 :                 if (upcall->im_id != im->im_id)
     640                 :            :                         break;
     641                 :          0 :                 len = strlen(im->im_name);
     642                 :            :                 ret = nfs_idmap_instantiate(key, authkey, im->im_name, len);
     643                 :          0 :                 break;
     644                 :            :         default:
     645                 :            :                 ret = -EINVAL;
     646                 :            :         }
     647                 :            : out:
     648                 :          0 :         return ret;
     649                 :            : }
     650                 :            : 
     651                 :            : static ssize_t
     652                 :          0 : idmap_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
     653                 :            : {
     654                 :            :         struct rpc_inode *rpci = RPC_I(file_inode(filp));
     655                 :          0 :         struct idmap *idmap = (struct idmap *)rpci->private;
     656                 :            :         struct key_construction *cons;
     657                 :            :         struct idmap_msg im;
     658                 :            :         size_t namelen_in;
     659                 :            :         int ret = -ENOKEY;
     660                 :            : 
     661                 :            :         /* If instantiation is successful, anyone waiting for key construction
     662                 :            :          * will have been woken up and someone else may now have used
     663                 :            :          * idmap_key_cons - so after this point we may no longer touch it.
     664                 :            :          */
     665         [ #  # ]:          0 :         if (idmap->idmap_upcall_data == NULL)
     666                 :            :                 goto out_noupcall;
     667                 :            : 
     668                 :          0 :         cons = idmap->idmap_upcall_data->key_cons;
     669                 :            : 
     670         [ #  # ]:          0 :         if (mlen != sizeof(im)) {
     671                 :            :                 ret = -ENOSPC;
     672                 :            :                 goto out;
     673                 :            :         }
     674                 :            : 
     675         [ #  # ]:          0 :         if (copy_from_user(&im, src, mlen) != 0) {
     676                 :            :                 ret = -EFAULT;
     677                 :            :                 goto out;
     678                 :            :         }
     679                 :            : 
     680         [ #  # ]:          0 :         if (!(im.im_status & IDMAP_STATUS_SUCCESS)) {
     681                 :            :                 ret = -ENOKEY;
     682                 :            :                 goto out;
     683                 :            :         }
     684                 :            : 
     685                 :          0 :         namelen_in = strnlen(im.im_name, IDMAP_NAMESZ);
     686         [ #  # ]:          0 :         if (namelen_in == 0 || namelen_in == IDMAP_NAMESZ) {
     687                 :            :                 ret = -EINVAL;
     688                 :            :                 goto out;
     689                 :            : }
     690                 :            : 
     691                 :          0 :         ret = nfs_idmap_read_and_verify_message(&im,
     692                 :          0 :                         &idmap->idmap_upcall_data->idmap_msg,
     693                 :            :                         cons->key, cons->authkey);
     694         [ #  # ]:          0 :         if (ret >= 0) {
     695                 :          0 :                 key_set_timeout(cons->key, nfs_idmap_cache_timeout);
     696                 :          0 :                 ret = mlen;
     697                 :            :         }
     698                 :            : 
     699                 :            : out:
     700                 :          0 :         nfs_idmap_complete_pipe_upcall_locked(idmap, ret);
     701                 :            : out_noupcall:
     702                 :          0 :         return ret;
     703                 :            : }
     704                 :            : 
     705                 :            : static void
     706                 :          0 : idmap_pipe_destroy_msg(struct rpc_pipe_msg *msg)
     707                 :            : {
     708                 :            :         struct idmap_legacy_upcalldata *data = container_of(msg,
     709                 :            :                         struct idmap_legacy_upcalldata,
     710                 :            :                         pipe_msg);
     711                 :          0 :         struct idmap *idmap = data->idmap;
     712                 :            : 
     713         [ #  # ]:          0 :         if (msg->errno)
     714                 :            :                 nfs_idmap_abort_pipe_upcall(idmap, msg->errno);
     715                 :          0 : }
     716                 :            : 
     717                 :            : static void
     718                 :          0 : idmap_release_pipe(struct inode *inode)
     719                 :            : {
     720                 :            :         struct rpc_inode *rpci = RPC_I(inode);
     721                 :          0 :         struct idmap *idmap = (struct idmap *)rpci->private;
     722                 :            : 
     723                 :            :         nfs_idmap_abort_pipe_upcall(idmap, -EPIPE);
     724                 :          0 : }
     725                 :            : 
     726                 :          0 : int nfs_map_name_to_uid(const struct nfs_server *server, const char *name, size_t namelen, kuid_t *uid)
     727                 :            : {
     728                 :          0 :         struct idmap *idmap = server->nfs_client->cl_idmap;
     729                 :          0 :         __u32 id = -1;
     730                 :            :         int ret = 0;
     731                 :            : 
     732         [ #  # ]:          0 :         if (!nfs_map_string_to_numeric(name, namelen, &id))
     733                 :          0 :                 ret = nfs_idmap_lookup_id(name, namelen, "uid", &id, idmap);
     734         [ #  # ]:          0 :         if (ret == 0) {
     735                 :          0 :                 *uid = make_kuid(&init_user_ns, id);
     736         [ #  # ]:          0 :                 if (!uid_valid(*uid))
     737                 :            :                         ret = -ERANGE;
     738                 :            :         }
     739                 :          0 :         trace_nfs4_map_name_to_uid(name, namelen, id, ret);
     740                 :          0 :         return ret;
     741                 :            : }
     742                 :            : 
     743                 :          0 : int nfs_map_group_to_gid(const struct nfs_server *server, const char *name, size_t namelen, kgid_t *gid)
     744                 :            : {
     745                 :          0 :         struct idmap *idmap = server->nfs_client->cl_idmap;
     746                 :          0 :         __u32 id = -1;
     747                 :            :         int ret = 0;
     748                 :            : 
     749         [ #  # ]:          0 :         if (!nfs_map_string_to_numeric(name, namelen, &id))
     750                 :          0 :                 ret = nfs_idmap_lookup_id(name, namelen, "gid", &id, idmap);
     751         [ #  # ]:          0 :         if (ret == 0) {
     752                 :          0 :                 *gid = make_kgid(&init_user_ns, id);
     753         [ #  # ]:          0 :                 if (!gid_valid(*gid))
     754                 :            :                         ret = -ERANGE;
     755                 :            :         }
     756                 :          0 :         trace_nfs4_map_group_to_gid(name, namelen, id, ret);
     757                 :          0 :         return ret;
     758                 :            : }
     759                 :            : 
     760                 :          0 : int nfs_map_uid_to_name(const struct nfs_server *server, kuid_t uid, char *buf, size_t buflen)
     761                 :            : {
     762                 :          0 :         struct idmap *idmap = server->nfs_client->cl_idmap;
     763                 :            :         int ret = -EINVAL;
     764                 :            :         __u32 id;
     765                 :            : 
     766                 :            :         id = from_kuid(&init_user_ns, uid);
     767         [ #  # ]:          0 :         if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
     768                 :          0 :                 ret = nfs_idmap_lookup_name(id, "user", buf, buflen, idmap);
     769         [ #  # ]:          0 :         if (ret < 0)
     770                 :            :                 ret = nfs_map_numeric_to_string(id, buf, buflen);
     771                 :            :         trace_nfs4_map_uid_to_name(buf, ret, id, ret);
     772                 :          0 :         return ret;
     773                 :            : }
     774                 :          0 : int nfs_map_gid_to_group(const struct nfs_server *server, kgid_t gid, char *buf, size_t buflen)
     775                 :            : {
     776                 :          0 :         struct idmap *idmap = server->nfs_client->cl_idmap;
     777                 :            :         int ret = -EINVAL;
     778                 :            :         __u32 id;
     779                 :            : 
     780                 :            :         id = from_kgid(&init_user_ns, gid);
     781         [ #  # ]:          0 :         if (!(server->caps & NFS_CAP_UIDGID_NOMAP))
     782                 :          0 :                 ret = nfs_idmap_lookup_name(id, "group", buf, buflen, idmap);
     783         [ #  # ]:          0 :         if (ret < 0)
     784                 :            :                 ret = nfs_map_numeric_to_string(id, buf, buflen);
     785                 :            :         trace_nfs4_map_gid_to_group(buf, ret, id, ret);
     786                 :          0 :         return ret;
     787                 :            : }

Generated by: LCOV version 1.9