3 * Privilege-separated helper
5 * (c) 2008 Straylight/Edgeware
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of Trivial IP Encryption (TrIPE).
12 * TrIPE is free software: you can redistribute it and/or modify it under
13 * the terms of the GNU General Public License as published by the Free
14 * Software Foundation; either version 3 of the License, or (at your
15 * option) any later version.
17 * TrIPE is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * You should have received a copy of the GNU General Public License
23 * along with TrIPE. If not, see <https://www.gnu.org/licenses/>.
26 /*----- Header files ------------------------------------------------------*/
30 /*----- Helper-side utilities ---------------------------------------------*/
34 * Arguments: @const char *excuse@ = what went wrong
38 * Use: Reports a fatal error and quits.
41 static void NORETURN lose(const char *excuse)
43 moan("helper process bailing out: %s; error: %s",
45 errno == -1 ? "Unexpected EOF" : strerror(errno));
49 /*----- Diagnostic functions ----------------------------------------------*/
53 * Arguments: @unsigned mask@ = trace mask to check
54 * @const char *fmt@ = message format
55 * @...@ = values for placeholders
59 * Use: Writes a trace message.
64 static void PRINTF_LIKE(2, 3) itrace(unsigned mask, const char *fmt, ...)
70 dstr_vputf(&d, fmt, &ap);
71 if (pc_putuint(PS_TRACE) ||
75 lose("write (trace)");
84 * Arguments: @const char *fmt@ = message format
85 * @...@ = values for placeholders
89 * Use: Writes a warning message.
92 #define A_END ((char *)0)
94 static void EXECL_LIKE(0) IGNORABLE warn(const char *fmt, ...)
97 dstr d = DSTR_INIT, dd = DSTR_INIT;
102 if (strcmp(fmt, "?ERRNO") == 0) {
103 dstr_putf(&d, " E%d", errno);
104 u_quotify(&d, strerror(errno));
109 dstr_vputf(&dd, fmt, &ap);
110 u_quotify(&d, dd.buf);
112 fmt = va_arg(ap, const char *);
116 if (pc_putuint(PS_WARN) ||
118 pc_put(d.buf, d.len))
119 lose("write (warn)");
125 /*----- Tunnel drivers ----------------------------------------------------*/
127 /* --- @topen_DRIVER@ --- *
129 * Arguments: @char **ifn@ = where to put the interface name
131 * Returns: A file descriptor, or @-1@ on failure.
133 * Use: Opens a tunnel device.
138 #include <sys/ioctl.h>
139 #include <linux/if.h>
140 #include <linux/if_tun.h>
142 static int topen_linux(char **ifn)
147 if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
148 warn("TUN", "-", "linux",
149 "open-error", "/dev/net/tun", "?ERRNO",
153 memset(&iff, 0, sizeof(iff));
155 iff.ifr_flags = IFF_TUN | IFF_NO_PI;
156 if (ioctl(fd, TUNSETIFF, &iff) < 0) {
157 warn("TUN", "-", "linux", "config-error", "?ERRNO", A_END);
161 iff.ifr_name[IFNAMSIZ - 1] = 0;
162 *ifn = xstrdup(iff.ifr_name);
170 static int topen_bsd(char **ifn)
178 sprintf(buf, "/dev/tun%u", n);
179 if ((fd = open(buf, O_RDWR)) >= 0)
183 T( itrace(T_PRIVSEP, "tunnel device %u busy: skipping", n); )
186 warn("TUN", "-", "bsd", "no-tunnel-devices", A_END);
189 warn("TUN", "-", "open-error", "%s", buf, "?ERRNO", A_END);
201 #include <sys/ioctl.h>
202 #include <linux/if.h>
205 static int topen_unet(char **ifn)
209 struct unet_info uni;
211 if ((fd = open("/dev/unet", O_RDWR)) < 0) {
212 warn("TUN", "-", "unet", "open-error", "/dev/unet", "?ERRNO", A_END);
215 if ((f = ioctl(fd, UNIOCGIFFLAGS)) < 0 ||
216 ioctl(fd, UNIOCSIFFLAGS, f | IFF_POINTOPOINT)) {
217 warn("TUN", "-", "unet", "config-error", "?ERRNO", A_END);
220 if (ioctl(fd, UNIOCGINFO, &uni)) {
221 warn("TUN", "-", "unet", "getinfo-error", "?ERRNO", A_END);
224 *ifn = xstrdup(uni.uni_ifname);
235 static const struct tunnel {
237 int (*open)(char **);
240 { "linux", topen_linux },
243 { "bsd", topen_bsd },
246 { "unet", topen_unet },
251 /*----- Helper process core -----------------------------------------------*/
253 int main(int argc, char *argv[])
255 struct sockaddr_un sun;
256 socklen_t slen = sizeof(sun);
259 const struct tunnel *t;
266 getpeername(0, (struct sockaddr *)&sun, &slen) ||
267 sun.sun_family != AF_UNIX)
268 die(EXIT_FAILURE, "please do not run this program again.");
271 if (pc_getuint(&rq)) {
272 if (errno == -1) break;
273 else lose("read (main)");
278 if (pc_getstring(&d)) lose("read (tunnel)");
279 for (t = tunnels;; t++) {
280 if (!t->name) lose("unknown tunnel");
281 if (strcmp(d.buf, t->name) == 0) break;
284 "privsep: received request for %s tunnel",
286 if ((fd = t->open(&ifn)) < 0)
289 n = fdpass_send(pc_fd, fd, &rq, sizeof(rq)); close(fd);
290 if (n < 0) { xfree(ifn); goto err; }
291 else if (n < sizeof(rq)) lose("partial write (fd-pass)");
292 if (pc_putstring(ifn)) lose("write (ifname)");
296 if (pc_putuint(PS_TUNERR) || pc_puterr(errno)) lose("write (error)");
306 /*----- That's all, folks -------------------------------------------------*/