aboutsummaryrefslogtreecommitdiffstats
path: root/net/sunrpc/svcauth_unix.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/sunrpc/svcauth_unix.c')
-rw-r--r--net/sunrpc/svcauth_unix.c110
1 files changed, 61 insertions, 49 deletions
diff --git a/net/sunrpc/svcauth_unix.c b/net/sunrpc/svcauth_unix.c
index 117f68a8aa40..207311610988 100644
--- a/net/sunrpc/svcauth_unix.c
+++ b/net/sunrpc/svcauth_unix.c
@@ -10,11 +10,13 @@
10#include <linux/seq_file.h> 10#include <linux/seq_file.h>
11#include <linux/hash.h> 11#include <linux/hash.h>
12#include <linux/string.h> 12#include <linux/string.h>
13#include <linux/slab.h>
13#include <net/sock.h> 14#include <net/sock.h>
14#include <net/ipv6.h> 15#include <net/ipv6.h>
15#include <linux/kernel.h> 16#include <linux/kernel.h>
16#define RPCDBG_FACILITY RPCDBG_AUTH 17#define RPCDBG_FACILITY RPCDBG_AUTH
17 18
19#include <linux/sunrpc/clnt.h>
18 20
19/* 21/*
20 * AUTHUNIX and AUTHNULL credentials are both handled here. 22 * AUTHUNIX and AUTHNULL credentials are both handled here.
@@ -125,8 +127,8 @@ static int ip_map_match(struct cache_head *corig, struct cache_head *cnew)
125{ 127{
126 struct ip_map *orig = container_of(corig, struct ip_map, h); 128 struct ip_map *orig = container_of(corig, struct ip_map, h);
127 struct ip_map *new = container_of(cnew, struct ip_map, h); 129 struct ip_map *new = container_of(cnew, struct ip_map, h);
128 return strcmp(orig->m_class, new->m_class) == 0 130 return strcmp(orig->m_class, new->m_class) == 0 &&
129 && ipv6_addr_equal(&orig->m_addr, &new->m_addr); 131 ipv6_addr_equal(&orig->m_addr, &new->m_addr);
130} 132}
131static void ip_map_init(struct cache_head *cnew, struct cache_head *citem) 133static void ip_map_init(struct cache_head *cnew, struct cache_head *citem)
132{ 134{
@@ -187,10 +189,13 @@ static int ip_map_parse(struct cache_detail *cd,
187 * for scratch: */ 189 * for scratch: */
188 char *buf = mesg; 190 char *buf = mesg;
189 int len; 191 int len;
190 int b1, b2, b3, b4, b5, b6, b7, b8;
191 char c;
192 char class[8]; 192 char class[8];
193 struct in6_addr addr; 193 union {
194 struct sockaddr sa;
195 struct sockaddr_in s4;
196 struct sockaddr_in6 s6;
197 } address;
198 struct sockaddr_in6 sin6;
194 int err; 199 int err;
195 200
196 struct ip_map *ipmp; 201 struct ip_map *ipmp;
@@ -209,24 +214,24 @@ static int ip_map_parse(struct cache_detail *cd,
209 len = qword_get(&mesg, buf, mlen); 214 len = qword_get(&mesg, buf, mlen);
210 if (len <= 0) return -EINVAL; 215 if (len <= 0) return -EINVAL;
211 216
212 if (sscanf(buf, "%u.%u.%u.%u%c", &b1, &b2, &b3, &b4, &c) == 4) { 217 if (rpc_pton(buf, len, &address.sa, sizeof(address)) == 0)
213 addr.s6_addr32[0] = 0; 218 return -EINVAL;
214 addr.s6_addr32[1] = 0; 219 switch (address.sa.sa_family) {
215 addr.s6_addr32[2] = htonl(0xffff); 220 case AF_INET:
216 addr.s6_addr32[3] = 221 /* Form a mapped IPv4 address in sin6 */
217 htonl((((((b1<<8)|b2)<<8)|b3)<<8)|b4); 222 memset(&sin6, 0, sizeof(sin6));
218 } else if (sscanf(buf, "%04x:%04x:%04x:%04x:%04x:%04x:%04x:%04x%c", 223 sin6.sin6_family = AF_INET6;
219 &b1, &b2, &b3, &b4, &b5, &b6, &b7, &b8, &c) == 8) { 224 sin6.sin6_addr.s6_addr32[2] = htonl(0xffff);
220 addr.s6_addr16[0] = htons(b1); 225 sin6.sin6_addr.s6_addr32[3] = address.s4.sin_addr.s_addr;
221 addr.s6_addr16[1] = htons(b2); 226 break;
222 addr.s6_addr16[2] = htons(b3); 227#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
223 addr.s6_addr16[3] = htons(b4); 228 case AF_INET6:
224 addr.s6_addr16[4] = htons(b5); 229 memcpy(&sin6, &address.s6, sizeof(sin6));
225 addr.s6_addr16[5] = htons(b6); 230 break;
226 addr.s6_addr16[6] = htons(b7); 231#endif
227 addr.s6_addr16[7] = htons(b8); 232 default:
228 } else
229 return -EINVAL; 233 return -EINVAL;
234 }
230 235
231 expiry = get_expiry(&mesg); 236 expiry = get_expiry(&mesg);
232 if (expiry ==0) 237 if (expiry ==0)
@@ -243,7 +248,8 @@ static int ip_map_parse(struct cache_detail *cd,
243 } else 248 } else
244 dom = NULL; 249 dom = NULL;
245 250
246 ipmp = ip_map_lookup(class, &addr); 251 /* IPv6 scope IDs are ignored for now */
252 ipmp = ip_map_lookup(class, &sin6.sin6_addr);
247 if (ipmp) { 253 if (ipmp) {
248 err = ip_map_update(ipmp, 254 err = ip_map_update(ipmp,
249 container_of(dom, struct unix_domain, h), 255 container_of(dom, struct unix_domain, h),
@@ -619,7 +625,7 @@ static int unix_gid_show(struct seq_file *m,
619 else 625 else
620 glen = 0; 626 glen = 0;
621 627
622 seq_printf(m, "%d %d:", ug->uid, glen); 628 seq_printf(m, "%u %d:", ug->uid, glen);
623 for (i = 0; i < glen; i++) 629 for (i = 0; i < glen; i++)
624 seq_printf(m, " %d", GROUP_AT(ug->gi, i)); 630 seq_printf(m, " %d", GROUP_AT(ug->gi, i));
625 seq_printf(m, "\n"); 631 seq_printf(m, "\n");
@@ -655,23 +661,25 @@ static struct unix_gid *unix_gid_lookup(uid_t uid)
655 return NULL; 661 return NULL;
656} 662}
657 663
658static int unix_gid_find(uid_t uid, struct group_info **gip, 664static struct group_info *unix_gid_find(uid_t uid, struct svc_rqst *rqstp)
659 struct svc_rqst *rqstp)
660{ 665{
661 struct unix_gid *ug = unix_gid_lookup(uid); 666 struct unix_gid *ug;
667 struct group_info *gi;
668 int ret;
669
670 ug = unix_gid_lookup(uid);
662 if (!ug) 671 if (!ug)
663 return -EAGAIN; 672 return ERR_PTR(-EAGAIN);
664 switch (cache_check(&unix_gid_cache, &ug->h, &rqstp->rq_chandle)) { 673 ret = cache_check(&unix_gid_cache, &ug->h, &rqstp->rq_chandle);
674 switch (ret) {
665 case -ENOENT: 675 case -ENOENT:
666 *gip = NULL; 676 return ERR_PTR(-ENOENT);
667 return 0;
668 case 0: 677 case 0:
669 *gip = ug->gi; 678 gi = get_group_info(ug->gi);
670 get_group_info(*gip);
671 cache_put(&ug->h, &unix_gid_cache); 679 cache_put(&ug->h, &unix_gid_cache);
672 return 0; 680 return gi;
673 default: 681 default:
674 return -EAGAIN; 682 return ERR_PTR(-EAGAIN);
675 } 683 }
676} 684}
677 685
@@ -681,13 +689,14 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
681 struct sockaddr_in *sin; 689 struct sockaddr_in *sin;
682 struct sockaddr_in6 *sin6, sin6_storage; 690 struct sockaddr_in6 *sin6, sin6_storage;
683 struct ip_map *ipm; 691 struct ip_map *ipm;
692 struct group_info *gi;
693 struct svc_cred *cred = &rqstp->rq_cred;
684 694
685 switch (rqstp->rq_addr.ss_family) { 695 switch (rqstp->rq_addr.ss_family) {
686 case AF_INET: 696 case AF_INET:
687 sin = svc_addr_in(rqstp); 697 sin = svc_addr_in(rqstp);
688 sin6 = &sin6_storage; 698 sin6 = &sin6_storage;
689 ipv6_addr_set(&sin6->sin6_addr, 0, 0, 699 ipv6_addr_set_v4mapped(sin->sin_addr.s_addr, &sin6->sin6_addr);
690 htonl(0x0000FFFF), sin->sin_addr.s_addr);
691 break; 700 break;
692 case AF_INET6: 701 case AF_INET6:
693 sin6 = svc_addr_in6(rqstp); 702 sin6 = svc_addr_in6(rqstp);
@@ -722,6 +731,17 @@ svcauth_unix_set_client(struct svc_rqst *rqstp)
722 ip_map_cached_put(rqstp, ipm); 731 ip_map_cached_put(rqstp, ipm);
723 break; 732 break;
724 } 733 }
734
735 gi = unix_gid_find(cred->cr_uid, rqstp);
736 switch (PTR_ERR(gi)) {
737 case -EAGAIN:
738 return SVC_DROP;
739 case -ENOENT:
740 break;
741 default:
742 put_group_info(cred->cr_group_info);
743 cred->cr_group_info = gi;
744 }
725 return SVC_OK; 745 return SVC_OK;
726} 746}
727 747
@@ -818,19 +838,11 @@ svcauth_unix_accept(struct svc_rqst *rqstp, __be32 *authp)
818 slen = svc_getnl(argv); /* gids length */ 838 slen = svc_getnl(argv); /* gids length */
819 if (slen > 16 || (len -= (slen + 2)*4) < 0) 839 if (slen > 16 || (len -= (slen + 2)*4) < 0)
820 goto badcred; 840 goto badcred;
821 if (unix_gid_find(cred->cr_uid, &cred->cr_group_info, rqstp) 841 cred->cr_group_info = groups_alloc(slen);
822 == -EAGAIN) 842 if (cred->cr_group_info == NULL)
823 return SVC_DROP; 843 return SVC_DROP;
824 if (cred->cr_group_info == NULL) { 844 for (i = 0; i < slen; i++)
825 cred->cr_group_info = groups_alloc(slen); 845 GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv);
826 if (cred->cr_group_info == NULL)
827 return SVC_DROP;
828 for (i = 0; i < slen; i++)
829 GROUP_AT(cred->cr_group_info, i) = svc_getnl(argv);
830 } else {
831 for (i = 0; i < slen ; i++)
832 svc_getnl(argv);
833 }
834 if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) { 846 if (svc_getu32(argv) != htonl(RPC_AUTH_NULL) || svc_getu32(argv) != 0) {
835 *authp = rpc_autherr_badverf; 847 *authp = rpc_autherr_badverf;
836 return SVC_DENIED; 848 return SVC_DENIED;