chiark / gitweb /
server/tripe.h: Allow `break' from FOREACH_PEER.
[tripe] / server / privsep.c
CommitLineData
388e0319
MW
1/* -*-c-*-
2 *
3 * Privilege separation communication protocol
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 "tripe.h"
30#include "priv.h"
31
32/*----- Static variables --------------------------------------------------*/
33
34static pid_t kid = -1;
e533c005 35static sig sig_chld;
388e0319
MW
36
37/*----- Fetching a tunnel file descriptor ---------------------------------*/
38
39/* --- @ps_tunfd@ --- *
40 *
41 * Arguments: @const tunnel_ops *tops@ = pointer to tunnel operations
42 * @char **ifn@ = where to put the interface name
43 *
44 * Returns: The file descriptor, or @-1@ on error.
45 *
46 * Use: Fetches a file descriptor for a tunnel driver.
47 */
48
49int ps_tunfd(const tunnel_ops *tops, char **ifn)
50{
51 unsigned code;
52 ssize_t n;
53 dstr d = DSTR_INIT;
54 int fd;
55
56 if (pc_fd == -1) {
57 a_warn("PRIVSEP", "helper-died", A_END);
58 return (-1);
59 }
60 T( trace(T_PRIVSEP,
61 "privsep: requesting descriptor for %s tunnel",
62 tops->name); )
63 if (pc_putuint(PS_TUNRQ) || pc_putstring(tops->name)) {
64 a_warn("PRIVSEP", "helper-write-error", "?ERRNO", A_END);
65 goto lose;
66 }
67 for (;;) {
68 n = fdpass_recv(pc_fd, &fd, &code, sizeof(code));
69 if (n < 0) goto readlose;
70 if (n < sizeof(code)) {
71 a_warn("PRIVSEP", "helper-short-read", A_END);
72 goto lose;
73 }
74 switch (code) {
75 case PS_TUNFD:
76 if (fd == -1) {
77 a_warn("PRIVSEP", "no-fd-from-helper", A_END);
78 goto lose;
79 }
80 if (pc_getstring(&d)) { close(fd); goto readlose; }
81 *ifn = xstrdup(d.buf);
82 T( trace(T_PRIVSEP,
83 "privsep: received winning descriptor for %s",
84 *ifn); )
85 goto done;
86 case PS_TUNERR:
87 if (pc_geterr(&errno)) goto readlose;
88 T( trace(T_PRIVSEP, "privsep: helper lost: %s", strerror(errno)); )
89 fd = -1;
90 goto done;
91#ifndef NTRACE
92 case PS_TRACE:
93 if (pc_getuint(&code) || pc_getstring(&d)) goto readlose;
94 trace(code, "%s", d.buf);
95 DRESET(&d);
96 break;
97#endif
98 case PS_WARN:
99 if (pc_getstring(&d)) goto readlose;
100 a_warn("*%s", d.buf, A_END);
101 DRESET(&d);
102 break;
103 default:
104 a_warn("PRIVSEP", "unknown-response-code", "%u", code, A_END);
105 goto lose;
106 }
107 }
108done:
109 dstr_destroy(&d);
110 return (fd);
111
112readlose:
113 a_warn("PRIVSEP", "helper-read-error", "?ERRNO", A_END);
114lose:
115 dstr_destroy(&d);
116 close(pc_fd);
117 pc_fd = -1;
118 return (-1);
119}
120
121/*----- Main code ---------------------------------------------------------*/
122
123/* --- @reap@ --- *
124 *
125 * Arguments: @int sig@ = signal number (always @SIGCHLD@; ignored)
126 *
127 * Returns: ---
128 *
129 * Use: Notices and reports child process death.
130 */
131
e533c005 132static void reap(int sig, void *p)
388e0319
MW
133{
134 pid_t k;
135 int st;
136
137 for (;;) {
138 k = waitpid(-1, &st, WNOHANG);
139 if (k < 0) {
140 switch (errno) {
141 case EINTR:
142 break;
143 default:
144 a_warn("SERVER", "waitpid-error", "?ERRNO", A_END);
145 case ECHILD:
146 return;
147 }
148 }
149 if (!k)
150 return;
151 if (k == kid) {
152 if (WIFEXITED(st))
153 a_warn("PRIVSEP", "child-exited", "%d", WEXITSTATUS(st), A_END);
154 else if (WIFSIGNALED(st))
155 a_warn("PRIVSEP", "child-killed", "%d", WTERMSIG(st), A_END);
156 else
157 a_warn("PRIVSEP", "child-died", "%d", st, A_END);
158 kid = -1;
159 }
160 }
161}
162
163/* --- @ps_split@ --- *
164 *
165 * Arguments: @int detachp@ = whether to detach the child from its terminal
166 *
167 * Returns: ---
168 *
169 * Use: Separates off the privileged tunnel-opening service from the
170 * rest of the server.
171 */
172
173void ps_split(int detachp)
174{
175 pid_t kid;
176 int fd[2];
b9537f3b 177 mdup_fd md[1];
388e0319
MW
178 const char *helper;
179
180 if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd)) {
181 die(EXIT_FAILURE,
182 "failed to create socket pair for privilege separation: %s",
183 strerror(errno));
184 }
185 helper = getenv("TRIPE_PRIVHELPER");
186 if (!helper) helper = PRIVSEP_HELPER;
187 fdflags(fd[0], 0, 0, FD_CLOEXEC, FD_CLOEXEC);
188 fdflags(fd[1], 0, 0, FD_CLOEXEC, FD_CLOEXEC);
e533c005 189 sig_add(&sig_chld, SIGCHLD, reap, 0);
388e0319
MW
190 kid = fork();
191 if (kid == 0) {
192 signal(SIGCHLD, SIG_DFL);
193 if (detachp) detachtty();
b9537f3b
MW
194 close(fd[1]);
195 md[0].cur = fd[0]; md[0].want = STDIN_FILENO;
196 if (mdup(md, 1)) goto lose;
388e0319
MW
197 execl(helper, helper, (char *)0);
198 lose:
199 fprintf(stderr, "helper: failed to run helper: %s\n", strerror(errno));
200 _exit(127);
201 }
202 T( trace(T_PRIVSEP, "privsep: forked child successfully"); )
203 close(fd[0]);
204 pc_fd = fd[1];
205}
206
207/* --- @ps_quit@ --- *
208 *
209 * Arguments: ---
210 *
211 * Returns: ---
212 *
213 * Use: Detaches from the helper process.
214 */
215
216void ps_quit(void) { if (pc_fd != -1) close(pc_fd); }
217
218/*----- That's all, folks -------------------------------------------------*/