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 -------------------------------------------------*/