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