2 * Copyright (C) 2012 Tobias Brunner
3 * Hochschule fuer Technik Rapperswil
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19 #include <sys/types.h>
24 #include <sys/prctl.h>
31 #include <utils/backtrace.h>
32 #include <threading/thread.h>
34 #include <nm/nm_backend.h>
37 * Hook in library for debugging messages
39 extern void (*dbg
) (debug_t group
, level_t level
, char *fmt
, ...);
42 * Simple logging hook for library logs, using syslog output
44 static void dbg_syslog(debug_t group
, level_t level
, char *fmt
, ...)
48 char buffer
[8192], groupstr
[4];
52 /* write in memory buffer first */
53 vsnprintf(buffer
, sizeof(buffer
), fmt
, args
);
54 /* cache group name */
55 snprintf(groupstr
, sizeof(groupstr
), "%N", debug_names
, group
);
56 syslog(LOG_DAEMON
|LOG_INFO
, "00[%s] %s", groupstr
, buffer
);
62 * Run the daemon and handle unix signals
68 /* handle SIGINT and SIGTERM in this handler */
70 sigaddset(&set
, SIGINT
);
71 sigaddset(&set
, SIGTERM
);
72 sigprocmask(SIG_BLOCK
, &set
, NULL
);
79 error
= sigwait(&set
, &sig
);
82 DBG1(DBG_DMN
, "error %d while waiting for a signal", error
);
89 DBG1(DBG_DMN
, "signal of type SIGINT received. Shutting down");
90 charon
->bus
->alert(charon
->bus
, ALERT_SHUTDOWN_SIGNAL
, sig
);
95 DBG1(DBG_DMN
, "signal of type SIGTERM received. Shutting down");
96 charon
->bus
->alert(charon
->bus
, ALERT_SHUTDOWN_SIGNAL
, sig
);
101 DBG1(DBG_DMN
, "unknown signal %d received. Ignored", sig
);
109 * Handle SIGSEGV/SIGILL signals raised by threads
111 static void segv_handler(int signal
)
113 backtrace_t
*backtrace
;
115 DBG1(DBG_DMN
, "thread %u received %d", thread_current_id(), signal
);
116 backtrace
= backtrace_create(2);
117 backtrace
->log(backtrace
, stderr
, TRUE
);
118 backtrace
->destroy(backtrace
);
120 DBG1(DBG_DMN
, "killing ourself, received critical signal");
125 * Initialize logging to syslog
127 static void initialize_logger()
129 sys_logger_t
*sys_logger
;
133 sys_logger
= sys_logger_create(LOG_DAEMON
, FALSE
);
134 def
= lib
->settings
->get_int(lib
->settings
,
135 "charon-nm.syslog.default", 1);
136 for (group
= 0; group
< DBG_MAX
; group
++)
138 sys_logger
->set_level(sys_logger
, group
,
139 lib
->settings
->get_int(lib
->settings
, "charon-nm.syslog.%N", def
,
140 debug_lower_names
, group
));
142 charon
->sys_loggers
->insert_last(charon
->sys_loggers
, sys_logger
);
143 charon
->bus
->add_logger(charon
->bus
, &sys_logger
->logger
);
149 static bool lookup_uid_gid()
154 struct passwd passwd
, *pwp
;
156 if (getpwnam_r(IPSEC_USER
, &passwd
, buf
, sizeof(buf
), &pwp
) != 0 ||
159 DBG1(DBG_DMN
, "resolving user '"IPSEC_USER
"' failed");
162 charon
->uid
= pwp
->pw_uid
;
168 struct group group
, *grp
;
170 if (getgrnam_r(IPSEC_GROUP
, &group
, buf
, sizeof(buf
), &grp
) != 0 ||
173 DBG1(DBG_DMN
, "resolving group '"IPSEC_GROUP
"' failed");
176 charon
->gid
= grp
->gr_gid
;
183 * Drop process capabilities
185 static bool drop_capabilities()
188 prctl(PR_SET_KEEPCAPS
, 1, 0, 0, 0);
191 if (setgid(charon
->gid
) != 0)
193 DBG1(DBG_DMN
, "change to unprivileged group failed");
196 if (setuid(charon
->uid
) != 0)
198 DBG1(DBG_DMN
, "change to unprivileged user failed");
201 if (!charon
->drop_capabilities(charon
))
203 DBG1(DBG_DMN
, "unable to drop daemon capabilities");
210 * Main function, starts NetworkManager backend.
212 int main(int argc
, char *argv
[])
214 struct sigaction action
;
215 int status
= SS_RC_INITIALIZATION_FAILED
;
217 /* logging for library during initialization, as we have no bus yet */
220 /* initialize library */
221 if (!library_init(NULL
))
224 exit(SS_RC_LIBSTRONGSWAN_INTEGRITY
);
227 if (lib
->integrity
&&
228 !lib
->integrity
->check_file(lib
->integrity
, "charon-nm", argv
[0]))
230 dbg_syslog(DBG_DMN
, 1, "integrity check of charon-nm failed");
232 exit(SS_RC_DAEMON_INTEGRITY
);
235 if (!libhydra_init("charon-nm"))
237 dbg_syslog(DBG_DMN
, 1, "initialization failed - aborting charon-nm");
240 exit(SS_RC_INITIALIZATION_FAILED
);
243 if (!libcharon_init("charon-nm"))
245 dbg_syslog(DBG_DMN
, 1, "initialization failed - aborting charon-nm");
249 if (!lookup_uid_gid())
251 dbg_syslog(DBG_DMN
, 1, "invalid uid/gid - aborting charon-nm");
257 DBG1(DBG_DMN
, "Starting charon NetworkManager backend (strongSwan "VERSION
")");
260 DBG1(DBG_DMN
, "integrity tests enabled:");
261 DBG1(DBG_DMN
, "lib 'libstrongswan': passed file and segment integrity tests");
262 DBG1(DBG_DMN
, "lib 'libhydra': passed file and segment integrity tests");
263 DBG1(DBG_DMN
, "lib 'libcharon': passed file and segment integrity tests");
264 DBG1(DBG_DMN
, "daemon 'charon-nm': passed file integrity test");
267 /* register NM backend to be loaded with plugins */
268 nm_backend_register();
270 /* initialize daemon */
271 if (!charon
->initialize(charon
,
272 lib
->settings
->get_str(lib
->settings
, "charon-nm.load", PLUGINS
)))
274 DBG1(DBG_DMN
, "initialization failed - aborting charon-nm");
278 if (!drop_capabilities())
280 DBG1(DBG_DMN
, "capability dropping failed - aborting charon-nm");
284 /* add handler for SEGV and ILL,
285 * INT and TERM are handled by sigwait() in run() */
286 action
.sa_handler
= segv_handler
;
288 sigemptyset(&action
.sa_mask
);
289 sigaddset(&action
.sa_mask
, SIGINT
);
290 sigaddset(&action
.sa_mask
, SIGTERM
);
291 sigaction(SIGSEGV
, &action
, NULL
);
292 sigaction(SIGILL
, &action
, NULL
);
293 sigaction(SIGBUS
, &action
, NULL
);
294 action
.sa_handler
= SIG_IGN
;
295 sigaction(SIGPIPE
, &action
, NULL
);
297 pthread_sigmask(SIG_SETMASK
, &action
.sa_mask
, NULL
);
299 /* start daemon (i.e. the threads in the thread-pool) */
300 charon
->start(charon
);
302 /* main thread goes to run loop */