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