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 | * | |
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 | ||
34 | static pid_t kid = -1; | |
e533c005 | 35 | static 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 | ||
49 | int 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 | } | |
108 | done: | |
109 | dstr_destroy(&d); | |
110 | return (fd); | |
111 | ||
112 | readlose: | |
113 | a_warn("PRIVSEP", "helper-read-error", "?ERRNO", A_END); | |
114 | lose: | |
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 | 132 | static 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 | ||
173 | void 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 | ||
216 | void ps_quit(void) { if (pc_fd != -1) close(pc_fd); } | |
217 | ||
218 | /*----- That's all, folks -------------------------------------------------*/ |