[SECURITY]: TCP/UDP getpeersec
[linux-3.10.git] / net / ipv4 / ip_sockglue.c
index 2bf8d78..b5c4f61 100644 (file)
@@ -50,6 +50,7 @@
 #define IP_CMSG_TOS            4
 #define IP_CMSG_RECVOPTS       8
 #define IP_CMSG_RETOPTS                16
+#define IP_CMSG_PASSSEC                32
 
 /*
  *     SOL_IP control messages.
@@ -109,6 +110,19 @@ static void ip_cmsg_recv_retopts(struct msghdr *msg, struct sk_buff *skb)
        put_cmsg(msg, SOL_IP, IP_RETOPTS, opt->optlen, opt->__data);
 }
 
+static void ip_cmsg_recv_security(struct msghdr *msg, struct sk_buff *skb)
+{
+       char *secdata;
+       u32 seclen;
+       int err;
+
+       err = security_socket_getpeersec_dgram(skb, &secdata, &seclen);
+       if (err)
+               return;
+
+       put_cmsg(msg, SOL_IP, SCM_SECURITY, seclen, secdata);
+}
+
 
 void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
 {
@@ -138,6 +152,11 @@ void ip_cmsg_recv(struct msghdr *msg, struct sk_buff *skb)
 
        if (flags & 1)
                ip_cmsg_recv_retopts(msg, skb);
+       if ((flags>>=1) == 0)
+               return;
+
+       if (flags & 1)
+               ip_cmsg_recv_security(msg, skb);
 }
 
 int ip_cmsg_send(struct msghdr *msg, struct ipcm_cookie *ipc)
@@ -393,7 +412,8 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
                            (1<<IP_RETOPTS) | (1<<IP_TOS) | 
                            (1<<IP_TTL) | (1<<IP_HDRINCL) | 
                            (1<<IP_MTU_DISCOVER) | (1<<IP_RECVERR) | 
-                           (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND))) || 
+                           (1<<IP_ROUTER_ALERT) | (1<<IP_FREEBIND) |
+                           (1<<IP_PASSSEC))) ||
                                optname == IP_MULTICAST_TTL || 
                                optname == IP_MULTICAST_LOOP) { 
                if (optlen >= sizeof(int)) {
@@ -478,6 +498,12 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
                        else
                                inet->cmsg_flags &= ~IP_CMSG_RETOPTS;
                        break;
+               case IP_PASSSEC:
+                       if (val)
+                               inet->cmsg_flags |= IP_CMSG_PASSSEC;
+                       else
+                               inet->cmsg_flags &= ~IP_CMSG_PASSSEC;
+                       break;
                case IP_TOS:    /* This sets both TOS and Precedence */
                        if (sk->sk_type == SOCK_STREAM) {
                                val &= ~3;
@@ -932,6 +958,9 @@ int ip_getsockopt(struct sock *sk, int level, int optname, char __user *optval,
                case IP_RETOPTS:
                        val = (inet->cmsg_flags & IP_CMSG_RETOPTS) != 0;
                        break;
+               case IP_PASSSEC:
+                       val = (inet->cmsg_flags & IP_CMSG_PASSSEC) != 0;
+                       break;
                case IP_TOS:
                        val = inet->tos;
                        break;