1 : /*
2 : * miredo.c - Miredo common daemon functions
3 : * $Id: miredo.c 1938 2007-02-22 20:55:28Z remi $
4 : *
5 : * See "Teredo: Tunneling IPv6 over UDP through NATs"
6 : * for more information
7 : */
8 :
9 : /***********************************************************************
10 : * Copyright © 2004-2007 Rémi Denis-Courmont. *
11 : * This program is free software; you can redistribute and/or modify *
12 : * it under the terms of the GNU General Public License as published *
13 : * by the Free Software Foundation; version 2 of the license. *
14 : * *
15 : * This program is distributed in the hope that it will be useful, *
16 : * but WITHOUT ANY WARRANTY; without even the implied warranty of *
17 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. *
18 : * See the GNU General Public License for more details. *
19 : * *
20 : * You should have received a copy of the GNU General Public License *
21 : * along with this program; if not, you can get it from: *
22 : * http://www.gnu.org/copyleft/gpl.html *
23 : ***********************************************************************/
24 :
25 : #ifdef HAVE_CONFIG_H
26 : # include <config.h>
27 : #endif
28 :
29 : #include <gettext.h>
30 :
31 : #include <string.h> // memset(), strsignal()
32 : #include <stdlib.h> // exit()
33 : #include <inttypes.h>
34 : #include <stdbool.h>
35 : #include <stdarg.h>
36 :
37 : #include <pthread.h> // pthread_sigmask()
38 : #include <signal.h> // sigaction()
39 : #include <errno.h>
40 : #include <sys/types.h>
41 : #include <sys/socket.h>
42 : #include <syslog.h>
43 : #include <unistd.h> // uid_t
44 : #include <sys/wait.h> // waitpid()
45 : #ifdef HAVE_SYS_CAPABILITY_H
46 : # include <sys/capability.h>
47 : #endif
48 :
49 : #ifndef LOG_PERROR
50 : # define LOG_PERROR 0
51 : #endif
52 :
53 : #include "miredo.h"
54 : #include "conf.h"
55 :
56 : uid_t unpriv_uid = 0;
57 : const char *miredo_chrootdir = NULL;
58 :
59 : extern int
60 : drop_privileges (void)
61 0 : {
62 : /*
63 : * We could chroot earlier, but we do it know to keep compatibility with
64 : * grsecurity Linux kernel patch that automatically removes capabilities
65 : * when chrooted.
66 : */
67 0 : if ((miredo_chrootdir != NULL)
68 : && (chroot (miredo_chrootdir) || chdir ("/")))
69 : {
70 0 : syslog (LOG_ALERT, _("Error (%s): %s\n"),
71 : "chroot", strerror (errno));
72 0 : return -1;
73 : }
74 :
75 : // Definitely drops privileges
76 0 : if (setuid (unpriv_uid))
77 : {
78 0 : syslog (LOG_ALERT, _("Error (%s): %s\n"), "setuid", strerror (errno));
79 0 : return -1;
80 : }
81 :
82 : #ifdef HAVE_LIBCAP
83 0 : cap_t s = cap_init ();
84 0 : if (s != NULL)
85 : {
86 0 : cap_set_proc (s);
87 0 : cap_free (s);
88 : }
89 : #endif
90 0 : return 0;
91 : }
92 :
93 :
94 : /*
95 : * Configuration and respawning stuff
96 : */
97 : static void logger (void *dummy, bool error, const char *fmt, va_list ap)
98 0 : {
99 : (void)dummy;
100 :
101 0 : vsyslog (error ? LOG_ERR : LOG_WARNING, fmt, ap);
102 0 : }
103 :
104 :
105 : extern int
106 : miredo (const char *confpath, const char *server_name, int pidfd)
107 0 : {
108 0 : int facility = LOG_DAEMON, retval;
109 0 : openlog (miredo_name, LOG_PID | LOG_PERROR, facility);
110 :
111 0 : miredo_conf *cnf = miredo_conf_create (logger, NULL);
112 0 : if (cnf == NULL)
113 0 : return -1;
114 :
115 : sigset_t set, oldset;
116 0 : sigemptyset (&set);
117 :
118 0 : sigaddset (&set, SIGINT);
119 0 : sigaddset (&set, SIGQUIT);
120 0 : sigaddset (&set, SIGTERM);
121 0 : sigaddset (&set, SIGCHLD);
122 0 : sigset_t exit_set = set;
123 :
124 0 : sigaddset (&set, SIGHUP);
125 0 : sigset_t reload_set = set;
126 :
127 0 : sigaddset (&set, SIGPIPE);
128 :
129 0 : pthread_sigmask (SIG_BLOCK, &set, &oldset);
130 :
131 : do
132 : {
133 0 : retval = 1;
134 :
135 0 : if (!miredo_conf_read_file (cnf, confpath))
136 : {
137 0 : syslog (LOG_WARNING, _("Loading configuration from %s failed"),
138 : confpath);
139 : }
140 :
141 0 : int newfac = LOG_DAEMON;
142 0 : miredo_conf_parse_syslog_facility (cnf, "SyslogFacility", &newfac);
143 :
144 : // Apply syslog facility change if needed
145 0 : if (newfac != facility)
146 : {
147 0 : closelog ();
148 0 : facility = newfac;
149 0 : openlog (miredo_name, LOG_PID, facility);
150 : }
151 0 : syslog (LOG_INFO, _("Starting..."));
152 :
153 : // Starts the main miredo process
154 0 : pid_t pid = fork ();
155 :
156 0 : switch (pid)
157 : {
158 : case -1:
159 0 : syslog (LOG_ALERT, _("Error (%s): %s\n"), "fork",
160 : strerror (errno));
161 0 : continue;
162 :
163 : case 0:
164 0 : close (pidfd);
165 0 : retval = miredo_run (cnf, server_name);
166 0 : miredo_conf_destroy (cnf);
167 0 : closelog ();
168 0 : exit (-retval);
169 : break;
170 :
171 : default:
172 0 : miredo_conf_clear (cnf, 0);
173 : }
174 :
175 : // Waits until the miredo process terminates
176 0 : int val = 0, status;
177 0 : while (sigwait (&set, &val) || !sigismember (&reload_set, val));
178 :
179 0 : if (sigismember (&exit_set, val))
180 : {
181 0 : syslog (LOG_NOTICE, _("Exiting on signal %d (%s)"),
182 : val, strsignal (val));
183 0 : retval = 0;
184 : }
185 : else
186 : {
187 0 : syslog (LOG_NOTICE,
188 : _("Reloading configuration on signal %d (%s)"),
189 : val, strsignal (val));
190 0 : retval = 2;
191 : }
192 :
193 : /* Terminate children (if not already done) */
194 0 : if (val != SIGCHLD)
195 0 : kill (pid, SIGTERM);
196 0 : while (waitpid (pid, &status, 0) == -1);
197 :
198 0 : if (WIFEXITED (status))
199 : {
200 0 : val = WEXITSTATUS (status);
201 0 : syslog (LOG_NOTICE, _("Terminated (exit code: %d)"), val);
202 0 : if (val)
203 0 : retval = 1;
204 : }
205 : else
206 0 : if (WIFSIGNALED (status))
207 : {
208 0 : val = WTERMSIG (status);
209 0 : syslog (LOG_INFO, _("Child %d killed by signal %d (%s)"),
210 : (int)pid, val, strsignal (val));
211 0 : retval = 2;
212 : /* TODO: exponential restart delay */
213 : }
214 : }
215 0 : while (retval == 2);
216 :
217 0 : miredo_conf_destroy (cnf);
218 :
219 0 : syslog (LOG_INFO, gettext (retval
220 : ? N_("Terminated with error(s).")
221 : : N_("Terminated with no error.")));
222 :
223 0 : closelog ();
224 0 : return -retval;
225 : }
226 :
227 :
228 : int (*miredo_diagnose) (void);
229 : int (*miredo_run) (miredo_conf *conf, const char *server);
230 :
231 : const char *miredo_name;
232 :
233 : # ifdef HAVE_LIBCAP
234 : const cap_value_t *miredo_capv;
235 : int miredo_capc;
236 : # endif
237 :
|