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