chiark / gitweb /
Use the new `mLib' annotations on varargs functions.
[tripe] / priv / helper.c
CommitLineData
388e0319
MW
1/* -*-c-*-
2 *
3 * Privilege-separated helper
4 *
5 * (c) 2008 Straylight/Edgeware
6 */
7
8/*----- Licensing notice --------------------------------------------------*
9 *
10 * This file is part of Trivial IP Encryption (TrIPE).
11 *
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.
16 *
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.
21 *
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.
25 */
26
27/*----- Header files ------------------------------------------------------*/
28
29#include "priv.h"
30
31/*----- Helper-side utilities ---------------------------------------------*/
32
33/* --- @lose@ --- *
34 *
35 * Arguments: @const char *excuse@ = what went wrong
36 *
37 * Returns: Doesn't.
38 *
39 * Use: Reports a fatal error and quits.
40 */
41
42static void lose(const char *excuse)
43{
44 moan("helper process bailing out: %s; error: %s",
45 excuse,
46 errno == -1 ? "Unexpected EOF" : strerror(errno));
47 _exit(127);
48}
49
50/*----- Diagnostic functions ----------------------------------------------*/
51
dd68bf2e 52/* --- @itrace@ --- *
388e0319
MW
53 *
54 * Arguments: @unsigned mask@ = trace mask to check
55 * @const char *fmt@ = message format
56 * @...@ = values for placeholders
57 *
58 * Returns: ---
59 *
60 * Use: Writes a trace message.
61 */
62
63#ifndef NTRACE
64
ddb384f1 65static void PRINTF_LIKE(2, 3) itrace(unsigned mask, const char *fmt, ...)
388e0319
MW
66{
67 va_list ap;
68 dstr d = DSTR_INIT;
69
70 va_start(ap, fmt);
71 dstr_vputf(&d, fmt, &ap);
72 if (pc_putuint(PS_TRACE) ||
73 pc_putuint(mask) ||
74 pc_putsz(d.len) ||
75 pc_put(d.buf, d.len))
76 lose("write (trace)");
77 va_end(ap);
78 dstr_destroy(&d);
79}
80
81#endif
82
83/* --- @warn@ --- *
84 *
85 * Arguments: @const char *fmt@ = message format
86 * @...@ = values for placeholders
87 *
88 * Returns: ---
89 *
90 * Use: Writes a warning message.
91 */
92
93#define A_END ((char *)0)
94
ddb384f1 95static void EXECL_LIKE(0) IGNORABLE warn(const char *fmt, ...)
388e0319
MW
96{
97 va_list ap;
98 dstr d = DSTR_INIT, dd = DSTR_INIT;
99
100 va_start(ap, fmt);
101 while (fmt) {
102 if (*fmt == '?') {
103 if (strcmp(fmt, "?ERRNO") == 0) {
104 dstr_putf(&d, " E%d", errno);
105 u_quotify(&d, strerror(errno));
106 } else
107 abort();
108 } else {
109 DRESET(&dd);
110 dstr_vputf(&dd, fmt, &ap);
111 u_quotify(&d, dd.buf);
112 }
113 fmt = va_arg(ap, const char *);
114 }
115 va_end(ap);
116
117 if (pc_putuint(PS_WARN) ||
118 pc_putsz(d.len) ||
119 pc_put(d.buf, d.len))
120 lose("write (warn)");
121
122 dstr_destroy(&d);
123 dstr_destroy(&dd);
124}
125
126/*----- Tunnel drivers ----------------------------------------------------*/
127
128/* --- @topen_DRIVER@ --- *
129 *
130 * Arguments: @char **ifn@ = where to put the interface name
131 *
132 * Returns: A file descriptor, or @-1@ on failure.
133 *
134 * Use: Opens a tunnel device.
135 */
136
137#ifdef TUN_LINUX
138
139#include <sys/ioctl.h>
140#include <linux/if.h>
141#include <linux/if_tun.h>
142
143static int topen_linux(char **ifn)
144{
145 int fd;
146 struct ifreq iff;
147
148 if ((fd = open("/dev/net/tun", O_RDWR)) < 0) {
149 warn("TUN", "-", "linux",
150 "open-error", "/dev/net/tun", "?ERRNO",
151 A_END);
152 return (-1);
153 }
154 memset(&iff, 0, sizeof(iff));
155 iff.ifr_name[0] = 0;
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);
159 close(fd);
160 return (-1);
161 }
162 iff.ifr_name[IFNAMSIZ - 1] = 0;
163 *ifn = xstrdup(iff.ifr_name);
164 return (fd);
165}
166
167#endif
168
169#ifdef TUN_BSD
170
171static int topen_bsd(char **ifn)
172{
173 int fd;
174 unsigned n;
175 char buf[16];
176
177 n = 0;
178 for (;;) {
179 sprintf(buf, "/dev/tun%u", n);
180 if ((fd = open(buf, O_RDWR)) >= 0)
181 break;
182 switch (errno) {
183 case EBUSY:
184 T( itrace(T_PRIVSEP, "tunnel device %u busy: skipping", n); )
185 break;
186 case ENOENT:
187 warn("TUN", "-", "bsd", "no-tunnel-devices", A_END);
188 return (-1);
189 default:
190 warn("TUN", "-", "open-error", "%s", buf, "?ERRNO", A_END);
191 break;
192 }
193 n++;
194 }
195 return (fd);
196}
197
198#endif
199
200#ifdef TUN_UNET
201
202#include <sys/ioctl.h>
203#include <linux/if.h>
204#include <unet.h>
205
206static int topen_unet(char **ifn)
207{
208 int fd;
209 int f;
210 struct unet_info uni;
211
212 if ((fd = open("/dev/unet", O_RDWR)) < 0) {
213 warn("TUN", "-", "unet", "open-error", "/dev/unet", "?ERRNO", A_END);
214 goto fail_0;
215 }
216 if ((f = ioctl(fd, UNIOCGIFFLAGS)) < 0 ||
217 ioctl(fd, UNIOCSIFFLAGS, f | IFF_POINTOPOINT)) {
218 warn("TUN", "-", "unet", "config-error", "?ERRNO", A_END);
219 goto fail_1;
220 }
221 if (ioctl(fd, UNIOCGINFO, &uni)) {
222 warn("TUN", "-", "unet", "getinfo-error", "?ERRNO", A_END);
223 goto fail_1;
224 }
225 *ifn = xstrdup(uni.uni_ifname);
226 return (fd);
227
228fail_1:
229 close(fd);
230fail_0:
231 return (-1);
232}
233
234#endif
235
236static const struct tunnel {
237 const char *name;
238 int (*open)(char **);
239} tunnels[] = {
240#ifdef TUN_LINUX
241 { "linux", topen_linux },
242#endif
243#ifdef TUN_BSD
244 { "bsd", topen_bsd },
245#endif
246#ifdef TUN_UNET
247 { "unet", topen_unet },
248#endif
249 { 0, 0 }
250};
251
252/*----- Helper process core -----------------------------------------------*/
253
254int main(int argc, char *argv[])
255{
256 struct sockaddr_un sun;
257 socklen_t slen = sizeof(sun);
258 unsigned rq;
259 dstr d = DSTR_INIT;
260 const struct tunnel *t;
261 char *ifn = 0;
262 int fd;
263 ssize_t n;
264
265 ego(argv[0]);
266 if (argc != 1 ||
267 getpeername(0, (struct sockaddr *)&sun, &slen) ||
268 sun.sun_family != AF_UNIX)
269 die(EXIT_FAILURE, "please do not run this program again.");
270
271 for (;;) {
272 if (pc_getuint(&rq)) {
273 if (errno == -1) break;
274 else lose("read (main)");
275 }
276 switch (rq) {
277 case PS_TUNRQ:
278 DRESET(&d);
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;
283 }
284 T( itrace(T_PRIVSEP,
285 "privsep: received request for %s tunnel",
286 t->name); )
287 if ((fd = t->open(&ifn)) < 0)
288 goto err;
289 rq = PS_TUNFD;
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)");
294 xfree(ifn);
295 break;
296 err:
297 if (pc_putuint(PS_TUNERR) || pc_puterr(errno)) lose("write (error)");
298 break;
299 default:
300 lose("bad request");
301 break;
302 }
303 }
304 _exit(0);
305}
306
307/*----- That's all, folks -------------------------------------------------*/