nfsd: nfsd should drop CAP_MKNOD for non-root
[safe/jmp/linux-2.6] / net / ipv4 / ip_sockglue.c
index e0514e8..43c0585 100644 (file)
@@ -5,8 +5,6 @@
  *
  *             The IP to API glue.
  *
- * Version:    $Id: ip_sockglue.c,v 1.62 2002/02/01 22:01:04 davem Exp $
- *
  * Authors:    see ip.c
  *
  * Fixes:
@@ -50,6 +48,7 @@
 #define IP_CMSG_RECVOPTS       8
 #define IP_CMSG_RETOPTS                16
 #define IP_CMSG_PASSSEC                32
+#define IP_CMSG_ORIGDSTADDR     64
 
 /*
  *     SOL_IP control messages.
@@ -96,7 +95,7 @@ static void ip_cmsg_recv_opts(struct msghdr *msg, struct sk_buff *skb)
 static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb)
 {
        unsigned char optbuf[sizeof(struct ip_options) + 40];
-       struct ip_options * opt = (struct ip_options*)optbuf;
+       struct ip_options * opt = (struct ip_options *)optbuf;
 
        if (IPCB(skb)->opt.optlen == 0)
                return;
@@ -128,6 +127,27 @@ static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
        security_release_secctx(secdata, seclen);
 }
 
+static void ip_cmsg_recv_dstaddr(struct msghdr *msg, struct sk_buff *skb)
+{
+       struct sockaddr_in sin;
+       struct iphdr *iph = ip_hdr(skb);
+       __be16 *ports = (__be16 *)skb_transport_header(skb);
+
+       if (skb_transport_offset(skb) + 4 > skb->len)
+               return;
+
+       /* All current transport protocols have the port numbers in the
+        * first four bytes of the transport header and this function is
+        * written with this assumption in mind.
+        */
+
+       sin.sin_family = AF_INET;
+       sin.sin_addr.s_addr = iph->daddr;
+       sin.sin_port = ports[1];
+       memset(sin.sin_zero, 0, sizeof(sin.sin_zero));
+
+       put_cmsg(msg, SOL_IP, IP_ORIGDSTADDR, sizeof(sin), &sin);
+}
 
 void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
 {
@@ -162,6 +182,12 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
 
        if (flags & 1)
                ip_cmsg_recv_security(msg, skb);
+
+       if ((flags>>=1) == 0)
+               return;
+       if (flags & 1)
+               ip_cmsg_recv_dstaddr(msg, skb);
+
 }
 
 int ip_cmsg_send(struct net *net, struct msghdr *msg, struct ipcm_cookie *ipc)
@@ -413,7 +439,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
                            int optname, char __user *optval, int optlen)
 {
        struct inet_sock *inet = inet_sk(sk);
-       int val=0,err;
+       int val = 0, err;
 
        if (((1<<optname) & ((1<<IP_PKTINFO) | (1<<IP_RECVTTL) |
                             (1<<IP_RECVOPTS) | (1<<IP_RECVTOS) |
@@ -421,9 +447,10 @@ static int do_ip_setsockopt(struct sock *sk, int level,
                             (1<<IP_TTL) | (1<<IP_HDRINCL) |
                             (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) |
                             (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
-                            (1<<IP_PASSSEC))) ||
+                            (1<<IP_PASSSEC) | (1<<IP_TRANSPARENT))) ||
            optname == IP_MULTICAST_TTL ||
-           optname == IP_MULTICAST_LOOP) {
+           optname == IP_MULTICAST_LOOP ||
+           optname == IP_RECVORIGDSTADDR) {
                if (optlen >= sizeof(int)) {
                        if (get_user(val, (int __user *) optval))
                                return -EFAULT;
@@ -439,7 +466,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
        /* If optlen==0, it is equivalent to val == 0 */
 
        if (ip_mroute_opt(optname))
-               return ip_mroute_setsockopt(sk,optname,optval,optlen);
+               return ip_mroute_setsockopt(sk, optname, optval, optlen);
 
        err = 0;
        lock_sock(sk);
@@ -511,6 +538,12 @@ static int do_ip_setsockopt(struct sock *sk, int level,
                else
                        inet->cmsg_flags &= ~IP_CMSG_PASSSEC;
                break;
+       case IP_RECVORIGDSTADDR:
+               if (val)
+                       inet->cmsg_flags |= IP_CMSG_ORIGDSTADDR;
+               else
+                       inet->cmsg_flags &= ~IP_CMSG_ORIGDSTADDR;
+               break;
        case IP_TOS:    /* This sets both TOS and Precedence */
                if (sk->sk_type == SOCK_STREAM) {
                        val &= ~3;
@@ -551,7 +584,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
                        goto e_inval;
                if (optlen<1)
                        goto e_inval;
-               if (val==-1)
+               if (val == -1)
                        val = 1;
                if (val < 0 || val > 255)
                        goto e_inval;
@@ -575,12 +608,12 @@ static int do_ip_setsockopt(struct sock *sk, int level,
 
                err = -EFAULT;
                if (optlen >= sizeof(struct ip_mreqn)) {
-                       if (copy_from_user(&mreq,optval,sizeof(mreq)))
+                       if (copy_from_user(&mreq, optval, sizeof(mreq)))
                                break;
                } else {
                        memset(&mreq, 0, sizeof(mreq));
                        if (optlen >= sizeof(struct in_addr) &&
-                           copy_from_user(&mreq.imr_address,optval,sizeof(struct in_addr)))
+                           copy_from_user(&mreq.imr_address, optval, sizeof(struct in_addr)))
                                break;
                }
 
@@ -628,11 +661,11 @@ static int do_ip_setsockopt(struct sock *sk, int level,
                        goto e_inval;
                err = -EFAULT;
                if (optlen >= sizeof(struct ip_mreqn)) {
-                       if (copy_from_user(&mreq,optval,sizeof(mreq)))
+                       if (copy_from_user(&mreq, optval, sizeof(mreq)))
                                break;
                } else {
                        memset(&mreq, 0, sizeof(mreq));
-                       if (copy_from_user(&mreq,optval,sizeof(struct ip_mreq)))
+                       if (copy_from_user(&mreq, optval, sizeof(struct ip_mreq)))
                                break;
                }
 
@@ -810,7 +843,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
                        err = -ENOBUFS;
                        break;
                }
-               gsf = kmalloc(optlen,GFP_KERNEL);
+               gsf = kmalloc(optlen, GFP_KERNEL);
                if (!gsf) {
                        err = -ENOBUFS;
                        break;
@@ -830,7 +863,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
                        goto mc_msf_out;
                }
                msize = IP_MSFILTER_SIZE(gsf->gf_numsrc);
-               msf = kmalloc(msize,GFP_KERNEL);
+               msf = kmalloc(msize, GFP_KERNEL);
                if (!msf) {
                        err = -ENOBUFS;
                        goto mc_msf_out;
@@ -880,6 +913,16 @@ static int do_ip_setsockopt(struct sock *sk, int level,
                err = xfrm_user_policy(sk, optname, optval, optlen);
                break;
 
+       case IP_TRANSPARENT:
+               if (!capable(CAP_NET_ADMIN)) {
+                       err = -EPERM;
+                       break;
+               }
+               if (optlen < 1)
+                       goto e_inval;
+               inet->transparent = !!val;
+               break;
+
        default:
                err = -ENOPROTOOPT;
                break;
@@ -963,9 +1006,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
                return -EOPNOTSUPP;
 
        if (ip_mroute_opt(optname))
-               return ip_mroute_getsockopt(sk,optname,optval,optlen);
+               return ip_mroute_getsockopt(sk, optname, optval, optlen);
 
-       if (get_user(len,optlen))
+       if (get_user(len, optlen))
                return -EFAULT;
        if (len < 0)
                return -EINVAL;
@@ -976,7 +1019,7 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
        case IP_OPTIONS:
        {
                unsigned char optbuf[sizeof(struct ip_options)+40];
-               struct ip_options * opt = (struct ip_options*)optbuf;
+               struct ip_options * opt = (struct ip_options *)optbuf;
                opt->optlen = 0;
                if (inet->opt)
                        memcpy(optbuf, inet->opt,
@@ -1014,6 +1057,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
        case IP_PASSSEC:
                val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0;
                break;
+       case IP_RECVORIGDSTADDR:
+               val = (inet->cmsg_flags & IP_CMSG_ORIGDSTADDR) != 0;
+               break;
        case IP_TOS:
                val = inet->tos;
                break;
@@ -1132,6 +1178,9 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
        case IP_FREEBIND:
                val = inet->freebind;
                break;
+       case IP_TRANSPARENT:
+               val = inet->transparent;
+               break;
        default:
                release_sock(sk);
                return -ENOPROTOOPT;
@@ -1143,13 +1192,13 @@ static int do_ip_getsockopt(struct sock *sk, int level, int optname,
                len = 1;
                if (put_user(len, optlen))
                        return -EFAULT;
-               if (copy_to_user(optval,&ucval,1))
+               if (copy_to_user(optval, &ucval, 1))
                        return -EFAULT;
        } else {
                len = min_t(unsigned int, sizeof(int), len);
                if (put_user(len, optlen))
                        return -EFAULT;
-               if (copy_to_user(optval,&val,len))
+               if (copy_to_user(optval, &val, len))
                        return -EFAULT;
        }
        return 0;
@@ -1167,7 +1216,7 @@ int ip_getsockopt(struct sock *sk, int level,
                        !ip_mroute_opt(optname)) {
                int len;
 
-               if (get_user(len,optlen))
+               if (get_user(len, optlen))
                        return -EFAULT;
 
                lock_sock(sk);