chiark / gitweb /
Manpages: Fix substitutions.
[tripe] / server / privsep.c
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;
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
131 static void reap(int sig)
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];
176   const char *helper;
177
178   if (socketpair(PF_UNIX, SOCK_STREAM, 0, fd)) {
179     die(EXIT_FAILURE,
180         "failed to create socket pair for privilege separation: %s",
181         strerror(errno));
182   }
183   helper = getenv("TRIPE_PRIVHELPER");
184   if (!helper) helper = PRIVSEP_HELPER;
185   fdflags(fd[0], 0, 0, FD_CLOEXEC, FD_CLOEXEC);
186   fdflags(fd[1], 0, 0, FD_CLOEXEC, FD_CLOEXEC);
187   signal(SIGCHLD, reap);
188   kid = fork();
189   if (kid == 0) {
190     signal(SIGCHLD, SIG_DFL);
191     if (detachp) detachtty();
192     if (dup2(fd[0], 0) < 0) goto lose;
193     close(fd[0]); close(fd[1]);
194     execl(helper, helper, (char *)0);
195   lose:
196     fprintf(stderr, "helper: failed to run helper: %s\n", strerror(errno));
197     _exit(127);
198   }
199   T( trace(T_PRIVSEP, "privsep: forked child successfully"); )
200   close(fd[0]);
201   pc_fd = fd[1];
202 }
203
204 /* --- @ps_quit@ --- *
205  *
206  * Arguments:   ---
207  *
208  * Returns:     ---
209  *
210  * Use:         Detaches from the helper process.
211  */
212
213 void ps_quit(void) { if (pc_fd != -1) close(pc_fd); }
214
215 /*----- That's all, folks -------------------------------------------------*/