ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/gvpe/src/util.C
Revision: 1.27
Committed: Wed Jul 17 16:40:57 2013 UTC (10 years, 10 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.26: +16 -0 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 pcg 1.1 /*
2     util.C -- process management and other utility functions
3 root 1.25 Copyright (C) 2003-2011 Marc Lehmann <gvpe@schmorp.de>
4 pcg 1.1
5 pcg 1.3 Some of these are taken from tinc, see the AUTHORS file.
6 pcg 1.1
7 pcg 1.16 This file is part of GVPE.
8    
9 pcg 1.22 GVPE is free software; you can redistribute it and/or modify it
10     under the terms of the GNU General Public License as published by the
11     Free Software Foundation; either version 3 of the License, or (at your
12     option) any later version.
13    
14     This program is distributed in the hope that it will be useful, but
15     WITHOUT ANY WARRANTY; without even the implied warranty of
16     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
17     Public License for more details.
18    
19     You should have received a copy of the GNU General Public License along
20     with this program; if not, see <http://www.gnu.org/licenses/>.
21    
22     Additional permission under GNU GPL version 3 section 7
23    
24     If you modify this Program, or any covered work, by linking or
25     combining it with the OpenSSL project's OpenSSL library (or a modified
26     version of that library), containing parts covered by the terms of the
27     OpenSSL or SSLeay licenses, the licensors of this Program grant you
28     additional permission to convey the resulting work. Corresponding
29     Source for a non-source form of such a combination shall include the
30     source code for the parts of OpenSSL used as well as that of the
31     covered work.
32 pcg 1.1 */
33    
34     #include "config.h"
35    
36     #include <cstdio>
37 pcg 1.12 #include <cstdlib>
38 pcg 1.1 #include <cstring>
39    
40 root 1.25 #include <queue>
41    
42 pcg 1.1 #include <errno.h>
43     #include <signal.h>
44     #include <sys/types.h>
45 pcg 1.4 #include <sys/wait.h>
46 pcg 1.1 #include <unistd.h>
47     #include <time.h>
48    
49 root 1.25 #if ENABLE_PTHREADS
50     # include <pthread.h>
51     #endif
52    
53 root 1.27 #include <openssl/rand.h>
54    
55 pcg 1.8 #include "netcompat.h"
56 pcg 1.1
57 pcg 1.18 #include "gettext.h"
58 pcg 1.1 #include "pidfile.h"
59     #include "dropin.h"
60    
61     #include "global.h"
62     #include "conf.h"
63 pcg 1.5 #include "util.h"
64 pcg 1.1 #include "slog.h"
65    
66     int
67     write_pidfile (void)
68     {
69     int pid;
70    
71 pcg 1.13 pid = check_pid (conf.pidfilename);
72 pcg 1.1
73     if (pid)
74     {
75 pcg 1.15 fprintf (stderr, _("A gvpe daemon is already running with pid %d.\n"), pid);
76 pcg 1.1 return 1;
77     }
78    
79     /* if it's locked, write-protected, or whatever */
80 pcg 1.13 if (!write_pid (conf.pidfilename))
81 pcg 1.1 return 1;
82    
83     return 0;
84     }
85    
86     int
87     kill_other (int signal)
88     {
89     int pid;
90    
91 pcg 1.13 pid = read_pid (conf.pidfilename);
92 pcg 1.1
93     if (!pid)
94     {
95 pcg 1.15 fprintf (stderr, _("No other gvpe daemon is running.\n"));
96 pcg 1.1 return 1;
97     }
98    
99     errno = 0; /* No error, sometimes errno is only changed on error */
100    
101     /* ESRCH is returned when no process with that pid is found */
102     if (kill (pid, signal) && errno == ESRCH)
103     {
104 pcg 1.15 fprintf (stderr, _("The gvpe daemon is no longer running. "));
105 pcg 1.1
106     fprintf (stderr, _("Removing stale lock file.\n"));
107 pcg 1.13 remove_pid (conf.pidfilename);
108 pcg 1.1 }
109    
110     return 0;
111     }
112    
113     int
114     detach (int do_detach)
115     {
116     /* First check if we can open a fresh new pidfile */
117    
118     if (write_pidfile ())
119     return -1;
120    
121     /* If we succeeded in doing that, detach */
122    
123     log_to (0);
124    
125     if (do_detach)
126     {
127     if (daemon (0, 0) < 0)
128     {
129     log_to (LOGTO_SYSLOG | LOGTO_STDERR);
130    
131     slog (L_ERR, _("couldn't detach from terminal: %s"), strerror (errno));
132     return -1;
133     }
134    
135     /* Now UPDATE the pid in the pidfile, because we changed it... */
136    
137 pcg 1.13 if (!write_pid (conf.pidfilename))
138 pcg 1.1 return -1;
139    
140     log_to (LOGTO_SYSLOG);
141     }
142     else
143     log_to (LOGTO_SYSLOG | LOGTO_STDERR);
144    
145 pcg 1.24 slog (L_INFO, _("gvpe daemon %s (%s %s) starting up."), VERSION, __DATE__, __TIME__);
146 pcg 1.1
147     return 0;
148     }
149    
150 root 1.25 /*****************************************************************************/
151    
152 pcg 1.23 pid_t
153     run_script (const run_script_cb &cb, bool wait)
154 pcg 1.4 {
155 pcg 1.23 sigset_t oldset;
156    
157 pcg 1.20 if (wait)
158 pcg 1.23 {
159     sigset_t sigchld;
160     sigemptyset (&sigchld);
161     sigaddset (&sigchld, SIGCHLD);
162     sigprocmask (SIG_BLOCK, &sigchld, &oldset);
163     }
164 pcg 1.4
165 pcg 1.23 pid_t pid = fork ();
166 pcg 1.20
167     if (pid == 0)
168 pcg 1.4 {
169 pcg 1.23 sigprocmask (SIG_SETMASK, &oldset, 0);
170    
171 pcg 1.19 execl ("/bin/sh", "/bin/sh", "-c", cb (), (char *) 0);
172     exit (EXIT_FAILURE);
173 pcg 1.4 }
174     else if (pid > 0)
175     {
176     if (wait)
177     {
178 pcg 1.19 int status;
179 pcg 1.20 int res = waitpid (pid, &status, 0);
180    
181 pcg 1.23 sigprocmask (SIG_SETMASK, &oldset, 0);
182 pcg 1.19
183 pcg 1.20 if (res < 0)
184 pcg 1.19 {
185     slog (L_WARN, _("waiting for an external command failed: %s."),
186     strerror (errno));
187 pcg 1.23 return 0;
188 pcg 1.19 }
189     else if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS)
190     {
191     slog (L_WARN, _("external command returned with exit status %d (%04x)."),
192     WEXITSTATUS (status), status);
193 pcg 1.23 return 0;
194 pcg 1.19 }
195 pcg 1.4 }
196     }
197 pcg 1.20 else
198     {
199     slog (L_ERR, _("unable to fork, exiting: %s"), strerror (errno));
200     exit (EXIT_FAILURE);
201     }
202 pcg 1.19
203 pcg 1.23 return pid;
204 pcg 1.4 }
205 pcg 1.7
206 root 1.25 /*****************************************************************************/
207    
208     #if 0 /* not yet used */
209    
210     #if ENABLE_PTHREADS
211     struct async_cb
212     {
213     callback<void ()> work_cb;
214     callback<void ()> done_cb;
215     };
216    
217     static ev::async async_done_w;
218     static std::queue< callback<void ()> > async_q;
219    
220     static callback<void ()> work_cb;
221    
222     static void *
223     async_exec (void *)
224     {
225     work_cb ();
226     async_done_w.send ();
227    
228     return 0;
229     }
230    
231     static void
232     async_q_next ()
233     {
234     work_cb = async_q.front (); async_q.pop ();
235    
236     sigset_t fullsigset, oldsigset;
237     pthread_attr_t attr;
238     pthread_t tid;
239    
240     pthread_attr_init (&attr);
241     pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
242     //pthread_attr_setstacksize (&attr, PTHREAD_STACK_MIN < X_STACKSIZE ? X_STACKSIZE : PTHREAD_STACK_MIN);
243     sigfillset (&fullsigset);
244     pthread_sigmask (SIG_SETMASK, &fullsigset, &oldsigset);
245    
246     if (pthread_create (&tid, &attr, async_exec, 0))
247     async_exec (0);
248    
249     pthread_sigmask (SIG_SETMASK, &oldsigset, 0);
250     pthread_attr_destroy (&attr);
251     }
252    
253     namespace {
254     void
255     async_done (ev::async &w, int revents)
256     {
257     callback<void ()> done_cb = async_q.front (); async_q.pop ();
258    
259     if (async_q.empty ())
260     async_done_w.stop ();
261     else
262     async_q_next ();
263    
264     done_cb ();
265     }
266     };
267    
268     void
269     async (callback<void ()> work_cb, callback<void ()> done_cb)
270     {
271     bool was_empty = async_q.empty ();
272    
273     async_q.push (work_cb);
274     async_q.push (done_cb);
275    
276     if (was_empty)
277     {
278     async_done_w.set<async_done> ();
279     async_done_w.start ();
280     async_q_next ();
281     }
282     }
283    
284     #else
285    
286     void
287     async (callback<void ()> work_cb, callback<void ()> done_cb)
288     {
289     work_cb ();
290     done_cb ();
291     }
292    
293     #endif
294    
295     #endif
296    
297     /*****************************************************************************/
298    
299 root 1.26 void hexdump (const char *header, void *data, int len)
300     {
301     u8 *p = (u8 *)data;
302    
303     printf ("%s:", header);
304    
305     while (len--)
306     printf (" %02x", *p++);
307    
308     printf ("\n");
309     }
310    
311     /*****************************************************************************/
312    
313 pcg 1.7 #if ENABLE_HTTP_PROXY
314     // works like strdup
315     u8 *
316     base64_encode (const u8 *data, unsigned int len)
317     {
318     const static char base64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
319    
320     unsigned int t, i;
321     const u8 *end = data + len;
322     u8 *res = new u8 [4 * ((len + 2) / 3) + 1];
323     u8 *out = res;
324    
325     while (data <= end - 3)
326     {
327     t = (((data[0] << 8) | data[1]) << 8) | data[2];
328     data += 3;
329    
330     *out++ = base64[(t >> 18) & 0x3f];
331     *out++ = base64[(t >> 12) & 0x3f];
332     *out++ = base64[(t >> 6) & 0x3f];
333     *out++ = base64[(t ) & 0x3f];
334     }
335    
336     for (t = 0, i = 0; data < end; i++)
337     t = (t << 8) | *data++;
338    
339     switch (i)
340     {
341     case 2:
342     *out++ = base64[(t >> 10) & 0x3f];
343     *out++ = base64[(t >> 4) & 0x3f];
344     *out++ = base64[(t << 2) & 0x3f];
345     *out++ = '=';
346     break;
347     case 1:
348     *out++ = base64[(t >> 2) & 0x3f];
349     *out++ = base64[(t << 4) & 0x3f];
350     *out++ = '=';
351     *out++ = '=';
352     break;
353     }
354    
355     *out++ = 0;
356    
357     return res;
358     }
359     #endif
360    
361 pcg 1.10 void
362     id2mac (unsigned int id, void *m)
363     {
364     mac &p = *(mac *)m;
365    
366     if (id)
367     {
368     p[0] = 0xfe;
369     p[1] = 0xfd;
370     p[2] = 0x80;
371     p[3] = 0x00;
372     p[4] = id >> 8;
373     p[5] = id;
374     }
375     else
376     {
377     p[0] = 0xff;
378     p[1] = 0xff;
379     p[2] = 0xff;
380     p[3] = 0xff;
381     p[4] = 0xff;
382     p[5] = 0xff;
383     }
384     }
385    
386 root 1.27 /*****************************************************************************/
387    
388     void rand_fill (void *data, int len)
389     {
390     int l = RAND_bytes ((unsigned char *)data, len);
391    
392     if (l > 0)
393     return;
394     else if (l == 0)
395     slog (L_WARN, _("Not enough random entropy to generate secure keys. Using weaker pseudo-random session keys."));
396     else
397     fatal (_("RAND_bytes failed, aborting."));
398     }
399