diff options
Diffstat (limited to 'net/sunrpc/svcauth_unix.c')
-rw-r--r-- | net/sunrpc/svcauth_unix.c | 110 |
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 | } |
131 | static void ip_map_init(struct cache_head *cnew, struct cache_head *citem) | 133 | static 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 | ||
658 | static int unix_gid_find(uid_t uid, struct group_info **gip, | 664 | static 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; |