]> git.sesse.net Git - vlc/blob - src/network/rootbind.c
Fix/split rootwrap_bind
[vlc] / src / network / rootbind.c
1 /*****************************************************************************
2  * rootbind.c: bind to reserved ports through the root wrapper
3  *****************************************************************************
4  * Copyright © 2005-2008 Rémi Denis-Courmont
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
19  *****************************************************************************/
20
21 #if HAVE_CONFIG_H
22 # include <config.h>
23 #endif
24
25 #if !defined (WIN32) && !defined (SYS_BEOS)
26 # define ENABLE_ROOTWRAP 1
27 #endif
28
29 #include <stddef.h>
30 struct sockaddr;
31 int rootwrap_bind (int, int, int, const struct sockaddr *, size_t);
32
33 #include <errno.h>
34
35 #ifdef ENABLE_ROOTWRAP
36
37 #include <string.h>
38
39 #include <sys/types.h>
40 #include <unistd.h>
41 #include <sys/socket.h>
42 #include <sys/uio.h>
43 #include <sys/un.h>
44 #include <netinet/in.h>
45 #include <pthread.h>
46
47 /**
48  * Receive a file descriptor from another process
49  */
50 static int recv_fd (int p)
51 {
52     struct msghdr hdr;
53     struct iovec iov;
54     struct cmsghdr *cmsg;
55     int val, fd;
56     char buf[CMSG_SPACE (sizeof (fd))];
57
58     hdr.msg_name = NULL;
59     hdr.msg_namelen = 0;
60     hdr.msg_iov = &iov;
61     hdr.msg_iovlen = 1;
62     hdr.msg_control = buf;
63     hdr.msg_controllen = sizeof (buf);
64
65     iov.iov_base = &val;
66     iov.iov_len = sizeof (val);
67
68     if (recvmsg (p, &hdr, 0) != sizeof (val))
69         return -1;
70
71     for (cmsg = CMSG_FIRSTHDR (&hdr); cmsg != NULL;
72          cmsg = CMSG_NXTHDR (&hdr, cmsg))
73     {
74         if ((cmsg->cmsg_level == SOL_SOCKET)
75          && (cmsg->cmsg_type = SCM_RIGHTS)
76          && (cmsg->cmsg_len >= CMSG_LEN (sizeof (fd))))
77         {
78             memcpy (&fd, CMSG_DATA (cmsg), sizeof (fd));
79             return fd;
80         }
81     }
82
83     errno = val;
84     return -1;
85 }
86
87 /**
88  * Tries to obtain a bound TCP socket from the root process
89  */
90 int rootwrap_bind (int family, int socktype, int protocol,
91                    const struct sockaddr *addr, size_t alen)
92 {
93     /* can't use libvlc */
94     static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
95     struct sockaddr_storage ss;
96     int fd, sock = -1;
97
98     const char *sockenv = getenv ("VLC_ROOTWRAP_SOCK");
99     if (sockenv != NULL)
100         sock = atoi (sock);
101     if (sock == -1)
102     {
103         errno = EACCES;
104         return -1;
105     }
106
107     switch (family)
108     {
109         case AF_INET:
110             if (alen < sizeof (struct sockaddr_in))
111             {
112                 errno = EINVAL;
113                 return -1;
114             }
115             break;
116
117 #ifdef AF_INET6
118         case AF_INET6:
119             if (alen < sizeof (struct sockaddr_in6))
120             {
121                 errno = EINVAL;
122                 return -1;
123             }
124             break;
125 #endif
126
127         default:
128             errno = EAFNOSUPPORT;
129             return -1;
130     }
131
132     if (family != addr->sa_family)
133     {
134         errno = EAFNOSUPPORT;
135         return -1;
136     }
137
138     /* Only TCP is implemented at the moment */
139     if ((socktype != SOCK_STREAM)
140      || (protocol && (protocol != IPPROTO_TCP)))
141     {
142         errno = EACCES;
143         return -1;
144     }
145
146     memset (&ss, 0, sizeof (ss));
147     memcpy (&ss, addr, alen > sizeof (ss) ? sizeof (ss) : alen);
148
149     pthread_mutex_lock (&mutex);
150     if (send (sock, &ss, sizeof (ss), 0) != sizeof (ss))
151         return -1;
152
153     fd = recv_fd (sock);
154     pthread_mutex_unlock (&mutex);
155     return fd;
156 }
157
158 #else
159 int rootwrap_bind (int family, int socktype, int protocol,
160                    const struct sockaddr *addr, size_t alen)
161 {
162     (void)family;
163     (void)socktype;
164     (void)protocol;
165     (void)addr;
166     (void)alen;
167     errno = EACCES;
168     return -1;
169 }
170
171 #endif /* ENABLE_ROOTWRAP */