LCOV - code coverage report
Current view: top level - net/sunrpc - svcauth_unix.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 6 317 1.9 %
Date: 2014-04-07 Functions: 2 33 6.1 %
Branches: 2 195 1.0 %

           Branch data     Line data    Source code
       1                 :            : #include <linux/types.h>
       2                 :            : #include <linux/sched.h>
       3                 :            : #include <linux/module.h>
       4                 :            : #include <linux/sunrpc/types.h>
       5                 :            : #include <linux/sunrpc/xdr.h>
       6                 :            : #include <linux/sunrpc/svcsock.h>
       7                 :            : #include <linux/sunrpc/svcauth.h>
       8                 :            : #include <linux/sunrpc/gss_api.h>
       9                 :            : #include <linux/sunrpc/addr.h>
      10                 :            : #include <linux/err.h>
      11                 :            : #include <linux/seq_file.h>
      12                 :            : #include <linux/hash.h>
      13                 :            : #include <linux/string.h>
      14                 :            : #include <linux/slab.h>
      15                 :            : #include <net/sock.h>
      16                 :            : #include <net/ipv6.h>
      17                 :            : #include <linux/kernel.h>
      18                 :            : #include <linux/user_namespace.h>
      19                 :            : #define RPCDBG_FACILITY RPCDBG_AUTH
      20                 :            : 
      21                 :            : 
      22                 :            : #include "netns.h"
      23                 :            : 
      24                 :            : /*
      25                 :            :  * AUTHUNIX and AUTHNULL credentials are both handled here.
      26                 :            :  * AUTHNULL is treated just like AUTHUNIX except that the uid/gid
      27                 :            :  * are always nobody (-2).  i.e. we do the same IP address checks for
      28                 :            :  * AUTHNULL as for AUTHUNIX, and that is done here.
      29                 :            :  */
      30                 :            : 
      31                 :            : 
      32                 :            : struct unix_domain {
      33                 :            :         struct auth_domain      h;
      34                 :            :         /* other stuff later */
      35                 :            : };
      36                 :            : 
      37                 :            : extern struct auth_ops svcauth_null;
      38                 :            : extern struct auth_ops svcauth_unix;
      39                 :            : 
      40                 :          0 : static void svcauth_unix_domain_release(struct auth_domain *dom)
      41                 :            : {
      42                 :            :         struct unix_domain *ud = container_of(dom, struct unix_domain, h);
      43                 :            : 
      44                 :          0 :         kfree(dom->name);
      45                 :          0 :         kfree(ud);
      46                 :          0 : }
      47                 :            : 
      48                 :          0 : struct auth_domain *unix_domain_find(char *name)
      49                 :            : {
      50                 :            :         struct auth_domain *rv;
      51                 :            :         struct unix_domain *new = NULL;
      52                 :            : 
      53                 :          0 :         rv = auth_domain_lookup(name, NULL);
      54                 :            :         while(1) {
      55         [ #  # ]:          0 :                 if (rv) {
      56 [ #  # ][ #  # ]:          0 :                         if (new && rv != &new->h)
      57                 :            :                                 svcauth_unix_domain_release(&new->h);
      58                 :            : 
      59         [ #  # ]:          0 :                         if (rv->flavour != &svcauth_unix) {
      60                 :          0 :                                 auth_domain_put(rv);
      61                 :          0 :                                 return NULL;
      62                 :            :                         }
      63                 :            :                         return rv;
      64                 :            :                 }
      65                 :            : 
      66                 :            :                 new = kmalloc(sizeof(*new), GFP_KERNEL);
      67         [ #  # ]:          0 :                 if (new == NULL)
      68                 :            :                         return NULL;
      69                 :            :                 kref_init(&new->h.ref);
      70                 :          0 :                 new->h.name = kstrdup(name, GFP_KERNEL);
      71         [ #  # ]:          0 :                 if (new->h.name == NULL) {
      72                 :          0 :                         kfree(new);
      73                 :          0 :                         return NULL;
      74                 :            :                 }
      75                 :          0 :                 new->h.flavour = &svcauth_unix;
      76                 :          0 :                 rv = auth_domain_lookup(name, &new->h);
      77                 :          0 :         }
      78                 :            : }
      79                 :            : EXPORT_SYMBOL_GPL(unix_domain_find);
      80                 :            : 
      81                 :            : 
      82                 :            : /**************************************************
      83                 :            :  * cache for IP address to unix_domain
      84                 :            :  * as needed by AUTH_UNIX
      85                 :            :  */
      86                 :            : #define IP_HASHBITS     8
      87                 :            : #define IP_HASHMAX      (1<<IP_HASHBITS)
      88                 :            : 
      89                 :            : struct ip_map {
      90                 :            :         struct cache_head       h;
      91                 :            :         char                    m_class[8]; /* e.g. "nfsd" */
      92                 :            :         struct in6_addr         m_addr;
      93                 :            :         struct unix_domain      *m_client;
      94                 :            : };
      95                 :            : 
      96                 :          0 : static void ip_map_put(struct kref *kref)
      97                 :            : {
      98                 :            :         struct cache_head *item = container_of(kref, struct cache_head, ref);
      99                 :          0 :         struct ip_map *im = container_of(item, struct ip_map,h);
     100                 :            : 
     101 [ #  # ][ #  # ]:          0 :         if (test_bit(CACHE_VALID, &item->flags) &&
     102                 :            :             !test_bit(CACHE_NEGATIVE, &item->flags))
     103                 :          0 :                 auth_domain_put(&im->m_client->h);
     104                 :          0 :         kfree(im);
     105                 :          0 : }
     106                 :            : 
     107                 :            : static inline int hash_ip6(const struct in6_addr *ip)
     108                 :            : {
     109                 :            :         return hash_32(ipv6_addr_hash(ip), IP_HASHBITS);
     110                 :            : }
     111                 :          0 : static int ip_map_match(struct cache_head *corig, struct cache_head *cnew)
     112                 :            : {
     113                 :            :         struct ip_map *orig = container_of(corig, struct ip_map, h);
     114                 :            :         struct ip_map *new = container_of(cnew, struct ip_map, h);
     115 [ #  # ][ #  # ]:          0 :         return strcmp(orig->m_class, new->m_class) == 0 &&
     116                 :            :                ipv6_addr_equal(&orig->m_addr, &new->m_addr);
     117                 :            : }
     118                 :          0 : static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
     119                 :            : {
     120                 :            :         struct ip_map *new = container_of(cnew, struct ip_map, h);
     121                 :            :         struct ip_map *item = container_of(citem, struct ip_map, h);
     122                 :            : 
     123                 :          0 :         strcpy(new->m_class, item->m_class);
     124                 :          0 :         new->m_addr = item->m_addr;
     125                 :          0 : }
     126                 :          0 : static void update(struct cache_head *cnew, struct cache_head *citem)
     127                 :            : {
     128                 :            :         struct ip_map *new = container_of(cnew, struct ip_map, h);
     129                 :            :         struct ip_map *item = container_of(citem, struct ip_map, h);
     130                 :            : 
     131                 :          0 :         kref_get(&item->m_client->h.ref);
     132                 :          0 :         new->m_client = item->m_client;
     133                 :          0 : }
     134                 :          0 : static struct cache_head *ip_map_alloc(void)
     135                 :            : {
     136                 :            :         struct ip_map *i = kmalloc(sizeof(*i), GFP_KERNEL);
     137         [ #  # ]:          0 :         if (i)
     138                 :          0 :                 return &i->h;
     139                 :            :         else
     140                 :            :                 return NULL;
     141                 :            : }
     142                 :            : 
     143                 :          0 : static void ip_map_request(struct cache_detail *cd,
     144                 :            :                                   struct cache_head *h,
     145                 :            :                                   char **bpp, int *blen)
     146                 :            : {
     147                 :            :         char text_addr[40];
     148                 :            :         struct ip_map *im = container_of(h, struct ip_map, h);
     149                 :            : 
     150         [ #  # ]:          0 :         if (ipv6_addr_v4mapped(&(im->m_addr))) {
     151                 :          0 :                 snprintf(text_addr, 20, "%pI4", &im->m_addr.s6_addr32[3]);
     152                 :            :         } else {
     153                 :          0 :                 snprintf(text_addr, 40, "%pI6", &im->m_addr);
     154                 :            :         }
     155                 :          0 :         qword_add(bpp, blen, im->m_class);
     156                 :          0 :         qword_add(bpp, blen, text_addr);
     157                 :          0 :         (*bpp)[-1] = '\n';
     158                 :          0 : }
     159                 :            : 
     160                 :            : static struct ip_map *__ip_map_lookup(struct cache_detail *cd, char *class, struct in6_addr *addr);
     161                 :            : static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm, struct unix_domain *udom, time_t expiry);
     162                 :            : 
     163                 :          0 : static int ip_map_parse(struct cache_detail *cd,
     164                 :            :                           char *mesg, int mlen)
     165                 :            : {
     166                 :            :         /* class ipaddress [domainname] */
     167                 :            :         /* should be safe just to use the start of the input buffer
     168                 :            :          * for scratch: */
     169                 :          0 :         char *buf = mesg;
     170                 :            :         int len;
     171                 :            :         char class[8];
     172                 :            :         union {
     173                 :            :                 struct sockaddr         sa;
     174                 :            :                 struct sockaddr_in      s4;
     175                 :            :                 struct sockaddr_in6     s6;
     176                 :            :         } address;
     177                 :            :         struct sockaddr_in6 sin6;
     178                 :            :         int err;
     179                 :            : 
     180                 :            :         struct ip_map *ipmp;
     181                 :            :         struct auth_domain *dom;
     182                 :            :         time_t expiry;
     183                 :            : 
     184         [ #  # ]:          0 :         if (mesg[mlen-1] != '\n')
     185                 :            :                 return -EINVAL;
     186                 :          0 :         mesg[mlen-1] = 0;
     187                 :            : 
     188                 :            :         /* class */
     189                 :          0 :         len = qword_get(&mesg, class, sizeof(class));
     190         [ #  # ]:          0 :         if (len <= 0) return -EINVAL;
     191                 :            : 
     192                 :            :         /* ip address */
     193                 :          0 :         len = qword_get(&mesg, buf, mlen);
     194         [ #  # ]:          0 :         if (len <= 0) return -EINVAL;
     195                 :            : 
     196         [ #  # ]:          0 :         if (rpc_pton(cd->net, buf, len, &address.sa, sizeof(address)) == 0)
     197                 :            :                 return -EINVAL;
     198      [ #  #  # ]:          0 :         switch (address.sa.sa_family) {
     199                 :            :         case AF_INET:
     200                 :            :                 /* Form a mapped IPv4 address in sin6 */
     201                 :          0 :                 sin6.sin6_family = AF_INET6;
     202                 :          0 :                 ipv6_addr_set_v4mapped(address.s4.sin_addr.s_addr,
     203                 :            :                                 &sin6.sin6_addr);
     204                 :            :                 break;
     205                 :            : #if IS_ENABLED(CONFIG_IPV6)
     206                 :            :         case AF_INET6:
     207                 :          0 :                 memcpy(&sin6, &address.s6, sizeof(sin6));
     208                 :          0 :                 break;
     209                 :            : #endif
     210                 :            :         default:
     211                 :            :                 return -EINVAL;
     212                 :            :         }
     213                 :            : 
     214                 :            :         expiry = get_expiry(&mesg);
     215         [ #  # ]:          0 :         if (expiry ==0)
     216                 :            :                 return -EINVAL;
     217                 :            : 
     218                 :            :         /* domainname, or empty for NEGATIVE */
     219                 :          0 :         len = qword_get(&mesg, buf, mlen);
     220         [ #  # ]:          0 :         if (len < 0) return -EINVAL;
     221                 :            : 
     222         [ #  # ]:          0 :         if (len) {
     223                 :          0 :                 dom = unix_domain_find(buf);
     224         [ #  # ]:          0 :                 if (dom == NULL)
     225                 :            :                         return -ENOENT;
     226                 :            :         } else
     227                 :            :                 dom = NULL;
     228                 :            : 
     229                 :            :         /* IPv6 scope IDs are ignored for now */
     230                 :          0 :         ipmp = __ip_map_lookup(cd, class, &sin6.sin6_addr);
     231         [ #  # ]:          0 :         if (ipmp) {
     232                 :          0 :                 err = __ip_map_update(cd, ipmp,
     233                 :            :                              container_of(dom, struct unix_domain, h),
     234                 :            :                              expiry);
     235                 :            :         } else
     236                 :            :                 err = -ENOMEM;
     237                 :            : 
     238         [ #  # ]:          0 :         if (dom)
     239                 :          0 :                 auth_domain_put(dom);
     240                 :            : 
     241                 :          0 :         cache_flush();
     242                 :          0 :         return err;
     243                 :            : }
     244                 :            : 
     245                 :          0 : static int ip_map_show(struct seq_file *m,
     246                 :            :                        struct cache_detail *cd,
     247                 :            :                        struct cache_head *h)
     248                 :            : {
     249                 :            :         struct ip_map *im;
     250                 :            :         struct in6_addr addr;
     251                 :            :         char *dom = "-no-domain-";
     252                 :            : 
     253         [ +  - ]:          1 :         if (h == NULL) {
     254                 :          1 :                 seq_puts(m, "#class IP domain\n");
     255                 :          1 :                 return 0;
     256                 :            :         }
     257                 :            :         im = container_of(h, struct ip_map, h);
     258                 :            :         /* class addr domain */
     259                 :          0 :         addr = im->m_addr;
     260                 :            : 
     261 [ #  # ][ #  # ]:          0 :         if (test_bit(CACHE_VALID, &h->flags) &&
     262                 :            :             !test_bit(CACHE_NEGATIVE, &h->flags))
     263                 :          0 :                 dom = im->m_client->h.name;
     264                 :            : 
     265         [ #  # ]:          0 :         if (ipv6_addr_v4mapped(&addr)) {
     266                 :          0 :                 seq_printf(m, "%s %pI4 %s\n",
     267                 :          0 :                         im->m_class, &addr.s6_addr32[3], dom);
     268                 :            :         } else {
     269                 :          0 :                 seq_printf(m, "%s %pI6 %s\n", im->m_class, &addr, dom);
     270                 :            :         }
     271                 :            :         return 0;
     272                 :            : }
     273                 :            : 
     274                 :            : 
     275                 :          0 : static struct ip_map *__ip_map_lookup(struct cache_detail *cd, char *class,
     276                 :            :                 struct in6_addr *addr)
     277                 :            : {
     278                 :            :         struct ip_map ip;
     279                 :            :         struct cache_head *ch;
     280                 :            : 
     281                 :          0 :         strcpy(ip.m_class, class);
     282                 :          0 :         ip.m_addr = *addr;
     283                 :          0 :         ch = sunrpc_cache_lookup(cd, &ip.h,
     284                 :          0 :                                  hash_str(class, IP_HASHBITS) ^
     285                 :            :                                  hash_ip6(addr));
     286                 :            : 
     287         [ #  # ]:          0 :         if (ch)
     288                 :          0 :                 return container_of(ch, struct ip_map, h);
     289                 :            :         else
     290                 :            :                 return NULL;
     291                 :            : }
     292                 :            : 
     293                 :            : static inline struct ip_map *ip_map_lookup(struct net *net, char *class,
     294                 :            :                 struct in6_addr *addr)
     295                 :            : {
     296                 :            :         struct sunrpc_net *sn;
     297                 :            : 
     298                 :            :         sn = net_generic(net, sunrpc_net_id);
     299                 :            :         return __ip_map_lookup(sn->ip_map_cache, class, addr);
     300                 :            : }
     301                 :            : 
     302                 :          0 : static int __ip_map_update(struct cache_detail *cd, struct ip_map *ipm,
     303                 :            :                 struct unix_domain *udom, time_t expiry)
     304                 :            : {
     305                 :            :         struct ip_map ip;
     306                 :            :         struct cache_head *ch;
     307                 :            : 
     308                 :          0 :         ip.m_client = udom;
     309                 :          0 :         ip.h.flags = 0;
     310         [ #  # ]:          0 :         if (!udom)
     311                 :          0 :                 set_bit(CACHE_NEGATIVE, &ip.h.flags);
     312                 :          0 :         ip.h.expiry_time = expiry;
     313                 :          0 :         ch = sunrpc_cache_update(cd, &ip.h, &ipm->h,
     314                 :          0 :                                  hash_str(ipm->m_class, IP_HASHBITS) ^
     315                 :            :                                  hash_ip6(&ipm->m_addr));
     316         [ #  # ]:          0 :         if (!ch)
     317                 :            :                 return -ENOMEM;
     318                 :            :         cache_put(ch, cd);
     319                 :            :         return 0;
     320                 :            : }
     321                 :            : 
     322                 :            : static inline int ip_map_update(struct net *net, struct ip_map *ipm,
     323                 :            :                 struct unix_domain *udom, time_t expiry)
     324                 :            : {
     325                 :            :         struct sunrpc_net *sn;
     326                 :            : 
     327                 :            :         sn = net_generic(net, sunrpc_net_id);
     328                 :            :         return __ip_map_update(sn->ip_map_cache, ipm, udom, expiry);
     329                 :            : }
     330                 :            : 
     331                 :          0 : void svcauth_unix_purge(struct net *net)
     332                 :            : {
     333                 :            :         struct sunrpc_net *sn;
     334                 :            : 
     335                 :          0 :         sn = net_generic(net, sunrpc_net_id);
     336                 :          0 :         cache_purge(sn->ip_map_cache);
     337                 :          0 : }
     338                 :            : EXPORT_SYMBOL_GPL(svcauth_unix_purge);
     339                 :            : 
     340                 :            : static inline struct ip_map *
     341                 :            : ip_map_cached_get(struct svc_xprt *xprt)
     342                 :            : {
     343                 :            :         struct ip_map *ipm = NULL;
     344                 :            :         struct sunrpc_net *sn;
     345                 :            : 
     346         [ #  # ]:          0 :         if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) {
     347                 :            :                 spin_lock(&xprt->xpt_lock);
     348                 :          0 :                 ipm = xprt->xpt_auth_cache;
     349         [ #  # ]:          0 :                 if (ipm != NULL) {
     350                 :          0 :                         sn = net_generic(xprt->xpt_net, sunrpc_net_id);
     351         [ #  # ]:          0 :                         if (cache_is_expired(sn->ip_map_cache, &ipm->h)) {
     352                 :            :                                 /*
     353                 :            :                                  * The entry has been invalidated since it was
     354                 :            :                                  * remembered, e.g. by a second mount from the
     355                 :            :                                  * same IP address.
     356                 :            :                                  */
     357                 :          0 :                                 xprt->xpt_auth_cache = NULL;
     358                 :            :                                 spin_unlock(&xprt->xpt_lock);
     359                 :          0 :                                 cache_put(&ipm->h, sn->ip_map_cache);
     360                 :            :                                 return NULL;
     361                 :            :                         }
     362                 :            :                         cache_get(&ipm->h);
     363                 :            :                 }
     364                 :            :                 spin_unlock(&xprt->xpt_lock);
     365                 :            :         }
     366                 :            :         return ipm;
     367                 :            : }
     368                 :            : 
     369                 :            : static inline void
     370                 :            : ip_map_cached_put(struct svc_xprt *xprt, struct ip_map *ipm)
     371                 :            : {
     372         [ #  # ]:          0 :         if (test_bit(XPT_CACHE_AUTH, &xprt->xpt_flags)) {
     373                 :            :                 spin_lock(&xprt->xpt_lock);
     374         [ #  # ]:          0 :                 if (xprt->xpt_auth_cache == NULL) {
     375                 :            :                         /* newly cached, keep the reference */
     376                 :          0 :                         xprt->xpt_auth_cache = ipm;
     377                 :            :                         ipm = NULL;
     378                 :            :                 }
     379                 :            :                 spin_unlock(&xprt->xpt_lock);
     380                 :            :         }
     381         [ #  # ]:          0 :         if (ipm) {
     382                 :            :                 struct sunrpc_net *sn;
     383                 :            : 
     384                 :          0 :                 sn = net_generic(xprt->xpt_net, sunrpc_net_id);
     385                 :          0 :                 cache_put(&ipm->h, sn->ip_map_cache);
     386                 :            :         }
     387                 :            : }
     388                 :            : 
     389                 :            : void
     390                 :          0 : svcauth_unix_info_release(struct svc_xprt *xpt)
     391                 :            : {
     392                 :            :         struct ip_map *ipm;
     393                 :            : 
     394                 :          0 :         ipm = xpt->xpt_auth_cache;
     395         [ #  # ]:          0 :         if (ipm != NULL) {
     396                 :            :                 struct sunrpc_net *sn;
     397                 :            : 
     398                 :          0 :                 sn = net_generic(xpt->xpt_net, sunrpc_net_id);
     399                 :          0 :                 cache_put(&ipm->h, sn->ip_map_cache);
     400                 :            :         }
     401                 :          0 : }
     402                 :            : 
     403                 :            : /****************************************************************************
     404                 :            :  * auth.unix.gid cache
     405                 :            :  * simple cache to map a UID to a list of GIDs
     406                 :            :  * because AUTH_UNIX aka AUTH_SYS has a max of 16
     407                 :            :  */
     408                 :            : #define GID_HASHBITS    8
     409                 :            : #define GID_HASHMAX     (1<<GID_HASHBITS)
     410                 :            : 
     411                 :            : struct unix_gid {
     412                 :            :         struct cache_head       h;
     413                 :            :         kuid_t                  uid;
     414                 :            :         struct group_info       *gi;
     415                 :            : };
     416                 :            : 
     417                 :            : static int unix_gid_hash(kuid_t uid)
     418                 :            : {
     419                 :          0 :         return hash_long(from_kuid(&init_user_ns, uid), GID_HASHBITS);
     420                 :            : }
     421                 :            : 
     422                 :          0 : static void unix_gid_put(struct kref *kref)
     423                 :            : {
     424                 :            :         struct cache_head *item = container_of(kref, struct cache_head, ref);
     425                 :          0 :         struct unix_gid *ug = container_of(item, struct unix_gid, h);
     426 [ #  # ][ #  # ]:          0 :         if (test_bit(CACHE_VALID, &item->flags) &&
     427                 :            :             !test_bit(CACHE_NEGATIVE, &item->flags))
     428         [ #  # ]:          0 :                 put_group_info(ug->gi);
     429                 :          0 :         kfree(ug);
     430                 :          0 : }
     431                 :            : 
     432                 :          0 : static int unix_gid_match(struct cache_head *corig, struct cache_head *cnew)
     433                 :            : {
     434                 :            :         struct unix_gid *orig = container_of(corig, struct unix_gid, h);
     435                 :            :         struct unix_gid *new = container_of(cnew, struct unix_gid, h);
     436                 :          0 :         return uid_eq(orig->uid, new->uid);
     437                 :            : }
     438                 :          0 : static void unix_gid_init(struct cache_head *cnew, struct cache_head *citem)
     439                 :            : {
     440                 :            :         struct unix_gid *new = container_of(cnew, struct unix_gid, h);
     441                 :            :         struct unix_gid *item = container_of(citem, struct unix_gid, h);
     442                 :          0 :         new->uid = item->uid;
     443                 :          0 : }
     444                 :          0 : static void unix_gid_update(struct cache_head *cnew, struct cache_head *citem)
     445                 :            : {
     446                 :            :         struct unix_gid *new = container_of(cnew, struct unix_gid, h);
     447                 :            :         struct unix_gid *item = container_of(citem, struct unix_gid, h);
     448                 :            : 
     449                 :          0 :         get_group_info(item->gi);
     450                 :          0 :         new->gi = item->gi;
     451                 :          0 : }
     452                 :          0 : static struct cache_head *unix_gid_alloc(void)
     453                 :            : {
     454                 :            :         struct unix_gid *g = kmalloc(sizeof(*g), GFP_KERNEL);
     455         [ #  # ]:          0 :         if (g)
     456                 :          0 :                 return &g->h;
     457                 :            :         else
     458                 :            :                 return NULL;
     459                 :            : }
     460                 :            : 
     461                 :          0 : static void unix_gid_request(struct cache_detail *cd,
     462                 :            :                              struct cache_head *h,
     463                 :            :                              char **bpp, int *blen)
     464                 :            : {
     465                 :            :         char tuid[20];
     466                 :            :         struct unix_gid *ug = container_of(h, struct unix_gid, h);
     467                 :            : 
     468                 :          0 :         snprintf(tuid, 20, "%u", from_kuid(&init_user_ns, ug->uid));
     469                 :          0 :         qword_add(bpp, blen, tuid);
     470                 :          0 :         (*bpp)[-1] = '\n';
     471                 :          0 : }
     472                 :            : 
     473                 :            : static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, kuid_t uid);
     474                 :            : 
     475                 :          0 : static int unix_gid_parse(struct cache_detail *cd,
     476                 :            :                         char *mesg, int mlen)
     477                 :            : {
     478                 :            :         /* uid expiry Ngid gid0 gid1 ... gidN-1 */
     479                 :            :         int id;
     480                 :            :         kuid_t uid;
     481                 :            :         int gids;
     482                 :            :         int rv;
     483                 :            :         int i;
     484                 :            :         int err;
     485                 :            :         time_t expiry;
     486                 :            :         struct unix_gid ug, *ugp;
     487                 :            : 
     488         [ #  # ]:          0 :         if (mesg[mlen - 1] != '\n')
     489                 :            :                 return -EINVAL;
     490                 :          0 :         mesg[mlen-1] = 0;
     491                 :            : 
     492                 :            :         rv = get_int(&mesg, &id);
     493         [ #  # ]:          0 :         if (rv)
     494                 :            :                 return -EINVAL;
     495                 :          0 :         uid = make_kuid(&init_user_ns, id);
     496                 :          0 :         ug.uid = uid;
     497                 :            : 
     498                 :            :         expiry = get_expiry(&mesg);
     499         [ #  # ]:          0 :         if (expiry == 0)
     500                 :            :                 return -EINVAL;
     501                 :            : 
     502                 :            :         rv = get_int(&mesg, &gids);
     503 [ #  # ][ #  # ]:          0 :         if (rv || gids < 0 || gids > 8192)
                 [ #  # ]
     504                 :            :                 return -EINVAL;
     505                 :            : 
     506                 :          0 :         ug.gi = groups_alloc(gids);
     507         [ #  # ]:          0 :         if (!ug.gi)
     508                 :            :                 return -ENOMEM;
     509                 :            : 
     510         [ #  # ]:          0 :         for (i = 0 ; i < gids ; i++) {
     511                 :            :                 int gid;
     512                 :            :                 kgid_t kgid;
     513                 :            :                 rv = get_int(&mesg, &gid);
     514                 :            :                 err = -EINVAL;
     515         [ #  # ]:          0 :                 if (rv)
     516                 :            :                         goto out;
     517                 :          0 :                 kgid = make_kgid(&init_user_ns, gid);
     518         [ #  # ]:          0 :                 if (!gid_valid(kgid))
     519                 :            :                         goto out;
     520                 :          0 :                 GROUP_AT(ug.gi, i) = kgid;
     521                 :            :         }
     522                 :            : 
     523                 :          0 :         ugp = unix_gid_lookup(cd, uid);
     524         [ #  # ]:          0 :         if (ugp) {
     525                 :            :                 struct cache_head *ch;
     526                 :          0 :                 ug.h.flags = 0;
     527                 :          0 :                 ug.h.expiry_time = expiry;
     528                 :          0 :                 ch = sunrpc_cache_update(cd,
     529                 :            :                                          &ug.h, &ugp->h,
     530                 :            :                                          unix_gid_hash(uid));
     531         [ #  # ]:          0 :                 if (!ch)
     532                 :            :                         err = -ENOMEM;
     533                 :            :                 else {
     534                 :            :                         err = 0;
     535                 :            :                         cache_put(ch, cd);
     536                 :            :                 }
     537                 :            :         } else
     538                 :            :                 err = -ENOMEM;
     539                 :            :  out:
     540         [ #  # ]:          0 :         if (ug.gi)
     541         [ #  # ]:          0 :                 put_group_info(ug.gi);
     542                 :          0 :         return err;
     543                 :            : }
     544                 :            : 
     545                 :          0 : static int unix_gid_show(struct seq_file *m,
     546                 :            :                          struct cache_detail *cd,
     547                 :            :                          struct cache_head *h)
     548                 :            : {
     549                 :            :         struct user_namespace *user_ns = &init_user_ns;
     550                 :            :         struct unix_gid *ug;
     551                 :            :         int i;
     552                 :            :         int glen;
     553                 :            : 
     554         [ +  - ]:          1 :         if (h == NULL) {
     555                 :          1 :                 seq_puts(m, "#uid cnt: gids...\n");
     556                 :          1 :                 return 0;
     557                 :            :         }
     558                 :            :         ug = container_of(h, struct unix_gid, h);
     559 [ #  # ][ #  # ]:          0 :         if (test_bit(CACHE_VALID, &h->flags) &&
     560                 :            :             !test_bit(CACHE_NEGATIVE, &h->flags))
     561                 :          0 :                 glen = ug->gi->ngroups;
     562                 :            :         else
     563                 :            :                 glen = 0;
     564                 :            : 
     565                 :          0 :         seq_printf(m, "%u %d:", from_kuid_munged(user_ns, ug->uid), glen);
     566         [ #  # ]:          0 :         for (i = 0; i < glen; i++)
     567                 :          0 :                 seq_printf(m, " %d", from_kgid_munged(user_ns, GROUP_AT(ug->gi, i)));
     568                 :          0 :         seq_printf(m, "\n");
     569                 :          0 :         return 0;
     570                 :            : }
     571                 :            : 
     572                 :            : static struct cache_detail unix_gid_cache_template = {
     573                 :            :         .owner          = THIS_MODULE,
     574                 :            :         .hash_size      = GID_HASHMAX,
     575                 :            :         .name           = "auth.unix.gid",
     576                 :            :         .cache_put      = unix_gid_put,
     577                 :            :         .cache_request  = unix_gid_request,
     578                 :            :         .cache_parse    = unix_gid_parse,
     579                 :            :         .cache_show     = unix_gid_show,
     580                 :            :         .match          = unix_gid_match,
     581                 :            :         .init           = unix_gid_init,
     582                 :            :         .update         = unix_gid_update,
     583                 :            :         .alloc          = unix_gid_alloc,
     584                 :            : };
     585                 :            : 
     586                 :          0 : int unix_gid_cache_create(struct net *net)
     587                 :            : {
     588                 :          0 :         struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
     589                 :            :         struct cache_detail *cd;
     590                 :            :         int err;
     591                 :            : 
     592                 :          0 :         cd = cache_create_net(&unix_gid_cache_template, net);
     593         [ #  # ]:          0 :         if (IS_ERR(cd))
     594                 :          0 :                 return PTR_ERR(cd);
     595                 :          0 :         err = cache_register_net(cd, net);
     596         [ #  # ]:          0 :         if (err) {
     597                 :          0 :                 cache_destroy_net(cd, net);
     598                 :          0 :                 return err;
     599                 :            :         }
     600                 :          0 :         sn->unix_gid_cache = cd;
     601                 :          0 :         return 0;
     602                 :            : }
     603                 :            : 
     604                 :          0 : void unix_gid_cache_destroy(struct net *net)
     605                 :            : {
     606                 :          0 :         struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
     607                 :          0 :         struct cache_detail *cd = sn->unix_gid_cache;
     608                 :            : 
     609                 :          0 :         sn->unix_gid_cache = NULL;
     610                 :          0 :         cache_purge(cd);
     611                 :          0 :         cache_unregister_net(cd, net);
     612                 :          0 :         cache_destroy_net(cd, net);
     613                 :          0 : }
     614                 :            : 
     615                 :          0 : static struct unix_gid *unix_gid_lookup(struct cache_detail *cd, kuid_t uid)
     616                 :            : {
     617                 :            :         struct unix_gid ug;
     618                 :            :         struct cache_head *ch;
     619                 :            : 
     620                 :          0 :         ug.uid = uid;
     621                 :          0 :         ch = sunrpc_cache_lookup(cd, &ug.h, unix_gid_hash(uid));
     622         [ #  # ]:          0 :         if (ch)
     623                 :          0 :                 return container_of(ch, struct unix_gid, h);
     624                 :            :         else
     625                 :            :                 return NULL;
     626                 :            : }
     627                 :            : 
     628                 :          0 : static struct group_info *unix_gid_find(kuid_t uid, struct svc_rqst *rqstp)
     629                 :            : {
     630                 :            :         struct unix_gid *ug;
     631                 :            :         struct group_info *gi;
     632                 :            :         int ret;
     633                 :          0 :         struct sunrpc_net *sn = net_generic(rqstp->rq_xprt->xpt_net,
     634                 :            :                                             sunrpc_net_id);
     635                 :            : 
     636                 :          0 :         ug = unix_gid_lookup(sn->unix_gid_cache, uid);
     637         [ #  # ]:          0 :         if (!ug)
     638                 :            :                 return ERR_PTR(-EAGAIN);
     639                 :          0 :         ret = cache_check(sn->unix_gid_cache, &ug->h, &rqstp->rq_chandle);
     640   [ #  #  #  # ]:          0 :         switch (ret) {
     641                 :            :         case -ENOENT:
     642                 :            :                 return ERR_PTR(-ENOENT);
     643                 :            :         case -ETIMEDOUT:
     644                 :          0 :                 return ERR_PTR(-ESHUTDOWN);
     645                 :            :         case 0:
     646                 :          0 :                 gi = get_group_info(ug->gi);
     647                 :          0 :                 cache_put(&ug->h, sn->unix_gid_cache);
     648                 :          0 :                 return gi;
     649                 :            :         default:
     650                 :          0 :                 return ERR_PTR(-EAGAIN);
     651                 :            :         }
     652                 :            : }
     653                 :            : 
     654                 :            : int
     655                 :          0 : svcauth_unix_set_client(struct svc_rqst *rqstp)
     656                 :            : {
     657                 :            :         struct sockaddr_in *sin;
     658                 :            :         struct sockaddr_in6 *sin6, sin6_storage;
     659                 :            :         struct ip_map *ipm;
     660                 :            :         struct group_info *gi;
     661                 :            :         struct svc_cred *cred = &rqstp->rq_cred;
     662                 :          0 :         struct svc_xprt *xprt = rqstp->rq_xprt;
     663                 :          0 :         struct net *net = xprt->xpt_net;
     664                 :          0 :         struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
     665                 :            : 
     666      [ #  #  # ]:          0 :         switch (rqstp->rq_addr.ss_family) {
     667                 :            :         case AF_INET:
     668                 :            :                 sin = svc_addr_in(rqstp);
     669                 :            :                 sin6 = &sin6_storage;
     670                 :          0 :                 ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &sin6->sin6_addr);
     671                 :            :                 break;
     672                 :            :         case AF_INET6:
     673                 :          0 :                 sin6 = svc_addr_in6(rqstp);
     674                 :          0 :                 break;
     675                 :            :         default:
     676                 :          0 :                 BUG();
     677                 :            :         }
     678                 :            : 
     679                 :          0 :         rqstp->rq_client = NULL;
     680         [ #  # ]:          0 :         if (rqstp->rq_proc == 0)
     681                 :            :                 return SVC_OK;
     682                 :            : 
     683                 :            :         ipm = ip_map_cached_get(xprt);
     684         [ #  # ]:          0 :         if (ipm == NULL)
     685                 :          0 :                 ipm = __ip_map_lookup(sn->ip_map_cache, rqstp->rq_server->sv_program->pg_class,
     686                 :            :                                     &sin6->sin6_addr);
     687                 :            : 
     688         [ #  # ]:          0 :         if (ipm == NULL)
     689                 :            :                 return SVC_DENIED;
     690                 :            : 
     691   [ #  #  #  #  :          0 :         switch (cache_check(sn->ip_map_cache, &ipm->h, &rqstp->rq_chandle)) {
                      # ]
     692                 :            :                 default:
     693                 :          0 :                         BUG();
     694                 :            :                 case -ETIMEDOUT:
     695                 :            :                         return SVC_CLOSE;
     696                 :            :                 case -EAGAIN:
     697                 :          0 :                         return SVC_DROP;
     698                 :            :                 case -ENOENT:
     699                 :          0 :                         return SVC_DENIED;
     700                 :            :                 case 0:
     701                 :          0 :                         rqstp->rq_client = &ipm->m_client->h;
     702                 :            :                         kref_get(&rqstp->rq_client->ref);
     703                 :            :                         ip_map_cached_put(xprt, ipm);
     704                 :            :                         break;
     705                 :            :         }
     706                 :            : 
     707                 :          0 :         gi = unix_gid_find(cred->cr_uid, rqstp);
     708   [ #  #  #  # ]:          0 :         switch (PTR_ERR(gi)) {
     709                 :            :         case -EAGAIN:
     710                 :            :                 return SVC_DROP;
     711                 :            :         case -ESHUTDOWN:
     712                 :          0 :                 return SVC_CLOSE;
     713                 :            :         case -ENOENT:
     714                 :            :                 break;
     715                 :            :         default:
     716         [ #  # ]:          0 :                 put_group_info(cred->cr_group_info);
     717                 :          0 :                 cred->cr_group_info = gi;
     718                 :            :         }
     719                 :            :         return SVC_OK;
     720                 :            : }
     721                 :            : 
     722                 :            : EXPORT_SYMBOL_GPL(svcauth_unix_set_client);
     723                 :            : 
     724                 :            : static int
     725                 :          0 : svcauth_null_accept(struct svc_rqst *rqstp, __be32 *authp)
     726                 :            : {
     727                 :            :         struct kvec     *argv = &rqstp->rq_arg.head[0];
     728                 :            :         struct kvec     *resv = &rqstp->rq_res.head[0];
     729                 :            :         struct svc_cred *cred = &rqstp->rq_cred;
     730                 :            : 
     731                 :          0 :         cred->cr_group_info = NULL;
     732                 :          0 :         cred->cr_principal = NULL;
     733                 :          0 :         rqstp->rq_client = NULL;
     734                 :            : 
     735         [ #  # ]:          0 :         if (argv->iov_len < 3*4)
     736                 :            :                 return SVC_GARBAGE;
     737                 :            : 
     738         [ #  # ]:          0 :         if (svc_getu32(argv) != 0) {
     739                 :            :                 dprintk("svc: bad null cred\n");
     740                 :          0 :                 *authp = rpc_autherr_badcred;
     741                 :          0 :                 return SVC_DENIED;
     742                 :            :         }
     743 [ #  # ][ #  # ]:          0 :         if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
     744                 :            :                 dprintk("svc: bad null verf\n");
     745                 :          0 :                 *authp = rpc_autherr_badverf;
     746                 :          0 :                 return SVC_DENIED;
     747                 :            :         }
     748                 :            : 
     749                 :            :         /* Signal that mapping to nobody uid/gid is required */
     750                 :          0 :         cred->cr_uid = INVALID_UID;
     751                 :          0 :         cred->cr_gid = INVALID_GID;
     752                 :          0 :         cred->cr_group_info = groups_alloc(0);
     753         [ #  # ]:          0 :         if (cred->cr_group_info == NULL)
     754                 :            :                 return SVC_CLOSE; /* kmalloc failure - client must retry */
     755                 :            : 
     756                 :            :         /* Put NULL verifier */
     757                 :            :         svc_putnl(resv, RPC_AUTH_NULL);
     758                 :            :         svc_putnl(resv, 0);
     759                 :            : 
     760                 :          0 :         rqstp->rq_cred.cr_flavor = RPC_AUTH_NULL;
     761                 :          0 :         return SVC_OK;
     762                 :            : }
     763                 :            : 
     764                 :            : static int
     765                 :          0 : svcauth_null_release(struct svc_rqst *rqstp)
     766                 :            : {
     767         [ #  # ]:          0 :         if (rqstp->rq_client)
     768                 :          0 :                 auth_domain_put(rqstp->rq_client);
     769                 :          0 :         rqstp->rq_client = NULL;
     770         [ #  # ]:          0 :         if (rqstp->rq_cred.cr_group_info)
     771         [ #  # ]:          0 :                 put_group_info(rqstp->rq_cred.cr_group_info);
     772                 :          0 :         rqstp->rq_cred.cr_group_info = NULL;
     773                 :            : 
     774                 :          0 :         return 0; /* don't drop */
     775                 :            : }
     776                 :            : 
     777                 :            : 
     778                 :            : struct auth_ops svcauth_null = {
     779                 :            :         .name           = "null",
     780                 :            :         .owner          = THIS_MODULE,
     781                 :            :         .flavour        = RPC_AUTH_NULL,
     782                 :            :         .accept         = svcauth_null_accept,
     783                 :            :         .release        = svcauth_null_release,
     784                 :            :         .set_client     = svcauth_unix_set_client,
     785                 :            : };
     786                 :            : 
     787                 :            : 
     788                 :            : static int
     789                 :          0 : svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
     790                 :            : {
     791                 :            :         struct kvec     *argv = &rqstp->rq_arg.head[0];
     792                 :            :         struct kvec     *resv = &rqstp->rq_res.head[0];
     793                 :            :         struct svc_cred *cred = &rqstp->rq_cred;
     794                 :            :         u32             slen, i;
     795                 :          0 :         int             len   = argv->iov_len;
     796                 :            : 
     797                 :          0 :         cred->cr_group_info = NULL;
     798                 :          0 :         cred->cr_principal = NULL;
     799                 :          0 :         rqstp->rq_client = NULL;
     800                 :            : 
     801         [ #  # ]:          0 :         if ((len -= 3*4) < 0)
     802                 :            :                 return SVC_GARBAGE;
     803                 :            : 
     804                 :            :         svc_getu32(argv);                       /* length */
     805                 :            :         svc_getu32(argv);                       /* time stamp */
     806                 :          0 :         slen = XDR_QUADLEN(svc_getnl(argv));    /* machname length */
     807 [ #  # ][ #  # ]:          0 :         if (slen > 64 || (len -= (slen + 3)*4) < 0)
     808                 :            :                 goto badcred;
     809                 :          0 :         argv->iov_base = (void*)((__be32*)argv->iov_base + slen); /* skip machname */
     810                 :          0 :         argv->iov_len -= slen*4;
     811                 :            :         /*
     812                 :            :          * Note: we skip uid_valid()/gid_valid() checks here for
     813                 :            :          * backwards compatibility with clients that use -1 id's.
     814                 :            :          * Instead, -1 uid or gid is later mapped to the
     815                 :            :          * (export-specific) anonymous id by nfsd_setuser.
     816                 :            :          * Supplementary gid's will be left alone.
     817                 :            :          */
     818                 :          0 :         cred->cr_uid = make_kuid(&init_user_ns, svc_getnl(argv)); /* uid */
     819                 :          0 :         cred->cr_gid = make_kgid(&init_user_ns, svc_getnl(argv)); /* gid */
     820                 :            :         slen = svc_getnl(argv);                 /* gids length */
     821 [ #  # ][ #  # ]:          0 :         if (slen > 16 || (len -= (slen + 2)*4) < 0)
     822                 :            :                 goto badcred;
     823                 :          0 :         cred->cr_group_info = groups_alloc(slen);
     824         [ #  # ]:          0 :         if (cred->cr_group_info == NULL)
     825                 :            :                 return SVC_CLOSE;
     826         [ #  # ]:          0 :         for (i = 0; i < slen; i++) {
     827                 :            :                 kgid_t kgid = make_kgid(&init_user_ns, svc_getnl(argv));
     828                 :          0 :                 GROUP_AT(cred->cr_group_info, i) = kgid;
     829                 :            :         }
     830 [ #  # ][ #  # ]:          0 :         if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
     831                 :          0 :                 *authp = rpc_autherr_badverf;
     832                 :          0 :                 return SVC_DENIED;
     833                 :            :         }
     834                 :            : 
     835                 :            :         /* Put NULL verifier */
     836                 :            :         svc_putnl(resv, RPC_AUTH_NULL);
     837                 :            :         svc_putnl(resv, 0);
     838                 :            : 
     839                 :          0 :         rqstp->rq_cred.cr_flavor = RPC_AUTH_UNIX;
     840                 :          0 :         return SVC_OK;
     841                 :            : 
     842                 :            : badcred:
     843                 :          0 :         *authp = rpc_autherr_badcred;
     844                 :          0 :         return SVC_DENIED;
     845                 :            : }
     846                 :            : 
     847                 :            : static int
     848                 :          0 : svcauth_unix_release(struct svc_rqst *rqstp)
     849                 :            : {
     850                 :            :         /* Verifier (such as it is) is already in place.
     851                 :            :          */
     852         [ #  # ]:          0 :         if (rqstp->rq_client)
     853                 :          0 :                 auth_domain_put(rqstp->rq_client);
     854                 :          0 :         rqstp->rq_client = NULL;
     855         [ #  # ]:          0 :         if (rqstp->rq_cred.cr_group_info)
     856         [ #  # ]:          0 :                 put_group_info(rqstp->rq_cred.cr_group_info);
     857                 :          0 :         rqstp->rq_cred.cr_group_info = NULL;
     858                 :            : 
     859                 :          0 :         return 0;
     860                 :            : }
     861                 :            : 
     862                 :            : 
     863                 :            : struct auth_ops svcauth_unix = {
     864                 :            :         .name           = "unix",
     865                 :            :         .owner          = THIS_MODULE,
     866                 :            :         .flavour        = RPC_AUTH_UNIX,
     867                 :            :         .accept         = svcauth_unix_accept,
     868                 :            :         .release        = svcauth_unix_release,
     869                 :            :         .domain_release = svcauth_unix_domain_release,
     870                 :            :         .set_client     = svcauth_unix_set_client,
     871                 :            : };
     872                 :            : 
     873                 :            : static struct cache_detail ip_map_cache_template = {
     874                 :            :         .owner          = THIS_MODULE,
     875                 :            :         .hash_size      = IP_HASHMAX,
     876                 :            :         .name           = "auth.unix.ip",
     877                 :            :         .cache_put      = ip_map_put,
     878                 :            :         .cache_request  = ip_map_request,
     879                 :            :         .cache_parse    = ip_map_parse,
     880                 :            :         .cache_show     = ip_map_show,
     881                 :            :         .match          = ip_map_match,
     882                 :            :         .init           = ip_map_init,
     883                 :            :         .update         = update,
     884                 :            :         .alloc          = ip_map_alloc,
     885                 :            : };
     886                 :            : 
     887                 :          0 : int ip_map_cache_create(struct net *net)
     888                 :            : {
     889                 :          0 :         struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
     890                 :            :         struct cache_detail *cd;
     891                 :            :         int err;
     892                 :            : 
     893                 :          0 :         cd = cache_create_net(&ip_map_cache_template, net);
     894         [ #  # ]:          0 :         if (IS_ERR(cd))
     895                 :          0 :                 return PTR_ERR(cd);
     896                 :          0 :         err = cache_register_net(cd, net);
     897         [ #  # ]:          0 :         if (err) {
     898                 :          0 :                 cache_destroy_net(cd, net);
     899                 :          0 :                 return err;
     900                 :            :         }
     901                 :          0 :         sn->ip_map_cache = cd;
     902                 :          0 :         return 0;
     903                 :            : }
     904                 :            : 
     905                 :          0 : void ip_map_cache_destroy(struct net *net)
     906                 :            : {
     907                 :          0 :         struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
     908                 :          0 :         struct cache_detail *cd = sn->ip_map_cache;
     909                 :            : 
     910                 :          0 :         sn->ip_map_cache = NULL;
     911                 :          0 :         cache_purge(cd);
     912                 :          0 :         cache_unregister_net(cd, net);
     913                 :          0 :         cache_destroy_net(cd, net);
     914                 :          0 : }

Generated by: LCOV version 1.9