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
13 * it under the terms of the GNU General Public License as published by
14 * the Free Software Foundation; either version 2 of the License, or
15 * (at your option) any later version.
17 * TrIPE is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with TrIPE; if not, write to the Free Software Foundation,
24 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 /*----- Header files ------------------------------------------------------*/
31 /*----- Helper-side utilities ---------------------------------------------*/
35 * Arguments: @const char *excuse@ = what went wrong
39 * Use: Reports a fatal error and quits.
42 static void lose(const char *excuse)
44 moan("helper process bailing out: %s; error: %s",
46 errno == -1 ? "Unexpected EOF" : strerror(errno));
50 /*----- Diagnostic functions ----------------------------------------------*/
54 * Arguments: @unsigned mask@ = trace mask to check
55 * @const char *fmt@ = message format
56 * @...@ = values for placeholders
60 * Use: Writes a trace message.
65 static void PRINTF_LIKE(2, 3) itrace(unsigned mask, const char *fmt, ...)
71 dstr_vputf(&d, fmt, &ap);
72 if (pc_putuint(PS_TRACE) ||
76 lose("write (trace)");
85 * Arguments: @const char *fmt@ = message format
86 * @...@ = values for placeholders
90 * Use: Writes a warning message.
93 #define A_END ((char *)0)
95 static void EXECL_LIKE(0) IGNORABLE warn(const char *fmt, ...)
98 dstr d = DSTR_INIT, dd = DSTR_INIT;
103 if (strcmp(fmt, "?ERRNO") == 0) {
104 dstr_putf(&d, " E%d", errno);
105 u_quotify(&d, strerror(errno));
110 dstr_vputf(&dd, fmt, &ap);
111 u_quotify(&d, dd.buf);
113 fmt = va_arg(ap, const char *);
117 if (pc_putuint(PS_WARN) ||
119 pc_put(d.buf, d.len))
120 lose("write (warn)");
126 /*----- Tunnel drivers ----------------------------------------------------*/
128 /* --- @topen_DRIVER@ --- *
130 * Arguments: @char **ifn@ = where to put the interface name
132 * Returns: A file descriptor, or @-1@ on failure.
134 * Use: Opens a tunnel device.
139 #include <sys/ioctl.h>
140 #include <linux/if.h>
141 #include <linux/if_tun.h>
143 static int topen_linux(char **ifn)
148 if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
149 warn("TUN", "-", "linux",
150 "open-error", "/dev/net/tun", "?ERRNO",
154 memset(&iff, 0, sizeof(iff));
156 iff.ifr_flags = IFF_TUN | IFF_NO_PI;
157 if (ioctl(fd, TUNSETIFF, &iff) < 0) {
158 warn("TUN", "-", "linux", "config-error", "?ERRNO", A_END);
162 iff.ifr_name[IFNAMSIZ - 1] = 0;
163 *ifn = xstrdup(iff.ifr_name);
171 static int topen_bsd(char **ifn)
179 sprintf(buf, "/dev/tun%u", n);
180 if ((fd = open(buf, O_RDWR)) >= 0)
184 T( itrace(T_PRIVSEP, "tunnel device %u busy: skipping", n); )
187 warn("TUN", "-", "bsd", "no-tunnel-devices", A_END);
190 warn("TUN", "-", "open-error", "%s", buf, "?ERRNO", A_END);
202 #include <sys/ioctl.h>
203 #include <linux/if.h>
206 static int topen_unet(char **ifn)
210 struct unet_info uni;
212 if ((fd = open("/dev/unet", O_RDWR)) < 0) {
213 warn("TUN", "-", "unet", "open-error", "/dev/unet", "?ERRNO", A_END);
216 if ((f = ioctl(fd, UNIOCGIFFLAGS)) < 0 ||
217 ioctl(fd, UNIOCSIFFLAGS, f | IFF_POINTOPOINT)) {
218 warn("TUN", "-", "unet", "config-error", "?ERRNO", A_END);
221 if (ioctl(fd, UNIOCGINFO, &uni)) {
222 warn("TUN", "-", "unet", "getinfo-error", "?ERRNO", A_END);
225 *ifn = xstrdup(uni.uni_ifname);
236 static const struct tunnel {
238 int (*open)(char **);
241 { "linux", topen_linux },
244 { "bsd", topen_bsd },
247 { "unet", topen_unet },
252 /*----- Helper process core -----------------------------------------------*/
254 int main(int argc, char *argv[])
256 struct sockaddr_un sun;
257 socklen_t slen = sizeof(sun);
260 const struct tunnel *t;
267 getpeername(0, (struct sockaddr *)&sun, &slen) ||
268 sun.sun_family != AF_UNIX)
269 die(EXIT_FAILURE, "please do not run this program again.");
272 if (pc_getuint(&rq)) {
273 if (errno == -1) break;
274 else lose("read (main)");
279 if (pc_getstring(&d)) lose("read (tunnel)");
280 for (t = tunnels;; t++) {
281 if (!t->name) lose("unknown tunnel");
282 if (strcmp(d.buf, t->name) == 0) break;
285 "privsep: received request for %s tunnel",
287 if ((fd = t->open(&ifn)) < 0)
290 n = fdpass_send(pc_fd, fd, &rq, sizeof(rq)); close(fd);
291 if (n < 0) { xfree(ifn); goto err; }
292 else if (n < sizeof(rq)) lose("partial write (fd-pass)");
293 if (pc_putstring(ifn)) lose("write (ifname)");
297 if (pc_putuint(PS_TUNERR) || pc_puterr(errno)) lose("write (error)");
307 /*----- That's all, folks -------------------------------------------------*/